@anywalletkit/protocol-swap2-usdt0 0.2.1 → 0.4.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/config.cjs CHANGED
@@ -24,11 +24,16 @@ __export(config_exports, {
24
24
  USDT0_BY_EID: () => USDT0_BY_EID,
25
25
  USDT0_CHAINS: () => USDT0_CHAINS,
26
26
  USDT0_SYMBOLS: () => USDT0_SYMBOLS,
27
+ tokenMatches: () => tokenMatches,
27
28
  usdt0: () => usdt0,
28
- usdt0Pins: () => usdt0Pins
29
+ usdt0ClaimTargets: () => usdt0ClaimTargets,
30
+ usdt0Pins: () => usdt0Pins,
31
+ usdt0VerifyQuote: () => usdt0VerifyQuote
29
32
  });
30
33
  module.exports = __toCommonJS(config_exports);
34
+ var import_viem = require("viem");
31
35
  var import_util = require("@anywalletkit/protocol-swap2-core/util");
36
+ var import_swap2_assets = require("@anywalletkit/swap2-assets");
32
37
  var LZ_ENDPOINT_A = "0x1a44076050125825900e736c501f859c50fE728c";
33
38
  var LZ_ENDPOINT_B = "0x6F475642a6e85809B1c36Fa62763669b1b48DD5B";
34
39
  var c = (chainId, eid, name, token, oft, endpoint, adapter = false) => ({
@@ -74,6 +79,71 @@ var usdt0 = {
74
79
  return from !== to && this.supportsChain(from) && this.supportsChain(to);
75
80
  }
76
81
  };
82
+ var OFT_SEND_ABI = (0, import_viem.parseAbi)([
83
+ "struct SendParam { uint32 dstEid; bytes32 to; uint256 amountLD; uint256 minAmountLD; bytes extraOptions; bytes composeMsg; bytes oftCmd; }",
84
+ "struct MessagingFee { uint256 nativeFee; uint256 lzTokenFee; }",
85
+ "function send(SendParam s, MessagingFee fee, address refundAddress) payable"
86
+ ]);
87
+ function tokenMatches(chain, symbolOrAddress) {
88
+ const same = (a, b) => !!a && a.toLowerCase() === b.toLowerCase();
89
+ if (symbolOrAddress.startsWith("0x")) return same(symbolOrAddress, chain.token);
90
+ if (!USDT0_SYMBOLS.includes(symbolOrAddress.toUpperCase().replace("USD\u20AE", "USDT"))) return false;
91
+ const known = (0, import_swap2_assets.ccAsset)(chain.caip2, symbolOrAddress);
92
+ return !known || same(known.contract ?? "", chain.token);
93
+ }
94
+ function usdt0VerifyQuote(params, quote) {
95
+ const src = usdt0ChainFor(params.sourceChain);
96
+ const dst = usdt0ChainFor(params.destChain);
97
+ if (!src || !dst || src === dst) return "not a USDT0 route between two deployments";
98
+ if (!tokenMatches(src, params.sourceToken)) return `source token ${params.sourceToken} is not USDT0 (${src.token}) on ${src.name}`;
99
+ if (!tokenMatches(dst, params.destToken)) return `destination token ${params.destToken} is not USDT0 (${dst.token}) on ${dst.name}`;
100
+ const tx = quote.txRequest;
101
+ if (!tx?.data || !tx.to || tx.serializedTx !== void 0) return "the quote carries no OFT call";
102
+ if (tx.to.toLowerCase() !== src.oft.toLowerCase()) return `the call targets ${tx.to}, not the ${src.name} OFT`;
103
+ if (tx.chainId !== void 0 && tx.chainId !== src.chainId) return `the call is for chain ${tx.chainId}, not ${src.chainId}`;
104
+ if (src.adapter ? !tx.approvalAddress || tx.approvalAddress.toLowerCase() !== src.oft.toLowerCase() : tx.approvalAddress !== void 0) {
105
+ return src.adapter ? "the Ethereum send approves another spender than the adapter" : "an OFT send needs no approval";
106
+ }
107
+ let sp;
108
+ let fee;
109
+ let refund;
110
+ try {
111
+ const d = (0, import_viem.decodeFunctionData)({ abi: OFT_SEND_ABI, data: tx.data });
112
+ [sp, fee, refund] = d.args;
113
+ } catch {
114
+ return "the call is not send(SendParam, MessagingFee, refund)";
115
+ }
116
+ let amountIn, floor, value;
117
+ try {
118
+ amountIn = BigInt(params.amountIn);
119
+ floor = BigInt(quote.minDestAmount);
120
+ if (params.minAmountOut !== void 0 && BigInt(params.minAmountOut) > floor) floor = BigInt(params.minAmountOut);
121
+ value = BigInt(tx.value ?? "0");
122
+ } catch {
123
+ return "the request does not name amounts";
124
+ }
125
+ if (sp.dstEid !== dst.eid) return `the send goes to eid ${sp.dstEid}, not ${dst.name} (${dst.eid})`;
126
+ if (sp.amountLD !== amountIn || BigInt(quote.sourceAmount) !== amountIn) return `the send moves ${sp.amountLD}, not the ${amountIn} input`;
127
+ if (sp.minAmountLD > sp.amountLD || sp.minAmountLD <= 0n || sp.minAmountLD < floor) return `the send's minAmountLD ${sp.minAmountLD} is below the ${floor} minimum`;
128
+ if (sp.extraOptions !== "0x" || sp.composeMsg !== "0x" || sp.oftCmd !== "0x") return "the send carries options, a compose message or an OFT command";
129
+ const live = params.dry === false;
130
+ if (params.destAddress || live) {
131
+ if (!(0, import_viem.isAddress)(params.destAddress)) return "the recipient is not an EVM address";
132
+ if (sp.to.toLowerCase() !== (0, import_viem.pad)((0, import_viem.getAddress)(params.destAddress), { size: 32 }).toLowerCase()) return `the send delivers to ${sp.to}, not the recipient`;
133
+ }
134
+ if (params.refundAddress || live) {
135
+ if (!(0, import_viem.isAddress)(params.refundAddress ?? "")) return "the refund address is not an EVM address";
136
+ if ((0, import_viem.getAddress)(refund) !== (0, import_viem.getAddress)(params.refundAddress)) return `the send refunds ${refund}, not the trader`;
137
+ }
138
+ if (fee.lzTokenFee !== 0n) return "the send pays an LZ-token fee";
139
+ if (value !== fee.nativeFee || (tx.nativeFee ?? "0") !== fee.nativeFee.toString()) return "msg.value is not the declared native fee of the send";
140
+ if (quote.intentId.replace(/~[0-9a-f]{32}$/, "") !== `usdt0:${src.eid}:${dst.eid}`) return "the intent id does not name this send";
141
+ return null;
142
+ }
143
+ function usdt0ClaimTargets(chain) {
144
+ const c2 = usdt0ChainFor(chain);
145
+ return c2 ? [c2.endpoint] : [];
146
+ }
77
147
  var usdt0Pins = Object.freeze({
78
148
  callTargets: (chain) => {
79
149
  const c2 = usdt0ChainFor(chain);
@@ -82,7 +152,9 @@ var usdt0Pins = Object.freeze({
82
152
  spenders: (chain) => {
83
153
  const c2 = usdt0ChainFor(chain);
84
154
  return c2?.adapter ? [c2.oft] : [];
85
- }
155
+ },
156
+ claimTargets: usdt0ClaimTargets,
157
+ verifyQuote: usdt0VerifyQuote
86
158
  });
87
159
  function usdt0ChainFor(chain) {
88
160
  return Object.prototype.hasOwnProperty.call(USDT0_CHAINS, chain) ? USDT0_CHAINS[chain] : void 0;
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/config.ts"],"sourcesContent":["// USDT0 — Tether's LayerZero OFT for USDT. Source: docs.usdt0.to\n// (technical-documentation/deployments, read 2026-10-20) — every row below was\n// then re-read on-chain over public RPCs the same day: the OFT's `token()` is\n// the listed token, `endpoint()` is the listed endpoint (and reports the\n// listed eid), `approvalRequired()` is true only for the Ethereum adapter,\n// `sharedDecimals()` = 6 everywhere, and `peers(eid)` are wired between the\n// chains. `oftVersion()` = (0x02e49c2c, 1) on all of them.\n//\n// Only chains the SDK ships (swap2-assets / wallet-evm) are listed. USDT0 is\n// also deployed on Conflux eSpace (1030, eid 30212), Flare (14, 30295),\n// Hedera (295, 30316), Mantle (5000, 30181), Morph (2818, 30322), Rootstock\n// (30, 30333), Stable (988, 30396), Tempo (4217, 30410), plus HyperCore, IOTA\n// and Stellar (non-EVM) — not wallet chains here, so not routable here.\nimport type {RemotePins} from \"@anywalletkit/protocol-swap2-core/types\";\nimport {evmRef, isEvm} from \"@anywalletkit/protocol-swap2-core/util\";\n\nexport interface Usdt0Chain {\n caip2: string;\n chainId: number;\n /** LayerZero V2 endpoint id. */\n eid: number;\n name: string;\n /** The ERC-20 the user holds: USDT on Ethereum, USDT0 elsewhere (6 decimals everywhere). */\n token: string;\n /**\n * The OFT contract `quoteSend` / `send` are called on. On Ethereum it is the\n * OFT *adapter* that locks USDT (`approvalRequired()` = true, approve the\n * token to it); elsewhere it is the OUpgradeable OFT that burns the caller's\n * USDT0 through the token's mint/burn role — no approval.\n */\n oft: string;\n /** LayerZero V2 EndpointV2 on that chain (`lzReceive` retries of a stored payload go here). */\n endpoint: string;\n /** True on Ethereum: the OFT is a lockbox adapter in front of plain USDT. */\n adapter: boolean;\n}\n\nconst LZ_ENDPOINT_A = \"0x1a44076050125825900e736c501f859c50fE728c\";\nconst LZ_ENDPOINT_B = \"0x6F475642a6e85809B1c36Fa62763669b1b48DD5B\";\n\nconst c = (chainId: number, eid: number, name: string, token: string, oft: string, endpoint: string, adapter = false): Usdt0Chain => ({\n caip2: `eip155:${chainId}`, chainId, eid, name, token, oft, endpoint, adapter,\n});\n\n/** CAIP-2 → USDT0 deployment. */\nexport const USDT0_CHAINS: Readonly<Record<string, Usdt0Chain>> = Object.freeze(Object.fromEntries([\n c(1, 30101, \"Ethereum\", \"0xdAC17F958D2ee523a2206206994597C13D831ec7\", \"0x6C96dE32CEa08842dcc4058c14d3aaAD7Fa41dee\", LZ_ENDPOINT_A, true),\n c(42161, 30110, \"Arbitrum\", \"0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9\", \"0x14E4A1B13bf7F943c8ff7C51fb60FA964A298D92\", LZ_ENDPOINT_A),\n c(10, 30111, \"OP Mainnet\", \"0x01bFF41798a0BcF287b996046Ca68b395DbC1071\", \"0xF03b4d9AC1D5d1E7c4cEf54C2A313b9fe051A0aD\", LZ_ENDPOINT_A),\n c(137, 30109, \"Polygon PoS\", \"0xc2132D05D31c914a87C6611C10748AEb04B58e8F\", \"0x6BA10300f0DC58B7a1e4c0e41f5daBb7D7829e13\", LZ_ENDPOINT_A),\n c(999, 30367, \"HyperEVM\", \"0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb\", \"0x904861a24F30EC96ea7CFC3bE9EA4B476d237e98\", \"0x3A73033C0b1407574C76BdBAc67f126f6b4a9AA9\"),\n c(57073, 30339, \"Ink\", \"0x0200C29006150606B650577BBE7B6248F58470c1\", \"0x1cB6De532588fCA4a21B7209DE7C456AF8434A65\", \"0xca29f3A6f966Cb2fc0dE625F8f325c0C46dbE958\"),\n c(80094, 30362, \"Berachain\", \"0x779Ded0c9e1022225f8E0630b35a9b54bE713736\", \"0x3Dc96399109df5ceb2C226664A086140bD0379cB\", LZ_ENDPOINT_B),\n c(130, 30320, \"Unichain\", \"0x9151434b16b9763660705744891fA906F660EcC5\", \"0xc07bE8994D035631c36fb4a89C918CeFB2f03EC3\", LZ_ENDPOINT_B),\n c(1329, 30280, \"Sei\", \"0x9151434b16b9763660705744891fA906F660EcC5\", \"0x56Fe74A2e3b484b921c447357203431a3485CC60\", LZ_ENDPOINT_A),\n c(9745, 30383, \"Plasma\", \"0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb\", \"0x02ca37966753bDdDf11216B73B16C1dE756A7CF9\", LZ_ENDPOINT_B),\n c(143, 30390, \"Monad\", \"0xe7cd86e13AC4309349F30B3435a9d337750fC82D\", \"0x9151434b16b9763660705744891fA906F660EcC5\", LZ_ENDPOINT_B),\n c(4326, 30398, \"MegaETH\", \"0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb\", \"0x9151434b16b9763660705744891fA906F660EcC5\", LZ_ENDPOINT_B),\n c(196, 30274, \"X Layer\", \"0x779Ded0c9e1022225f8E0630b35a9b54bE713736\", \"0x94bcCa6BdfD6a61817aB0E960BfedE4984505554\", LZ_ENDPOINT_A),\n // 2026-10-20 (evm-chains-6 batch): docs.usdt0.to deployments, re-read on-chain (token(), approvalRequired() = false,\n // sharedDecimals() = 6, endpoint(), peers(30110) = the Arbitrum OFT).\n c(5000, 30181, \"Mantle\", \"0x779Ded0c9e1022225f8E0630b35a9b54bE713736\", \"0xcb768e263FB1C62214E7cab4AA8d036D76dc59CC\", LZ_ENDPOINT_A),\n c(2818, 30322, \"Morph\", \"0xe7cd86e13AC4309349F30B3435a9d337750fC82D\", \"0xcb768e263FB1C62214E7cab4AA8d036D76dc59CC\", LZ_ENDPOINT_B),\n c(14, 30295, \"Flare\", \"0xe7cd86e13AC4309349F30B3435a9d337750fC82D\", \"0x567287d2A9829215a37e3B88843d32f9221E7588\", LZ_ENDPOINT_A),\n].map((x) => [x.caip2, x])));\n\n/** LayerZero eid → deployment. */\nexport const USDT0_BY_EID: Readonly<Record<number, Usdt0Chain>> = Object.freeze(\n Object.fromEntries(Object.values(USDT0_CHAINS).map((x) => [x.eid, x])),\n);\n\n/** LayerZero Scan — message status by source transaction hash. */\nexport const LZ_SCAN_API = \"https://scan.layerzero-api.com\";\n\n/** Token symbols the catalog uses for the same asset across chains. */\nexport const USDT0_SYMBOLS: readonly string[] = Object.freeze([\"USDT0\", \"USDT\", \"USD₮0\", \"USD₮\"]);\n\nexport const usdt0 = {\n supportsChain(chain: string): boolean {\n return isEvm(chain) && !!USDT0_CHAINS[`eip155:${evmRef(chain)}`];\n },\n supports(from: string, to: string): boolean {\n return from !== to && this.supportsChain(from) && this.supportsChain(to);\n },\n};\n\n/**\n * The USDT0 OFT a send calls on a chain, and the adapter it approves where one locks USDT (Ethereum) —\n * the app's pins for `remoteProvider({name: \"usdt0\", baseUrl, ...usdt0Pins})` (scan 2026-10-27 modules, F8/F16).\n */\nexport const usdt0Pins: RemotePins = Object.freeze({\n callTargets: (chain: string): readonly string[] => { const c = usdt0ChainFor(chain); return c ? [c.oft] : []; },\n spenders: (chain: string): readonly string[] => { const c = usdt0ChainFor(chain); return c?.adapter ? [c.oft] : []; },\n});\nfunction usdt0ChainFor(chain: string): Usdt0Chain | undefined {\n return Object.prototype.hasOwnProperty.call(USDT0_CHAINS, chain) ? USDT0_CHAINS[chain] : undefined;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAcA,kBAA4B;AAuB5B,IAAM,gBAAgB;AACtB,IAAM,gBAAgB;AAEtB,IAAM,IAAI,CAAC,SAAiB,KAAa,MAAc,OAAe,KAAa,UAAkB,UAAU,WAAuB;AAAA,EACpI,OAAO,UAAU,OAAO;AAAA,EAAI;AAAA,EAAS;AAAA,EAAK;AAAA,EAAM;AAAA,EAAO;AAAA,EAAK;AAAA,EAAU;AACxE;AAGO,IAAM,eAAqD,OAAO,OAAO,OAAO,YAAY;AAAA,EACjG,EAAE,GAAG,OAAO,YAAY,8CAA8C,8CAA8C,eAAe,IAAI;AAAA,EACvI,EAAE,OAAO,OAAO,YAAY,8CAA8C,8CAA8C,aAAa;AAAA,EACrI,EAAE,IAAI,OAAO,cAAc,8CAA8C,8CAA8C,aAAa;AAAA,EACpI,EAAE,KAAK,OAAO,eAAe,8CAA8C,8CAA8C,aAAa;AAAA,EACtI,EAAE,KAAK,OAAO,YAAY,8CAA8C,8CAA8C,4CAA4C;AAAA,EAClK,EAAE,OAAO,OAAO,OAAO,8CAA8C,8CAA8C,4CAA4C;AAAA,EAC/J,EAAE,OAAO,OAAO,aAAa,8CAA8C,8CAA8C,aAAa;AAAA,EACtI,EAAE,KAAK,OAAO,YAAY,8CAA8C,8CAA8C,aAAa;AAAA,EACnI,EAAE,MAAM,OAAO,OAAO,8CAA8C,8CAA8C,aAAa;AAAA,EAC/H,EAAE,MAAM,OAAO,UAAU,8CAA8C,8CAA8C,aAAa;AAAA,EAClI,EAAE,KAAK,OAAO,SAAS,8CAA8C,8CAA8C,aAAa;AAAA,EAChI,EAAE,MAAM,OAAO,WAAW,8CAA8C,8CAA8C,aAAa;AAAA,EACnI,EAAE,KAAK,OAAO,WAAW,8CAA8C,8CAA8C,aAAa;AAAA;AAAA;AAAA,EAGlI,EAAE,KAAM,OAAO,UAAU,8CAA8C,8CAA8C,aAAa;AAAA,EAClI,EAAE,MAAM,OAAO,SAAS,8CAA8C,8CAA8C,aAAa;AAAA,EACjI,EAAE,IAAI,OAAO,SAAS,8CAA8C,8CAA8C,aAAa;AACjI,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;AAGpB,IAAM,eAAqD,OAAO;AAAA,EACvE,OAAO,YAAY,OAAO,OAAO,YAAY,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;AACvE;AAGO,IAAM,cAAc;AAGpB,IAAM,gBAAmC,OAAO,OAAO,CAAC,SAAS,QAAQ,cAAS,WAAM,CAAC;AAEzF,IAAM,QAAQ;AAAA,EACnB,cAAc,OAAwB;AACpC,eAAO,mBAAM,KAAK,KAAK,CAAC,CAAC,aAAa,cAAU,oBAAO,KAAK,CAAC,EAAE;AAAA,EACjE;AAAA,EACA,SAAS,MAAc,IAAqB;AAC1C,WAAO,SAAS,MAAM,KAAK,cAAc,IAAI,KAAK,KAAK,cAAc,EAAE;AAAA,EACzE;AACF;AAMO,IAAM,YAAwB,OAAO,OAAO;AAAA,EACjD,aAAa,CAAC,UAAqC;AAAE,UAAMA,KAAI,cAAc,KAAK;AAAG,WAAOA,KAAI,CAACA,GAAE,GAAG,IAAI,CAAC;AAAA,EAAG;AAAA,EAC9G,UAAU,CAAC,UAAqC;AAAE,UAAMA,KAAI,cAAc,KAAK;AAAG,WAAOA,IAAG,UAAU,CAACA,GAAE,GAAG,IAAI,CAAC;AAAA,EAAG;AACtH,CAAC;AACD,SAAS,cAAc,OAAuC;AAC5D,SAAO,OAAO,UAAU,eAAe,KAAK,cAAc,KAAK,IAAI,aAAa,KAAK,IAAI;AAC3F;","names":["c"]}
1
+ {"version":3,"sources":["../src/config.ts"],"sourcesContent":["// USDT0 — Tether's LayerZero OFT for USDT. Source: docs.usdt0.to\n// (technical-documentation/deployments, read 2026-10-20) — every row below was\n// then re-read on-chain over public RPCs the same day: the OFT's `token()` is\n// the listed token, `endpoint()` is the listed endpoint (and reports the\n// listed eid), `approvalRequired()` is true only for the Ethereum adapter,\n// `sharedDecimals()` = 6 everywhere, and `peers(eid)` are wired between the\n// chains. `oftVersion()` = (0x02e49c2c, 1) on all of them.\n//\n// Only chains the SDK ships (swap2-assets / wallet-evm) are listed. USDT0 is\n// also deployed on Conflux eSpace (1030, eid 30212), Flare (14, 30295),\n// Hedera (295, 30316), Mantle (5000, 30181), Morph (2818, 30322), Rootstock\n// (30, 30333), Stable (988, 30396), Tempo (4217, 30410), plus HyperCore, IOTA\n// and Stellar (non-EVM) — not wallet chains here, so not routable here.\nimport {decodeFunctionData, getAddress, isAddress, pad, parseAbi, type Hex} from \"viem\";\nimport type {Quote, QuoteParams, RemotePins} from \"@anywalletkit/protocol-swap2-core/types\";\nimport {evmRef, isEvm} from \"@anywalletkit/protocol-swap2-core/util\";\nimport {ccAsset} from \"@anywalletkit/swap2-assets\";\n\nexport interface Usdt0Chain {\n caip2: string;\n chainId: number;\n /** LayerZero V2 endpoint id. */\n eid: number;\n name: string;\n /** The ERC-20 the user holds: USDT on Ethereum, USDT0 elsewhere (6 decimals everywhere). */\n token: string;\n /**\n * The OFT contract `quoteSend` / `send` are called on. On Ethereum it is the\n * OFT *adapter* that locks USDT (`approvalRequired()` = true, approve the\n * token to it); elsewhere it is the OUpgradeable OFT that burns the caller's\n * USDT0 through the token's mint/burn role — no approval.\n */\n oft: string;\n /** LayerZero V2 EndpointV2 on that chain (`lzReceive` retries of a stored payload go here). */\n endpoint: string;\n /** True on Ethereum: the OFT is a lockbox adapter in front of plain USDT. */\n adapter: boolean;\n}\n\nconst LZ_ENDPOINT_A = \"0x1a44076050125825900e736c501f859c50fE728c\";\nconst LZ_ENDPOINT_B = \"0x6F475642a6e85809B1c36Fa62763669b1b48DD5B\";\n\nconst c = (chainId: number, eid: number, name: string, token: string, oft: string, endpoint: string, adapter = false): Usdt0Chain => ({\n caip2: `eip155:${chainId}`, chainId, eid, name, token, oft, endpoint, adapter,\n});\n\n/** CAIP-2 → USDT0 deployment. */\nexport const USDT0_CHAINS: Readonly<Record<string, Usdt0Chain>> = Object.freeze(Object.fromEntries([\n c(1, 30101, \"Ethereum\", \"0xdAC17F958D2ee523a2206206994597C13D831ec7\", \"0x6C96dE32CEa08842dcc4058c14d3aaAD7Fa41dee\", LZ_ENDPOINT_A, true),\n c(42161, 30110, \"Arbitrum\", \"0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9\", \"0x14E4A1B13bf7F943c8ff7C51fb60FA964A298D92\", LZ_ENDPOINT_A),\n c(10, 30111, \"OP Mainnet\", \"0x01bFF41798a0BcF287b996046Ca68b395DbC1071\", \"0xF03b4d9AC1D5d1E7c4cEf54C2A313b9fe051A0aD\", LZ_ENDPOINT_A),\n c(137, 30109, \"Polygon PoS\", \"0xc2132D05D31c914a87C6611C10748AEb04B58e8F\", \"0x6BA10300f0DC58B7a1e4c0e41f5daBb7D7829e13\", LZ_ENDPOINT_A),\n c(999, 30367, \"HyperEVM\", \"0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb\", \"0x904861a24F30EC96ea7CFC3bE9EA4B476d237e98\", \"0x3A73033C0b1407574C76BdBAc67f126f6b4a9AA9\"),\n c(57073, 30339, \"Ink\", \"0x0200C29006150606B650577BBE7B6248F58470c1\", \"0x1cB6De532588fCA4a21B7209DE7C456AF8434A65\", \"0xca29f3A6f966Cb2fc0dE625F8f325c0C46dbE958\"),\n c(80094, 30362, \"Berachain\", \"0x779Ded0c9e1022225f8E0630b35a9b54bE713736\", \"0x3Dc96399109df5ceb2C226664A086140bD0379cB\", LZ_ENDPOINT_B),\n c(130, 30320, \"Unichain\", \"0x9151434b16b9763660705744891fA906F660EcC5\", \"0xc07bE8994D035631c36fb4a89C918CeFB2f03EC3\", LZ_ENDPOINT_B),\n c(1329, 30280, \"Sei\", \"0x9151434b16b9763660705744891fA906F660EcC5\", \"0x56Fe74A2e3b484b921c447357203431a3485CC60\", LZ_ENDPOINT_A),\n c(9745, 30383, \"Plasma\", \"0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb\", \"0x02ca37966753bDdDf11216B73B16C1dE756A7CF9\", LZ_ENDPOINT_B),\n c(143, 30390, \"Monad\", \"0xe7cd86e13AC4309349F30B3435a9d337750fC82D\", \"0x9151434b16b9763660705744891fA906F660EcC5\", LZ_ENDPOINT_B),\n c(4326, 30398, \"MegaETH\", \"0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb\", \"0x9151434b16b9763660705744891fA906F660EcC5\", LZ_ENDPOINT_B),\n c(196, 30274, \"X Layer\", \"0x779Ded0c9e1022225f8E0630b35a9b54bE713736\", \"0x94bcCa6BdfD6a61817aB0E960BfedE4984505554\", LZ_ENDPOINT_A),\n // 2026-10-20 (evm-chains-6 batch): docs.usdt0.to deployments, re-read on-chain (token(), approvalRequired() = false,\n // sharedDecimals() = 6, endpoint(), peers(30110) = the Arbitrum OFT).\n c(5000, 30181, \"Mantle\", \"0x779Ded0c9e1022225f8E0630b35a9b54bE713736\", \"0xcb768e263FB1C62214E7cab4AA8d036D76dc59CC\", LZ_ENDPOINT_A),\n c(2818, 30322, \"Morph\", \"0xe7cd86e13AC4309349F30B3435a9d337750fC82D\", \"0xcb768e263FB1C62214E7cab4AA8d036D76dc59CC\", LZ_ENDPOINT_B),\n c(14, 30295, \"Flare\", \"0xe7cd86e13AC4309349F30B3435a9d337750fC82D\", \"0x567287d2A9829215a37e3B88843d32f9221E7588\", LZ_ENDPOINT_A),\n].map((x) => [x.caip2, x])));\n\n/** LayerZero eid → deployment. */\nexport const USDT0_BY_EID: Readonly<Record<number, Usdt0Chain>> = Object.freeze(\n Object.fromEntries(Object.values(USDT0_CHAINS).map((x) => [x.eid, x])),\n);\n\n/** LayerZero Scan — message status by source transaction hash. */\nexport const LZ_SCAN_API = \"https://scan.layerzero-api.com\";\n\n/** Token symbols the catalog uses for the same asset across chains. */\nexport const USDT0_SYMBOLS: readonly string[] = Object.freeze([\"USDT0\", \"USDT\", \"USD₮0\", \"USD₮\"]);\n\nexport const usdt0 = {\n supportsChain(chain: string): boolean {\n return isEvm(chain) && !!USDT0_CHAINS[`eip155:${evmRef(chain)}`];\n },\n supports(from: string, to: string): boolean {\n return from !== to && this.supportsChain(from) && this.supportsChain(to);\n },\n};\n\nconst OFT_SEND_ABI = parseAbi([\n \"struct SendParam { uint32 dstEid; bytes32 to; uint256 amountLD; uint256 minAmountLD; bytes extraOptions; bytes composeMsg; bytes oftCmd; }\",\n \"struct MessagingFee { uint256 nativeFee; uint256 lzTokenFee; }\",\n \"function send(SendParam s, MessagingFee fee, address refundAddress) payable\",\n]);\n\n/**\n * Does `symbolOrAddress` name this deployment's token on `chain`? The contract itself, or a USDT / USDT0 symbol the\n * catalog does not bind to another contract (OP's legacy bridged USDT is not the OFT token). The provider and\n * {@link usdt0VerifyQuote} both check the request with it.\n */\nexport function tokenMatches(chain: Usdt0Chain, symbolOrAddress: string): boolean {\n const same = (a: string | undefined | null, b: string) => !!a && a.toLowerCase() === b.toLowerCase();\n if (symbolOrAddress.startsWith(\"0x\")) return same(symbolOrAddress, chain.token);\n if (!USDT0_SYMBOLS.includes(symbolOrAddress.toUpperCase().replace(\"USD₮\", \"USDT\"))) return false;\n const known = ccAsset(chain.caip2, symbolOrAddress);\n return !known || same(known.contract ?? \"\", chain.token);\n}\n\n/**\n * A remote USDT0 quote's `send`, decoded on the device against the app's own request (scan 2026-10-30, F3): exactly\n * `send(SendParam, MessagingFee, refund)` on the source OFT; the destination chain's eid; the recipient as `to`; the\n * input as `amountLD`; a `minAmountLD` no larger than the input that guarantees the quoted minimum and the caller's\n * floor; empty `extraOptions`, `composeMsg` and `oftCmd` (what the provider sends); no LZ-token fee; the trader as\n * refund; `msg.value` = the declared native fee = the call's `nativeFee`; the adapter as spender on Ethereum only.\n * The reason it fails, or null. The engine's native-fee ceiling bounds the fee itself.\n */\nexport function usdt0VerifyQuote(params: QuoteParams, quote: Quote): string | null {\n const src = usdt0ChainFor(params.sourceChain);\n const dst = usdt0ChainFor(params.destChain);\n if (!src || !dst || src === dst) return \"not a USDT0 route between two deployments\";\n // The OFT burns or locks its own token whatever the request named, so both sides are bound here (reaudit 2026-10-30, #1).\n if (!tokenMatches(src, params.sourceToken)) return `source token ${params.sourceToken} is not USDT0 (${src.token}) on ${src.name}`;\n if (!tokenMatches(dst, params.destToken)) return `destination token ${params.destToken} is not USDT0 (${dst.token}) on ${dst.name}`;\n const tx = quote.txRequest;\n if (!tx?.data || !tx.to || tx.serializedTx !== undefined) return \"the quote carries no OFT call\";\n if (tx.to.toLowerCase() !== src.oft.toLowerCase()) return `the call targets ${tx.to}, not the ${src.name} OFT`;\n if (tx.chainId !== undefined && tx.chainId !== src.chainId) return `the call is for chain ${tx.chainId}, not ${src.chainId}`;\n if (src.adapter ? !tx.approvalAddress || tx.approvalAddress.toLowerCase() !== src.oft.toLowerCase() : tx.approvalAddress !== undefined) {\n return src.adapter ? \"the Ethereum send approves another spender than the adapter\" : \"an OFT send needs no approval\";\n }\n let sp: {dstEid: number; to: Hex; amountLD: bigint; minAmountLD: bigint; extraOptions: Hex; composeMsg: Hex; oftCmd: Hex};\n let fee: {nativeFee: bigint; lzTokenFee: bigint};\n let refund: string;\n try {\n const d = decodeFunctionData({abi: OFT_SEND_ABI, data: tx.data as Hex});\n [sp, fee, refund] = d.args as unknown as [typeof sp, typeof fee, string];\n } catch {\n return \"the call is not send(SendParam, MessagingFee, refund)\";\n }\n let amountIn: bigint, floor: bigint, value: bigint;\n try {\n amountIn = BigInt(params.amountIn);\n floor = BigInt(quote.minDestAmount);\n if (params.minAmountOut !== undefined && BigInt(params.minAmountOut) > floor) floor = BigInt(params.minAmountOut);\n value = BigInt(tx.value ?? \"0\");\n } catch {\n return \"the request does not name amounts\";\n }\n if (sp.dstEid !== dst.eid) return `the send goes to eid ${sp.dstEid}, not ${dst.name} (${dst.eid})`;\n if (sp.amountLD !== amountIn || BigInt(quote.sourceAmount) !== amountIn) return `the send moves ${sp.amountLD}, not the ${amountIn} input`;\n if (sp.minAmountLD > sp.amountLD || sp.minAmountLD <= 0n || sp.minAmountLD < floor) return `the send's minAmountLD ${sp.minAmountLD} is below the ${floor} minimum`;\n if (sp.extraOptions !== \"0x\" || sp.composeMsg !== \"0x\" || sp.oftCmd !== \"0x\") return \"the send carries options, a compose message or an OFT command\";\n // A dry quote without addresses prices the provider's placeholders; it is never built (the engine re-quotes live).\n const live = params.dry === false;\n if (params.destAddress || live) {\n if (!isAddress(params.destAddress)) return \"the recipient is not an EVM address\";\n if (sp.to.toLowerCase() !== pad(getAddress(params.destAddress), {size: 32}).toLowerCase()) return `the send delivers to ${sp.to}, not the recipient`;\n }\n if (params.refundAddress || live) {\n if (!isAddress(params.refundAddress ?? \"\")) return \"the refund address is not an EVM address\";\n if (getAddress(refund) !== getAddress(params.refundAddress!)) return `the send refunds ${refund}, not the trader`;\n }\n if (fee.lzTokenFee !== 0n) return \"the send pays an LZ-token fee\";\n if (value !== fee.nativeFee || (tx.nativeFee ?? \"0\") !== fee.nativeFee.toString()) return \"msg.value is not the declared native fee of the send\";\n if (quote.intentId.replace(/~[0-9a-f]{32}$/, \"\") !== `usdt0:${src.eid}:${dst.eid}`) return \"the intent id does not name this send\";\n return null;\n}\n\n/**\n * The contracts a USDT0 claim may call on `chain`: its LayerZero EndpointV2 (`lzReceive`, retrying a stored\n * payload). Empty for a chain USDT0 is not listed on.\n */\nexport function usdt0ClaimTargets(chain: string): readonly string[] {\n const c = usdt0ChainFor(chain);\n return c ? [c.endpoint] : [];\n}\n\n/**\n * The USDT0 OFT a send calls on a chain, the adapter it approves where one locks USDT (Ethereum), the endpoint\n * a stored-payload claim calls, and {@link usdt0VerifyQuote} — the app's pins for\n * `remoteProvider({name: \"usdt0\", baseUrl, ...usdt0Pins})` (scan 2026-10-27 modules, F8/F16; the send's\n * arguments since scan 2026-10-30, F3).\n */\nexport const usdt0Pins: RemotePins & {claimTargets(chain: string): readonly string[]} = Object.freeze({\n callTargets: (chain: string): readonly string[] => { const c = usdt0ChainFor(chain); return c ? [c.oft] : []; },\n spenders: (chain: string): readonly string[] => { const c = usdt0ChainFor(chain); return c?.adapter ? [c.oft] : []; },\n claimTargets: usdt0ClaimTargets,\n verifyQuote: usdt0VerifyQuote,\n});\nfunction usdt0ChainFor(chain: string): Usdt0Chain | undefined {\n return Object.prototype.hasOwnProperty.call(USDT0_CHAINS, chain) ? USDT0_CHAINS[chain] : undefined;\n}\n"],"mappings":"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","names":["c"]}
package/dist/config.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { RemotePins } from '@anywalletkit/protocol-swap2-core/types';
1
+ import { RemotePins, QuoteParams, Quote } from '@anywalletkit/protocol-swap2-core/types';
2
2
 
3
3
  interface Usdt0Chain {
4
4
  caip2: string;
@@ -33,9 +33,33 @@ declare const usdt0: {
33
33
  supports(from: string, to: string): boolean;
34
34
  };
35
35
  /**
36
- * The USDT0 OFT a send calls on a chain, and the adapter it approves where one locks USDT (Ethereum) —
37
- * the app's pins for `remoteProvider({name: "usdt0", baseUrl, ...usdt0Pins})` (scan 2026-10-27 modules, F8/F16).
36
+ * Does `symbolOrAddress` name this deployment's token on `chain`? The contract itself, or a USDT / USDT0 symbol the
37
+ * catalog does not bind to another contract (OP's legacy bridged USDT is not the OFT token). The provider and
38
+ * {@link usdt0VerifyQuote} both check the request with it.
38
39
  */
39
- declare const usdt0Pins: RemotePins;
40
+ declare function tokenMatches(chain: Usdt0Chain, symbolOrAddress: string): boolean;
41
+ /**
42
+ * A remote USDT0 quote's `send`, decoded on the device against the app's own request (scan 2026-10-30, F3): exactly
43
+ * `send(SendParam, MessagingFee, refund)` on the source OFT; the destination chain's eid; the recipient as `to`; the
44
+ * input as `amountLD`; a `minAmountLD` no larger than the input that guarantees the quoted minimum and the caller's
45
+ * floor; empty `extraOptions`, `composeMsg` and `oftCmd` (what the provider sends); no LZ-token fee; the trader as
46
+ * refund; `msg.value` = the declared native fee = the call's `nativeFee`; the adapter as spender on Ethereum only.
47
+ * The reason it fails, or null. The engine's native-fee ceiling bounds the fee itself.
48
+ */
49
+ declare function usdt0VerifyQuote(params: QuoteParams, quote: Quote): string | null;
50
+ /**
51
+ * The contracts a USDT0 claim may call on `chain`: its LayerZero EndpointV2 (`lzReceive`, retrying a stored
52
+ * payload). Empty for a chain USDT0 is not listed on.
53
+ */
54
+ declare function usdt0ClaimTargets(chain: string): readonly string[];
55
+ /**
56
+ * The USDT0 OFT a send calls on a chain, the adapter it approves where one locks USDT (Ethereum), the endpoint
57
+ * a stored-payload claim calls, and {@link usdt0VerifyQuote} — the app's pins for
58
+ * `remoteProvider({name: "usdt0", baseUrl, ...usdt0Pins})` (scan 2026-10-27 modules, F8/F16; the send's
59
+ * arguments since scan 2026-10-30, F3).
60
+ */
61
+ declare const usdt0Pins: RemotePins & {
62
+ claimTargets(chain: string): readonly string[];
63
+ };
40
64
 
41
- export { LZ_SCAN_API, USDT0_BY_EID, USDT0_CHAINS, USDT0_SYMBOLS, type Usdt0Chain, usdt0, usdt0Pins };
65
+ export { LZ_SCAN_API, USDT0_BY_EID, USDT0_CHAINS, USDT0_SYMBOLS, type Usdt0Chain, tokenMatches, usdt0, usdt0ClaimTargets, usdt0Pins, usdt0VerifyQuote };
package/dist/config.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { RemotePins } from '@anywalletkit/protocol-swap2-core/types';
1
+ import { RemotePins, QuoteParams, Quote } from '@anywalletkit/protocol-swap2-core/types';
2
2
 
3
3
  interface Usdt0Chain {
4
4
  caip2: string;
@@ -33,9 +33,33 @@ declare const usdt0: {
33
33
  supports(from: string, to: string): boolean;
34
34
  };
35
35
  /**
36
- * The USDT0 OFT a send calls on a chain, and the adapter it approves where one locks USDT (Ethereum) —
37
- * the app's pins for `remoteProvider({name: "usdt0", baseUrl, ...usdt0Pins})` (scan 2026-10-27 modules, F8/F16).
36
+ * Does `symbolOrAddress` name this deployment's token on `chain`? The contract itself, or a USDT / USDT0 symbol the
37
+ * catalog does not bind to another contract (OP's legacy bridged USDT is not the OFT token). The provider and
38
+ * {@link usdt0VerifyQuote} both check the request with it.
38
39
  */
39
- declare const usdt0Pins: RemotePins;
40
+ declare function tokenMatches(chain: Usdt0Chain, symbolOrAddress: string): boolean;
41
+ /**
42
+ * A remote USDT0 quote's `send`, decoded on the device against the app's own request (scan 2026-10-30, F3): exactly
43
+ * `send(SendParam, MessagingFee, refund)` on the source OFT; the destination chain's eid; the recipient as `to`; the
44
+ * input as `amountLD`; a `minAmountLD` no larger than the input that guarantees the quoted minimum and the caller's
45
+ * floor; empty `extraOptions`, `composeMsg` and `oftCmd` (what the provider sends); no LZ-token fee; the trader as
46
+ * refund; `msg.value` = the declared native fee = the call's `nativeFee`; the adapter as spender on Ethereum only.
47
+ * The reason it fails, or null. The engine's native-fee ceiling bounds the fee itself.
48
+ */
49
+ declare function usdt0VerifyQuote(params: QuoteParams, quote: Quote): string | null;
50
+ /**
51
+ * The contracts a USDT0 claim may call on `chain`: its LayerZero EndpointV2 (`lzReceive`, retrying a stored
52
+ * payload). Empty for a chain USDT0 is not listed on.
53
+ */
54
+ declare function usdt0ClaimTargets(chain: string): readonly string[];
55
+ /**
56
+ * The USDT0 OFT a send calls on a chain, the adapter it approves where one locks USDT (Ethereum), the endpoint
57
+ * a stored-payload claim calls, and {@link usdt0VerifyQuote} — the app's pins for
58
+ * `remoteProvider({name: "usdt0", baseUrl, ...usdt0Pins})` (scan 2026-10-27 modules, F8/F16; the send's
59
+ * arguments since scan 2026-10-30, F3).
60
+ */
61
+ declare const usdt0Pins: RemotePins & {
62
+ claimTargets(chain: string): readonly string[];
63
+ };
40
64
 
41
- export { LZ_SCAN_API, USDT0_BY_EID, USDT0_CHAINS, USDT0_SYMBOLS, type Usdt0Chain, usdt0, usdt0Pins };
65
+ export { LZ_SCAN_API, USDT0_BY_EID, USDT0_CHAINS, USDT0_SYMBOLS, type Usdt0Chain, tokenMatches, usdt0, usdt0ClaimTargets, usdt0Pins, usdt0VerifyQuote };
package/dist/config.js CHANGED
@@ -3,15 +3,21 @@ import {
3
3
  USDT0_BY_EID,
4
4
  USDT0_CHAINS,
5
5
  USDT0_SYMBOLS,
6
+ tokenMatches,
6
7
  usdt0,
7
- usdt0Pins
8
- } from "./chunk-7YL2Y3QA.js";
8
+ usdt0ClaimTargets,
9
+ usdt0Pins,
10
+ usdt0VerifyQuote
11
+ } from "./chunk-M5SCA7EC.js";
9
12
  export {
10
13
  LZ_SCAN_API,
11
14
  USDT0_BY_EID,
12
15
  USDT0_CHAINS,
13
16
  USDT0_SYMBOLS,
17
+ tokenMatches,
14
18
  usdt0,
15
- usdt0Pins
19
+ usdt0ClaimTargets,
20
+ usdt0Pins,
21
+ usdt0VerifyQuote
16
22
  };
17
23
  //# sourceMappingURL=config.js.map
package/dist/index.cjs CHANGED
@@ -32,14 +32,19 @@ __export(src_exports, {
32
32
  Usdt0Swap2Protocol: () => Usdt0Swap2Protocol,
33
33
  default: () => Usdt0Swap2Protocol,
34
34
  describeUsdt0Activity: () => describeUsdt0Activity,
35
+ tokenMatches: () => tokenMatches,
35
36
  usdt0: () => usdt0,
37
+ usdt0ClaimTargets: () => usdt0ClaimTargets,
36
38
  usdt0Pins: () => usdt0Pins,
37
- usdt0Provider: () => usdt0Provider
39
+ usdt0Provider: () => usdt0Provider,
40
+ usdt0VerifyQuote: () => usdt0VerifyQuote
38
41
  });
39
42
  module.exports = __toCommonJS(src_exports);
40
43
 
41
44
  // src/config.ts
45
+ var import_viem = require("viem");
42
46
  var import_util = require("@anywalletkit/protocol-swap2-core/util");
47
+ var import_swap2_assets = require("@anywalletkit/swap2-assets");
43
48
  var LZ_ENDPOINT_A = "0x1a44076050125825900e736c501f859c50fE728c";
44
49
  var LZ_ENDPOINT_B = "0x6F475642a6e85809B1c36Fa62763669b1b48DD5B";
45
50
  var c = (chainId, eid, name, token, oft, endpoint, adapter = false) => ({
@@ -85,6 +90,71 @@ var usdt0 = {
85
90
  return from !== to && this.supportsChain(from) && this.supportsChain(to);
86
91
  }
87
92
  };
93
+ var OFT_SEND_ABI = (0, import_viem.parseAbi)([
94
+ "struct SendParam { uint32 dstEid; bytes32 to; uint256 amountLD; uint256 minAmountLD; bytes extraOptions; bytes composeMsg; bytes oftCmd; }",
95
+ "struct MessagingFee { uint256 nativeFee; uint256 lzTokenFee; }",
96
+ "function send(SendParam s, MessagingFee fee, address refundAddress) payable"
97
+ ]);
98
+ function tokenMatches(chain, symbolOrAddress) {
99
+ const same2 = (a, b) => !!a && a.toLowerCase() === b.toLowerCase();
100
+ if (symbolOrAddress.startsWith("0x")) return same2(symbolOrAddress, chain.token);
101
+ if (!USDT0_SYMBOLS.includes(symbolOrAddress.toUpperCase().replace("USD\u20AE", "USDT"))) return false;
102
+ const known = (0, import_swap2_assets.ccAsset)(chain.caip2, symbolOrAddress);
103
+ return !known || same2(known.contract ?? "", chain.token);
104
+ }
105
+ function usdt0VerifyQuote(params, quote) {
106
+ const src = usdt0ChainFor(params.sourceChain);
107
+ const dst = usdt0ChainFor(params.destChain);
108
+ if (!src || !dst || src === dst) return "not a USDT0 route between two deployments";
109
+ if (!tokenMatches(src, params.sourceToken)) return `source token ${params.sourceToken} is not USDT0 (${src.token}) on ${src.name}`;
110
+ if (!tokenMatches(dst, params.destToken)) return `destination token ${params.destToken} is not USDT0 (${dst.token}) on ${dst.name}`;
111
+ const tx = quote.txRequest;
112
+ if (!tx?.data || !tx.to || tx.serializedTx !== void 0) return "the quote carries no OFT call";
113
+ if (tx.to.toLowerCase() !== src.oft.toLowerCase()) return `the call targets ${tx.to}, not the ${src.name} OFT`;
114
+ if (tx.chainId !== void 0 && tx.chainId !== src.chainId) return `the call is for chain ${tx.chainId}, not ${src.chainId}`;
115
+ if (src.adapter ? !tx.approvalAddress || tx.approvalAddress.toLowerCase() !== src.oft.toLowerCase() : tx.approvalAddress !== void 0) {
116
+ return src.adapter ? "the Ethereum send approves another spender than the adapter" : "an OFT send needs no approval";
117
+ }
118
+ let sp;
119
+ let fee;
120
+ let refund;
121
+ try {
122
+ const d = (0, import_viem.decodeFunctionData)({ abi: OFT_SEND_ABI, data: tx.data });
123
+ [sp, fee, refund] = d.args;
124
+ } catch {
125
+ return "the call is not send(SendParam, MessagingFee, refund)";
126
+ }
127
+ let amountIn, floor, value;
128
+ try {
129
+ amountIn = BigInt(params.amountIn);
130
+ floor = BigInt(quote.minDestAmount);
131
+ if (params.minAmountOut !== void 0 && BigInt(params.minAmountOut) > floor) floor = BigInt(params.minAmountOut);
132
+ value = BigInt(tx.value ?? "0");
133
+ } catch {
134
+ return "the request does not name amounts";
135
+ }
136
+ if (sp.dstEid !== dst.eid) return `the send goes to eid ${sp.dstEid}, not ${dst.name} (${dst.eid})`;
137
+ if (sp.amountLD !== amountIn || BigInt(quote.sourceAmount) !== amountIn) return `the send moves ${sp.amountLD}, not the ${amountIn} input`;
138
+ if (sp.minAmountLD > sp.amountLD || sp.minAmountLD <= 0n || sp.minAmountLD < floor) return `the send's minAmountLD ${sp.minAmountLD} is below the ${floor} minimum`;
139
+ if (sp.extraOptions !== "0x" || sp.composeMsg !== "0x" || sp.oftCmd !== "0x") return "the send carries options, a compose message or an OFT command";
140
+ const live = params.dry === false;
141
+ if (params.destAddress || live) {
142
+ if (!(0, import_viem.isAddress)(params.destAddress)) return "the recipient is not an EVM address";
143
+ if (sp.to.toLowerCase() !== (0, import_viem.pad)((0, import_viem.getAddress)(params.destAddress), { size: 32 }).toLowerCase()) return `the send delivers to ${sp.to}, not the recipient`;
144
+ }
145
+ if (params.refundAddress || live) {
146
+ if (!(0, import_viem.isAddress)(params.refundAddress ?? "")) return "the refund address is not an EVM address";
147
+ if ((0, import_viem.getAddress)(refund) !== (0, import_viem.getAddress)(params.refundAddress)) return `the send refunds ${refund}, not the trader`;
148
+ }
149
+ if (fee.lzTokenFee !== 0n) return "the send pays an LZ-token fee";
150
+ if (value !== fee.nativeFee || (tx.nativeFee ?? "0") !== fee.nativeFee.toString()) return "msg.value is not the declared native fee of the send";
151
+ if (quote.intentId.replace(/~[0-9a-f]{32}$/, "") !== `usdt0:${src.eid}:${dst.eid}`) return "the intent id does not name this send";
152
+ return null;
153
+ }
154
+ function usdt0ClaimTargets(chain) {
155
+ const c2 = usdt0ChainFor(chain);
156
+ return c2 ? [c2.endpoint] : [];
157
+ }
88
158
  var usdt0Pins = Object.freeze({
89
159
  callTargets: (chain) => {
90
160
  const c2 = usdt0ChainFor(chain);
@@ -93,19 +163,21 @@ var usdt0Pins = Object.freeze({
93
163
  spenders: (chain) => {
94
164
  const c2 = usdt0ChainFor(chain);
95
165
  return c2?.adapter ? [c2.oft] : [];
96
- }
166
+ },
167
+ claimTargets: usdt0ClaimTargets,
168
+ verifyQuote: usdt0VerifyQuote
97
169
  });
98
170
  function usdt0ChainFor(chain) {
99
171
  return Object.prototype.hasOwnProperty.call(USDT0_CHAINS, chain) ? USDT0_CHAINS[chain] : void 0;
100
172
  }
101
173
 
102
174
  // src/provider.ts
103
- var import_viem2 = require("viem");
175
+ var import_viem3 = require("viem");
104
176
 
105
177
  // src/activity.ts
106
178
  var import_activity = require("@anywalletkit/protocol-swap2-core/activity");
107
- var import_viem = require("viem");
108
- var SEND_ABI = (0, import_viem.parseAbi)([
179
+ var import_viem2 = require("viem");
180
+ var SEND_ABI = (0, import_viem2.parseAbi)([
109
181
  "struct SendParam { uint32 dstEid; bytes32 to; uint256 amountLD; uint256 minAmountLD; bytes extraOptions; bytes composeMsg; bytes oftCmd; }",
110
182
  "struct MessagingFee { uint256 nativeFee; uint256 lzTokenFee; }",
111
183
  "function send(SendParam sp, MessagingFee fee, address refundAddress)"
@@ -121,7 +193,7 @@ function sendDestination(tx) {
121
193
  const data = tx.call?.data;
122
194
  if (!data || data.length < 10 + 64 * 2) return null;
123
195
  try {
124
- const [sp] = (0, import_viem.decodeFunctionData)({ abi: SEND_ABI, data }).args;
196
+ const [sp] = (0, import_viem2.decodeFunctionData)({ abi: SEND_ABI, data }).args;
125
197
  return USDT0_BY_EID[sp.dstEid] ?? null;
126
198
  } catch {
127
199
  return null;
@@ -159,9 +231,9 @@ function describeUsdt0Activity(tx, ctx) {
159
231
  }
160
232
 
161
233
  // src/provider.ts
162
- var import_swap2_assets = require("@anywalletkit/swap2-assets");
234
+ var import_swap2_assets2 = require("@anywalletkit/swap2-assets");
163
235
  var import_util2 = require("@anywalletkit/protocol-swap2-core/util");
164
- var OFT_ABI = (0, import_viem2.parseAbi)([
236
+ var OFT_ABI = (0, import_viem3.parseAbi)([
165
237
  "struct SendParam { uint32 dstEid; bytes32 to; uint256 amountLD; uint256 minAmountLD; bytes extraOptions; bytes composeMsg; bytes oftCmd; }",
166
238
  "struct MessagingFee { uint256 nativeFee; uint256 lzTokenFee; }",
167
239
  "struct OFTLimit { uint256 minAmountLD; uint256 maxAmountLD; }",
@@ -175,7 +247,7 @@ var OFT_ABI = (0, import_viem2.parseAbi)([
175
247
  "function approvalRequired() view returns (bool)",
176
248
  "function peers(uint32 eid) view returns (bytes32)"
177
249
  ]);
178
- var ENDPOINT_ABI = (0, import_viem2.parseAbi)([
250
+ var ENDPOINT_ABI = (0, import_viem3.parseAbi)([
179
251
  "struct Origin { uint32 srcEid; bytes32 sender; uint64 nonce; }",
180
252
  "function lzReceive(Origin origin, address receiver, bytes32 guid, bytes message, bytes extraData) payable"
181
253
  ]);
@@ -189,12 +261,6 @@ var GAS_CLAIM = "300000";
189
261
  var ZERO_B32 = `0x${"00".repeat(32)}`;
190
262
  var same = (a, b) => !!a && a.toLowerCase() === b.toLowerCase();
191
263
  var isHexData = (v) => typeof v === "string" && /^0x(?:[0-9a-fA-F]{2})*$/.test(v);
192
- function tokenMatches(chain, symbolOrAddress) {
193
- if (symbolOrAddress.startsWith("0x")) return same(symbolOrAddress, chain.token);
194
- if (!USDT0_SYMBOLS.includes(symbolOrAddress.toUpperCase().replace("USD\u20AE", "USDT"))) return false;
195
- const known = (0, import_swap2_assets.ccAsset)(chain.caip2, symbolOrAddress);
196
- return !known || same(known.contract ?? "", chain.token);
197
- }
198
264
  function rpcSafeReason(err, chainName) {
199
265
  const e = err;
200
266
  const text = `${e?.shortMessage ?? ""}
@@ -217,7 +283,7 @@ function usdt0Provider(config = {}) {
217
283
  const urls = typeof raw === "string" ? [raw] : [...raw ?? []];
218
284
  if (urls.length === 0) return null;
219
285
  const opts = { timeout: RPC_TIMEOUT_MS, ...config.fetchImpl ? { fetchFn: config.fetchImpl } : {} };
220
- return (0, import_viem2.createPublicClient)({ transport: urls.length === 1 ? (0, import_viem2.http)(urls[0], opts) : (0, import_viem2.fallback)(urls.map((u) => (0, import_viem2.http)(u, opts))), ccipRead: false });
286
+ return (0, import_viem3.createPublicClient)({ transport: urls.length === 1 ? (0, import_viem3.http)(urls[0], opts) : (0, import_viem3.fallback)(urls.map((u) => (0, import_viem3.http)(u, opts))), ccipRead: false });
221
287
  };
222
288
  const verified = /* @__PURE__ */ new Map();
223
289
  function verifyChain(chain) {
@@ -227,8 +293,8 @@ function usdt0Provider(config = {}) {
227
293
  const c2 = client(chain.caip2);
228
294
  if (!c2) throw new Error(`usdt0: no RPC for ${chain.caip2}`);
229
295
  const [token, approval] = await Promise.all([
230
- c2.readContract({ address: (0, import_viem2.getAddress)(chain.oft), abi: OFT_ABI, functionName: "token" }),
231
- c2.readContract({ address: (0, import_viem2.getAddress)(chain.oft), abi: OFT_ABI, functionName: "approvalRequired" })
296
+ c2.readContract({ address: (0, import_viem3.getAddress)(chain.oft), abi: OFT_ABI, functionName: "token" }),
297
+ c2.readContract({ address: (0, import_viem3.getAddress)(chain.oft), abi: OFT_ABI, functionName: "approvalRequired" })
232
298
  ]);
233
299
  if (!same(token, chain.token)) throw new Error(`usdt0: OFT ${chain.oft} on ${chain.name} reports token ${token}, expected ${chain.token}`);
234
300
  if (approval !== chain.adapter) throw new Error(`usdt0: OFT ${chain.oft} on ${chain.name} reports approvalRequired=${String(approval)}, expected ${String(chain.adapter)}`);
@@ -246,8 +312,8 @@ function usdt0Provider(config = {}) {
246
312
  p = (async () => {
247
313
  const c2 = client(src.caip2);
248
314
  if (!c2) throw new Error(`usdt0: no RPC for ${src.caip2}`);
249
- const peer = await c2.readContract({ address: (0, import_viem2.getAddress)(src.oft), abi: OFT_ABI, functionName: "peers", args: [dst.eid] });
250
- if (!same(peer, (0, import_viem2.pad)((0, import_viem2.getAddress)(dst.oft), { size: 32 }))) throw new Error(`usdt0: ${src.name} OFT has no peer for ${dst.name} (eid ${dst.eid}) \u2014 route not wired`);
315
+ const peer = await c2.readContract({ address: (0, import_viem3.getAddress)(src.oft), abi: OFT_ABI, functionName: "peers", args: [dst.eid] });
316
+ if (!same(peer, (0, import_viem3.pad)((0, import_viem3.getAddress)(dst.oft), { size: 32 }))) throw new Error(`usdt0: ${src.name} OFT has no peer for ${dst.name} (eid ${dst.eid}) \u2014 route not wired`);
251
317
  })();
252
318
  p.catch(() => peers.delete(key));
253
319
  peers.set(key, p);
@@ -263,7 +329,7 @@ function usdt0Provider(config = {}) {
263
329
  }
264
330
  const sendParam = (dstEid, recipient, amountLD, minAmountLD) => ({
265
331
  dstEid,
266
- to: (0, import_viem2.pad)((0, import_viem2.getAddress)(recipient), { size: 32 }),
332
+ to: (0, import_viem3.pad)((0, import_viem3.getAddress)(recipient), { size: 32 }),
267
333
  amountLD,
268
334
  minAmountLD,
269
335
  extraOptions: "0x",
@@ -283,6 +349,7 @@ function usdt0Provider(config = {}) {
283
349
  return {
284
350
  name: "usdt0",
285
351
  describeActivity: describeUsdt0Activity,
352
+ claimTargets: usdt0ClaimTargets,
286
353
  enabled: () => config.enabled ?? true,
287
354
  supportsChain: (chain) => usdt0.supportsChain(chain) && client(chain) !== null,
288
355
  supportsChainPair: (from, to) => usdt0.supports(from, to) && client(from) !== null,
@@ -310,16 +377,16 @@ function usdt0Provider(config = {}) {
310
377
  const dry = params.dry !== false;
311
378
  const recipient = params.destAddress || (dry ? EVM_PLACEHOLDER : "");
312
379
  if (!recipient) return refuse("a live quote needs a recipient");
313
- if (!(0, import_viem2.isAddress)(recipient)) return refuse("destination must be an EVM address");
380
+ if (!(0, import_viem3.isAddress)(recipient)) return refuse("destination must be an EVM address");
314
381
  const refund = params.refundAddress || (dry ? EVM_PLACEHOLDER : "");
315
382
  if (!refund) return refuse("a live quote needs a refund address");
316
- if (!(0, import_viem2.isAddress)(refund)) return refuse("refund address must be an EVM address");
383
+ if (!(0, import_viem3.isAddress)(refund)) return refuse("refund address must be an EVM address");
317
384
  const c2 = client(src.caip2);
318
385
  if (!c2) return refuse(`no RPC configured for ${src.caip2}`);
319
386
  try {
320
387
  await Promise.all([verifyChain(src), verifyPeer(src, dst)]);
321
388
  const probe = sendParam(dst.eid, recipient, amount, 0n);
322
- const [limit, feeDetails, receipt] = await c2.readContract({ address: (0, import_viem2.getAddress)(src.oft), abi: OFT_ABI, functionName: "quoteOFT", args: [probe] });
389
+ const [limit, feeDetails, receipt] = await c2.readContract({ address: (0, import_viem3.getAddress)(src.oft), abi: OFT_ABI, functionName: "quoteOFT", args: [probe] });
323
390
  if (amount < limit.minAmountLD) return refuse(`amount ${amount} is below the OFT minimum ${limit.minAmountLD}`);
324
391
  if (amount > limit.maxAmountLD) return refuse(`amount ${amount} exceeds the OFT maximum ${limit.maxAmountLD}`);
325
392
  const received = receipt.amountReceivedLD;
@@ -327,10 +394,10 @@ function usdt0Provider(config = {}) {
327
394
  if (received > amount) return refuse("OFT reports more received than sent \u2014 refusing");
328
395
  if (params.minAmountOut !== void 0 && received < BigInt(params.minAmountOut)) return refuse(`received ${received} is below the caller's floor ${params.minAmountOut}`);
329
396
  const sp = sendParam(dst.eid, recipient, amount, received);
330
- const fee = await c2.readContract({ address: (0, import_viem2.getAddress)(src.oft), abi: OFT_ABI, functionName: "quoteSend", args: [sp, false] });
397
+ const fee = await c2.readContract({ address: (0, import_viem3.getAddress)(src.oft), abi: OFT_ABI, functionName: "quoteSend", args: [sp, false] });
331
398
  if (fee.lzTokenFee !== 0n) return refuse("OFT asks for a fee in LZ token \u2014 unsupported");
332
399
  const nativeFee = fee.nativeFee + fee.nativeFee * FEE_HEADROOM_BPS / 10000n;
333
- const data = (0, import_viem2.encodeFunctionData)({ abi: OFT_ABI, functionName: "send", args: [sp, { nativeFee, lzTokenFee: 0n }, (0, import_viem2.getAddress)(refund)] });
400
+ const data = (0, import_viem3.encodeFunctionData)({ abi: OFT_ABI, functionName: "send", args: [sp, { nativeFee, lzTokenFee: 0n }, (0, import_viem3.getAddress)(refund)] });
334
401
  const protocolFees = feeDetails.filter((f) => f.feeAmountLD > 0n).map((f) => ({ type: "protocol", amount: f.feeAmountLD.toString(), token: src.token, included: true, description: f.description || "OFT fee" }));
335
402
  const feeUsd = protocolFees.reduce((a, f) => a + Number(f.amount) / 1e6, 0);
336
403
  const eta = src.chainId === 1 ? 1e3 : 240;
@@ -361,8 +428,8 @@ function usdt0Provider(config = {}) {
361
428
  dstEid: String(dst.eid),
362
429
  oft: src.oft,
363
430
  token: src.token,
364
- recipient: (0, import_viem2.getAddress)(recipient),
365
- refundAddress: (0, import_viem2.getAddress)(refund),
431
+ recipient: (0, import_viem3.getAddress)(recipient),
432
+ refundAddress: (0, import_viem3.getAddress)(refund),
366
433
  amountLD: amount.toString(),
367
434
  minAmountLD: received.toString(),
368
435
  nativeFee: nativeFee.toString()
@@ -399,7 +466,7 @@ function usdt0Provider(config = {}) {
399
466
  const { src, dst } = parsed;
400
467
  if (!same(tx.to, src.oft)) throw new Error(`usdt0: deposit target ${tx.to} is not the ${src.name} OFT`);
401
468
  const pd = quote.providerData ?? {};
402
- if (!/^\d+$/.test(pd.amountLD ?? "") || !/^\d+$/.test(pd.minAmountLD ?? "") || !/^\d+$/.test(pd.nativeFee ?? "") || !(0, import_viem2.isAddress)(pd.recipient ?? "")) {
469
+ if (!/^\d+$/.test(pd.amountLD ?? "") || !/^\d+$/.test(pd.minAmountLD ?? "") || !/^\d+$/.test(pd.nativeFee ?? "") || !(0, import_viem3.isAddress)(pd.recipient ?? "")) {
403
470
  throw new Error("usdt0: quote carries no sealed send parameters");
404
471
  }
405
472
  const c2 = client(src.caip2);
@@ -408,7 +475,7 @@ function usdt0Provider(config = {}) {
408
475
  let fee;
409
476
  try {
410
477
  await Promise.all([verifyChain(src), verifyPeer(src, dst)]);
411
- fee = await c2.readContract({ address: (0, import_viem2.getAddress)(src.oft), abi: OFT_ABI, functionName: "quoteSend", args: [sp, false] });
478
+ fee = await c2.readContract({ address: (0, import_viem3.getAddress)(src.oft), abi: OFT_ABI, functionName: "quoteSend", args: [sp, false] });
412
479
  } catch (err) {
413
480
  throw new Error(rpcSafeReason(err, src.name));
414
481
  }
@@ -460,10 +527,10 @@ function usdt0Provider(config = {}) {
460
527
  chain: dst.caip2,
461
528
  to: dst.endpoint,
462
529
  value,
463
- data: (0, import_viem2.encodeFunctionData)({
530
+ data: (0, import_viem3.encodeFunctionData)({
464
531
  abi: ENDPOINT_ABI,
465
532
  functionName: "lzReceive",
466
- args: [{ srcEid: src.eid, sender: (0, import_viem2.pad)((0, import_viem2.getAddress)(src.oft), { size: 32 }), nonce: BigInt(nonce) }, (0, import_viem2.getAddress)(dst.oft), guid, message, "0x"]
533
+ args: [{ srcEid: src.eid, sender: (0, import_viem3.pad)((0, import_viem3.getAddress)(src.oft), { size: 32 }), nonce: BigInt(nonce) }, (0, import_viem3.getAddress)(dst.oft), guid, message, "0x"]
467
534
  }),
468
535
  chainId: dst.chainId,
469
536
  gasLimit: GAS_CLAIM