@shapeshiftoss/utils 1.1.1 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/.tsbuildinfo +1 -1
- package/dist/cjs/index.d.ts +2 -0
- package/dist/cjs/index.js +2 -0
- package/dist/cjs/paymentUri/constants.d.ts +3 -0
- package/dist/cjs/paymentUri/constants.js +29 -0
- package/dist/cjs/paymentUri/paymentUri.d.ts +7 -0
- package/dist/cjs/paymentUri/paymentUri.js +96 -0
- package/dist/cjs/paymentUri/paymentUri.test.d.ts +1 -0
- package/dist/cjs/paymentUri/paymentUri.test.js +95 -0
- package/dist/esm/.tsbuildinfo +1 -1
- package/dist/esm/index.d.ts +2 -0
- package/dist/esm/index.js +2 -0
- package/dist/esm/paymentUri/constants.d.ts +3 -0
- package/dist/esm/paymentUri/constants.js +26 -0
- package/dist/esm/paymentUri/paymentUri.d.ts +7 -0
- package/dist/esm/paymentUri/paymentUri.js +92 -0
- package/dist/esm/paymentUri/paymentUri.test.d.ts +1 -0
- package/dist/esm/paymentUri/paymentUri.test.js +93 -0
- package/package.json +3 -3
package/dist/cjs/index.d.ts
CHANGED
|
@@ -15,6 +15,8 @@ export * from './getChainShortName';
|
|
|
15
15
|
export * from './getNativeFeeAssetReference';
|
|
16
16
|
export * from './historyTimeframe';
|
|
17
17
|
export * from './makeAsset/makeAsset';
|
|
18
|
+
export * from './paymentUri/constants';
|
|
19
|
+
export * from './paymentUri/paymentUri';
|
|
18
20
|
export * from './promises';
|
|
19
21
|
export * from './sha256';
|
|
20
22
|
export * from './timeout';
|
package/dist/cjs/index.js
CHANGED
|
@@ -33,6 +33,8 @@ __exportStar(require("./getChainShortName"), exports);
|
|
|
33
33
|
__exportStar(require("./getNativeFeeAssetReference"), exports);
|
|
34
34
|
__exportStar(require("./historyTimeframe"), exports);
|
|
35
35
|
__exportStar(require("./makeAsset/makeAsset"), exports);
|
|
36
|
+
__exportStar(require("./paymentUri/constants"), exports);
|
|
37
|
+
__exportStar(require("./paymentUri/paymentUri"), exports);
|
|
36
38
|
__exportStar(require("./promises"), exports);
|
|
37
39
|
__exportStar(require("./sha256"), exports);
|
|
38
40
|
__exportStar(require("./timeout"), exports);
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.URN_SCHEME_TO_CHAIN_ID = exports.CHAIN_ID_TO_URN_SCHEME = void 0;
|
|
4
|
+
const caip_1 = require("@shapeshiftoss/caip");
|
|
5
|
+
exports.CHAIN_ID_TO_URN_SCHEME = {
|
|
6
|
+
[caip_1.ethChainId]: 'ethereum',
|
|
7
|
+
[caip_1.arbitrumChainId]: 'arbitrum',
|
|
8
|
+
[caip_1.optimismChainId]: 'optimism',
|
|
9
|
+
[caip_1.polygonChainId]: 'polygon',
|
|
10
|
+
[caip_1.bscChainId]: 'smartchain',
|
|
11
|
+
[caip_1.avalancheChainId]: 'avalanchec',
|
|
12
|
+
[caip_1.baseChainId]: 'base',
|
|
13
|
+
[caip_1.gnosisChainId]: 'xdai',
|
|
14
|
+
[caip_1.btcChainId]: 'bitcoin',
|
|
15
|
+
[caip_1.bchChainId]: 'bitcoincash',
|
|
16
|
+
[caip_1.dogeChainId]: 'dogecoin',
|
|
17
|
+
[caip_1.ltcChainId]: 'litecoin',
|
|
18
|
+
[caip_1.zecChainId]: 'zcash',
|
|
19
|
+
[caip_1.thorchainChainId]: 'thorchain',
|
|
20
|
+
[caip_1.cosmosChainId]: 'cosmos',
|
|
21
|
+
[caip_1.mayachainChainId]: 'mayachain',
|
|
22
|
+
[caip_1.solanaChainId]: 'solana',
|
|
23
|
+
[caip_1.tronChainId]: 'tron',
|
|
24
|
+
};
|
|
25
|
+
exports.URN_SCHEME_TO_CHAIN_ID = {
|
|
26
|
+
...Object.fromEntries(Object.entries(exports.CHAIN_ID_TO_URN_SCHEME).map(([chainId, scheme]) => [scheme, chainId])),
|
|
27
|
+
// The app emitted doge: QR codes for a year before adopting Dogecoin Core's scheme
|
|
28
|
+
doge: caip_1.dogeChainId,
|
|
29
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Asset } from '@shapeshiftoss/types';
|
|
2
|
+
export type BuildPaymentUriArgs = {
|
|
3
|
+
address: string;
|
|
4
|
+
asset: Pick<Asset, 'assetId' | 'chainId' | 'precision'>;
|
|
5
|
+
amountCryptoPrecision?: string;
|
|
6
|
+
};
|
|
7
|
+
export declare const buildPaymentUri: (args: BuildPaymentUriArgs) => string;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildPaymentUri = void 0;
|
|
4
|
+
const caip_1 = require("@shapeshiftoss/caip");
|
|
5
|
+
const bigAmount_1 = require("../bigAmount/bigAmount");
|
|
6
|
+
const bignumber_1 = require("../bignumber/bignumber");
|
|
7
|
+
const constants_1 = require("./constants");
|
|
8
|
+
const toBaseUnit = (asset, amountCryptoPrecision) => bigAmount_1.BigAmount.fromPrecision({ value: amountCryptoPrecision, precision: asset.precision }).toBaseUnit();
|
|
9
|
+
// EIP-681 encourages scientific notation, and writes it without the exponent's plus sign
|
|
10
|
+
const toEip681Amount = (amountCryptoBaseUnit) => (0, bignumber_1.bn)(amountCryptoBaseUnit).toExponential().replace('+', '').replace('e0', '');
|
|
11
|
+
const buildEvmUri = ({ address, asset, amountCryptoPrecision }) => {
|
|
12
|
+
const target = `@${Number((0, caip_1.fromChainId)(asset.chainId).chainReference)}`;
|
|
13
|
+
const { assetNamespace, assetReference } = (0, caip_1.fromAssetId)(asset.assetId);
|
|
14
|
+
// transfer(address,uint256) is erc20's alone, so erc721 and erc1155 get no amount
|
|
15
|
+
const takesAmount = assetNamespace === caip_1.ASSET_NAMESPACE.slip44 || assetNamespace === caip_1.ASSET_NAMESPACE.erc20;
|
|
16
|
+
if (!amountCryptoPrecision || !takesAmount)
|
|
17
|
+
return `ethereum:${address}${target}`;
|
|
18
|
+
const amount = toEip681Amount(toBaseUnit(asset, amountCryptoPrecision));
|
|
19
|
+
return assetNamespace === caip_1.ASSET_NAMESPACE.erc20
|
|
20
|
+
? `ethereum:${assetReference}${target}/transfer?address=${address}&uint256=${amount}`
|
|
21
|
+
: `ethereum:${address}${target}?value=${amount}`;
|
|
22
|
+
};
|
|
23
|
+
const BASE58_ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
|
|
24
|
+
// The same check as web3.js's PublicKey: base58 that decodes to exactly 32 bytes
|
|
25
|
+
const isSolanaPublicKey = (address) => {
|
|
26
|
+
let value = 0n;
|
|
27
|
+
for (const char of address) {
|
|
28
|
+
const digit = BASE58_ALPHABET.indexOf(char);
|
|
29
|
+
if (digit === -1)
|
|
30
|
+
return false;
|
|
31
|
+
value = value * 58n + BigInt(digit);
|
|
32
|
+
}
|
|
33
|
+
const leadingZeroBytes = address.length - address.replace(/^1+/, '').length;
|
|
34
|
+
const significantBytes = value === 0n ? 0 : Math.ceil(value.toString(16).length / 2);
|
|
35
|
+
return leadingZeroBytes + significantBytes === 32;
|
|
36
|
+
};
|
|
37
|
+
const buildSolanaUri = ({ address, asset, amountCryptoPrecision }) => {
|
|
38
|
+
if (!amountCryptoPrecision)
|
|
39
|
+
return address;
|
|
40
|
+
if (!isSolanaPublicKey(address))
|
|
41
|
+
throw new Error(`Invalid Solana address: ${address}`);
|
|
42
|
+
// Solana Pay normalises the amount rather than passing it through verbatim
|
|
43
|
+
const amount = (0, bignumber_1.bn)(amountCryptoPrecision).toFixed();
|
|
44
|
+
const { assetNamespace, assetReference } = (0, caip_1.fromAssetId)(asset.assetId);
|
|
45
|
+
if (assetNamespace === caip_1.ASSET_NAMESPACE.splToken) {
|
|
46
|
+
// Solana Pay takes decimal ui units, and the recipient is the native account, not its ATA
|
|
47
|
+
return `solana:${address}?amount=${amount}&spl-token=${assetReference}`;
|
|
48
|
+
}
|
|
49
|
+
return `solana:${address}?amount=${amount}`;
|
|
50
|
+
};
|
|
51
|
+
const buildTonUri = ({ address, asset, amountCryptoPrecision }) => {
|
|
52
|
+
if (!amountCryptoPrecision)
|
|
53
|
+
return address;
|
|
54
|
+
const { assetNamespace, assetReference } = (0, caip_1.fromAssetId)(asset.assetId);
|
|
55
|
+
const amount = toBaseUnit(asset, amountCryptoPrecision);
|
|
56
|
+
// A jetton transfer names its master contract, and its amount is in the jetton's own units
|
|
57
|
+
if (assetNamespace === caip_1.ASSET_NAMESPACE.jetton) {
|
|
58
|
+
return `ton://transfer/${address}?jetton=${assetReference}&amount=${amount}`;
|
|
59
|
+
}
|
|
60
|
+
return `ton://transfer/${address}?amount=${amount}`;
|
|
61
|
+
};
|
|
62
|
+
// BIP-21 takes decimal coin units
|
|
63
|
+
const buildBip21Uri = ({ address, asset, amountCryptoPrecision }) => {
|
|
64
|
+
const scheme = constants_1.CHAIN_ID_TO_URN_SCHEME[asset.chainId];
|
|
65
|
+
if (!amountCryptoPrecision || !scheme)
|
|
66
|
+
return address;
|
|
67
|
+
// CashAddr already carries its scheme
|
|
68
|
+
const target = address.startsWith(`${scheme}:`) ? address.slice(scheme.length + 1) : address;
|
|
69
|
+
return `${scheme}:${target}?amount=${(0, bignumber_1.bn)(amountCryptoPrecision).toFixed()}`;
|
|
70
|
+
};
|
|
71
|
+
const buildPaymentUri = (args) => {
|
|
72
|
+
const { asset, amountCryptoPrecision } = args;
|
|
73
|
+
if (amountCryptoPrecision) {
|
|
74
|
+
const amount = (0, bignumber_1.bn)(amountCryptoPrecision);
|
|
75
|
+
if (!amount.isFinite() || amount.isNegative()) {
|
|
76
|
+
throw new Error(`Invalid payment amount: ${amountCryptoPrecision}`);
|
|
77
|
+
}
|
|
78
|
+
if ((amount.decimalPlaces() ?? 0) > asset.precision) {
|
|
79
|
+
throw new Error(`Payment amount ${amountCryptoPrecision} exceeds ${asset.precision} decimals`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
switch ((0, caip_1.fromChainId)(args.asset.chainId).chainNamespace) {
|
|
83
|
+
case caip_1.CHAIN_NAMESPACE.Utxo:
|
|
84
|
+
case caip_1.CHAIN_NAMESPACE.CosmosSdk:
|
|
85
|
+
return buildBip21Uri(args);
|
|
86
|
+
case caip_1.CHAIN_NAMESPACE.Evm:
|
|
87
|
+
return buildEvmUri(args);
|
|
88
|
+
case caip_1.CHAIN_NAMESPACE.Solana:
|
|
89
|
+
return buildSolanaUri(args);
|
|
90
|
+
case caip_1.CHAIN_NAMESPACE.Ton:
|
|
91
|
+
return buildTonUri(args);
|
|
92
|
+
default:
|
|
93
|
+
return args.address;
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
exports.buildPaymentUri = buildPaymentUri;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const vitest_1 = require("vitest");
|
|
4
|
+
const paymentUri_1 = require("./paymentUri");
|
|
5
|
+
const asset = (assetId, chainId, precision) => ({
|
|
6
|
+
assetId,
|
|
7
|
+
chainId,
|
|
8
|
+
precision,
|
|
9
|
+
});
|
|
10
|
+
const BTC = asset('bip122:000000000019d6689c085ae165831e93/slip44:0', 'bip122:000000000019d6689c085ae165831e93', 8);
|
|
11
|
+
const BCH = asset('bip122:000000000000000000651ef99cb9fcbe/slip44:145', 'bip122:000000000000000000651ef99cb9fcbe', 8);
|
|
12
|
+
const ETH = asset('eip155:1/slip44:60', 'eip155:1', 18);
|
|
13
|
+
const BASE_ETH = asset('eip155:8453/slip44:60', 'eip155:8453', 18);
|
|
14
|
+
const USDC = asset('eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', 'eip155:1', 6);
|
|
15
|
+
const FOX = asset('eip155:1/erc20:0xc770eefad204b5180df6a14ee197d99d808ee52d', 'eip155:1', 18);
|
|
16
|
+
const SOL = asset('solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/slip44:501', 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp', 9);
|
|
17
|
+
const WIF = asset('solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/token:EKpQGSJtjMFqKZ9KQanSqYXRcF8fBopzLHYxdM65zcjm', 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp', 6);
|
|
18
|
+
const TON = asset('ton:mainnet/slip44:607', 'ton:mainnet', 9);
|
|
19
|
+
const TON_USDT = asset('ton:mainnet/jetton:EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs', 'ton:mainnet', 6);
|
|
20
|
+
const ATOM = asset('cosmos:cosmoshub-4/slip44:118', 'cosmos:cosmoshub-4', 6);
|
|
21
|
+
const BTC_ADDRESS = 'bc1qar0srrr7xfkvy5l643lydnw9re59gtzz';
|
|
22
|
+
const EVM_ADDRESS = '0xAbC0000000000000000000000000000000000001';
|
|
23
|
+
const SOL_ADDRESS = 'GsbwXfJraMomNxBcjYLcG3mxkBUiyWXAB32fGbSMQRdW';
|
|
24
|
+
const TON_ADDRESS = 'UQBFtnj3-yYK4p7XqXsyC5LNxfL2Rm5m0m3F0pvfDy7YQ9tk';
|
|
25
|
+
(0, vitest_1.describe)('buildPaymentUri', () => {
|
|
26
|
+
(0, vitest_1.it)('builds a BIP-21 uri with a decimal coin amount', () => {
|
|
27
|
+
(0, vitest_1.expect)((0, paymentUri_1.buildPaymentUri)({ address: BTC_ADDRESS, asset: BTC, amountCryptoPrecision: '0.05' })).toBe(`bitcoin:${BTC_ADDRESS}?amount=0.05`);
|
|
28
|
+
});
|
|
29
|
+
(0, vitest_1.it)('does not double-prefix a cashaddr that already carries its scheme', () => {
|
|
30
|
+
const address = 'bitcoincash:qr95sy3j9xwd2ap32xkykttr4cvcu7as4y';
|
|
31
|
+
(0, vitest_1.expect)((0, paymentUri_1.buildPaymentUri)({ address, asset: BCH, amountCryptoPrecision: '1' })).toBe('bitcoincash:qr95sy3j9xwd2ap32xkykttr4cvcu7as4y?amount=1');
|
|
32
|
+
});
|
|
33
|
+
(0, vitest_1.it)('carries the chain id so an l2 deposit cannot be paid on mainnet', () => {
|
|
34
|
+
(0, vitest_1.expect)((0, paymentUri_1.buildPaymentUri)({ address: EVM_ADDRESS, asset: BASE_ETH, amountCryptoPrecision: '2' })).toBe(`ethereum:${EVM_ADDRESS}@8453?value=2e18`);
|
|
35
|
+
});
|
|
36
|
+
(0, vitest_1.it)('targets the contract and moves the destination into the call for an erc20', () => {
|
|
37
|
+
(0, vitest_1.expect)((0, paymentUri_1.buildPaymentUri)({ address: EVM_ADDRESS, asset: USDC, amountCryptoPrecision: '1.5' })).toBe(`ethereum:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48@1/transfer?address=${EVM_ADDRESS}&uint256=1.5e6`);
|
|
38
|
+
});
|
|
39
|
+
(0, vitest_1.it)('keeps every digit of a full-precision erc20 amount', () => {
|
|
40
|
+
(0, vitest_1.expect)((0, paymentUri_1.buildPaymentUri)({
|
|
41
|
+
address: EVM_ADDRESS,
|
|
42
|
+
asset: FOX,
|
|
43
|
+
amountCryptoPrecision: '123.123456789012345678',
|
|
44
|
+
})).toBe(`ethereum:0xc770eefad204b5180df6a14ee197d99d808ee52d@1/transfer?address=${EVM_ADDRESS}&uint256=1.23123456789012345678e20`);
|
|
45
|
+
(0, vitest_1.expect)((0, paymentUri_1.buildPaymentUri)({ address: EVM_ADDRESS, asset: USDC, amountCryptoPrecision: '0.000001' })).toBe(`ethereum:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48@1/transfer?address=${EVM_ADDRESS}&uint256=1`);
|
|
46
|
+
});
|
|
47
|
+
(0, vitest_1.it)('builds a Solana Pay uri with ui units', () => {
|
|
48
|
+
(0, vitest_1.expect)((0, paymentUri_1.buildPaymentUri)({ address: SOL_ADDRESS, asset: SOL, amountCryptoPrecision: '1.5' })).toBe(`solana:${SOL_ADDRESS}?amount=1.5`);
|
|
49
|
+
});
|
|
50
|
+
(0, vitest_1.it)('names the mint and keeps the native account as recipient for an spl token', () => {
|
|
51
|
+
(0, vitest_1.expect)((0, paymentUri_1.buildPaymentUri)({ address: SOL_ADDRESS, asset: WIF, amountCryptoPrecision: '0.1' })).toBe(`solana:${SOL_ADDRESS}?amount=0.1&spl-token=EKpQGSJtjMFqKZ9KQanSqYXRcF8fBopzLHYxdM65zcjm`);
|
|
52
|
+
});
|
|
53
|
+
(0, vitest_1.it)('builds a ton transfer link in nanotons', () => {
|
|
54
|
+
(0, vitest_1.expect)((0, paymentUri_1.buildPaymentUri)({ address: TON_ADDRESS, asset: TON, amountCryptoPrecision: '1.5' })).toBe(`ton://transfer/${TON_ADDRESS}?amount=1500000000`);
|
|
55
|
+
});
|
|
56
|
+
(0, vitest_1.it)('names the jetton master and uses the jetton units for a jetton', () => {
|
|
57
|
+
(0, vitest_1.expect)((0, paymentUri_1.buildPaymentUri)({ address: TON_ADDRESS, asset: TON_USDT, amountCryptoPrecision: '5' })).toBe(`ton://transfer/${TON_ADDRESS}?jetton=EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs&amount=5000000`);
|
|
58
|
+
});
|
|
59
|
+
(0, vitest_1.it)('uses the cosmos sdk scheme', () => {
|
|
60
|
+
const address = 'cosmos1zqf0dq3nl3fhr8xk3pd2yq2sxwv0h2gd8qzptc';
|
|
61
|
+
(0, vitest_1.expect)((0, paymentUri_1.buildPaymentUri)({ address, asset: ATOM, amountCryptoPrecision: '1' })).toBe(`cosmos:${address}?amount=1`);
|
|
62
|
+
});
|
|
63
|
+
(0, vitest_1.it)('falls back to the bare address on a chain with no scheme', () => {
|
|
64
|
+
const address = '0x04a1b2c3';
|
|
65
|
+
const starknet = asset('starknet:SN_MAIN/slip44:9004', 'starknet:SN_MAIN', 18);
|
|
66
|
+
(0, vitest_1.expect)((0, paymentUri_1.buildPaymentUri)({ address, asset: starknet, amountCryptoPrecision: '1' })).toBe(address);
|
|
67
|
+
});
|
|
68
|
+
(0, vitest_1.it)('omits the amount from schemes that need one, but keeps the evm chain id', () => {
|
|
69
|
+
(0, vitest_1.expect)((0, paymentUri_1.buildPaymentUri)({ address: BTC_ADDRESS, asset: BTC })).toBe(BTC_ADDRESS);
|
|
70
|
+
(0, vitest_1.expect)((0, paymentUri_1.buildPaymentUri)({ address: SOL_ADDRESS, asset: SOL })).toBe(SOL_ADDRESS);
|
|
71
|
+
(0, vitest_1.expect)((0, paymentUri_1.buildPaymentUri)({ address: TON_ADDRESS, asset: TON_USDT })).toBe(TON_ADDRESS);
|
|
72
|
+
(0, vitest_1.expect)((0, paymentUri_1.buildPaymentUri)({ address: EVM_ADDRESS, asset: BASE_ETH })).toBe(`ethereum:${EVM_ADDRESS}@8453`);
|
|
73
|
+
});
|
|
74
|
+
(0, vitest_1.it)('passes a zero amount through', () => {
|
|
75
|
+
(0, vitest_1.expect)((0, paymentUri_1.buildPaymentUri)({ address: BTC_ADDRESS, asset: BTC, amountCryptoPrecision: '0' })).toBe(`bitcoin:${BTC_ADDRESS}?amount=0`);
|
|
76
|
+
(0, vitest_1.expect)((0, paymentUri_1.buildPaymentUri)({ address: EVM_ADDRESS, asset: ETH, amountCryptoPrecision: '0' })).toBe(`ethereum:${EVM_ADDRESS}@1?value=0`);
|
|
77
|
+
});
|
|
78
|
+
(0, vitest_1.it)('throws on a Solana address that is not a public key, as Solana Pay did', () => {
|
|
79
|
+
(0, vitest_1.expect)((0, paymentUri_1.buildPaymentUri)({ address: 'not-a-pubkey', asset: SOL })).toBe('not-a-pubkey');
|
|
80
|
+
(0, vitest_1.expect)(() => (0, paymentUri_1.buildPaymentUri)({ address: 'not-a-pubkey', asset: SOL, amountCryptoPrecision: '1' })).toThrow('Invalid Solana address');
|
|
81
|
+
(0, vitest_1.expect)(() => (0, paymentUri_1.buildPaymentUri)({ address: `${SOL_ADDRESS}1`, asset: SOL, amountCryptoPrecision: '1' })).toThrow('Invalid Solana address');
|
|
82
|
+
});
|
|
83
|
+
(0, vitest_1.it)('writes a scientific-notation amount as a plain decimal', () => {
|
|
84
|
+
(0, vitest_1.expect)((0, paymentUri_1.buildPaymentUri)({ address: BTC_ADDRESS, asset: BTC, amountCryptoPrecision: '1e-8' })).toBe(`bitcoin:${BTC_ADDRESS}?amount=0.00000001`);
|
|
85
|
+
(0, vitest_1.expect)((0, paymentUri_1.buildPaymentUri)({ address: SOL_ADDRESS, asset: SOL, amountCryptoPrecision: '1e-9' })).toBe(`solana:${SOL_ADDRESS}?amount=0.000000001`);
|
|
86
|
+
});
|
|
87
|
+
(0, vitest_1.it)('throws on an amount finer than the asset', () => {
|
|
88
|
+
(0, vitest_1.expect)(() => (0, paymentUri_1.buildPaymentUri)({ address: BTC_ADDRESS, asset: BTC, amountCryptoPrecision: '0.000000001' })).toThrow('exceeds 8 decimals');
|
|
89
|
+
(0, vitest_1.expect)(() => (0, paymentUri_1.buildPaymentUri)({ address: EVM_ADDRESS, asset: USDC, amountCryptoPrecision: '0.0000001' })).toThrow('exceeds 6 decimals');
|
|
90
|
+
});
|
|
91
|
+
(0, vitest_1.it)('throws on an amount no wallet could pay', () => {
|
|
92
|
+
(0, vitest_1.expect)(() => (0, paymentUri_1.buildPaymentUri)({ address: BTC_ADDRESS, asset: BTC, amountCryptoPrecision: '-1' })).toThrow('Invalid payment amount');
|
|
93
|
+
(0, vitest_1.expect)(() => (0, paymentUri_1.buildPaymentUri)({ address: EVM_ADDRESS, asset: ETH, amountCryptoPrecision: 'abc' })).toThrow('Invalid payment amount');
|
|
94
|
+
});
|
|
95
|
+
});
|