@ember-finance/sdk 2.13.0 → 2.15.0-ccip.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.
Files changed (43) hide show
  1. package/dist/src/abis/CcipRouter.json +58 -0
  2. package/dist/src/abis/index.d.ts +3 -1
  3. package/dist/src/abis/index.js +4 -1
  4. package/dist/src/api/v2/models/account-transaction-transaction-data.d.ts +2 -1
  5. package/dist/src/api/v2/models/account-transaction.d.ts +2 -0
  6. package/dist/src/api/v2/models/account-transaction.js +3 -1
  7. package/dist/src/api/v2/models/bridge-transaction.d.ts +50 -0
  8. package/dist/src/api/v2/models/bridge-transaction.js +14 -0
  9. package/dist/src/api/v2/models/chain.d.ts +6 -0
  10. package/dist/src/api/v2/models/evm-ccip-lane.d.ts +73 -0
  11. package/dist/src/api/v2/models/evm-ccip-lane.js +14 -0
  12. package/dist/src/api/v2/models/evm-ccip-rate-limits.d.ts +36 -0
  13. package/dist/src/api/v2/models/evm-ccip-rate-limits.js +14 -0
  14. package/dist/src/api/v2/models/evm-ccip-token-pool.d.ts +122 -0
  15. package/dist/src/api/v2/models/evm-ccip-token-pool.js +17 -0
  16. package/dist/src/api/v2/models/evm-contracts.d.ts +9 -0
  17. package/dist/src/api/v2/models/evm-oftadapter.d.ts +11 -0
  18. package/dist/src/api/v2/models/evm-oftadapter.js +4 -1
  19. package/dist/src/api/v2/models/evm-oftpeer.d.ts +12 -0
  20. package/dist/src/api/v2/models/index.d.ts +4 -0
  21. package/dist/src/api/v2/models/index.js +4 -0
  22. package/dist/src/evm-vaults/interfaces/index.d.ts +39 -0
  23. package/dist/src/evm-vaults/on-chain-calls/tx-builder.d.ts +15 -1
  24. package/dist/src/evm-vaults/on-chain-calls/tx-builder.js +36 -0
  25. package/dist/src/evm-vaults/on-chain-calls/user.d.ts +40 -1
  26. package/dist/src/evm-vaults/on-chain-calls/user.js +75 -0
  27. package/dist/src/evm-vaults/on-chain-calls/vault-reader.d.ts +14 -1
  28. package/dist/src/evm-vaults/on-chain-calls/vault-reader.js +30 -0
  29. package/dist/src/evm-vaults/utils/ccip.d.ts +23 -0
  30. package/dist/src/evm-vaults/utils/ccip.js +32 -0
  31. package/dist/src/evm-vaults/utils/deployment-parser.d.ts +46 -1
  32. package/dist/src/evm-vaults/utils/deployment-parser.js +74 -0
  33. package/dist/src/evm-vaults/utils/index.d.ts +1 -0
  34. package/dist/src/evm-vaults/utils/index.js +1 -0
  35. package/dist/src/sui-vaults/on-chain-calls/operator.d.ts +124 -0
  36. package/dist/src/sui-vaults/on-chain-calls/operator.js +174 -0
  37. package/dist/src/sui-vaults/on-chain-calls/tx-builder.d.ts +197 -5
  38. package/dist/src/sui-vaults/on-chain-calls/tx-builder.js +493 -7
  39. package/dist/src/sui-vaults/on-chain-calls/user.d.ts +82 -3
  40. package/dist/src/sui-vaults/on-chain-calls/user.js +129 -6
  41. package/dist/src/sui-vaults/on-chain-calls/vault-admin.d.ts +10 -2
  42. package/dist/src/sui-vaults/on-chain-calls/vault-admin.js +11 -6
  43. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
1
  import { EVMDeploymentParser } from "../utils/index.js";
2
- import { EvmProtocolInfo, VaultPauseOperation, ITransactionCall, IPermitSignature, IOFTSendParam, IOFTMessagingFee } from "../interfaces/index.js";
2
+ import { EvmProtocolInfo, VaultPauseOperation, ITransactionCall, IPermitSignature, IOFTSendParam, IOFTMessagingFee, ICcipSendParam } from "../interfaces/index.js";
3
3
  import { NumStr } from "../../common/types.js";
4
4
  /**
5
5
  * EVM Transaction Builder for Ember Protocol (ERC-4626 Compatible)
@@ -543,6 +543,20 @@ export declare class EVMTxBuilder {
543
543
  * @returns Transaction call object
544
544
  */
545
545
  bridgeSend(adapterAddress: string, sendParam: IOFTSendParam, fee: IOFTMessagingFee, refundAddress: string): ITransactionCall;
546
+ /**
547
+ * Builds the CCIP send call.
548
+ *
549
+ * The counterpart to bridgeSend, but the call goes to Chainlink's Router
550
+ * rather than to our own pool: the Router pulls the tokens, charges the fee
551
+ * and hands off to the pool. That is also why the approval for a CCIP bridge
552
+ * goes to the Router and not to the pool.
553
+ *
554
+ * @param routerAddress The CCIP Router on the source chain
555
+ * @param sendParam Destination, receiver and amount
556
+ * @param tokenAddress The receipt token being bridged
557
+ * @param fee Fee from getCcipFeeQuote, sent as value when paying natively
558
+ */
559
+ ccipSend(routerAddress: string, sendParam: ICcipSendParam, tokenAddress: string, fee: bigint): ITransactionCall;
546
560
  private atomicCall;
547
561
  /** Claim the caller's own escrowed (deferred) holdback collateral. */
548
562
  atomicClaimHoldback(vaultAddress: string): ITransactionCall;
@@ -4,6 +4,8 @@ import EmberETHVaultABI from "../../abis/EmberETHVault.json" with { type: "json"
4
4
  import EmberProtocolConfigABI from "../../abis/EmberProtocolConfig.json" with { type: "json" };
5
5
  import ERC20TokenABI from "../../abis/ERC20Token.json" with { type: "json" };
6
6
  import EmberVaultOFTAdapterABI from "../../abis/EmberVaultMintBurnOFTAdapter.json" with { type: "json" };
7
+ import CcipRouterABI from "../../abis/CcipRouter.json" with { type: "json" };
8
+ import { ZERO_ADDRESS, encodeCcipReceiver, encodeCcipExtraArgs } from "../utils/ccip.js";
7
9
  import AtomicLiquidityABI from "../../abis/AtomicLiquidity.json" with { type: "json" };
8
10
  import EmberDepositParkingLotABI from "../../abis/EmberDepositParkingLot.json" with { type: "json" };
9
11
  import OpenCoverVaultABI from "../../abis/OpenCoverVault.json" with { type: "json" };
@@ -1147,6 +1149,40 @@ export class EVMTxBuilder {
1147
1149
  chainId: this.getChainId()
1148
1150
  };
1149
1151
  }
1152
+ /**
1153
+ * Builds the CCIP send call.
1154
+ *
1155
+ * The counterpart to bridgeSend, but the call goes to Chainlink's Router
1156
+ * rather than to our own pool: the Router pulls the tokens, charges the fee
1157
+ * and hands off to the pool. That is also why the approval for a CCIP bridge
1158
+ * goes to the Router and not to the pool.
1159
+ *
1160
+ * @param routerAddress The CCIP Router on the source chain
1161
+ * @param sendParam Destination, receiver and amount
1162
+ * @param tokenAddress The receipt token being bridged
1163
+ * @param fee Fee from getCcipFeeQuote, sent as value when paying natively
1164
+ */
1165
+ ccipSend(routerAddress, sendParam, tokenAddress, fee) {
1166
+ const feeToken = sendParam.feeToken ?? ZERO_ADDRESS;
1167
+ return {
1168
+ to: routerAddress,
1169
+ functionName: "ccipSend",
1170
+ args: [
1171
+ sendParam.destinationChainSelector,
1172
+ {
1173
+ receiver: encodeCcipReceiver(sendParam.receiver),
1174
+ data: "0x",
1175
+ tokenAmounts: [{ token: tokenAddress, amount: sendParam.amount }],
1176
+ feeToken,
1177
+ extraArgs: encodeCcipExtraArgs(sendParam.destinationGasLimit)
1178
+ }
1179
+ ],
1180
+ abi: CcipRouterABI.abi,
1181
+ // Paying in a token means the Router pulls it instead, so no value.
1182
+ value: feeToken === ZERO_ADDRESS ? fee : 0n,
1183
+ chainId: this.getChainId()
1184
+ };
1185
+ }
1150
1186
  // ============================================
1151
1187
  // Atomic Liquidity Vault methods (BFE-817/818)
1152
1188
  //
@@ -1,6 +1,6 @@
1
1
  import { Signer, Provider } from "ethers";
2
2
  import { EVMOnChainCalls } from "./onchain-calls.js";
3
- import { EvmProtocolInfo, IUserCallOptions, IEvmCallOptions, ICoverVaultCallOptions, EvmOnChainCallResponse, IPermitSignature, IETHDepositOptions, IBridgeSendOptions, IOFTFeeQuote } from "../interfaces/index.js";
3
+ import { EvmProtocolInfo, IUserCallOptions, IEvmCallOptions, ICoverVaultCallOptions, EvmOnChainCallResponse, IPermitSignature, IETHDepositOptions, IBridgeSendOptions, IOFTFeeQuote, ICcipFeeQuote, ICcipBridgeSendOptions } from "../interfaces/index.js";
4
4
  import { NumStr } from "../../common/types.js";
5
5
  import { Chain } from "../../api/v2/index.js";
6
6
  /**
@@ -423,6 +423,45 @@ export declare class EVMUserCalls extends EVMOnChainCalls {
423
423
  * @returns Transaction execution response
424
424
  */
425
425
  bridgeSendToken(destinationChain: Chain, tokenAddress: string, amount: NumStr, receiver: string, feeQuote: IOFTFeeQuote, options?: IBridgeSendOptions): Promise<EvmOnChainCallResponse>;
426
+ /**
427
+ * Bridges a receipt token to a destination chain using the vault's CCIP pool.
428
+ *
429
+ * The counterpart to bridgeSendToken. Call getBridgeTransportForVault first
430
+ * and pick the matching method — a vault has exactly one active bridge, and
431
+ * calling the wrong one throws rather than silently doing nothing.
432
+ *
433
+ * One difference from the LayerZero path worth knowing: the allowance goes
434
+ * to the CCIP Router, not to the pool, because the Router is what pulls the
435
+ * tokens. An unconfigured route throws here rather than reverting on chain.
436
+ *
437
+ * @param destinationChain Destination chain metadata (must include ccipChainSelector)
438
+ * @param tokenAddress Receipt token address (also the vault identifier in EVM deployment data)
439
+ * @param amount Amount to bridge in local token decimals
440
+ * @param receiver Recipient wallet address on the destination chain
441
+ * @param feeQuote Fee quote returned by reader.getCcipFeeQuote
442
+ * @param options Optional bridge/send overrides
443
+ * @returns Transaction execution response
444
+ */
445
+ bridgeSendTokenViaCcip(destinationChain: Chain, tokenAddress: string, amount: NumStr, receiver: string, feeQuote: ICcipFeeQuote, options?: ICcipBridgeSendOptions): Promise<EvmOnChainCallResponse>;
446
+ /**
447
+ * Reports which bridge a vault uses, or undefined if it has none.
448
+ *
449
+ * A vault has exactly one active bridge, but different vaults use different
450
+ * ones, so branch on this rather than assuming either transport.
451
+ *
452
+ * @param tokenAddress Receipt token address (also the vault identifier in EVM deployment data)
453
+ */
454
+ getBridgeTransportForVault(tokenAddress: string): "LayerZero" | "CCIP" | undefined;
455
+ /**
456
+ * Lists the networks a vault can bridge to, whichever transport it uses.
457
+ *
458
+ * Empty for a vault with no bridge, and for a bridged vault with no route
459
+ * configured yet. A network absent from this list cannot be sent to — the
460
+ * send would revert on chain — so drive the destination picker from it.
461
+ *
462
+ * @param tokenAddress Receipt token address (also the vault identifier in EVM deployment data)
463
+ */
464
+ getBridgeDestinationsForVault(tokenAddress: string): string[];
426
465
  /**
427
466
  * Gets the vault contract instance for read operations
428
467
  * @param vaultAddress The address of the vault
@@ -637,6 +637,81 @@ export class EVMUserCalls extends EVMOnChainCalls {
637
637
  }, refundAddress);
638
638
  return this.execCall(txCall, options);
639
639
  }
640
+ /**
641
+ * Bridges a receipt token to a destination chain using the vault's CCIP pool.
642
+ *
643
+ * The counterpart to bridgeSendToken. Call getBridgeTransportForVault first
644
+ * and pick the matching method — a vault has exactly one active bridge, and
645
+ * calling the wrong one throws rather than silently doing nothing.
646
+ *
647
+ * One difference from the LayerZero path worth knowing: the allowance goes
648
+ * to the CCIP Router, not to the pool, because the Router is what pulls the
649
+ * tokens. An unconfigured route throws here rather than reverting on chain.
650
+ *
651
+ * @param destinationChain Destination chain metadata (must include ccipChainSelector)
652
+ * @param tokenAddress Receipt token address (also the vault identifier in EVM deployment data)
653
+ * @param amount Amount to bridge in local token decimals
654
+ * @param receiver Recipient wallet address on the destination chain
655
+ * @param feeQuote Fee quote returned by reader.getCcipFeeQuote
656
+ * @param options Optional bridge/send overrides
657
+ * @returns Transaction execution response
658
+ */
659
+ async bridgeSendTokenViaCcip(destinationChain, tokenAddress, amount, receiver, feeQuote, options) {
660
+ if (!this.provider) {
661
+ throw new Error("Provider required for bridge send read operations and allowance checks");
662
+ }
663
+ const pool = this.parser.getCcipTokenPoolByVaultAddress(tokenAddress);
664
+ if (!pool?.router) {
665
+ throw new Error(`CCIP token pool not found for token address: ${tokenAddress}`);
666
+ }
667
+ if (destinationChain.ccipChainSelector === undefined ||
668
+ destinationChain.ccipChainSelector === null) {
669
+ throw new Error(`Destination chain "${destinationChain.name ?? destinationChain.identifier}" has no ccipChainSelector — cannot address a CCIP destination`);
670
+ }
671
+ const remoteChainSelector = destinationChain.ccipChainSelector;
672
+ const lane = this.parser.getCcipLaneByVaultAndSelector(tokenAddress, remoteChainSelector);
673
+ if (!lane) {
674
+ throw new Error(`No CCIP lane configured from this chain to "${destinationChain.identifier}" for token ${tokenAddress}`);
675
+ }
676
+ const amountBigInt = BigInt(amount);
677
+ // The Router moves the tokens, so it is the Router that needs approval.
678
+ const token = new ethers.Contract(tokenAddress, ["function allowance(address,address) view returns (uint256)"], this.provider);
679
+ const currentAllowance = await token.allowance(await this.getWalletAddress(), pool.router);
680
+ if (currentAllowance < amountBigInt) {
681
+ throw new Error(`Insufficient allowance for bridge transfer. Current allowance: ${currentAllowance}, required: ${amountBigInt}`);
682
+ }
683
+ const txCall = this.txBuilder.ccipSend(pool.router, {
684
+ destinationChainSelector: remoteChainSelector,
685
+ receiver,
686
+ amount: amountBigInt,
687
+ feeToken: options?.feeToken,
688
+ destinationGasLimit: options?.destinationGasLimit
689
+ }, tokenAddress, feeQuote.fee);
690
+ return this.execCall(txCall, options);
691
+ }
692
+ /**
693
+ * Reports which bridge a vault uses, or undefined if it has none.
694
+ *
695
+ * A vault has exactly one active bridge, but different vaults use different
696
+ * ones, so branch on this rather than assuming either transport.
697
+ *
698
+ * @param tokenAddress Receipt token address (also the vault identifier in EVM deployment data)
699
+ */
700
+ getBridgeTransportForVault(tokenAddress) {
701
+ return this.parser.getBridgeTransportByVaultAddress(tokenAddress);
702
+ }
703
+ /**
704
+ * Lists the networks a vault can bridge to, whichever transport it uses.
705
+ *
706
+ * Empty for a vault with no bridge, and for a bridged vault with no route
707
+ * configured yet. A network absent from this list cannot be sent to — the
708
+ * send would revert on chain — so drive the destination picker from it.
709
+ *
710
+ * @param tokenAddress Receipt token address (also the vault identifier in EVM deployment data)
711
+ */
712
+ getBridgeDestinationsForVault(tokenAddress) {
713
+ return this.parser.getBridgeDestinationsByVaultAddress(tokenAddress);
714
+ }
640
715
  // ============================================
641
716
  // Read-Only Methods
642
717
  // ============================================
@@ -1,6 +1,6 @@
1
1
  import { Provider } from "ethers";
2
2
  import { EVMDeploymentParser } from "../utils/deployment-parser.js";
3
- import { EvmProtocolInfo, IOFTSendParam, IOFTFeeQuote, IOFTVaultSupportedChain, IParkingLotInfo } from "../interfaces/index.js";
3
+ import { EvmProtocolInfo, IOFTSendParam, IOFTFeeQuote, IOFTVaultSupportedChain, IParkingLotInfo, ICcipSendParam, ICcipFeeQuote } from "../interfaces/index.js";
4
4
  import { NumStr } from "../../common/types.js";
5
5
  import { Chain, VaultsApi } from "../../api/v2/index.js";
6
6
  /**
@@ -524,4 +524,17 @@ export declare class EVMVaultReader {
524
524
  * @returns Combined fee quote including native fee and expected amounts
525
525
  */
526
526
  getOFTFeeQuote(vaultId: string, sendParam: IOFTSendParam, payInLzToken?: boolean): Promise<IOFTFeeQuote>;
527
+ /**
528
+ * Quotes what a CCIP bridge send will cost.
529
+ *
530
+ * The counterpart to getOFTFeeQuote. CCIP charges one fee rather than
531
+ * LayerZero's native/LZ-token pair, and quotes no received amount: a
532
+ * burn-and-mint pool mints exactly what it burned, so the amount received is
533
+ * the amount sent.
534
+ *
535
+ * @param vaultId The vault (receipt token) address on the source chain
536
+ * @param sendParam Destination, receiver and amount
537
+ * @returns The fee and the token it is charged in
538
+ */
539
+ getCcipFeeQuote(vaultId: string, sendParam: ICcipSendParam): Promise<ICcipFeeQuote>;
527
540
  }
@@ -4,6 +4,8 @@ import EmberVaultABI from "../../abis/EmberVault.json" with { type: "json" };
4
4
  import EmberETHVaultABI from "../../abis/EmberETHVault.json" with { type: "json" };
5
5
  import EmberProtocolConfigABI from "../../abis/EmberProtocolConfig.json" with { type: "json" };
6
6
  import ERC20TokenABI from "../../abis/ERC20Token.json" with { type: "json" };
7
+ import CcipRouterABI from "../../abis/CcipRouter.json" with { type: "json" };
8
+ import { ZERO_ADDRESS, encodeCcipReceiver, encodeCcipExtraArgs } from "../utils/ccip.js";
7
9
  import EmberVaultOFTAdapterABI from "../../abis/EmberVaultMintBurnOFTAdapter.json" with { type: "json" };
8
10
  import EmberDepositParkingLotABI from "../../abis/EmberDepositParkingLot.json" with { type: "json" };
9
11
  import { Configuration, VaultsApi } from "../../api/v2/index.js";
@@ -736,4 +738,32 @@ export class EVMVaultReader {
736
738
  maxAmountLD: oftQuote.oftLimit.maxAmountLD
737
739
  };
738
740
  }
741
+ /**
742
+ * Quotes what a CCIP bridge send will cost.
743
+ *
744
+ * The counterpart to getOFTFeeQuote. CCIP charges one fee rather than
745
+ * LayerZero's native/LZ-token pair, and quotes no received amount: a
746
+ * burn-and-mint pool mints exactly what it burned, so the amount received is
747
+ * the amount sent.
748
+ *
749
+ * @param vaultId The vault (receipt token) address on the source chain
750
+ * @param sendParam Destination, receiver and amount
751
+ * @returns The fee and the token it is charged in
752
+ */
753
+ async getCcipFeeQuote(vaultId, sendParam) {
754
+ const pool = this.parser.getCcipTokenPoolByVaultAddress(vaultId);
755
+ if (!pool?.router) {
756
+ throw new Error(`CCIP token pool not found for vault: ${vaultId}`);
757
+ }
758
+ const feeToken = sendParam.feeToken ?? ZERO_ADDRESS;
759
+ const router = new Contract(pool.router, CcipRouterABI.abi, this.provider);
760
+ const fee = await router.getFee(sendParam.destinationChainSelector, {
761
+ receiver: encodeCcipReceiver(sendParam.receiver),
762
+ data: "0x",
763
+ tokenAmounts: [{ token: vaultId, amount: sendParam.amount }],
764
+ feeToken,
765
+ extraArgs: encodeCcipExtraArgs(sendParam.destinationGasLimit)
766
+ });
767
+ return { fee, feeToken };
768
+ }
739
769
  }
@@ -0,0 +1,23 @@
1
+ /** The native currency, as CCIP names it when no fee token is given. */
2
+ export declare const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
3
+ /**
4
+ * Encodes a receiver for a CCIP message.
5
+ *
6
+ * CCIP carries the receiver as `bytes` rather than `address`, because the far
7
+ * end of a lane need not be an EVM chain. On an EVM destination that is the
8
+ * address left-padded to 32 bytes, which is why the same account looks
9
+ * different on the two sides of a transfer.
10
+ */
11
+ export declare const encodeCcipReceiver: (receiver: string) => string;
12
+ /**
13
+ * Encodes CCIP extraArgs.
14
+ *
15
+ * `allowOutOfOrderExecution` is true because a token transfer carries no
16
+ * message the destination has to apply in sequence; requiring ordering would
17
+ * make one stuck message block every later one on the lane.
18
+ *
19
+ * gasLimit is 0 by default: a plain token transfer runs no code on the
20
+ * destination beyond the pool's own mint, and paying for gas that is never used
21
+ * only raises the fee.
22
+ */
23
+ export declare const encodeCcipExtraArgs: (destinationGasLimit?: bigint) => string;
@@ -0,0 +1,32 @@
1
+ import { AbiCoder, getAddress, zeroPadValue } from "ethers";
2
+ /** The native currency, as CCIP names it when no fee token is given. */
3
+ export const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
4
+ /**
5
+ * Tag for CCIP's EVMExtraArgsV2, the first four bytes of
6
+ * keccak256("CCIP EVMExtraArgsV2"). Verified against a deployed ramp.
7
+ */
8
+ const EVM_EXTRA_ARGS_V2_TAG = "0x181dcf10";
9
+ /**
10
+ * Encodes a receiver for a CCIP message.
11
+ *
12
+ * CCIP carries the receiver as `bytes` rather than `address`, because the far
13
+ * end of a lane need not be an EVM chain. On an EVM destination that is the
14
+ * address left-padded to 32 bytes, which is why the same account looks
15
+ * different on the two sides of a transfer.
16
+ */
17
+ export const encodeCcipReceiver = (receiver) => zeroPadValue(getAddress(receiver), 32);
18
+ /**
19
+ * Encodes CCIP extraArgs.
20
+ *
21
+ * `allowOutOfOrderExecution` is true because a token transfer carries no
22
+ * message the destination has to apply in sequence; requiring ordering would
23
+ * make one stuck message block every later one on the lane.
24
+ *
25
+ * gasLimit is 0 by default: a plain token transfer runs no code on the
26
+ * destination beyond the pool's own mint, and paying for gas that is never used
27
+ * only raises the fee.
28
+ */
29
+ export const encodeCcipExtraArgs = (destinationGasLimit = 0n) => {
30
+ const encoded = AbiCoder.defaultAbiCoder().encode(["uint256", "bool"], [destinationGasLimit, true]);
31
+ return EVM_EXTRA_ARGS_V2_TAG + encoded.slice(2);
32
+ };
@@ -1,4 +1,4 @@
1
- import { EvmOFTAdapter } from "../../api/v2/index.js";
1
+ import { EvmCcipLane, EvmCcipTokenPool, EvmOFTAdapter } from "../../api/v2/index.js";
2
2
  import { EvmProtocolInfo } from "../interfaces/index.js";
3
3
  export declare class EVMDeploymentParser {
4
4
  deployment: EvmProtocolInfo;
@@ -124,4 +124,49 @@ export declare class EVMDeploymentParser {
124
124
  * @param vaultAddress The vault address (receipt token address in EVM deployment data)
125
125
  */
126
126
  getOFTAdapterObjectByVaultAddress(vaultAddress: string): EvmOFTAdapter | undefined;
127
+ /**
128
+ * Finds the CCIP token pool entry for a given vault address.
129
+ * @param vaultAddress The vault address (receipt token address in EVM deployment data)
130
+ */
131
+ getCcipTokenPoolByVaultAddress(vaultAddress: string): EvmCcipTokenPool | undefined;
132
+ /**
133
+ * Reports which bridge a vault uses, or undefined if it has none.
134
+ *
135
+ * A vault has exactly one active bridge, but different vaults use different
136
+ * ones, so call this before choosing between the LayerZero and CCIP send
137
+ * methods rather than assuming either.
138
+ *
139
+ * @param vaultAddress The vault address (receipt token address in EVM deployment data)
140
+ */
141
+ getBridgeTransportByVaultAddress(vaultAddress: string): "LayerZero" | "CCIP" | undefined;
142
+ /**
143
+ * Lists the networks a vault can bridge to, whichever transport it uses.
144
+ *
145
+ * Returns an empty array for a vault with no bridge, so it is safe to render
146
+ * directly. Names are as the deployment records them, which is what
147
+ * bridgeSendTokenViaCcip takes as its destination.
148
+ *
149
+ * @param vaultAddress The vault address (receipt token address in EVM deployment data)
150
+ */
151
+ getBridgeDestinationsByVaultAddress(vaultAddress: string): string[];
152
+ /**
153
+ * Finds the configured CCIP lane from a vault to a destination chain selector.
154
+ *
155
+ * A missing lane means the route is not configured and a send would revert.
156
+ *
157
+ * @param vaultAddress The vault address on the source chain
158
+ * @param remoteChainSelector The destination CCIP chain selector
159
+ */
160
+ getCcipLaneByVaultAndSelector(vaultAddress: string, remoteChainSelector: string): EvmCcipLane | undefined;
161
+ /**
162
+ * Finds the configured CCIP lane from a vault to a destination network.
163
+ *
164
+ * Lanes are keyed by the destination's CCIP chain selector, which nothing
165
+ * outside CCIP knows, so this looks the lane up by network name instead.
166
+ * A missing lane means the route is not configured — sending would revert.
167
+ *
168
+ * @param vaultAddress The vault address on the source chain
169
+ * @param destinationNetwork The destination network name, e.g. "atlantic"
170
+ */
171
+ getCcipLaneByVaultAndNetwork(vaultAddress: string, destinationNetwork: string): EvmCcipLane | undefined;
127
172
  }
@@ -206,4 +206,78 @@ export class EVMDeploymentParser {
206
206
  }
207
207
  return entry;
208
208
  }
209
+ /**
210
+ * Finds the CCIP token pool entry for a given vault address.
211
+ * @param vaultAddress The vault address (receipt token address in EVM deployment data)
212
+ */
213
+ getCcipTokenPoolByVaultAddress(vaultAddress) {
214
+ return Object.values(this.deployment.contracts?.ccipTokenPools ?? {}).find(pool => pool.vaultAddress?.toLowerCase() === vaultAddress.toLowerCase());
215
+ }
216
+ /**
217
+ * Reports which bridge a vault uses, or undefined if it has none.
218
+ *
219
+ * A vault has exactly one active bridge, but different vaults use different
220
+ * ones, so call this before choosing between the LayerZero and CCIP send
221
+ * methods rather than assuming either.
222
+ *
223
+ * @param vaultAddress The vault address (receipt token address in EVM deployment data)
224
+ */
225
+ getBridgeTransportByVaultAddress(vaultAddress) {
226
+ if (this.getCcipTokenPoolByVaultAddress(vaultAddress))
227
+ return "CCIP";
228
+ if (this.getOFTAdapterObjectByVaultAddress(vaultAddress))
229
+ return "LayerZero";
230
+ return undefined;
231
+ }
232
+ /**
233
+ * Lists the networks a vault can bridge to, whichever transport it uses.
234
+ *
235
+ * Returns an empty array for a vault with no bridge, so it is safe to render
236
+ * directly. Names are as the deployment records them, which is what
237
+ * bridgeSendTokenViaCcip takes as its destination.
238
+ *
239
+ * @param vaultAddress The vault address (receipt token address in EVM deployment data)
240
+ */
241
+ getBridgeDestinationsByVaultAddress(vaultAddress) {
242
+ // Both transports record the far end the same way, under remoteNetwork,
243
+ // but one keys its map by CCIP chain selector and the other by LayerZero
244
+ // endpoint id — neither of which a caller has any way to resolve. Reading
245
+ // the values rather than the keys is what keeps the two symmetric.
246
+ const pool = this.getCcipTokenPoolByVaultAddress(vaultAddress);
247
+ const adapter = this.getOFTAdapterObjectByVaultAddress(vaultAddress);
248
+ const networks = [
249
+ ...Object.values(pool?.lanes ?? {}),
250
+ ...Object.values(adapter?.peers ?? {})
251
+ ]
252
+ .map(entry => entry.remoteNetwork)
253
+ .filter((network) => !!network);
254
+ return [...new Set(networks)];
255
+ }
256
+ /**
257
+ * Finds the configured CCIP lane from a vault to a destination chain selector.
258
+ *
259
+ * A missing lane means the route is not configured and a send would revert.
260
+ *
261
+ * @param vaultAddress The vault address on the source chain
262
+ * @param remoteChainSelector The destination CCIP chain selector
263
+ */
264
+ getCcipLaneByVaultAndSelector(vaultAddress, remoteChainSelector) {
265
+ // Lanes are keyed by selector, so this is a direct hit rather than the
266
+ // scan the by-network lookup has to do.
267
+ return this.getCcipTokenPoolByVaultAddress(vaultAddress)?.lanes?.[remoteChainSelector];
268
+ }
269
+ /**
270
+ * Finds the configured CCIP lane from a vault to a destination network.
271
+ *
272
+ * Lanes are keyed by the destination's CCIP chain selector, which nothing
273
+ * outside CCIP knows, so this looks the lane up by network name instead.
274
+ * A missing lane means the route is not configured — sending would revert.
275
+ *
276
+ * @param vaultAddress The vault address on the source chain
277
+ * @param destinationNetwork The destination network name, e.g. "atlantic"
278
+ */
279
+ getCcipLaneByVaultAndNetwork(vaultAddress, destinationNetwork) {
280
+ const pool = this.getCcipTokenPoolByVaultAddress(vaultAddress);
281
+ return Object.values(pool?.lanes ?? {}).find(lane => lane.remoteNetwork?.toLowerCase() === destinationNetwork.toLowerCase());
282
+ }
209
283
  }
@@ -1,2 +1,3 @@
1
1
  export * from "./deployment-parser.js";
2
2
  export * from "./permit-utils.js";
3
+ export * from "./ccip.js";
@@ -1,2 +1,3 @@
1
1
  export * from "./deployment-parser.js";
2
2
  export * from "./permit-utils.js";
3
+ export * from "./ccip.js";
@@ -137,6 +137,79 @@ export declare class OperatorCalls extends OnChainCalls {
137
137
  * @returns OnChainCallResponse
138
138
  */
139
139
  atomicCollectPlatformFee(vaultId: string, loss: NumStr, options?: IVaultOptionalParams & SuiTransactionBlockResponseOptions): Promise<OnChainCallResponse>;
140
+ /**
141
+ * Step 2 of 2 for Suilend activation: opens the obligation the supply is
142
+ * held in. Must run after `atomicSetStrategySuilend` and before the first
143
+ * supply, which aborts `ESuilendObligationMissing` until it has.
144
+ *
145
+ * Not optional — Suilend accounts rewards against an obligation, so cTokens
146
+ * held outside one earn base interest and no rewards. Callable by either
147
+ * the vault admin or the operator.
148
+ * @param vaultId The id of the atomic vault
149
+ * @param poolCoinType The Suilend pool coin type (P)
150
+ * @param lendingMarketId Object id of the Suilend LendingMarket<P>
151
+ * @param options Optional tx execution params
152
+ * @returns OnChainCallResponse
153
+ */
154
+ atomicOpenSuilendObligation(vaultId: string, poolCoinType: string, lendingMarketId: string, options?: IVaultOptionalParams & SuiTransactionBlockResponseOptions): Promise<OnChainCallResponse>;
155
+ /**
156
+ * Claim one accrued Suilend pool reward into an allowlisted sub-account.
157
+ * One call per (reserve, reward slot, deposit-or-borrow) triple — batch in
158
+ * a PTB, and sweep every occupied slot rather than only the live campaign.
159
+ * @param vaultId The id of the atomic vault
160
+ * @param poolCoinType The Suilend pool coin type (P)
161
+ * @param lendingMarketId Object id of the Suilend LendingMarket<P>
162
+ * @param rewardSourceType Coin type identifying the reserve the reward
163
+ * accrues on — the vault's collateral for the strategy position, the
164
+ * foreign type's own reserve for secondary-collateral rewards
165
+ * @param rewardType Coin type of the reward being claimed
166
+ * @param subAccount Allowlisted sub-account to receive the reward
167
+ * @param rewardIndex Slot index in the reserve's pool_rewards vector
168
+ * @param isDepositReward True for the deposit-side reward manager
169
+ * @param options Optional tx execution params
170
+ * @returns OnChainCallResponse
171
+ */
172
+ atomicClaimSuilendStrategyReward(vaultId: string, poolCoinType: string, lendingMarketId: string, rewardSourceType: string, rewardType: string, subAccount: string, rewardIndex: NumStr, isDepositReward: boolean, options?: IVaultOptionalParams & SuiTransactionBlockResponseOptions): Promise<OnChainCallResponse>;
173
+ /**
174
+ * Drain a foreign collateral position from the vault's Suilend obligation.
175
+ * Only needed when a third party has deposited into it via Suilend's
176
+ * permissionless `claim_rewards_and_deposit`; teardown refuses to run while
177
+ * any deposit remains, so this is the unblock.
178
+ * @param vaultId The id of the atomic vault
179
+ * @param poolCoinType The Suilend pool coin type (P)
180
+ * @param lendingMarketId Object id of the Suilend LendingMarket<P>
181
+ * @param rewardType Coin type of the foreign collateral position
182
+ * @param subAccount Allowlisted sub-account to receive the proceeds
183
+ * @param options Optional tx execution params
184
+ * @returns OnChainCallResponse
185
+ */
186
+ atomicWithdrawSuilendSecondaryCollateral(vaultId: string, poolCoinType: string, lendingMarketId: string, rewardType: string, subAccount: string, options?: IVaultOptionalParams & SuiTransactionBlockResponseOptions): Promise<OnChainCallResponse>;
187
+ /**
188
+ * SUI variant of `atomicWithdrawSuilendSecondaryCollateral`. Use whenever
189
+ * the foreign position is SUI — the generic call rejects it, because
190
+ * Suilend stakes idle SUI reserve balance and the combined redemption path
191
+ * has no unstake step.
192
+ * @param vaultId The id of the atomic vault
193
+ * @param poolCoinType The Suilend pool coin type (P)
194
+ * @param lendingMarketId Object id of the Suilend LendingMarket<P>
195
+ * @param subAccount Allowlisted sub-account to receive the proceeds
196
+ * @param options Optional tx execution params
197
+ * @returns OnChainCallResponse
198
+ */
199
+ atomicWithdrawSuilendSecondaryCollateralSui(vaultId: string, poolCoinType: string, lendingMarketId: string, subAccount: string, options?: IVaultOptionalParams & SuiTransactionBlockResponseOptions): Promise<OnChainCallResponse>;
200
+ /**
201
+ * Collect accrued AlphaLend rewards into an allowlisted sub-account. Call
202
+ * once per reward type BEFORE exiting the strategy — the exit burns the
203
+ * PositionCap and strands anything uncollected. Requires an AlphaLend Pyth
204
+ * price refresh earlier in the same PTB. `rewardType` must not be SUI.
205
+ * @param vaultId The id of the atomic vault
206
+ * @param lendingProtocolId Object id of the AlphaLend LendingProtocol
207
+ * @param rewardType Coin type of the reward being collected
208
+ * @param subAccount Allowlisted sub-account to receive the reward
209
+ * @param options Optional tx execution params
210
+ * @returns OnChainCallResponse
211
+ */
212
+ atomicCollectAlphalendStrategyReward(vaultId: string, lendingProtocolId: string, rewardType: string, subAccount: string, options?: IVaultOptionalParams & SuiTransactionBlockResponseOptions): Promise<OnChainCallResponse>;
140
213
  /**
141
214
  * Supply collateral from an atomic vault into the Suilend strategy
142
215
  * @param vaultId The id of the atomic vault
@@ -240,4 +313,55 @@ export declare class OperatorCalls extends OnChainCalls {
240
313
  * @returns OnChainCallResponse
241
314
  */
242
315
  atomicUpdateVaultRate(vaultId: string, newRate: NumStr, options?: IVaultOptionalParams & SuiTransactionBlockResponseOptions): Promise<OnChainCallResponse>;
316
+ /**
317
+ * Exits the Suilend strategy on a SUI-collateral vault
318
+ * @param vaultId Id of the atomic vault (collateral must be SUI)
319
+ * @param poolCoinType The Suilend pool coin type (P)
320
+ * @param lendingMarketId Object id of the Suilend LendingMarket<P>
321
+ * @param options Optional tx execution params
322
+ * @returns OnChainCallResponse
323
+ */
324
+ atomicSetStrategyNoneFromSuilendSui(vaultId: string, poolCoinType: string, lendingMarketId: string, options?: IVaultOptionalParams & SuiTransactionBlockResponseOptions): Promise<OnChainCallResponse>;
325
+ /**
326
+ * Exits the AlphaLend strategy on a SUI-collateral vault
327
+ * @param vaultId Id of the atomic vault (collateral must be SUI)
328
+ * @param lendingProtocolId Object id of the AlphaLend LendingProtocol
329
+ * @param acceptResidual Abandon a dust residual rather than aborting the
330
+ * exit. Only pass true deliberately: the residual is forfeited.
331
+ * @param options Optional tx execution params
332
+ * @returns OnChainCallResponse
333
+ */
334
+ atomicSetStrategyNoneFromAlphalendSui(vaultId: string, lendingProtocolId: string, acceptResidual: boolean, options?: IVaultOptionalParams & SuiTransactionBlockResponseOptions): Promise<OnChainCallResponse>;
335
+ /**
336
+ * Withdraws collateral from the Suilend strategy on a SUI-collateral vault
337
+ * @param vaultId Id of the atomic vault (collateral must be SUI)
338
+ * @param poolCoinType The Suilend pool coin type (P)
339
+ * @param lendingMarketId Object id of the Suilend LendingMarket<P>
340
+ * @param amount Amount of collateral to withdraw, in base units
341
+ * @param options Optional tx execution params
342
+ * @returns OnChainCallResponse
343
+ */
344
+ atomicWithdrawFromSuilendStrategySui(vaultId: string, poolCoinType: string, lendingMarketId: string, amount: NumStr, options?: IVaultOptionalParams & SuiTransactionBlockResponseOptions): Promise<OnChainCallResponse>;
345
+ /**
346
+ * Withdraws collateral from the AlphaLend strategy on a SUI-collateral vault
347
+ * @param vaultId Id of the atomic vault (collateral must be SUI)
348
+ * @param lendingProtocolId Object id of the AlphaLend LendingProtocol
349
+ * @param amount Amount of collateral to withdraw, in base units
350
+ * @param options Optional tx execution params
351
+ * @returns OnChainCallResponse
352
+ */
353
+ atomicWithdrawFromAlphalendStrategySui(vaultId: string, lendingProtocolId: string, amount: NumStr, options?: IVaultOptionalParams & SuiTransactionBlockResponseOptions): Promise<OnChainCallResponse>;
354
+ /**
355
+ * Collects accrued AlphaLend rewards through the SUI system state and
356
+ * forwards them to an allowlisted sub-account.
357
+ *
358
+ * Call before exiting the strategy — the exit burns the `PositionCap` and
359
+ * strands anything uncollected.
360
+ * @param vaultId Id of the atomic vault
361
+ * @param lendingProtocolId Object id of the AlphaLend LendingProtocol
362
+ * @param subAccount Allowlisted sub-account to receive the rewards
363
+ * @param options Optional tx execution params
364
+ * @returns OnChainCallResponse
365
+ */
366
+ atomicCollectAlphalendStrategyRewardSui(vaultId: string, lendingProtocolId: string, subAccount: string, options?: IVaultOptionalParams & SuiTransactionBlockResponseOptions): Promise<OnChainCallResponse>;
243
367
  }