Skip to content

Commit db3455e

Browse files
committed
chore: add support for crc-nim swaps
1 parent a153f4d commit db3455e

8 files changed

+112
-15
lines changed

client/PublicRequestTypes.ts

+26-2
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,13 @@ export interface EuroHtlcCreationInstructions {
288288
bankLabel?: string;
289289
}
290290

291+
export interface SinpeMovilHtlcCreationInstructions {
292+
type: 'CRC';
293+
value: number; // CRC cents
294+
fee: number; // CRC cents
295+
recipientLabel?: string;
296+
}
297+
291298
export interface NimiqHtlcSettlementInstructions {
292299
type: 'NIM';
293300
recipient: string; // My address, must be redeem address of HTLC
@@ -333,6 +340,20 @@ export interface EuroHtlcSettlementInstructions {
333340
};
334341
}
335342

343+
export interface SinpeMovilHtlcSettlementInstructions {
344+
type: 'CRC';
345+
value: number; // CRC cents
346+
fee: number; // CRC cents
347+
recipientLabel?: string;
348+
settlement: {
349+
type: 'sinpemovil',
350+
phoneNumber: string,
351+
// } | {
352+
// Mock not supported yet
353+
// type: 'mock',
354+
};
355+
}
356+
336357
export interface NimiqHtlcRefundInstructions {
337358
type: 'NIM';
338359
sender: string; // HTLC address
@@ -368,13 +389,15 @@ export type HtlcCreationInstructions =
368389
NimiqHtlcCreationInstructions
369390
| BitcoinHtlcCreationInstructions
370391
| PolygonHtlcCreationInstructions
371-
| EuroHtlcCreationInstructions;
392+
| EuroHtlcCreationInstructions
393+
| SinpeMovilHtlcCreationInstructions;
372394

373395
export type HtlcSettlementInstructions =
374396
NimiqHtlcSettlementInstructions
375397
| BitcoinHtlcSettlementInstructions
376398
| PolygonHtlcSettlementInstructions
377-
| EuroHtlcSettlementInstructions;
399+
| EuroHtlcSettlementInstructions
400+
| SinpeMovilHtlcSettlementInstructions;
378401

379402
export type HtlcRefundInstructions =
380403
NimiqHtlcRefundInstructions
@@ -428,6 +451,7 @@ export interface SetupSwapResult {
428451
btc?: SignedBtcTransaction;
429452
usdc?: SignedPolygonTransaction;
430453
eur?: string; // When funding EUR: empty string, when redeeming EUR: JWS of the settlement instructions
454+
crc?: string; // When funding CRC: empty string, when redeeming CRC: JWS of the settlement instructions
431455
refundTx?: string;
432456
}
433457

client/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
"types": "types/index.d.ts",
1111
"dependencies": {
1212
"@nimiq/core-web": "^1.6.1",
13-
"@nimiq/fastspot-api": "^1.8.0",
13+
"@nimiq/fastspot-api": "https://github.com/nimiq/fastspot-api#3a7c4b68529d7ec9ba8955a399412eaae946c528",
1414
"@nimiq/rpc": "^0.4.0",
1515
"@nimiq/utils": "^0.5.0",
1616
"@opengsn/common": "^2.2.5",

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
"dependencies": {
2222
"@nimiq/browser-warning": "^1.1.1",
2323
"@nimiq/electrum-client": "https://github.com/nimiq/electrum-client#build",
24-
"@nimiq/fastspot-api": "^1.8.0",
24+
"@nimiq/fastspot-api": "https://github.com/nimiq/fastspot-api#3a7c4b68529d7ec9ba8955a399412eaae946c528",
2525
"@nimiq/iqons": "^1.5.2",
2626
"@nimiq/keyguard-client": "^1.6.0",
2727
"@nimiq/ledger-api": "^2.3.0",

src/lib/RequestParser.ts

+10-4
Original file line numberDiff line numberDiff line change
@@ -527,11 +527,11 @@ export class RequestParser {
527527

528528
// Validate and parse only what we use in the Hub
529529

530-
if (!['NIM', 'BTC', 'USDC_MATIC', 'EUR'].includes(setupSwapRequest.fund.type)) {
530+
if (!['NIM', 'BTC', 'USDC_MATIC', 'EUR', 'CRC'].includes(setupSwapRequest.fund.type)) {
531531
throw new Error('Funding type is not supported');
532532
}
533533

534-
if (!['NIM', 'BTC', 'USDC_MATIC', 'EUR'].includes(setupSwapRequest.redeem.type)) {
534+
if (!['NIM', 'BTC', 'USDC_MATIC', 'EUR', 'CRC'].includes(setupSwapRequest.redeem.type)) {
535535
throw new Error('Redeeming type is not supported');
536536
}
537537

@@ -631,7 +631,10 @@ export class RequestParser {
631631
} : setupSwapRequest.fund.type === 'USDC_MATIC' ? {
632632
...setupSwapRequest.fund,
633633
type: SwapAsset[setupSwapRequest.fund.type],
634-
} : { // EUR
634+
} : setupSwapRequest.fund.type === 'EUR' ? {
635+
...setupSwapRequest.fund,
636+
type: SwapAsset[setupSwapRequest.fund.type],
637+
} : { // CRC
635638
...setupSwapRequest.fund,
636639
type: SwapAsset[setupSwapRequest.fund.type],
637640
},
@@ -649,7 +652,10 @@ export class RequestParser {
649652
} : setupSwapRequest.redeem.type === 'USDC_MATIC' ? {
650653
...setupSwapRequest.redeem,
651654
type: SwapAsset[setupSwapRequest.redeem.type],
652-
} : { // EUR
655+
} : setupSwapRequest.redeem.type === 'EUR' ? {
656+
...setupSwapRequest.redeem,
657+
type: SwapAsset[setupSwapRequest.redeem.type],
658+
} : { // CRC
653659
...setupSwapRequest.redeem,
654660
type: SwapAsset[setupSwapRequest.redeem.type],
655661
},

src/lib/RequestTypes.ts

+16
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,11 @@ export interface ParsedSetupSwapRequest extends ParsedSimpleRequest {
209209
value: number, // Eurocents
210210
fee: number, // Eurocents
211211
bankLabel?: string,
212+
} | {
213+
type: SwapAsset.CRC,
214+
value: number, // CRC cents
215+
fee: number, // CRC cents
216+
recipientLabel?: string,
212217
};
213218

214219
redeem: {
@@ -251,6 +256,17 @@ export interface ParsedSetupSwapRequest extends ParsedSimpleRequest {
251256
} | {
252257
type: 'mock',
253258
};
259+
} | {
260+
type: SwapAsset.CRC,
261+
value: number; // CRC cents
262+
fee: number; // CRC cents
263+
recipientLabel?: string;
264+
settlement: {
265+
type: 'sinpemovil',
266+
phoneNumber: string,
267+
// } | {
268+
// type: 'mock',
269+
};
254270
};
255271

256272
// Data needed for display

src/views/SetupSwap.vue

+9
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,15 @@ export default class SetupSwap extends BitcoinSyncBaseView {
208208
};
209209
}
210210
211+
if (this.request.fund.type === SwapAsset.CRC) {
212+
fundingInfo = {
213+
type: SwapAsset.CRC,
214+
amount: this.request.fund.value,
215+
fee: this.request.fund.fee,
216+
recipientLabel: this.request.fund.recipientLabel,
217+
};
218+
}
219+
211220
if (this.request.redeem.type === SwapAsset.NIM) {
212221
const signer = this._account.findSignerForAddress(this.request.redeem.recipient);
213222
if (!signer) {

src/views/SetupSwapSuccess.vue

+46-3
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ export default class SetupSwapSuccess extends BitcoinSyncBaseView {
101101
case SwapAsset.USDC_MATIC:
102102
redeemAddress = this.request.redeem.request.from;
103103
break;
104+
case SwapAsset.CRC:
104105
case SwapAsset.EUR:
105106
// Assemble recipient object
106107
redeemAddress = {
@@ -127,7 +128,7 @@ export default class SetupSwapSuccess extends BitcoinSyncBaseView {
127128
128129
confirmedSwap = await confirmSwap({
129130
id: this.request.swapId,
130-
} as PreSwap, this.request.redeem.type === SwapAsset.EUR ? {
131+
} as PreSwap, this.request.redeem.type === SwapAsset.EUR || this.request.redeem.type === SwapAsset.CRC ? {
131132
asset: this.request.redeem.type,
132133
...(redeemAddress as { kty: string, crv: string, x: string }),
133134
} : {
@@ -276,6 +277,18 @@ export default class SetupSwapSuccess extends BitcoinSyncBaseView {
276277
// TODO: Validate correct recipient public key
277278
}
278279
280+
if (confirmedSwap.from.asset === SwapAsset.CRC || confirmedSwap.to.asset === SwapAsset.CRC) {
281+
// TODO: Fetch contract from OASIS API and compare instead of trusting Fastspot
282+
283+
if (hashRoot && confirmedSwap.hash !== hashRoot) {
284+
this.$rpc.reject(new Error('HTLC hash roots do not match'));
285+
return;
286+
}
287+
hashRoot = confirmedSwap.hash;
288+
289+
// TODO: Validate correct recipient public key
290+
}
291+
279292
if (!hashRoot) {
280293
this.$rpc.reject(new Error('UNEXPECTED: Could not extract swap hash from contracts'));
281294
return;
@@ -330,6 +343,18 @@ export default class SetupSwapSuccess extends BitcoinSyncBaseView {
330343
};
331344
}
332345
346+
if (this.request.fund.type === SwapAsset.CRC) {
347+
const crcContract = confirmedSwap.contracts[SwapAsset.CRC] as Contract<SwapAsset.CRC>;
348+
const crcHtlcData = crcContract.htlc;
349+
350+
fundingHtlcInfo = {
351+
type: SwapAsset.CRC,
352+
hash: hashRoot,
353+
timeout: crcContract.timeout,
354+
htlcId: crcHtlcData.address,
355+
};
356+
}
357+
333358
if (this.request.redeem.type === SwapAsset.NIM) {
334359
const nimHtlcData = confirmedSwap.contracts[SwapAsset.NIM]!.htlc as NimHtlcDetails;
335360
@@ -433,6 +458,18 @@ export default class SetupSwapSuccess extends BitcoinSyncBaseView {
433458
};
434459
}
435460
461+
if (this.request.redeem.type === SwapAsset.CRC) {
462+
const crcContract = confirmedSwap.contracts[SwapAsset.CRC] as Contract<SwapAsset.CRC>;
463+
const crcHtlcData = crcContract.htlc;
464+
465+
redeemingHtlcInfo = {
466+
type: SwapAsset.CRC,
467+
hash: hashRoot,
468+
timeout: crcContract.timeout,
469+
htlcId: crcHtlcData.address,
470+
};
471+
}
472+
436473
if (this._isDestroyed) return;
437474
438475
if (!fundingHtlcInfo || !redeemingHtlcInfo) {
@@ -448,6 +485,7 @@ export default class SetupSwapSuccess extends BitcoinSyncBaseView {
448485
let polygonTransaction: SignedPolygonTransaction | undefined;
449486
let refundTransaction: string | undefined;
450487
let euroSettlement: string | undefined;
488+
let crcSettlement: string | undefined;
451489
try {
452490
const signingResult = await this._signSwapTransactions({
453491
fund: fundingHtlcInfo,
@@ -459,6 +497,7 @@ export default class SetupSwapSuccess extends BitcoinSyncBaseView {
459497
nimProxy: nimiqProxyTransaction,
460498
btc: bitcoinTransaction,
461499
eur: euroSettlement,
500+
crc: crcSettlement,
462501
usdc: polygonTransaction,
463502
refundTx: refundTransaction,
464503
} = signingResult);
@@ -505,6 +544,7 @@ export default class SetupSwapSuccess extends BitcoinSyncBaseView {
505544
btc: bitcoinTransaction,
506545
usdc: polygonTransaction,
507546
eur: euroSettlement,
547+
crc: crcSettlement,
508548
refundTx: refundTransaction,
509549
};
510550
@@ -522,10 +562,10 @@ export default class SetupSwapSuccess extends BitcoinSyncBaseView {
522562
523563
protected _getOasisRecipientPublicKey() {
524564
// note that this method gets overwritten for SetupSwapLedger
525-
if (!this.keyguardResult || !this.keyguardResult.eurPubKey) {
565+
if (!this.keyguardResult || !this.keyguardResult.fiatPubKey) {
526566
throw new Error('Cannot find OASIS recipient public key');
527567
}
528-
return Nimiq.BufferUtils.toBase64Url(Nimiq.BufferUtils.fromHex(this.keyguardResult.eurPubKey))
568+
return Nimiq.BufferUtils.toBase64Url(Nimiq.BufferUtils.fromHex(this.keyguardResult.fiatPubKey))
529569
.replace(/\.*$/, ''); // OASIS cannot handle trailing filler dots
530570
}
531571
@@ -535,6 +575,7 @@ export default class SetupSwapSuccess extends BitcoinSyncBaseView {
535575
btc?: SignedBtcTransaction,
536576
usdc?: SignedPolygonTransaction,
537577
eur?: string,
578+
crc?: string,
538579
refundTx?: string,
539580
} | null> {
540581
// Note that this method gets overwritten for SetupSwapLedger
@@ -550,6 +591,7 @@ export default class SetupSwapSuccess extends BitcoinSyncBaseView {
550591
btc: bitcoinTransaction,
551592
usdc: polygonTransaction,
552593
eur: euroSettlement,
594+
crc: crcSettlement,
553595
refundTx,
554596
} = await client.signSwapTransactions(keyguardRequest);
555597
@@ -584,6 +626,7 @@ export default class SetupSwapSuccess extends BitcoinSyncBaseView {
584626
} : undefined,
585627
usdc: polygonTransaction,
586628
eur: euroSettlement,
629+
crc: crcSettlement,
587630
refundTx,
588631
};
589632
}

yarn.lock

+3-4
Original file line numberDiff line numberDiff line change
@@ -1520,10 +1520,9 @@
15201520
dependencies:
15211521
bitcoinjs-lib "^5.1.10"
15221522

1523-
"@nimiq/fastspot-api@^1.8.0":
1524-
version "1.8.0"
1525-
resolved "https://registry.yarnpkg.com/@nimiq/fastspot-api/-/fastspot-api-1.8.0.tgz#705a9e79e425c3e6536d8994fd0b39d88af1b268"
1526-
integrity sha512-qNkibJnxS8ndOn4tuy1m3lSNKybBYApo+wy1ajTKcQ0lHo3VfLY0sAJ+WRE7diVWCa7iumu6wsFVudyc3k8/NQ==
1523+
"@nimiq/fastspot-api@https://github.com/nimiq/fastspot-api#3a7c4b68529d7ec9ba8955a399412eaae946c528":
1524+
version "1.9.0"
1525+
resolved "https://github.com/nimiq/fastspot-api#3a7c4b68529d7ec9ba8955a399412eaae946c528"
15271526

15281527
"@nimiq/iqons@^1.5.2", "@nimiq/iqons@^1.6.0":
15291528
version "1.6.0"

0 commit comments

Comments
 (0)