Resolve "Protocol Parsing: BIP21/PayPro, bch-mnemonic, etc"
This commit is contained in:
@@ -0,0 +1,169 @@
|
||||
import { test, expect, describe } from 'vitest';
|
||||
|
||||
import { PayPro } from '../../src/protocols/paypro.js';
|
||||
import { Address, Satoshis } from '@xocash/primitives';
|
||||
|
||||
const BCH_ADDRESS = 'bch:qrlt8kd0gy0z4kcpvr9lmqesjupp0jg4gym58kzted';
|
||||
const CASH_ADDRESS = 'bitcoincash:qrlt8kd0gy0z4kcpvr9lmqesjupp0jg4gyquzsnp0a';
|
||||
const TEST_TOKEN_CATEGORY_ID =
|
||||
'f6677f3d3805d70949b375d36e094ff0ec9ece2a2cb1fde6d8b0e90b368f1f63';
|
||||
|
||||
const BASE_RAW = {
|
||||
address: Address.fromCashAddr(CASH_ADDRESS),
|
||||
satoshis: Satoshis.fromSats(546),
|
||||
};
|
||||
|
||||
const SUCCESS_CASES = [
|
||||
// Basic URI
|
||||
{
|
||||
url: 'bch:qrlt8kd0gy0z4kcpvr9lmqesjupp0jg4gym58kzted',
|
||||
raw: BASE_RAW,
|
||||
result: `bch:zrlt8kd0gy0z4kcpvr9lmqesjupp0jg4gyu75gvdx7?s=546`,
|
||||
},
|
||||
// Basic URI with amount
|
||||
{
|
||||
url: 'bch:qrlt8kd0gy0z4kcpvr9lmqesjupp0jg4gym58kzted?amount=0.00000546',
|
||||
raw: BASE_RAW,
|
||||
result: `bch:zrlt8kd0gy0z4kcpvr9lmqesjupp0jg4gyu75gvdx7?s=546`,
|
||||
},
|
||||
// Basic URI with Sats and Amount
|
||||
{
|
||||
url: 'bch:qrlt8kd0gy0z4kcpvr9lmqesjupp0jg4gym58kzted?s=546&amount=0.00000546',
|
||||
raw: BASE_RAW,
|
||||
result: `bch:zrlt8kd0gy0z4kcpvr9lmqesjupp0jg4gyu75gvdx7?s=546`,
|
||||
},
|
||||
// URI with Tokens and Fungible Tokens
|
||||
{
|
||||
url: 'bch:qrlt8kd0gy0z4kcpvr9lmqesjupp0jg4gym58kzted?c=f6677f3d3805d70949b375d36e094ff0ec9ece2a2cb1fde6d8b0e90b368f1f63&f=10000',
|
||||
raw: {
|
||||
...BASE_RAW,
|
||||
satoshis: Satoshis.fromSats(657),
|
||||
tokenCategoryId: TEST_TOKEN_CATEGORY_ID,
|
||||
fungibleTokenAmount: 10000,
|
||||
},
|
||||
result: `bch:zrlt8kd0gy0z4kcpvr9lmqesjupp0jg4gyu75gvdx7?s=657&c=f6677f3d3805d70949b375d36e094ff0ec9ece2a2cb1fde6d8b0e90b368f1f63&f=10000`,
|
||||
},
|
||||
// URI with Tokens and Non-Fungible Tokens
|
||||
{
|
||||
url: 'bch:qrlt8kd0gy0z4kcpvr9lmqesjupp0jg4gym58kzted?c=f6677f3d3805d70949b375d36e094ff0ec9ece2a2cb1fde6d8b0e90b368f1f63&n=01',
|
||||
raw: {
|
||||
...BASE_RAW,
|
||||
satoshis: Satoshis.fromSats(654),
|
||||
tokenCategoryId: TEST_TOKEN_CATEGORY_ID,
|
||||
nftCommitment: '01',
|
||||
},
|
||||
result: `bch:zrlt8kd0gy0z4kcpvr9lmqesjupp0jg4gyu75gvdx7?s=654&c=f6677f3d3805d70949b375d36e094ff0ec9ece2a2cb1fde6d8b0e90b368f1f63&n=01`,
|
||||
},
|
||||
// URI with Sats, Token Category and Fungible Tokens
|
||||
{
|
||||
url: 'bch:qrlt8kd0gy0z4kcpvr9lmqesjupp0jg4gym58kzted?s=546&c=f6677f3d3805d70949b375d36e094ff0ec9ece2a2cb1fde6d8b0e90b368f1f63&f=10000',
|
||||
raw: {
|
||||
...BASE_RAW,
|
||||
tokenCategoryId: TEST_TOKEN_CATEGORY_ID,
|
||||
fungibleTokenAmount: 10000,
|
||||
},
|
||||
result: `bch:zrlt8kd0gy0z4kcpvr9lmqesjupp0jg4gyu75gvdx7?s=546&c=f6677f3d3805d70949b375d36e094ff0ec9ece2a2cb1fde6d8b0e90b368f1f63&f=10000`,
|
||||
},
|
||||
// URI with Sats, Token Category and Non-Fungible Tokens
|
||||
{
|
||||
url: 'bch:qrlt8kd0gy0z4kcpvr9lmqesjupp0jg4gym58kzted?s=546&c=f6677f3d3805d70949b375d36e094ff0ec9ece2a2cb1fde6d8b0e90b368f1f63&n=01',
|
||||
raw: {
|
||||
...BASE_RAW,
|
||||
tokenCategoryId: TEST_TOKEN_CATEGORY_ID,
|
||||
nftCommitment: '01',
|
||||
},
|
||||
result: `bch:zrlt8kd0gy0z4kcpvr9lmqesjupp0jg4gyu75gvdx7?s=546&c=f6677f3d3805d70949b375d36e094ff0ec9ece2a2cb1fde6d8b0e90b368f1f63&n=01`,
|
||||
},
|
||||
// URI with Expiry
|
||||
{
|
||||
url: 'bch:qrlt8kd0gy0z4kcpvr9lmqesjupp0jg4gym58kzted?e=1715769600',
|
||||
raw: {
|
||||
...BASE_RAW,
|
||||
expiry: 1715769600,
|
||||
},
|
||||
result: `bch:zrlt8kd0gy0z4kcpvr9lmqesjupp0jg4gyu75gvdx7?s=546&e=1715769600`,
|
||||
},
|
||||
// URI with Message
|
||||
{
|
||||
url: 'bch:qrlt8kd0gy0z4kcpvr9lmqesjupp0jg4gym58kzted?m=Hello',
|
||||
raw: {
|
||||
...BASE_RAW,
|
||||
message: 'Hello',
|
||||
},
|
||||
result: `bch:zrlt8kd0gy0z4kcpvr9lmqesjupp0jg4gyu75gvdx7?s=546&m=Hello`,
|
||||
},
|
||||
// URI with Message and Expiry
|
||||
{
|
||||
url: 'bch:qrlt8kd0gy0z4kcpvr9lmqesjupp0jg4gym58kzted?m=Hello&e=1715769600',
|
||||
raw: {
|
||||
...BASE_RAW,
|
||||
message: 'Hello',
|
||||
expiry: 1715769600,
|
||||
},
|
||||
result: `bch:zrlt8kd0gy0z4kcpvr9lmqesjupp0jg4gyu75gvdx7?s=546&m=Hello&e=1715769600`,
|
||||
},
|
||||
// URI with optional params
|
||||
{
|
||||
url: 'bch:qrlt8kd0gy0z4kcpvr9lmqesjupp0jg4gym58kzted?x-custom=value',
|
||||
raw: BASE_RAW,
|
||||
result: `bch:zrlt8kd0gy0z4kcpvr9lmqesjupp0jg4gyu75gvdx7?s=546`,
|
||||
},
|
||||
// URI with multiple optional params
|
||||
{
|
||||
url: 'bch:qrlt8kd0gy0z4kcpvr9lmqesjupp0jg4gym58kzted?x-custom=value&x-custom2=value2',
|
||||
raw: BASE_RAW,
|
||||
result: `bch:zrlt8kd0gy0z4kcpvr9lmqesjupp0jg4gyu75gvdx7?s=546`,
|
||||
},
|
||||
];
|
||||
|
||||
const FAILURE_CASES = [
|
||||
// Duplicate amount
|
||||
`${BCH_ADDRESS}?amount=1&amount=2`,
|
||||
// Duplicate sats
|
||||
`${BCH_ADDRESS}?s=1&s=2`,
|
||||
// Duplicate token category
|
||||
`${BCH_ADDRESS}?c=1&c=2`,
|
||||
// Category without tokens
|
||||
`${BCH_ADDRESS}?c=1`,
|
||||
// Fungible tokens without category
|
||||
`${BCH_ADDRESS}?f=1`,
|
||||
// Non-fungible tokens without category
|
||||
`${BCH_ADDRESS}?n=1`,
|
||||
// Amount and sats are different
|
||||
`${BCH_ADDRESS}?s=1&amount=2`,
|
||||
// requestUrl is populated
|
||||
`${BCH_ADDRESS}?r=https://example.com`,
|
||||
// Invalid key
|
||||
`${BCH_ADDRESS}?invalid=1`,
|
||||
// Invalid amount
|
||||
`${BCH_ADDRESS}?amount=invalid`,
|
||||
// Invalid sats
|
||||
`${BCH_ADDRESS}?s=invalid`,
|
||||
// Invalid expiry
|
||||
`${BCH_ADDRESS}?e=invalid`,
|
||||
// Not an address
|
||||
`bch:invalid`,
|
||||
// Bip21
|
||||
`bitcoincash:qrlt8kd0gy0z4kcpvr9lmqesjupp0jg4gyquzsnp0a`,
|
||||
// Bip21 with amount
|
||||
`bitcoincash:qrlt8kd0gy0z4kcpvr9lmqesjupp0jg4gyquzsnp0a?amount=0.00000546`,
|
||||
];
|
||||
|
||||
describe('PayProPaymentUrl', () => {
|
||||
test.each(SUCCESS_CASES)('should be able to parse a valid url', (url) => {
|
||||
const paymentUrl = PayPro.from(url.url);
|
||||
expect(paymentUrl.toRaw()).toEqual(url.raw);
|
||||
if (url.result) {
|
||||
expect(paymentUrl.toUrl()).toEqual(url.result);
|
||||
} else {
|
||||
expect(paymentUrl.toUrl()).toEqual(url.url);
|
||||
}
|
||||
});
|
||||
|
||||
test.each(FAILURE_CASES)(
|
||||
'should throw an error for an invalid url',
|
||||
(url) => {
|
||||
expect(() => PayPro.from(url)).toThrow();
|
||||
},
|
||||
);
|
||||
});
|
||||
Reference in New Issue
Block a user