Skip to content

Commit 94abd03

Browse files
committed
feat: make KoraLabsHandleProvider compliant with bitcoin
1 parent 07ac410 commit 94abd03

File tree

9 files changed

+133
-92
lines changed

9 files changed

+133
-92
lines changed

packages/cardano-services-client/src/HandleProvider/KoraLabsHandleProvider.ts

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -26,21 +26,23 @@ export interface KoraLabsHandleProviderDeps {
2626
policyId: Cardano.PolicyId;
2727
}
2828

29-
export const toHandleResolution = ({
30-
apiResponse,
31-
policyId
32-
}: {
33-
apiResponse: IHandle;
34-
policyId: Cardano.PolicyId;
35-
}): HandleResolution => ({
36-
backgroundImage: apiResponse.bg_image ? Asset.Uri(apiResponse.bg_image) : undefined,
37-
cardanoAddress: Cardano.PaymentAddress(apiResponse.resolved_addresses.ada),
38-
handle: apiResponse.name,
39-
hasDatum: apiResponse.has_datum,
40-
image: apiResponse.image ? Asset.Uri(apiResponse.image) : undefined,
41-
policyId,
42-
profilePic: apiResponse.pfp_image ? Asset.Uri(apiResponse.pfp_image) : undefined
43-
});
29+
export const toHandleResolution = ({ apiResponse, policyId }: { apiResponse: IHandle; policyId: Cardano.PolicyId }) => {
30+
const cardano = Cardano.PaymentAddress(apiResponse.resolved_addresses.ada);
31+
const result: HandleResolution = {
32+
addresses: { cardano },
33+
backgroundImage: apiResponse.bg_image ? Asset.Uri(apiResponse.bg_image) : undefined,
34+
cardanoAddress: cardano,
35+
handle: apiResponse.name,
36+
hasDatum: apiResponse.has_datum,
37+
image: apiResponse.image ? Asset.Uri(apiResponse.image) : undefined,
38+
policyId,
39+
profilePic: apiResponse.pfp_image ? Asset.Uri(apiResponse.pfp_image) : undefined
40+
};
41+
42+
if ('btc' in apiResponse.resolved_addresses) result.addresses.bitcoin = apiResponse.resolved_addresses.btc;
43+
44+
return result;
45+
};
4446

4547
/**
4648
* Creates a KoraLabs Provider instance to resolve Standard Handles

packages/cardano-services-client/test/util.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,21 +40,25 @@ export const getWrongHandleProviderResponse = {
4040
}
4141
};
4242

43+
const aliceCardanoAddress =
44+
'addr_test1qqk4sr4f7vtqzd2w90d5nfu3n59jhhpawyphnek2y7er02nkrezryq3ydtmkg0e7e2jvzg443h0ffzfwd09wpcxy2fuqmcnecd';
4345
export const getAliceHandleProviderResponse = {
46+
addresses: { cardano: aliceCardanoAddress },
4447
backgroundImage: undefined,
45-
cardanoAddress:
46-
'addr_test1qqk4sr4f7vtqzd2w90d5nfu3n59jhhpawyphnek2y7er02nkrezryq3ydtmkg0e7e2jvzg443h0ffzfwd09wpcxy2fuqmcnecd',
48+
cardanoAddress: aliceCardanoAddress,
4749
handle: 'alice',
4850
hasDatum: false,
4951
image: Asset.Uri('ipfs://c8fc19c2e61bab6059bf8a466e6e754833a08a62a6c56feasd'),
5052
policyId: Cardano.PolicyId('50fdcdbfa3154db86a87e4b5697ae30d272e0bbcfa8122efd3e301cb'),
5153
profilePic: undefined
5254
};
5355

56+
const bobCardanoAddress =
57+
'addr_test1qzrljm7nskakjydxlr450ktsj08zuw6aktvgfkmmyw9semrkrezryq3ydtmkg0e7e2jvzg443h0ffzfwd09wpcxy2fuql9tk0g';
5458
export const getBobHandleProviderResponse = {
59+
addresses: { cardano: bobCardanoAddress },
5560
backgroundImage: Asset.Uri('ipfs://zrljm7nskakjydxlr450ktsj08zuw6aktvgfkmmyw9semrkrezryq3yd'),
56-
cardanoAddress:
57-
'addr_test1qzrljm7nskakjydxlr450ktsj08zuw6aktvgfkmmyw9semrkrezryq3ydtmkg0e7e2jvzg443h0ffzfwd09wpcxy2fuql9tk0g',
61+
cardanoAddress: bobCardanoAddress,
5862
handle: 'bob',
5963
hasDatum: false,
6064
image: Asset.Uri('ipfs://c8fc19c2e61bab6059bf8a466e6e754833a08a62a6c56fe'),

packages/cardano-services/src/Handle/TypeOrmHandleProvider.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ export class TypeOrmHandleProvider extends TypeormProvider implements HandleProv
7171
]);
7272

7373
return {
74+
addresses: { cardano: cardanoAddress },
7475
backgroundImage: handleMetadataEntity?.backgroundImage || undefined,
7576
cardanoAddress,
7677
defaultForPaymentCredential: defaultForPaymentCredential || undefined,

packages/cardano-services/test/Handle/HandleHttpService.test.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,13 +126,15 @@ describe('HandleHttpService', () => {
126126
});
127127

128128
it('valid not empty response is openApi schema compliant', async () => {
129+
const cardanoAddress = <Cardano.PaymentAddress>'test_address';
129130
await createServer({
130131
getPolicyIds: () => Promise.resolve([<Cardano.PolicyId>'test_policy']),
131132
healthCheck: () => Promise.resolve({ ok: true }),
132133
resolveHandles: () =>
133134
Promise.resolve([
134135
{
135-
cardanoAddress: <Cardano.PaymentAddress>'test_address',
136+
addresses: { cardano: cardanoAddress },
137+
cardanoAddress,
136138
handle: 'test',
137139
hasDatum: true,
138140
policyId: <Cardano.PolicyId>'test_policy',
@@ -146,6 +148,7 @@ describe('HandleHttpService', () => {
146148
expect({ body, status }).toEqual({
147149
body: [
148150
{
151+
addresses: { cardano: 'test_address' },
149152
cardanoAddress: 'test_address',
150153
handle: 'test',
151154
hasDatum: true,

packages/cardano-services/test/TxSubmit/NodeTxSubmitProvider.test.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,12 @@ import { NoCache, NodeTxSubmitProvider, NodeTxSubmitProviderProps } from '../../
1313
import { generateRandomHexString } from '@cardano-sdk/util-dev';
1414
import { dummyLogger as logger } from 'ts-log';
1515

16+
const cardanoAddress = Cardano.PaymentAddress(
17+
'addr_test1qqk4sr4f7vtqzd2w90d5nfu3n59jhhpawyphnek2y7er02nkrezryq3ydtmkg0e7e2jvzg443h0ffzfwd09wpcxy2fuqmcnecd'
18+
);
1619
const mockHandleResolution = {
17-
cardanoAddress: Cardano.PaymentAddress(
18-
'addr_test1qqk4sr4f7vtqzd2w90d5nfu3n59jhhpawyphnek2y7er02nkrezryq3ydtmkg0e7e2jvzg443h0ffzfwd09wpcxy2fuqmcnecd'
19-
),
20+
addresses: { cardano: cardanoAddress },
21+
cardanoAddress,
2022
handle: 'alice',
2123
hasDatum: false,
2224
policyId: Cardano.PolicyId('50fdcdbfa3154db86a87e4b5697ae30d272e0bbcfa8122efd3e301cb'),

packages/core/src/Provider/HandleProvider/types.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,13 @@ export type Handle = string;
1010
* @param resolvedAt the point at which the Handle was resolved
1111
*/
1212
export interface HandleResolution {
13+
addresses: {
14+
bitcoin?: string;
15+
cardano: Cardano.PaymentAddress;
16+
};
1317
policyId: Cardano.PolicyId;
1418
handle: Handle;
19+
/** @deprecated Use `addresses.cardano` instead. */
1520
cardanoAddress: Cardano.PaymentAddress;
1621
hasDatum: boolean;
1722
defaultForStakeCredential?: Handle;

packages/tx-construction/test/tx-builder/TxBuilder.test.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,10 @@ const rewardAccount2 = Cardano.RewardAccount('stake_test1up7pvfq8zn4quy45r2g5722
4040
const rewardAccount3 = Cardano.RewardAccount('stake_test1uqehkck0lajq8gr28t9uxnuvgcqrc6070x3k9r8048z8y5gssrtvn');
4141
const rewardAccount4 = Cardano.RewardAccount('stake_test17rphkx6acpnf78fuvxn0mkew3l0fd058hzquvz7w36x4gtcljw6kf');
4242

43+
const cardanoAddress = Cardano.PaymentAddress('addr_test1vr8nl4u0u6fmtfnawx2rxfz95dy7m46t6dhzdftp2uha87syeufdg');
4344
const resolvedHandle = {
44-
cardanoAddress: Cardano.PaymentAddress('addr_test1vr8nl4u0u6fmtfnawx2rxfz95dy7m46t6dhzdftp2uha87syeufdg'),
45+
addresses: { cardano: cardanoAddress },
46+
cardanoAddress,
4547
handle: 'alice',
4648
hasDatum: false,
4749
policyId: Cardano.PolicyId('b0d07d45fe9514f80213f4020e5a61241458be626841cde717cb38a7'),

packages/wallet/src/services/HandlesTracker.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ export const createHandlesTracker = (
135135
}
136136
return {
137137
...assetInfo,
138+
addresses: { cardano: txOut.address },
138139
cardanoAddress: txOut.address,
139140
handle: Asset.util.getAssetNameAsText(handleAssetId),
140141
hasDatum: !!txOut.datum

packages/wallet/test/services/HandlesTracker.test.ts

Lines changed: 89 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ const handleOutput = utxo.find(
3434
)![1];
3535

3636
const expectedHandleInfo: HandleInfo = {
37+
addresses: { cardano: handleOutput.address },
3738
assetId: handleAssetId,
3839
cardanoAddress: handleOutput.address,
3940
fingerprint: handleFingerprint,
@@ -64,10 +65,10 @@ const hydrateHandle = (handleInfo: HandleInfo) =>
6465

6566
const exponentialBackoffDelay = (iteration: number) => Math.pow(2, iteration) * HYDRATE_HANDLE_INITIAL_INTERVAL;
6667

67-
const lastInteration = HYDRATE_HANDLE_MAX_RETRIES - 1;
68+
const lastIteration = HYDRATE_HANDLE_MAX_RETRIES - 1;
6869

6970
const retrySyntax = (retries: number) =>
70-
Array.from({ length: retries }, (_, i) => exponentialBackoffDelay(i) - (i === lastInteration ? 2 : 1))
71+
Array.from({ length: retries }, (_, i) => exponentialBackoffDelay(i) - (i === lastIteration ? 2 : 1))
7172
.map((exponentialDelay) => ` - ${exponentialDelay}ms `)
7273
.join('');
7374

@@ -81,24 +82,27 @@ const handleReferenceTokenAssetId = Cardano.AssetId.fromParts(
8182
describe('createHandlesTracker', () => {
8283
it('matches utxo$ assets to given handlePolicyIds and adds context from assetInfo$ and tip$ observables', () => {
8384
createTestScheduler().run(({ hot, expectObservable }) => {
84-
const utxo$ = hot( '-ab-', { a: utxo, b: utxo2 });
85+
const utxo$ = hot('-ab-', { a: utxo, b: utxo2 });
8586
const assetInfo$ = hot('-a-b', {
8687
a: new Map(),
8788
b: new Map([[handleAssetId, handleAssetInfo]])
8889
});
8990
const handlePolicyIds$ = hot('-a--', { a: [handlePolicyId] });
9091

91-
const handles$ = createHandlesTracker({
92-
assetInfo$,
93-
handlePolicyIds$,
94-
handleProvider: {
95-
getPolicyIds: async (): Promise<Cardano.PolicyId[]> => [handlePolicyId],
96-
healthCheck: jest.fn(),
97-
resolveHandles: async () => []
92+
const handles$ = createHandlesTracker(
93+
{
94+
assetInfo$,
95+
handlePolicyIds$,
96+
handleProvider: {
97+
getPolicyIds: async (): Promise<Cardano.PolicyId[]> => [handlePolicyId],
98+
healthCheck: jest.fn(),
99+
resolveHandles: async () => []
100+
},
101+
logger,
102+
utxo$
98103
},
99-
logger,
100-
utxo$
101-
}, { hydrateHandle: () => hydrateHandle });
104+
{ hydrateHandle: () => hydrateHandle }
105+
);
102106

103107
expectObservable(handles$).toBe('---ab', {
104108
a: [expectedHandleInfo],
@@ -109,7 +113,7 @@ describe('createHandlesTracker', () => {
109113

110114
it('filters out handles that have total supply >1', () => {
111115
createTestScheduler().run(({ hot, expectObservable }) => {
112-
const utxo$ = hot( '-a', { a: utxo });
116+
const utxo$ = hot('-a', { a: utxo });
113117
const assetInfo$ = hot('-a', {
114118
a: new Map([
115119
[
@@ -123,38 +127,46 @@ describe('createHandlesTracker', () => {
123127
});
124128
const handlePolicyIds$ = hot('-a-', { a: [handlePolicyId] });
125129

126-
const handles$ = createHandlesTracker({
127-
assetInfo$,
128-
handlePolicyIds$,
129-
handleProvider: {
130-
getPolicyIds: async (): Promise<Cardano.PolicyId[]> => [handlePolicyId],
131-
healthCheck: jest.fn(),
132-
resolveHandles: async () => []
130+
const handles$ = createHandlesTracker(
131+
{
132+
assetInfo$,
133+
handlePolicyIds$,
134+
handleProvider: {
135+
getPolicyIds: async (): Promise<Cardano.PolicyId[]> => [handlePolicyId],
136+
healthCheck: jest.fn(),
137+
resolveHandles: async () => []
138+
},
139+
logger,
140+
utxo$
133141
},
134-
logger,
135-
utxo$
136-
}, { hydrateHandle: () => hydrateHandle });
142+
{ hydrateHandle: () => hydrateHandle }
143+
);
137144

138145
expectObservable(handles$).toBe('-a', { a: [] });
139146
});
140147
});
141148

142149
it('filters out cip68 reference tokens', () => {
143150
createTestScheduler().run(({ hot, expectObservable }) => {
144-
const utxo$ = hot('-a', { a: [[utxo[0][0], {
145-
address: utxo[0][1].address,
146-
value: {
147-
assets: new Map([
148-
[handleReferenceTokenAssetId, 1n]
149-
]),
150-
coins: 9_825_963n
151-
}
152-
}
153-
] as Cardano.Utxo] });
151+
const utxo$ = hot('-a', {
152+
a: [
153+
[
154+
utxo[0][0],
155+
{
156+
address: utxo[0][1].address,
157+
value: {
158+
assets: new Map([[handleReferenceTokenAssetId, 1n]]),
159+
coins: 9_825_963n
160+
}
161+
}
162+
] as Cardano.Utxo
163+
]
164+
});
154165
const assetInfo$ = hot('-a', {
155166
a: new Map([
156167
[
157-
handleReferenceTokenAssetId, {
168+
handleReferenceTokenAssetId,
169+
{
158170
...handleAssetInfo,
159171
supply: 1n
160172
}
@@ -163,39 +175,45 @@ describe('createHandlesTracker', () => {
163175
});
164176
const handlePolicyIds$ = hot('-a-', { a: [handlePolicyId] });
165177

166-
const handles$ = createHandlesTracker({
167-
assetInfo$,
168-
handlePolicyIds$,
169-
handleProvider: {
170-
getPolicyIds: async (): Promise<Cardano.PolicyId[]> => [handlePolicyId],
171-
healthCheck: jest.fn(),
172-
resolveHandles: async () => []
178+
const handles$ = createHandlesTracker(
179+
{
180+
assetInfo$,
181+
handlePolicyIds$,
182+
handleProvider: {
183+
getPolicyIds: async (): Promise<Cardano.PolicyId[]> => [handlePolicyId],
184+
healthCheck: jest.fn(),
185+
resolveHandles: async () => []
186+
},
187+
logger,
188+
utxo$
173189
},
174-
logger,
175-
utxo$
176-
}, { hydrateHandle: () => hydrateHandle });
190+
{ hydrateHandle: () => hydrateHandle }
191+
);
177192

178193
expectObservable(handles$).toBe('-a', { a: [] });
179194
});
180195
});
181196

182197
it('does not emit duplicates with no changes', () => {
183198
createTestScheduler().run(({ hot, expectObservable }) => {
184-
const utxo$ = hot( '-a-', { a: utxo });
185-
const assetInfo$ = hot( '-aa', { a: new Map([[handleAssetId, handleAssetInfo]]) });
199+
const utxo$ = hot('-a-', { a: utxo });
200+
const assetInfo$ = hot('-aa', { a: new Map([[handleAssetId, handleAssetInfo]]) });
186201
const handlePolicyIds$ = hot('-a-', { a: [handlePolicyId] });
187202

188-
const handles$ = createHandlesTracker({
189-
assetInfo$,
190-
handlePolicyIds$,
191-
handleProvider: {
192-
getPolicyIds: async (): Promise<Cardano.PolicyId[]> => [handlePolicyId],
193-
healthCheck: jest.fn(),
194-
resolveHandles: async () => []
203+
const handles$ = createHandlesTracker(
204+
{
205+
assetInfo$,
206+
handlePolicyIds$,
207+
handleProvider: {
208+
getPolicyIds: async (): Promise<Cardano.PolicyId[]> => [handlePolicyId],
209+
healthCheck: jest.fn(),
210+
resolveHandles: async () => []
211+
},
212+
logger,
213+
utxo$
195214
},
196-
logger,
197-
utxo$
198-
}, { hydrateHandle: () => hydrateHandle });
215+
{ hydrateHandle: () => hydrateHandle }
216+
);
199217

200218
expectObservable(handles$).toBe('-ab', {
201219
a: [expectedHandleInfo],
@@ -206,22 +224,25 @@ describe('createHandlesTracker', () => {
206224

207225
it('shares a single subscription to dependency observables', () => {
208226
createTestScheduler().run(({ hot, expectSubscriptions }) => {
209-
const utxo$ = hot( '-a', { a: utxo });
227+
const utxo$ = hot('-a', { a: utxo });
210228
const assetInfo$ = hot('-a', {
211229
a: new Map([[handleAssetId, handleAssetInfo]])
212230
});
213231
const handlePolicyIds$ = hot('a-', { a: [handlePolicyId] });
214-
const handles$ = createHandlesTracker({
215-
assetInfo$,
216-
handlePolicyIds$,
217-
handleProvider: {
218-
getPolicyIds: async (): Promise<Cardano.PolicyId[]> => [handlePolicyId],
219-
healthCheck: jest.fn(),
220-
resolveHandles: async () => []
232+
const handles$ = createHandlesTracker(
233+
{
234+
assetInfo$,
235+
handlePolicyIds$,
236+
handleProvider: {
237+
getPolicyIds: async (): Promise<Cardano.PolicyId[]> => [handlePolicyId],
238+
healthCheck: jest.fn(),
239+
resolveHandles: async () => []
240+
},
241+
logger,
242+
utxo$
221243
},
222-
logger,
223-
utxo$
224-
}, { hydrateHandle: () => hydrateHandle });
244+
{ hydrateHandle: () => hydrateHandle }
245+
);
225246
combineLatest([handles$, handles$]).pipe(take(1)).subscribe();
226247
expectSubscriptions(utxo$.subscriptions).toBe('^!');
227248
expectSubscriptions(assetInfo$.subscriptions).toBe('^!');

0 commit comments

Comments
 (0)