Skip to content

Commit

Permalink
chore: add support for crc-nim swaps
Browse files Browse the repository at this point in the history
  • Loading branch information
onmax committed Jun 18, 2024
1 parent a153f4d commit 18b8051
Show file tree
Hide file tree
Showing 9 changed files with 242 additions and 81 deletions.
121 changes: 73 additions & 48 deletions client/PublicRequestTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,15 +157,15 @@ export interface PaymentOptions<C extends Currency, T extends PaymentType> {
}

export type AvailablePaymentOptions = NimiqDirectPaymentOptions
| EtherDirectPaymentOptions
| BitcoinDirectPaymentOptions;
| EtherDirectPaymentOptions
| BitcoinDirectPaymentOptions;

export type PaymentOptionsForCurrencyAndType<C extends Currency, T extends PaymentType> =
T extends PaymentType.DIRECT ?
C extends Currency.NIM ? NimiqDirectPaymentOptions
: C extends Currency.BTC ? BitcoinDirectPaymentOptions
: C extends Currency.ETH ? EtherDirectPaymentOptions
: PaymentOptions<C, T>
C extends Currency.NIM ? NimiqDirectPaymentOptions
: C extends Currency.BTC ? BitcoinDirectPaymentOptions
: C extends Currency.ETH ? EtherDirectPaymentOptions
: PaymentOptions<C, T>
: PaymentOptions<C, T>;

export interface MultiCurrencyCheckoutRequest extends BasicRequest {
Expand Down Expand Up @@ -288,6 +288,13 @@ export interface EuroHtlcCreationInstructions {
bankLabel?: string;
}

export interface SinpeMovilHtlcCreationInstructions {
type: 'CRC';
value: number; // CRC cents
fee: number; // CRC cents
recipientLabel?: string;
}

export interface NimiqHtlcSettlementInstructions {
type: 'NIM';
recipient: string; // My address, must be redeem address of HTLC
Expand Down Expand Up @@ -333,6 +340,21 @@ export interface EuroHtlcSettlementInstructions {
};
}

export interface SinpeMovilHtlcSettlementInstructions {
type: 'CRC';
value: number; // CRC cents
fee: number; // CRC cents
recipientLabel?: string;
settlement: {
type: "sinpemovil",
contractId: string,
phoneNumber: number,
// } | {
// Mock not supported yet
// type: 'mock',
};
}

export interface NimiqHtlcRefundInstructions {
type: 'NIM';
sender: string; // HTLC address
Expand Down Expand Up @@ -368,13 +390,15 @@ export type HtlcCreationInstructions =
NimiqHtlcCreationInstructions
| BitcoinHtlcCreationInstructions
| PolygonHtlcCreationInstructions
| EuroHtlcCreationInstructions;
| EuroHtlcCreationInstructions
| SinpeMovilHtlcCreationInstructions;

export type HtlcSettlementInstructions =
NimiqHtlcSettlementInstructions
| BitcoinHtlcSettlementInstructions
| PolygonHtlcSettlementInstructions
| EuroHtlcSettlementInstructions;
| EuroHtlcSettlementInstructions
| SinpeMovilHtlcSettlementInstructions;

export type HtlcRefundInstructions =
NimiqHtlcRefundInstructions
Expand Down Expand Up @@ -428,6 +452,7 @@ export interface SetupSwapResult {
btc?: SignedBtcTransaction;
usdc?: SignedPolygonTransaction;
eur?: string; // When funding EUR: empty string, when redeeming EUR: JWS of the settlement instructions
crc?: string; // When funding CRC: empty string, when redeeming CRC: JWS of the settlement instructions
refundTx?: string;
}

Expand Down Expand Up @@ -543,22 +568,22 @@ export type CreateCashlinkRequest = BasicRequest & {
theme?: CashlinkTheme,
fiatCurrency?: string,
} & (
{} | {
message: string,
autoTruncateMessage?: boolean,
}
) & (
{} | {
senderAddress: string,
senderBalance?: number,
}
) & ({
{} | {
message: string,
autoTruncateMessage?: boolean,
}
) & (
{} | {
senderAddress: string,
senderBalance?: number,
}
) & ({
returnLink?: false,
} | {
returnLink: true,
skipSharing?: boolean,
}
);
);

export interface ManageCashlinkRequest extends BasicRequest {
cashlinkAddress: string;
Expand Down Expand Up @@ -643,41 +668,41 @@ export interface SignedPolygonTransaction {
}

export type RpcRequest = SignTransactionRequest
| CreateCashlinkRequest
| ManageCashlinkRequest
| CheckoutRequest
| BasicRequest
| SimpleRequest
| ChooseAddressRequest
| OnboardRequest
| RenameRequest
| SignMessageRequest
| ExportRequest
| SignBtcTransactionRequest
| AddBtcAddressesRequest
| SignPolygonTransactionRequest
| SetupSwapRequest
| RefundSwapRequest;
| CreateCashlinkRequest
| ManageCashlinkRequest
| CheckoutRequest
| BasicRequest
| SimpleRequest
| ChooseAddressRequest
| OnboardRequest
| RenameRequest
| SignMessageRequest
| ExportRequest
| SignBtcTransactionRequest
| AddBtcAddressesRequest
| SignPolygonTransactionRequest
| SetupSwapRequest
| RefundSwapRequest;

export type RpcResult = SignedTransaction
| Account
| Account[]
| SimpleResult
| ChooseAddressResult
| Address
| Cashlink
| Cashlink[]
| SignedMessage
| ExportResult
| SignedBtcTransaction
| AddBtcAddressesResult
| SignedPolygonTransaction
| SetupSwapResult;
| Account
| Account[]
| SimpleResult
| ChooseAddressResult
| Address
| Cashlink
| Cashlink[]
| SignedMessage
| ExportResult
| SignedBtcTransaction
| AddBtcAddressesResult
| SignedPolygonTransaction
| SetupSwapResult;

export type ResultByRequestType<T> =
T extends RequestType.RENAME ? Account :
T extends RequestType.ONBOARD | RequestType.SIGNUP | RequestType.LOGIN
| RequestType.MIGRATE | RequestType.LIST ? Account[] :
| RequestType.MIGRATE | RequestType.LIST ? Account[] :
T extends RequestType.LIST_CASHLINKS ? Cashlink[] :
T extends RequestType.CHOOSE_ADDRESS ? ChooseAddressResult :
T extends RequestType.ADD_ADDRESS ? Address :
Expand Down
2 changes: 1 addition & 1 deletion client/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"compilerOptions": {
"outDir": "./build/",
"outDir": "dist/build",
"target": "ES2020",
"module": "ES2020", // Lowest version that allows dynamic imports
"strict": true,
Expand Down
62 changes: 62 additions & 0 deletions demos/Demo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -661,6 +661,68 @@ class Demo {
}
});

document.querySelector('button#setup-swap.nim-to-nim').addEventListener('click', async () => {
const accountId = '44012bb58ff5';

const account = (await demo.list()).find((wallet) => wallet.accountId === accountId);
if (!account) {
alert('Account for the demo swap not found. Currently only Sören has this account.');
throw new Error('Account not found');
}

if (account.type === WalletType.LEGACY) {
alert('Cannot sign BTC transactions with a legacy account');
throw new Error('Cannot use legacy account');
}

const request: SetupSwapRequest = {
appName: 'Hub Demos',
fund: {
type: 'NIM',
sender: account.addresses[0].address,
value: 2709.79904 * 1e5,
fee: 0,
extraData: 'anlssPDlYuJ5R8hvRtmP3EVjywhona4vd7BI3MCOFNcxBOoUIitb4QMZNYm9TPJr6LpTyq2WJSLYwtBr6jaor6LrJjgvNFcr4gEAEWWF',
validityStartHeight: 1140000,
},
redeem: {
type: 'BTC',
input: {
transactionHash: 'ef4aaf6087d0cc48ff09355d715c257078467ca4d9dd75a20824e70a78fb43cc',
outputIndex: 0,
outputScript: BitcoinJS.address.toOutputScript('tb1q0hzaqgespv4a67wrc843gkjd5s668l6arm820utp32m9nss90ejq83klw7', BitcoinJS.networks.testnet).toString('hex'),
witnessScript: '6382012088a820193589bd4cf26be8ba53caad962522d8c2d06bea36a8afa2eb26382f34572be28876a91484eb9bcbd90ce7d3360992259e4b9b818215a96088ac67044934565fb17576a91457f4babc23d2369572394cf80f28daeb9c3b58f188ac68',
value: Math.round(0.001004 * 1e8),
},
output: {
address: redeemAddress,
value: 0.001 * 1e8,
},
},

fiatCurrency: 'eur',
nimFiatRate: 0.00267,
btcFiatRate: 8662.93,
serviceNetworkFee: 10.73171 * 1e5,
serviceExchangeFee: 5.40878 * 1e5,
nimiqAddresses: account.addresses.map((address) => ({
address: address.address,
balance: Math.round(Math.random() * 10000 + 3000) * 1e5,
})),
bitcoinAccount: {
balance: Math.round((Math.random() * 0.001 + 0.001) * 1e8),
},
};
try {
const result = await demo.client.setupSwap(request, demo._defaultBehavior as PopupRequestBehavior);
console.log('Result', result);
document.querySelector('#result').innerHTML = `Signed successfully!<br>NIM:&nbsp;${result.nim.serializedTx}<br>BTC:&nbsp;${result.btc.serializedTx}`;
} catch (e) {
console.error(e);
document.querySelector('#result').textContent = `Error: ${e.message || e}`;
}
});

document.querySelector('button#activate-usdc')!.addEventListener('click', async () => {
const $radio = document.querySelector('input[name="address"]:checked');
if (!$radio) {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"dependencies": {
"@nimiq/browser-warning": "^1.1.1",
"@nimiq/electrum-client": "https://github.com/nimiq/electrum-client#build",
"@nimiq/fastspot-api": "^1.8.0",
"@nimiq/fastspot-api": "https://github.com/nimiq/fastspot-api#3a7c4b68529d7ec9ba8955a399412eaae946c528",
"@nimiq/iqons": "^1.5.2",
"@nimiq/keyguard-client": "^1.6.0",
"@nimiq/ledger-api": "^2.3.0",
Expand Down
14 changes: 10 additions & 4 deletions src/lib/RequestParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -527,11 +527,11 @@ export class RequestParser {

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

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

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

Expand Down Expand Up @@ -631,7 +631,10 @@ export class RequestParser {
} : setupSwapRequest.fund.type === 'USDC_MATIC' ? {
...setupSwapRequest.fund,
type: SwapAsset[setupSwapRequest.fund.type],
} : { // EUR
} : setupSwapRequest.fund.type === 'EUR' ? {
...setupSwapRequest.fund,
type: SwapAsset[setupSwapRequest.fund.type],
} : { // CRC
...setupSwapRequest.fund,
type: SwapAsset[setupSwapRequest.fund.type],
},
Expand All @@ -649,7 +652,10 @@ export class RequestParser {
} : setupSwapRequest.redeem.type === 'USDC_MATIC' ? {
...setupSwapRequest.redeem,
type: SwapAsset[setupSwapRequest.redeem.type],
} : { // EUR
} : setupSwapRequest.redeem.type === 'EUR' ? {
...setupSwapRequest.redeem,
type: SwapAsset[setupSwapRequest.redeem.type],
} : { // CRC
...setupSwapRequest.redeem,
type: SwapAsset[setupSwapRequest.redeem.type],
},
Expand Down
57 changes: 37 additions & 20 deletions src/lib/RequestTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,15 +60,15 @@ export type ParsedProtocolSpecificsForCurrency<C extends Currency> =
: undefined;

export type AvailableParsedPaymentOptions = ParsedNimiqDirectPaymentOptions
| ParsedEtherDirectPaymentOptions
| ParsedBitcoinDirectPaymentOptions;
| ParsedEtherDirectPaymentOptions
| ParsedBitcoinDirectPaymentOptions;

export type ParsedPaymentOptionsForCurrencyAndType<C extends Currency, T extends PaymentType> =
T extends PaymentType.DIRECT ?
C extends Currency.NIM ? ParsedNimiqDirectPaymentOptions
: C extends Currency.BTC ? ParsedBitcoinDirectPaymentOptions
: C extends Currency.ETH ? ParsedEtherDirectPaymentOptions
: ParsedPaymentOptions<C, T>
C extends Currency.NIM ? ParsedNimiqDirectPaymentOptions
: C extends Currency.BTC ? ParsedBitcoinDirectPaymentOptions
: C extends Currency.ETH ? ParsedEtherDirectPaymentOptions
: ParsedPaymentOptions<C, T>
: ParsedPaymentOptions<C, T>;

export interface ParsedCheckoutRequest extends ParsedBasicRequest {
Expand Down Expand Up @@ -209,6 +209,11 @@ export interface ParsedSetupSwapRequest extends ParsedSimpleRequest {
value: number, // Eurocents
fee: number, // Eurocents
bankLabel?: string,
} | {
type: SwapAsset.CRC,
value: number, // CRC cents
fee: number, // CRC cents
recipientLabel?: string,
};

redeem: {
Expand Down Expand Up @@ -251,6 +256,18 @@ export interface ParsedSetupSwapRequest extends ParsedSimpleRequest {
} | {
type: 'mock',
};
} | {
type: SwapAsset.CRC,
value: number; // CRC cents
fee: number; // CRC cents
recipientLabel?: string;
settlement: {
type: "sinpemovil",
contractId: string,
phoneNumber: number,
// } | {
// type: 'mock',
};
};

// Data needed for display
Expand Down Expand Up @@ -320,17 +337,17 @@ export interface ParsedRefundSwapRequest extends ParsedSimpleRequest {

// Discriminated Unions
export type ParsedRpcRequest = ParsedSignTransactionRequest
| ParsedCreateCashlinkRequest
| ParsedManageCashlinkRequest
| ParsedCheckoutRequest
| ParsedBasicRequest
| ParsedSimpleRequest
| ParsedOnboardRequest
| ParsedRenameRequest
| ParsedSignMessageRequest
| ParsedExportRequest
| ParsedSignBtcTransactionRequest
| ParsedAddBtcAddressesRequest
| ParsedSignPolygonTransactionRequest
| ParsedSetupSwapRequest
| ParsedRefundSwapRequest;
| ParsedCreateCashlinkRequest
| ParsedManageCashlinkRequest
| ParsedCheckoutRequest
| ParsedBasicRequest
| ParsedSimpleRequest
| ParsedOnboardRequest
| ParsedRenameRequest
| ParsedSignMessageRequest
| ParsedExportRequest
| ParsedSignBtcTransactionRequest
| ParsedAddBtcAddressesRequest
| ParsedSignPolygonTransactionRequest
| ParsedSetupSwapRequest
| ParsedRefundSwapRequest;
Loading

0 comments on commit 18b8051

Please sign in to comment.