Files
hash-wallet/cw_core/test/payment_uris_test.dart
T
90194f7136 CW-1523-AnyPay Redesign (#3383)
* feat: Add network selector and compatible networks screen to send page for EVMs

* feat: add redesigned payanything flow and handle cases for evms, solana and tron

* feat: adding the swap part to the entire flow

* refactor: update navigation and error handling in send and swap flows

* adjust structuring and use the chain badge icons, also fix crypto and currency values not consistent on single network picker

* fix: modify guard for non-evm chains and minor cleanup

* use multipicker layout for receive section, streamline send to available balances and adjust colors as needed

* handle btc case for picker, update style and images across

* fix all pending issues with scanning qr and network handling for both evm and non evm, plus token and amount resolving

* fix all pending issues with scanning qr and network handling for both evm and non evm, plus token and amount resolving

* fix: expand fetch for tokens across networks and fix other issues regarding scanning from homepage

* auto-reformat

* fix conflict

* handle evm qr scan from homepage and add guards for swap and switch flows

* chore: Cleanup

* chore: set estimated fee to 0 when switching wallet

* fix merge conflicts

* fix to review comments and reformatting for lints

* fix: root cause for token bug reported

* chore: cleanup

* feat: add improved anypay swap screen which focuses on the receive amount
fix: fiat input toggle erro (also present on prod)
reformat: anypay related widgets

* feat: add alert for unsupported networks in payment requests

* fix: prevent rate and provider from showing until amount is calculated and loaded
fix: remove send icon in rate widget and align to center
fix: adjust network badge in swap confirm widget

* feat: embed tokens for solana and tron in QR generated for swap from external

* test: add unit tests for Tron, Solana, and ERC681 URI handling and detection

* fix: review comments

* fix: handle more edgecases

* feat: enhance ERC681URI to support raw token amounts and decimals

* refactor: streamline EVM chain ID retrieval in send page and recipient network row

* fix: minor review comments

---------

Co-authored-by: Robert Malikowski <malikowskirobert@gmail.com>
2026-08-11 02:16:12 +02:00

223 lines
7.2 KiB
Dart

import "package:cw_core/payment_uris.dart";
import "package:flutter_test/flutter_test.dart";
void main() {
group("TronURI", () {
const address = "TNPeeaaFB7K9cmo4uQpcU32zGK8G1NYqeL";
const contract = "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t";
test("includes the TRC20 contract as the token param", () {
final uri = TronURI(amount: "1.5", address: address, contractAddress: contract);
expect(uri.toString(), "tron:$address?amount=1.5&token=$contract");
});
test("omits the token param for native TRX", () {
final uri = TronURI(amount: "1.5", address: address);
expect(uri.toString(), "tron:$address?amount=1.5");
expect(uri.toString().contains("token="), false);
});
test("includes the token param when there is no amount", () {
final uri = TronURI(amount: "", address: address, contractAddress: contract);
expect(uri.toString(), "tron:$address?token=$contract");
});
test("converts a comma decimal separator in the amount", () {
final uri = TronURI(amount: "1,5", address: address);
expect(uri.toString(), "tron:$address?amount=1.5");
});
test("emits a bare address without amount or contract", () {
final uri = TronURI(amount: "", address: address);
expect(uri.toString(), "tron:$address");
});
});
group("SolanaURI", () {
const address = "4Nd1mYvNQyJ8BDVXLgkvSGpVdQMZ3hxwVFkfwXNq6Wgk";
const mint = "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB";
test("includes the SPL mint as the spl-token param", () {
final uri = SolanaURI(amount: "2", address: address, contractAddress: mint);
expect(uri.toString(), "solana:$address?amount=2&spl-token=$mint");
});
test("omits the spl-token param for native SOL", () {
final uri = SolanaURI(amount: "2", address: address);
expect(uri.toString(), "solana:$address?amount=2");
expect(uri.toString().contains("spl-token="), false);
});
test("includes the spl-token param when there is no amount", () {
final uri = SolanaURI(amount: "", address: address, contractAddress: mint);
expect(uri.toString(), "solana:$address?spl-token=$mint");
});
test("converts a comma decimal separator in the amount", () {
final uri = SolanaURI(amount: "0,5", address: address);
expect(uri.toString(), "solana:$address?amount=0.5");
});
test("emits a bare address without amount or mint", () {
final uri = SolanaURI(amount: "", address: address);
expect(uri.toString(), "solana:$address");
});
});
group("ERC681URI", () {
const recipient = "0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6";
const contract = "0xdAC17F958D2ee523a2206206994597C13D831ec7";
test("builds a plain native transfer on mainnet", () {
final uri = ERC681URI(chainId: 1, address: recipient, amount: "", contractAddress: null);
expect(uri.toString(), "ethereum:$recipient");
});
test("appends the chainId for non-mainnet native transfers", () {
final uri = ERC681URI(chainId: 137, address: recipient, amount: "", contractAddress: null);
expect(uri.toString(), "ethereum:$recipient@137");
});
test("emits the native amount in ERC-681 scientific notation", () {
final uri = ERC681URI(chainId: 1, address: recipient, amount: "1", contractAddress: null);
expect(uri.toString(), "ethereum:$recipient?value=1.0e18");
});
test("builds the transfer form for a token", () {
final uri =
ERC681URI(chainId: 137, address: recipient, amount: "", contractAddress: contract);
expect(uri.toString(), "ethereum:$contract@137/transfer?address=$recipient");
});
test("parses the transfer form back into recipient, contract and chainId", () {
final parsed = ERC681URI.fromUri(
Uri.parse("ethereum:$contract@1/transfer?address=$recipient&uint256=1000000"),
);
expect(parsed.address, recipient);
expect(parsed.contractAddress, contract);
expect(parsed.chainId, 1);
expect(parsed.rawTokenAmount, "1000000");
expect(parsed.amount, "");
});
test("keeps the uint256 raw so the caller can apply the token decimals", () {
final parsed = ERC681URI.fromUri(
Uri.parse(
"ethereum:0xdAC17F958D2ee523a2206206994597C13D831ec7@1/transfer?address=$recipient&uint256=1000000",
),
);
expect(parsed.rawTokenAmount, "1000000");
expect(parsed.amount, "");
});
test("prefers the amount param over the uint256 when both are present", () {
final parsed = ERC681URI.fromUri(
Uri.parse(
"ethereum:$contract@1/transfer?address=$recipient&uint256=1000000000000000000&amount=1",
),
);
expect(parsed.amount, "1");
expect(parsed.rawTokenAmount, "1000000000000000000");
});
test("treats a uint256 with a decimal point as a display amount", () {
final parsed = ERC681URI.fromUri(
Uri.parse("ethereum:$contract@1/transfer?address=$recipient&uint256=1.5"),
);
expect(parsed.amount, "1.5");
expect(parsed.rawTokenAmount, null);
});
test("parses a native transfer with chainId", () {
final parsed = ERC681URI.fromUri(
Uri.parse("ethereum:$recipient@137?value=2000000000000000000"),
);
expect(parsed.address, recipient);
expect(parsed.contractAddress, null);
expect(parsed.chainId, 137);
expect(parsed.amount, "2");
});
test("emits the uint256 and the amount param for an 18 decimal token", () {
final uri =
ERC681URI(chainId: 137, address: recipient, amount: "1", contractAddress: contract);
expect(
uri.toString(),
"ethereum:$contract@137/transfer?address=$recipient&uint256=1000000000000000000&amount=1",
);
});
test("omits the uint256 for tokens that do not use 18 decimals", () {
final uri = ERC681URI(
chainId: 137,
address: recipient,
amount: "1.5",
contractAddress: contract,
tokenDecimals: 6,
);
expect(uri.toString(), "ethereum:$contract@137/transfer?address=$recipient&amount=1.5");
});
test("emits a stored raw token amount verbatim", () {
final uri = ERC681URI(
chainId: 1,
address: recipient,
amount: "",
contractAddress: contract,
tokenDecimals: 6,
rawTokenAmount: "1000000",
);
expect(uri.toString(), "ethereum:$contract/transfer?address=$recipient&uint256=1000000");
});
test("parses a scientific notation value", () {
final parsed = ERC681URI.fromUri(
Uri.parse("ethereum:$recipient@1?value=2.014e18"),
);
expect(parsed.amount, "2.014");
});
test("parses a Cake style amount param", () {
final parsed = ERC681URI.fromUri(
Uri.parse("ethereum:$recipient?amount=1.5"),
);
expect(parsed.address, recipient);
expect(parsed.amount, "1.5");
expect(parsed.chainId, 1);
});
test("defaults to mainnet when the chainId is absent", () {
final parsed = ERC681URI.fromUri(Uri.parse("ethereum:$recipient"));
expect(parsed.address, recipient);
expect(parsed.contractAddress, null);
expect(parsed.chainId, 1);
expect(parsed.amount, "");
});
});
}