@forevermoney/sdk 0.5.4 → 0.5.5

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/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.5.5 — 2026-09-21
4
+
5
+ - Discover destination off-ramps from the canonical CCIP router for the source
6
+ chain, retaining the configured legacy off-ramp for historical transfers.
7
+ Cache discovery for five minutes per provider and coalesce concurrent reads.
8
+ - Recognise both legacy and CCIP v2 execution events and select the latest
9
+ execution across off-ramps. This fixes completed Finney-to-Robinhood SN80
10
+ deliveries remaining in the waiting state. Verified against a real delivery.
11
+
3
12
  ## 0.5.4 — 2026-09-21
4
13
 
5
14
  - Added the canonical Robinhood SN80 token to deployment metadata and enabled
package/dist/index.cjs CHANGED
@@ -708,7 +708,8 @@ var CCIP_EXECUTION_ABI = Object.freeze([
708
708
  "event ExecutionStateChanged(uint64 indexed sourceChainSelector,uint64 indexed sequenceNumber,bytes32 indexed messageId,bytes32 messageHash,uint8 state,bytes returnData,uint256 gasUsed)"
709
709
  ]);
710
710
  var CCIP_ROUTER_ABI = Object.freeze([
711
- "function isOffRamp(uint64 sourceChainSelector,address offRamp) view returns (bool)"
711
+ "function isOffRamp(uint64 sourceChainSelector,address offRamp) view returns (bool)",
712
+ "function getOffRamps() view returns ((uint64 sourceChainSelector,address offRamp)[])"
712
713
  ]);
713
714
  var foreverMoneyAbis = Object.freeze({
714
715
  alphaGateway: ALPHA_GATEWAY_ABI,
@@ -2072,6 +2073,41 @@ function bridgeMessageIdFromReceipt(direction, receipt) {
2072
2073
  // src/bridge/tracking.ts
2073
2074
  var ccipExecutionAbi = (0, import_viem11.parseAbi)(CCIP_EXECUTION_ABI);
2074
2075
  var alphaGatewayAbi2 = (0, import_viem11.parseAbi)(ALPHA_GATEWAY_ABI);
2076
+ var routerAbi = (0, import_viem11.parseAbi)(CCIP_ROUTER_ABI);
2077
+ var executionV2Abi = (0, import_viem11.parseAbi)([
2078
+ "event ExecutionStateChanged(uint64 indexed sourceChainSelector,uint64 indexed sequenceNumber,bytes32 indexed messageId,uint8 state,bytes returnData)"
2079
+ ]);
2080
+ var rampCache = /* @__PURE__ */ new WeakMap();
2081
+ function deliveryOffRamps(provider, client, router, selector, legacy) {
2082
+ let cache = rampCache.get(provider);
2083
+ if (!cache) {
2084
+ cache = /* @__PURE__ */ new Map();
2085
+ rampCache.set(provider, cache);
2086
+ }
2087
+ const key = `${router}:${selector}:${legacy}`;
2088
+ const cached = cache.get(key);
2089
+ if (cached && cached.expires > Date.now()) return cached.request;
2090
+ const request = client.readContract({
2091
+ address: router,
2092
+ abi: routerAbi,
2093
+ functionName: "getOffRamps"
2094
+ }).then((ramps) => {
2095
+ const addresses = /* @__PURE__ */ new Map([
2096
+ [legacy.toLowerCase(), legacy]
2097
+ ]);
2098
+ for (const ramp of ramps) {
2099
+ if (ramp.sourceChainSelector === selector)
2100
+ addresses.set(ramp.offRamp.toLowerCase(), ramp.offRamp);
2101
+ }
2102
+ return [...addresses.values()];
2103
+ });
2104
+ const entry = { expires: Date.now() + 3e5, request };
2105
+ cache.set(key, entry);
2106
+ void request.catch(() => {
2107
+ if (cache.get(key) === entry) cache.delete(key);
2108
+ });
2109
+ return request;
2110
+ }
2075
2111
  function destinationChainId(direction) {
2076
2112
  assertBridgeDirection(direction);
2077
2113
  const evm = getForeverMoneyEvmDeployment(
@@ -2185,13 +2221,29 @@ async function getCcipDeliveryStatus(provider, input) {
2185
2221
  const evmToSubtensor = isEvmToSubtensorDirection(input.direction);
2186
2222
  const sourceSelector = evmToSubtensor ? evm.ccipSelector : foreverMoneyDeployment.subtensor.ccipSelector;
2187
2223
  const offRamp = evmToSubtensor ? evmChain === "base" ? foreverMoneyDeployment.subtensor.contracts.ccipOffRampFromBase : foreverMoneyDeployment.subtensor.contracts.ccipOffRampFromRobinhood : evm.contracts.ccipOffRampFromSubtensor;
2188
- const logs = await client.getLogs({
2189
- address: offRamp,
2190
- fromBlock: BigInt(input.fromBlock),
2191
- toBlock: "latest",
2192
- event: ccipExecutionAbi[0],
2193
- args: { sourceChainSelector: sourceSelector, messageId },
2194
- strict: true
2224
+ const offRamps = await deliveryOffRamps(
2225
+ provider,
2226
+ client,
2227
+ evmToSubtensor ? foreverMoneyDeployment.subtensor.contracts.ccipRouter : evm.contracts.ccipRouter,
2228
+ sourceSelector,
2229
+ offRamp
2230
+ );
2231
+ const batches = await Promise.all(
2232
+ [executionV2Abi[0], ccipExecutionAbi[0]].map(
2233
+ (event) => client.getLogs({
2234
+ address: offRamps.length === 1 ? offRamps[0] : [...offRamps],
2235
+ fromBlock: BigInt(input.fromBlock),
2236
+ toBlock: "latest",
2237
+ event,
2238
+ args: { sourceChainSelector: sourceSelector, messageId },
2239
+ strict: true
2240
+ })
2241
+ )
2242
+ );
2243
+ const logs = batches.flat().sort((a, b) => {
2244
+ const blockA = a.blockNumber ?? 0n;
2245
+ const blockB = b.blockNumber ?? 0n;
2246
+ return blockA === blockB ? (a.logIndex ?? 0) - (b.logIndex ?? 0) : blockA < blockB ? -1 : 1;
2195
2247
  });
2196
2248
  const latest = logs.at(-1);
2197
2249
  if (latest === void 0) return "waiting";