From 0f500c8c3ab5c7816cd56f1bad3b1f07d2d1e043 Mon Sep 17 00:00:00 2001 From: Kristijan Date: Tue, 9 Jun 2026 10:41:18 +0200 Subject: [PATCH 01/16] Init commit - token pools --- .../contracts/ccip/cct/JettonMinter.tolk | 208 ++++ .../contracts/ccip/cct/JettonWallet.tolk | 160 +++ .../contracts/ccip/cct/fees-management.tolk | 71 ++ .../contracts/ccip/fee_quoter/types.tolk | 2 - contracts/contracts/ccip/pool/TODO.md | 36 + .../pool/burn_mint_token_pool/contract.tolk | 287 +++++ .../pool/burn_mint_token_pool/errors.tolk | 17 + .../pool/burn_mint_token_pool/messages.tolk | 12 + .../pool/burn_mint_token_pool/storage.tolk | 57 + .../ccip/pool/burn_mint_token_pool/types.tolk | 35 + contracts/contracts/ccip/pool/errors.tolk | 35 + contracts/contracts/ccip/pool/events.tolk | 122 ++ .../lock_release_token_pool/contract.tolk | 266 +++++ .../pool/lock_release_token_pool/errors.tolk | 16 + .../pool/lock_release_token_pool/events.tolk | 41 + .../lock_release_token_pool/messages.tolk | 9 + .../pool/lock_release_token_pool/storage.tolk | 54 + .../pool/lock_release_token_pool/types.tolk | 24 + contracts/contracts/ccip/pool/messages.tolk | 107 ++ .../contracts/ccip/pool/rate_limiter.tolk | 70 ++ contracts/contracts/ccip/pool/token_pool.tolk | 1008 +++++++++++++++++ .../contracts/ccip/pool/tolk-1.4-docs.md | 987 ++++++++++++++++ contracts/contracts/ccip/pool/types.tolk | 166 +++ .../tests/ccip/pool/BurnMintTokenPool.spec.ts | 397 +++++++ .../ccip/pool/LockReleaseTokenPool.spec.ts | 381 +++++++ .../tests/ccip/pool/TokenPool.behavior.ts | 415 +++++++ .../wrappers/BurnMintTokenPool.compile.ts | 7 + .../wrappers/LockReleaseTokenPool.compile.ts | 7 + .../wrappers/ccip.cct.JettonMinter.compile.ts | 7 + .../wrappers/ccip.cct.JettonWallet.compile.ts | 7 + contracts/wrappers/ccip/BurnMintTokenPool.ts | 156 +++ contracts/wrappers/ccip/CCTJettonCode.ts | 10 + contracts/wrappers/ccip/CCTJettonMinter.ts | 123 ++ .../wrappers/ccip/LockReleaseTokenPool.ts | 141 +++ contracts/wrappers/ccip/TokenPool.ts | 346 ++++++ 35 files changed, 5785 insertions(+), 2 deletions(-) create mode 100644 contracts/contracts/ccip/cct/JettonMinter.tolk create mode 100644 contracts/contracts/ccip/cct/JettonWallet.tolk create mode 100644 contracts/contracts/ccip/cct/fees-management.tolk create mode 100644 contracts/contracts/ccip/pool/TODO.md create mode 100644 contracts/contracts/ccip/pool/burn_mint_token_pool/contract.tolk create mode 100644 contracts/contracts/ccip/pool/burn_mint_token_pool/errors.tolk create mode 100644 contracts/contracts/ccip/pool/burn_mint_token_pool/messages.tolk create mode 100644 contracts/contracts/ccip/pool/burn_mint_token_pool/storage.tolk create mode 100644 contracts/contracts/ccip/pool/burn_mint_token_pool/types.tolk create mode 100644 contracts/contracts/ccip/pool/errors.tolk create mode 100644 contracts/contracts/ccip/pool/events.tolk create mode 100644 contracts/contracts/ccip/pool/lock_release_token_pool/contract.tolk create mode 100644 contracts/contracts/ccip/pool/lock_release_token_pool/errors.tolk create mode 100644 contracts/contracts/ccip/pool/lock_release_token_pool/events.tolk create mode 100644 contracts/contracts/ccip/pool/lock_release_token_pool/messages.tolk create mode 100644 contracts/contracts/ccip/pool/lock_release_token_pool/storage.tolk create mode 100644 contracts/contracts/ccip/pool/lock_release_token_pool/types.tolk create mode 100644 contracts/contracts/ccip/pool/messages.tolk create mode 100644 contracts/contracts/ccip/pool/rate_limiter.tolk create mode 100644 contracts/contracts/ccip/pool/token_pool.tolk create mode 100644 contracts/contracts/ccip/pool/tolk-1.4-docs.md create mode 100644 contracts/contracts/ccip/pool/types.tolk create mode 100644 contracts/tests/ccip/pool/BurnMintTokenPool.spec.ts create mode 100644 contracts/tests/ccip/pool/LockReleaseTokenPool.spec.ts create mode 100644 contracts/tests/ccip/pool/TokenPool.behavior.ts create mode 100644 contracts/wrappers/BurnMintTokenPool.compile.ts create mode 100644 contracts/wrappers/LockReleaseTokenPool.compile.ts create mode 100644 contracts/wrappers/ccip.cct.JettonMinter.compile.ts create mode 100644 contracts/wrappers/ccip.cct.JettonWallet.compile.ts create mode 100644 contracts/wrappers/ccip/BurnMintTokenPool.ts create mode 100644 contracts/wrappers/ccip/CCTJettonCode.ts create mode 100644 contracts/wrappers/ccip/CCTJettonMinter.ts create mode 100644 contracts/wrappers/ccip/LockReleaseTokenPool.ts create mode 100644 contracts/wrappers/ccip/TokenPool.ts diff --git a/contracts/contracts/ccip/cct/JettonMinter.tolk b/contracts/contracts/ccip/cct/JettonMinter.tolk new file mode 100644 index 000000000..2990dc99d --- /dev/null +++ b/contracts/contracts/ccip/cct/JettonMinter.tolk @@ -0,0 +1,208 @@ +import "@stdlib/strings" +import "../../lib/jetton/errors" +import "../../lib/jetton/jetton-utils" +import "../../lib/jetton/storage" +import "../../lib/jetton/messages" +import "fees-management" + +contract JettonMinter { + author: "The Tolk Team" + incomingMessages: AllowedMessageToMinter + storage: MinterStorage +} + +type AllowedMessageToMinter = + | MintNewJettons + | BurnNotificationForMinter + | RequestWalletAddress + | ChangeMinterAdmin + | ClaimMinterAdmin + | DropMinterAdmin + | ChangeMinterMetadataUri + | UpgradeMinterCode + | TopUpTons + +fun onBouncedMessage(in: InMessageBounced) { + in.bouncedBody.skipBouncedPrefix(); + // process only mint bounces; on other messages, an exception will be thrown, it's okay + val msg = lazy InternalTransferStep.fromSlice(in.bouncedBody); + + var storage = lazy MinterStorage.load(); + storage.totalSupply -= msg.jettonAmount; + storage.save(); +} + +fun assertSenderIsAdmin(senderAddress: address, adminAddress: address?) { + // theoretically, minter's admin can be dropped and be `null`, so being precise, we should check: + // ``` + // assert (adminAddress != null) throw ERROR_NOT_OWNER; + // ``` + // but in practice, the above assertion is reduntant, we just bypass the nullability check: + assert (senderAddress == adminAddress!) throw ERROR_NOT_OWNER; + // then, if admin is `null`, error code 7 will be thrown (while executing operator `==`), + // it's suitable for current implementation +} + +fun onInternalMessage(in: InMessage) { + val msg = lazy AllowedMessageToMinter.fromSlice(in.body); + + match (msg) { + BurnNotificationForMinter => { + var storage = lazy MinterStorage.load(); + assert (in.senderAddress == calcAddressOfJettonWallet(msg.burnInitiator, contract.getAddress(), storage.jettonWalletCode)) throw ERROR_NOT_VALID_WALLET; + storage.totalSupply -= msg.jettonAmount; + storage.save(); + + if (msg.sendExcessesTo == null) { + return; + } + + val excessesMsg = createMessage({ + bounce: BounceMode.NoBounce, + dest: msg.sendExcessesTo, + value: 0, + body: ReturnExcessesBack { + queryId: msg.queryId + } + }); + excessesMsg.send(SEND_MODE_IGNORE_ERRORS | SEND_MODE_CARRY_ALL_REMAINING_MESSAGE_VALUE); + } + + RequestWalletAddress => { + var ownerAddress: Cell
? = msg.includeOwnerAddress + ? msg.ownerAddress.toCell() + : null; + + var walletAddress: address? = null; + if (msg.ownerAddress.getWorkchain() == MY_WORKCHAIN) { + val storage = lazy MinterStorage.load(); + walletAddress = calcAddressOfJettonWallet(msg.ownerAddress, contract.getAddress(), storage.jettonWalletCode); + } + + val respondMsg = createMessage({ + bounce: BounceMode.NoBounce, + dest: in.senderAddress, + value: 0, + body: ResponseWalletAddress { + queryId: msg.queryId, + jettonWalletAddress: walletAddress, + ownerAddress: ownerAddress, + } + }); + respondMsg.send(SEND_MODE_CARRY_ALL_REMAINING_MESSAGE_VALUE | SEND_MODE_BOUNCE_ON_ACTION_FAIL); + } + + MintNewJettons => { + var storage = lazy MinterStorage.load(); + assertSenderIsAdmin(in.senderAddress, storage.adminAddress); + assert (msg.mintRecipient.getWorkchain() == MY_WORKCHAIN) throw ERROR_WRONG_WORKCHAIN; + + val internalTransferMsg = lazy msg.internalTransferMsg.load({ + throwIfOpcodeDoesNotMatch: ERROR_INVALID_OP + }); + var forwardTonAmount = internalTransferMsg.forwardTonAmount; + internalTransferMsg.forwardPayload.checkIsCorrectTLBEither(); + + // a little more than needed, it’s ok since it’s sent by the admin and excesses will return back + checkAmountIsEnoughToTransfer(msg.tonAmount, forwardTonAmount, in.originalForwardFee); + + storage.totalSupply += internalTransferMsg.jettonAmount; + storage.save(); + + reserveToncoinsOnBalance(ton("0.01"), RESERVE_MODE_EXACT_AMOUNT); // reserve for storage fees + + val deployMsg = createMessage({ + bounce: BounceMode.Only256BitsOfBody, + dest: calcDeployedJettonWallet(msg.mintRecipient, contract.getAddress(), storage.jettonWalletCode), + value: msg.tonAmount, + body: msg.internalTransferMsg, + }); + deployMsg.send(SEND_MODE_PAY_FEES_SEPARATELY | SEND_MODE_BOUNCE_ON_ACTION_FAIL); + } + + ChangeMinterAdmin => { + var storage = lazy MinterStorage.load(); + assertSenderIsAdmin(in.senderAddress, storage.adminAddress); + storage.nextAdminAddress = msg.newAdminAddress; + storage.save(); + } + + ClaimMinterAdmin => { + var storage = lazy MinterStorage.load(); + assertSenderIsAdmin(in.senderAddress, storage.nextAdminAddress); + storage.adminAddress = storage.nextAdminAddress; + storage.nextAdminAddress = null; + storage.save(); + } + + DropMinterAdmin => { + var storage = lazy MinterStorage.load(); + assertSenderIsAdmin(in.senderAddress, storage.adminAddress); + storage.adminAddress = null; + storage.nextAdminAddress = null; + storage.save(); + } + + ChangeMinterMetadataUri => { + var storage = lazy MinterStorage.load(); + assertSenderIsAdmin(in.senderAddress, storage.adminAddress); + // convert "inlined snake string" to a normal (ref) string, bypassing the type system + storage.metadataUri = msg.newMetadataUri.toCell() as unknown as string; + storage.save(); + } + + UpgradeMinterCode => { + var storage = lazy MinterStorage.load(); + assertSenderIsAdmin(in.senderAddress, storage.adminAddress); + contract.setData(msg.newData); + contract.setCodePostponed(msg.newCode); + } + + TopUpTons => { + // just accept tons + } + + else => throw 0xFFFF + } +} + + + +struct JettonDataReply { + totalSupply: int + mintable: bool + adminAddress: address? + jettonContent: Cell + jettonWalletCode: cell +} + +struct (0x00) OnchainMetadataReply { + contentDict: map +} + +get fun get_jetton_data(): JettonDataReply { + val storage = lazy MinterStorage.load(); + var metadata: OnchainMetadataReply = { + contentDict: [] + }; + metadata.contentDict.set("uri".sha256(), storage.metadataUri.prefixWith00()); + metadata.contentDict.set("decimals".sha256(), "9".prefixWith00()); + + return { + totalSupply: storage.totalSupply, + mintable: true, + adminAddress: storage.adminAddress, + jettonContent: metadata.toCell(), + jettonWalletCode: storage.jettonWalletCode, + } +} + +get fun get_wallet_address(ownerAddress: address): address { + val storage = lazy MinterStorage.load(); + return calcAddressOfJettonWallet(ownerAddress, contract.getAddress(), storage.jettonWalletCode); +} + +get fun get_next_admin_address(): address? { + val storage = lazy MinterStorage.load(); + return storage.nextAdminAddress; +} diff --git a/contracts/contracts/ccip/cct/JettonWallet.tolk b/contracts/contracts/ccip/cct/JettonWallet.tolk new file mode 100644 index 000000000..f4b738cec --- /dev/null +++ b/contracts/contracts/ccip/cct/JettonWallet.tolk @@ -0,0 +1,160 @@ +import "@stdlib/gas-payments" +import "../../lib/jetton/errors" +import "../../lib/jetton/jetton-utils" +import "../../lib/jetton/storage" +import "../../lib/jetton/messages" +import "fees-management" + +contract JettonWallet { + author: "The Tolk Team" + incomingMessages: AllowedMessageToWallet + storage: WalletStorage +} + +type AllowedMessageToWallet = + | AskToTransfer + | AskToBurn + | InternalTransferStep + | TopUpTons + +type BounceOpToHandle = InternalTransferStep | BurnNotificationForMinter + +fun onBouncedMessage(in: InMessageBounced) { + in.bouncedBody.skipBouncedPrefix(); + + val msg = lazy BounceOpToHandle.fromSlice(in.bouncedBody); + val restoreAmount = match (msg) { + InternalTransferStep => msg.jettonAmount, // safe to fetch jettonAmount, because + BurnNotificationForMinter => msg.jettonAmount, // it's in the beginning of a message + }; + + var storage = lazy WalletStorage.load(); + storage.jettonBalance += restoreAmount; + storage.save(); +} + +fun onInternalMessage(in: InMessage) { + val msg = lazy AllowedMessageToWallet.fromSlice(in.body); + + match (msg) { + InternalTransferStep => { + var storage = lazy WalletStorage.load(); + if (in.senderAddress != storage.minterAddress) { + assert (in.senderAddress == calcAddressOfJettonWallet(msg.transferInitiator!, storage.minterAddress, contract.getCode())) throw ERROR_NOT_VALID_WALLET; + } + storage.jettonBalance += msg.jettonAmount; + storage.save(); + + if (msg.forwardTonAmount != 0) { + val notifyOwnerMsg = createMessage({ + bounce: BounceMode.NoBounce, + dest: storage.ownerAddress, + value: msg.forwardTonAmount, + body: TransferNotificationForRecipient { + queryId: msg.queryId, + jettonAmount: msg.jettonAmount, + transferInitiator: msg.transferInitiator, + forwardPayload: msg.forwardPayload, + } + }); + notifyOwnerMsg.send(SEND_MODE_PAY_FEES_SEPARATELY | SEND_MODE_BOUNCE_ON_ACTION_FAIL); + } + + if (msg.sendExcessesTo != null) { + var toLeaveOnBalance = contract.getOriginalBalance() - in.valueCoins + contract.getStorageDuePayment(); + reserveToncoinsOnBalance(max(toLeaveOnBalance, calculateJettonWalletMinStorageFee()), RESERVE_MODE_AT_MOST); + + val excessesMsg = createMessage({ + bounce: BounceMode.NoBounce, + dest: msg.sendExcessesTo, + value: 0, + body: ReturnExcessesBack { + queryId: msg.queryId + } + }); + excessesMsg.send(SEND_MODE_CARRY_ALL_BALANCE | SEND_MODE_IGNORE_ERRORS); + } + } + + AskToTransfer => { + msg.forwardPayload.checkIsCorrectTLBEither(); + assert (msg.transferRecipient.getWorkchain() == MY_WORKCHAIN) throw ERROR_WRONG_WORKCHAIN; + checkAmountIsEnoughToTransfer(in.valueCoins, msg.forwardTonAmount, in.originalForwardFee); + + var storage = lazy WalletStorage.load(); + assert (in.senderAddress == storage.ownerAddress) throw ERROR_NOT_OWNER; + assert (storage.jettonBalance >= msg.jettonAmount) throw ERROR_BALANCE_ERROR; + storage.jettonBalance -= msg.jettonAmount; + storage.save(); + + val deployMsg = createMessage({ + bounce: BounceMode.Only256BitsOfBody, + dest: calcDeployedJettonWallet(msg.transferRecipient, storage.minterAddress, contract.getCode()), + value: 0, + body: InternalTransferStep { + queryId: msg.queryId, + jettonAmount: msg.jettonAmount, + transferInitiator: storage.ownerAddress, + sendExcessesTo: msg.sendExcessesTo, + forwardTonAmount: msg.forwardTonAmount, + forwardPayload: msg.forwardPayload, + } + }); + deployMsg.send(SEND_MODE_CARRY_ALL_REMAINING_MESSAGE_VALUE | SEND_MODE_BOUNCE_ON_ACTION_FAIL); + } + + AskToBurn => { + checkAmountIsEnoughToBurn(in.valueCoins); + + var storage = lazy WalletStorage.load(); + assert (in.senderAddress == storage.ownerAddress) throw ERROR_NOT_OWNER; + assert (storage.jettonBalance >= msg.jettonAmount) throw ERROR_BALANCE_ERROR; + storage.jettonBalance -= msg.jettonAmount; + storage.save(); + + val notifyMinterMsg = createMessage({ + bounce: BounceMode.Only256BitsOfBody, + dest: storage.minterAddress, + value: 0, + body: BurnNotificationForMinter { + queryId: msg.queryId, + jettonAmount: msg.jettonAmount, + burnInitiator: storage.ownerAddress, + sendExcessesTo: msg.sendExcessesTo, + } + }); + notifyMinterMsg.send(SEND_MODE_CARRY_ALL_REMAINING_MESSAGE_VALUE | SEND_MODE_BOUNCE_ON_ACTION_FAIL); + } + + TopUpTons => { + // just accept tons + } + + else => throw 0xFFFF + } +} + + + +struct JettonWalletDataReply { + jettonBalance: coins + ownerAddress: address + minterAddress: address + jettonWalletCode: cell +} + +get fun get_wallet_data(): JettonWalletDataReply { + var storage = lazy WalletStorage.load(); + + return { + jettonBalance: storage.jettonBalance, + ownerAddress: storage.ownerAddress, + minterAddress: storage.minterAddress, + jettonWalletCode: contract.getCode(), + } +} + +get fun get_status(): int { + var storage = lazy WalletStorage.load(); + return storage.status; +} diff --git a/contracts/contracts/ccip/cct/fees-management.tolk b/contracts/contracts/ccip/cct/fees-management.tolk new file mode 100644 index 000000000..bc0609003 --- /dev/null +++ b/contracts/contracts/ccip/cct/fees-management.tolk @@ -0,0 +1,71 @@ +import "@stdlib/gas-payments" +import "../../lib/jetton/errors" + +// we're working in basechain, but theoretically, a jetton might even work in masterchain +const MY_WORKCHAIN = BASECHAIN + +fun getPrecompiledGasConsumption(): int? + asm "GETPRECOMPILEDGAS" + +// Storage costs +// these constants are used to estimate storage fee (how much we should pay for storing a wallet contract) + +const STORAGE_SIZE_MaxWallet_bits = 1033 +const STORAGE_SIZE_MaxWallet_cells = 3 +const STORAGE_SIZE_InitStateWallet_bits = 931 +const STORAGE_SIZE_InitStateWallet_cells = 3 + +const MESSAGE_SIZE_BurnNotification_bits = 754 // body = 32+64+124+(3+8+256)+(3+8+256) +const MESSAGE_SIZE_BurnNotification_cells = 1 // body always in ref + +const MIN_STORAGE_DURATION = 5 * 365 * 24 * 3600 // 5 years + + +// Gas costs +// these constants are used to estimate gas fee (how much we should remain on balance for a swap to succeed); +// they must be absolutely equal to consumed gas; if not, tests fail; +// actual consumed gas (desired value of these constants) are printed to console after tests run + +const GAS_CONSUMPTION_JettonTransfer = 6153 +const GAS_CONSUMPTION_JettonReceive = 7253 +const GAS_CONSUMPTION_BurnRequest = 4368 +const GAS_CONSUMPTION_BurnNotification = 3855 + + +fun calculateJettonWalletMinStorageFee() { + return calculateStorageFee(MY_WORKCHAIN, MIN_STORAGE_DURATION, STORAGE_SIZE_MaxWallet_bits, STORAGE_SIZE_MaxWallet_cells); +} + +fun forwardInitStateOverhead() { + return calculateForwardFeeWithoutLumpPrice(MY_WORKCHAIN, STORAGE_SIZE_InitStateWallet_bits, STORAGE_SIZE_InitStateWallet_cells); +} + +fun checkAmountIsEnoughToTransfer(msgValue: int, forwardTonAmount: int, fwdFee: int) { + var fwdCount = forwardTonAmount != 0 ? 2 : 1; // second sending (forward) will be cheaper that first + + var jettonWalletGasConsumption = getPrecompiledGasConsumption(); + var sendTransferGasConsumption = (jettonWalletGasConsumption == null) ? GAS_CONSUMPTION_JettonTransfer : jettonWalletGasConsumption; + var receiveTransferGasConsumption = (jettonWalletGasConsumption == null) ? GAS_CONSUMPTION_JettonReceive : jettonWalletGasConsumption; + + assert (msgValue > + forwardTonAmount + + // 3 messages: wal1->wal2, wal2->owner, wal2->response + // but last one is optional (it is ok if it fails) + fwdCount * fwdFee + + forwardInitStateOverhead() + // additional fwd fees related to initstate in iternal_transfer + calculateGasFee(MY_WORKCHAIN, sendTransferGasConsumption) + + calculateGasFee(MY_WORKCHAIN, receiveTransferGasConsumption) + + calculateJettonWalletMinStorageFee() + ) throw ERROR_NOT_ENOUGH_GAS; +} + +fun checkAmountIsEnoughToBurn(msgValue: int) { + var jettonWalletGasConsumption = getPrecompiledGasConsumption(); + var sendBurnGasConsumption = (jettonWalletGasConsumption == null) ? GAS_CONSUMPTION_BurnRequest : jettonWalletGasConsumption; + + assert (msgValue > + calculateForwardFee(MY_WORKCHAIN, MESSAGE_SIZE_BurnNotification_bits, MESSAGE_SIZE_BurnNotification_cells) + + calculateGasFee(MY_WORKCHAIN, sendBurnGasConsumption) + + calculateGasFee(MY_WORKCHAIN, GAS_CONSUMPTION_BurnNotification) + ) throw ERROR_NOT_ENOUGH_GAS; +} diff --git a/contracts/contracts/ccip/fee_quoter/types.tolk b/contracts/contracts/ccip/fee_quoter/types.tolk index 193981a77..8fd2353aa 100644 --- a/contracts/contracts/ccip/fee_quoter/types.tolk +++ b/contracts/contracts/ccip/fee_quoter/types.tolk @@ -78,8 +78,6 @@ const VAL_1E18: uint256 = 1000000000000000000; /// The fixed bytes does not cover struct data (this is represented by MESSAGE_FIXED_BYTES_PER_TOKEN) const TON_2_EVM_MESSAGE_FIXED_BYTES = 15 * 32; -const CCIP_LOCK_OR_BURN_V1_RET_BYTES = 32; - const CHAIN_FAMILY_SELECTOR_EVM: uint32 = 0x2812d52c; const CHAIN_FAMILY_SELECTOR_SVM: uint32 = 0x1e10bdc4; const CHAIN_FAMILY_SELECTOR_TVM: uint32 = 0x647e2ba9; diff --git a/contracts/contracts/ccip/pool/TODO.md b/contracts/contracts/ccip/pool/TODO.md new file mode 100644 index 000000000..258022be8 --- /dev/null +++ b/contracts/contracts/ccip/pool/TODO.md @@ -0,0 +1,36 @@ + +## Overview + +- Our goal is to translate token pool EVM implementation to TON/Tolk +- We will start with TokenPool.sol lib and the lock release pool +- The reimplementation in TON/Tolk should be as close as possible to EVM original, diviate only when required and where makes sense + - Can check translation as example: + - TVM: chainlink-ton/contracts/contracts/mcms/mcms.tolk + - EVM: ccip-owner-contracts/src/ManyChainMultiSig.sol +- We need to build same type of core token pool lib that different instances would extend and change behaviour - we used a hooks pattern for MCMS/RBACTimelock, but Tolk didn't have closures before 1.4, should have closures at 1.4: chainlink-ton/contracts/contracts/ccip/pool/TODO.md so this can be simplified in next version. +- We want to focus on resolving the async communication correctly, costs time and gas + - Need to authorise off/onramp calls via Router sync call on EVM - here we said we're going to authorise calls from executors, but how to support any + - Need to call advanced hooks, this can probably stay async + - Need to validate RMN curse, this can probably be propagated down from Router as it is with on/offramp - list of pools is going to be in pool registry, doesn't exist yet + - As we go we want to keep updating the documentation and design in llm-wiki, specifically the section on TokenPool like "### M1.4 Token Pool Core Library (IPoolV2, hardcoded defaultFinality)" in + - We might want to extract that into a separate (per-component) design page +- As we go along want to start building a basic test harness for token pools contracts (using wTON as Jetton), and add coverage as we move forward - we should use EVM available tests as inspiration to follow the spec, as we did for MCMS +- As we go along document issues, missing-components, todos, etc. with explicit enumerated comments so we can reference them as we iterate (e.g., TON-TP/16) + +## TODOs + +## Iterations progress notes + +1. Iteration 1 + - Added a first-pass generic TokenPool lib scaffold in `types.tolk`, `errors.tolk`, and `token_pool.tolk`. + - Scope is intentionally the shared core only: storage layout, EVM-parity request/response structs, decimals conversion, chain config management, fee config management, rate-limiter helpers, and MCMS-style runtime hooks for access checks and concrete token movement. + - Deliberately deferred in this pass: concrete contract entrypoints, async pending-operation state machines, lockbox integration, Jetton wallet hosting flow, Router/OnRamp/ReceiveExecutor wiring, and finality codec parity beyond the current default/single-fast-config check. + +2. Iteration 2 + - Added a first concrete non-lockbox `LockReleaseTokenPool` contract on top of the generic pool lib, plus a first sandbox harness. + - Async design choice for TVM: do not synchronously query Router or RMN from the pool. Instead, duplicate the minimum required auth/curse state locally in the pool and update it asynchronously through messages, analogous to `OffRamp_UpdateCursedSubjects`. + - Current concrete flow: + - outbound lock is triggered by `TransferNotificationForRecipient` on the pool wallet, not a synchronous pool call; + - inbound release starts from `LockReleaseTokenPool_ReleaseOrMint`, creates a pending operation keyed by `queryId`, and only resolves after `ReturnExcessesBack` from the expected recipient wallet; + - bounce handling currently covers the pool wallet transfer bounce path. + - Still deferred: executor integration, router-owned custody flow, lockbox-backed variant, richer failure taxonomy, and a generalized pending-op state machine shared across pool variants. \ No newline at end of file diff --git a/contracts/contracts/ccip/pool/burn_mint_token_pool/contract.tolk b/contracts/contracts/ccip/pool/burn_mint_token_pool/contract.tolk new file mode 100644 index 000000000..8c5620343 --- /dev/null +++ b/contracts/contracts/ccip/pool/burn_mint_token_pool/contract.tolk @@ -0,0 +1,287 @@ +// SPDX-License-Identifier: BUSL-1.1 +import "../../../lib/utils.tolk" +import "../../../lib/access/ownable_2step.tolk" +import "../../../lib/jetton/jetton_client.tolk" +import "../../../lib/jetton/messages.tolk" +import "../../../lib/jetton/jetton-utils.tolk" +import "../../rmn_remote/lib" +import "../token_pool.tolk" +import "../types" +import "../messages" +import "../events" +import "../errors" + +import "messages" +import "types" +import "errors" +import "storage" + +fun onInternalMessage(in: InMessage) { + var st = Storage.load(); + var pool = loadPool(st); + val handled = pool.onInternalMessage(in.senderAddress, in.valueCoins, in.body); + if (handled) { + st = pool.context != null ? pool.context! : st; + st.poolData = pool.data.toCell(); + st.store(); + return; + } + + val msg = lazy BurnMintTokenPool_CustomInMessage.fromSlice(in.body); + match (msg) { + BurnMintTokenPool_ClaimMinterAdmin => { + onClaimMinterAdmin(mutate st, in.senderAddress, msg); + st.store(); + } + TransferNotificationForRecipient => { + onJettonTransferNotification(mutate st, msg, in.senderAddress); + st.store(); + } + ReturnExcessesBack => { + onReturnExcessesBack(mutate st, msg, in.senderAddress); + st.store(); + } + else => { + assert(in.body.isEmpty()) throw 0xFFFF; + } + } +} + +fun onClaimMinterAdmin( + mutate st: Storage, + sender: address, + msg: BurnMintTokenPool_ClaimMinterAdmin, +) { + st.poolData.load().adminConfig.load().ownable.load().requireOwner(sender); + + createMessage({ + bounce: true, + value: BurnMintTokenPool_CLAIM_ADMIN_VALUE, + dest: st.jettonClient.load().masterAddress, + body: ClaimMinterAdmin { + queryId: msg.queryId, + }, + }).send(SEND_MODE_PAY_FEES_SEPARATELY); +} + +/// @notice Token pool used for burn and mint tokens. This uses a burn and mint mechanism. +/// @dev One token per BurnMintTokenPool. In this variant the pool contract owns the Jetton wallet and the Jetton minter admin role. +fun onJettonTransferNotification( + mutate st: Storage, + msg: TransferNotificationForRecipient, + sender: address, +) { + val jettonClient = st.jettonClient.load(); + assert(jettonClient.isWallet(sender), Error.IncorrectJettonSender); + + val payload = loadForwardPayloadAsSlice(msg.forwardPayload); + assert(payload != null, Error.MissingForwardPayload); + + val requestMsg = TokenPool_LockOrBurn.fromSlice(payload!); + val request = requestMsg.request.load(); + assert(request.amount == msg.jettonAmount, Error.AmountMismatch); + assert(msg.transferInitiator != null, Error.MissingTransferInitiator); + assert(!st.pendingBurns.get(requestMsg.queryId).isFound, Error.PendingBurnAlreadyExists); + val transferInitiator = msg.transferInitiator!; + + var pool = loadPool(st); + val prepared = pool.prepareLockOrBurn(transferInitiator, request, requestMsg.requestedFinalityConfig, requestMsg.tokenArgs); + st.poolData = pool.data.toCell(); + + st.pendingBurns.set(requestMsg.queryId, BurnMintTokenPool_PendingBurn { + replyTo: requestMsg.replyTo, + request: prepared.request.toCell(), + out: prepared.out.toCell(), + destTokenAmount: prepared.destTokenAmount, + expectedSender: jettonClient.masterAddress, + }.toCell()); + + createMessage({ + bounce: true, + value: BurnMintTokenPool_BURN_VALUE, + dest: sender, + body: AskToBurn { + queryId: requestMsg.queryId, + jettonAmount: prepared.destTokenAmount as coins, + sendExcessesTo: contract.getAddress(), + customPayload: null, + }, + }).send(SEND_MODE_PAY_FEES_SEPARATELY); +} + +fun hookHandleReleaseOrMintMessage( + ctx: Storage?, + sender: address, + msg: TokenPool_ReleaseOrMint, + prepared: TokenPool_ReleaseOrMintPrepared, +): Storage? { + assert(ctx != null, TokenPool_Error.UnsupportedOperation); + var st = ctx!; + assert(!st.pendingMints.get(msg.queryId).isFound, Error.PendingMintAlreadyExists); + val jettonClient = st.jettonClient.load(); + + val recipientWallet = calcAddressOfJettonWallet( + prepared.request.receiver, + jettonClient.masterAddress, + jettonClient.jettonWalletCode, + ); + + st.pendingMints.set(msg.queryId, BurnMintTokenPool_PendingMint { + replyTo: msg.replyTo, + request: prepared.request.toCell(), + out: prepared.out.toCell(), + expectedSender: recipientWallet, + }.toCell()); + + createMessage({ + bounce: true, + value: BurnMintTokenPool_MINT_VALUE, + dest: jettonClient.masterAddress, + body: MintNewJettons { + queryId: msg.queryId, + mintRecipient: prepared.request.receiver, + tonAmount: BurnMintTokenPool_MINT_VALUE, + internalTransferMsg: InternalTransferStep { + queryId: msg.queryId, + jettonAmount: prepared.localAmount as coins, + transferInitiator: null, + sendExcessesTo: contract.getAddress(), + forwardTonAmount: 0, + forwardPayload: beginCell().storeUint(0, 1).endCell().beginParse(), + }.toCell(), + }, + }).send(SEND_MODE_PAY_FEES_SEPARATELY); + + return st; +} + +fun onReturnExcessesBack( + mutate st: Storage, + msg: ReturnExcessesBack, + sender: address, +) { + val burnEntry = st.pendingBurns.get(msg.queryId); + if (burnEntry.isFound) { + val pending = burnEntry.loadValue().load(); + assert(sender == pending.expectedSender, Error.UnexpectedBurnConfirmationSender); + + st.pendingBurns.delete(msg.queryId); + val request = pending.request.load(); + + emit(TOKEN_POOL_LOCKED_OR_BURNED_TOPIC, TokenPool_LockedOrBurned { + remoteChainSelector: request.remoteChainSelector, + details: TokenPool_LockedOrBurnedDetails { + token: request.localToken, + sender: request.originalSender, + amount: pending.destTokenAmount, + }.toCell(), + }); + + if (pending.replyTo != null) { + createMessage({ + bounce: true, + value: BurnMintTokenPool_REPLY_VALUE, + dest: pending.replyTo!, + body: TokenPool_LockOrBurnResponse { + queryId: msg.queryId, + out: pending.out, + destTokenAmount: pending.destTokenAmount, + }, + }).send(SEND_MODE_PAY_FEES_SEPARATELY | SEND_MODE_CARRY_ALL_REMAINING_MESSAGE_VALUE); + } + return; + } + + val mintEntry = st.pendingMints.get(msg.queryId); + assert(mintEntry.isFound, Error.PendingMintNotFound); + + val pending = mintEntry.loadValue().load(); + assert(sender == pending.expectedSender, Error.UnexpectedMintConfirmationSender); + + st.pendingMints.delete(msg.queryId); + val request = pending.request.load(); + val out = pending.out.load(); + + emit(TOKEN_POOL_RELEASED_OR_MINTED_TOPIC, TokenPool_ReleasedOrMinted { + remoteChainSelector: request.remoteChainSelector, + details: TokenPool_ReleasedOrMintedDetails { + token: request.localToken, + amount: out.destinationAmount, + participants: TokenPool_ReleasedOrMintedParticipants { + sender: contract.getAddress(), + recipient: request.receiver, + }.toCell(), + }.toCell(), + }); + + if (pending.replyTo != null) { + createMessage({ + bounce: true, + value: BurnMintTokenPool_REPLY_VALUE, + dest: pending.replyTo!, + body: TokenPool_ReleaseOrMintResponse { + queryId: msg.queryId, + out: pending.out, + }, + }).send(SEND_MODE_PAY_FEES_SEPARATELY | SEND_MODE_CARRY_ALL_REMAINING_MESSAGE_VALUE); + } +} + +fun loadPool(st: Storage): TokenPool { + return TokenPool { + data: st.poolData.load(), + context: st, + hooks: TokenPool_Hooks { + ensureOutboundAccess: null, + ensureInboundAccess: null, + ensureNotCursed: null, + preflightCheck: null, + postflightCheck: null, + applyLockOrBurn: null, + applyReleaseOrMint: null, + handleReleaseOrMintMessage: hookHandleReleaseOrMintMessage, + }, + }; +} + +get fun typeAndVersion(): (slice, slice) { + return (BurnMintTokenPool_CONTRACT_NAME, BurnMintTokenPool_CONTRACT_VERSION); +} + +get fun token(): address { + return Storage.load().poolData.load().token; +} + +get fun tokenDecimals(): uint8 { + return Storage.load().poolData.load().tokenDecimals; +} + +get fun isSupportedChain(remoteChainSelector: uint64): bool { + return Storage.load().poolData.load().remoteChainConfigs.get(remoteChainSelector).isFound; +} + +get fun onRamp(remoteChainSelector: uint64): address? { + val entry = Storage.load().poolData.load().mirroredPolicy.load().onRamps.get(remoteChainSelector); + return entry.isFound ? entry.loadValue() : null; +} + +get fun offRamp(remoteChainSelector: uint64): address? { + val entry = Storage.load().poolData.load().mirroredPolicy.load().offRamps.get(remoteChainSelector); + return entry.isFound ? entry.loadValue() : null; +} + +get fun hasPendingBurn(queryId: uint64): bool { + return Storage.load().pendingBurns.get(queryId).isFound; +} + +get fun hasPendingMint(queryId: uint64): bool { + return Storage.load().pendingMints.get(queryId).isFound; +} + +get fun verifyNotCursed(subject: uint128): bool { + return !Storage.load().poolData.load().mirroredPolicy.load().cursedSubjects.isCursed(subject); +} + +get fun owner(): address { + return Storage.load().poolData.load().adminConfig.load().ownable.load().owner; +} diff --git a/contracts/contracts/ccip/pool/burn_mint_token_pool/errors.tolk b/contracts/contracts/ccip/pool/burn_mint_token_pool/errors.tolk new file mode 100644 index 000000000..bf72b0e44 --- /dev/null +++ b/contracts/contracts/ccip/pool/burn_mint_token_pool/errors.tolk @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: BUSL-1.1 + +const BurnMintTokenPool_FACILITY_NAME = "link.chain.ton.ccip.BurnMintTokenPool"; +const BurnMintTokenPool_FACILITY_ID = 412; // (crc32() % 640) + 10 + +enum Error { + IncorrectJettonSender = BurnMintTokenPool_FACILITY_ID * 100 + MissingTransferInitiator + MissingForwardPayload + AmountMismatch + PendingBurnAlreadyExists + PendingBurnNotFound + PendingMintAlreadyExists + PendingMintNotFound + UnexpectedBurnConfirmationSender + UnexpectedMintConfirmationSender +} \ No newline at end of file diff --git a/contracts/contracts/ccip/pool/burn_mint_token_pool/messages.tolk b/contracts/contracts/ccip/pool/burn_mint_token_pool/messages.tolk new file mode 100644 index 000000000..82c179be9 --- /dev/null +++ b/contracts/contracts/ccip/pool/burn_mint_token_pool/messages.tolk @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: BUSL-1.1 +import "../../../lib/jetton/messages.tolk" +import "../messages" + +struct (0x93c174a1) BurnMintTokenPool_ClaimMinterAdmin { + queryId: uint64; +} + +type BurnMintTokenPool_CustomInMessage = + | BurnMintTokenPool_ClaimMinterAdmin + | TransferNotificationForRecipient + | ReturnExcessesBack; diff --git a/contracts/contracts/ccip/pool/burn_mint_token_pool/storage.tolk b/contracts/contracts/ccip/pool/burn_mint_token_pool/storage.tolk new file mode 100644 index 000000000..50003bb3e --- /dev/null +++ b/contracts/contracts/ccip/pool/burn_mint_token_pool/storage.tolk @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: BUSL-1.1 +import "../../../lib/jetton/jetton_client.tolk" +import "../../../lib/access/ownable_2step.tolk" +import "../../rmn_remote/lib" +import "../token_pool.tolk" +import "../types" + +import "types" + +struct Storage { + poolData: Cell; + jettonClient: Cell; + pendingBurns: map>; + pendingMints: map>; +} + +fun Storage.load(): Storage { + return Storage.fromCell(contract.getData()); +} + +fun Storage.store(self) { + contract.setData(self.toCell()); +} + +fun BurnMintTokenPool_initialStorage(config: BurnMintTokenPool_Config): Storage { + return Storage { + poolData: TokenPool_Data { + adminConfig: TokenPool_AdminConfig { + ownable: Ownable2Step { + owner: config.owner, + pendingOwner: null, + }.toCell(), + rmnProxy: config.rmnProxy, + dynamicConfig: TokenPool_DynamicConfig { + router: config.router, + rateLimitAdmin: null, + feeAdmin: null, + }.toCell(), + allowedFinalityConfig: TOKEN_POOL_DEFAULT_FINALITY, + }.toCell(), + mirroredPolicy: TokenPool_MirroredPolicy { + onRamps: createEmptyMap(), + offRamps: createEmptyMap(), + cursedSubjects: CursedSubjects { + data: createEmptyMap(), + }, + }.toCell(), + token: config.token, + tokenDecimals: config.tokenDecimals, + remoteChainConfigs: createEmptyMap(), + tokenTransferFeeConfigs: createEmptyMap(), + }.toCell(), + jettonClient: config.jettonClient.toCell(), + pendingBurns: createEmptyMap(), + pendingMints: createEmptyMap(), + }; +} \ No newline at end of file diff --git a/contracts/contracts/ccip/pool/burn_mint_token_pool/types.tolk b/contracts/contracts/ccip/pool/burn_mint_token_pool/types.tolk new file mode 100644 index 000000000..25771ecae --- /dev/null +++ b/contracts/contracts/ccip/pool/burn_mint_token_pool/types.tolk @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: BUSL-1.1 +import "../../../lib/jetton/jetton_client.tolk" +import "../../rmn_remote/lib" +import "../types" + +const BurnMintTokenPool_CONTRACT_NAME = "BurnMintTokenPool".literalSlice(); +const BurnMintTokenPool_CONTRACT_VERSION = "0.1.0".literalSlice(); +const BurnMintTokenPool_CLAIM_ADMIN_VALUE = ton("0.05"); +const BurnMintTokenPool_BURN_VALUE = ton("0.05"); +const BurnMintTokenPool_MINT_VALUE = ton("0.1"); +const BurnMintTokenPool_REPLY_VALUE = ton("0.01"); + +struct BurnMintTokenPool_PendingBurn { + replyTo: address? = null; + request: Cell; + out: Cell; + destTokenAmount: uint256; + expectedSender: address; +} + +struct BurnMintTokenPool_PendingMint { + replyTo: address? = null; + request: Cell; + out: Cell; + expectedSender: address; +} + +struct BurnMintTokenPool_Config { + owner: address; + token: address; + tokenDecimals: uint8; + rmnProxy: address; + router: address; + jettonClient: JettonClient; +} diff --git a/contracts/contracts/ccip/pool/errors.tolk b/contracts/contracts/ccip/pool/errors.tolk new file mode 100644 index 000000000..86038d7e7 --- /dev/null +++ b/contracts/contracts/ccip/pool/errors.tolk @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: BUSL-1.1 +import "../../lib/utils" + +const TokenPool_FACILITY_NAME = "link.chain.ton.ccip.TokenPool"; +const TokenPool_FACILITY_ID = 149; // (crc32() % 640) + 10 + +enum TokenPool_Error { + InvalidTransferFeeBps = TokenPool_FACILITY_ID * 100 // (uint256 bps); + InvalidTokenTransferFeeConfig // (uint64 destChainSelector); + CallerIsNotARampOnRouter // (address caller); + ZeroAddressInvalid // (); + NonExistentChain // (uint64 remoteChainSelector); + ChainNotAllowed // (uint64 remoteChainSelector); + CursedByRMN // (); + ChainAlreadyExists // (uint64 chainSelector); + InvalidSourcePoolAddress // (bytes sourcePoolAddress); + InvalidToken // (address token); + Unauthorized // (address caller); + PoolAlreadyAdded // (uint64 remoteChainSelector, bytes remotePoolAddress); + InvalidRemotePoolForChain // (uint64 remoteChainSelector, bytes remotePoolAddress); + InvalidRemoteChainDecimals // (bytes sourcePoolData); + OverflowDetected // (uint8 remoteDecimals, uint8 localDecimals, uint256 remoteAmount); + InvalidDecimalArgs // (uint8 expected, uint8 actual); + CallerIsNotOwnerOrFeeAdmin // (address caller); + UnsupportedOperation // (); + + // TODO: extra + InvalidRequestedFinality + RateLimitExceeded +} + +@inline +fun TokenPool_errorCode(local: uint16): uint16 { + return getErrorCode(stringCrc32("link.chain.ton.ccip.TokenPool"), local); +} diff --git a/contracts/contracts/ccip/pool/events.tolk b/contracts/contracts/ccip/pool/events.tolk new file mode 100644 index 000000000..8bc8d656e --- /dev/null +++ b/contracts/contracts/ccip/pool/events.tolk @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: BUSL-1.1 +import "../common/types" + +const TOKEN_POOL_LOCKED_OR_BURNED_TOPIC = stringCrc32("TokenPool_LockedOrBurned"); +const TOKEN_POOL_RELEASED_OR_MINTED_TOPIC = stringCrc32("TokenPool_ReleasedOrMinted"); +const TOKEN_POOL_CHAIN_ADDED_TOPIC = stringCrc32("TokenPool_ChainAdded"); +const TOKEN_POOL_CHAIN_REMOVED_TOPIC = stringCrc32("TokenPool_ChainRemoved"); +const TOKEN_POOL_REMOTE_POOL_ADDED_TOPIC = stringCrc32("TokenPool_RemotePoolAdded"); +const TOKEN_POOL_REMOTE_POOL_REMOVED_TOPIC = stringCrc32("TokenPool_RemotePoolRemoved"); +const TOKEN_POOL_DYNAMIC_CONFIG_SET_TOPIC = stringCrc32("TokenPool_DynamicConfigSet"); +const TOKEN_POOL_RAMP_ACCESS_UPDATED_TOPIC = stringCrc32("TokenPool_RampAccessUpdated"); +const TOKEN_POOL_CURSED_SUBJECTS_UPDATED_TOPIC = stringCrc32("TokenPool_CursedSubjectsUpdated"); +const TOKEN_POOL_FINALITY_CONFIG_SET_TOPIC = stringCrc32("TokenPool_FinalityConfigSet"); + +struct TokenPool_LockedOrBurnedDetails { + token: address; + sender: address; + amount: uint256; +} + +// event LockedOrBurned(uint64 indexed remoteChainSelector, address token, address sender, uint256 amount); +// event ReleasedOrMinted( +// uint64 indexed remoteChainSelector, address token, address sender, address recipient, uint256 amount +// ); +struct TokenPool_LockedOrBurned { + remoteChainSelector: uint64; + details: Cell; +} + +struct TokenPool_ReleasedOrMintedParticipants { + sender: address; + recipient: address; +} + +struct TokenPool_ReleasedOrMintedDetails { + token: address; + amount: uint256; + participants: Cell; +} + +struct TokenPool_ReleasedOrMinted { + remoteChainSelector: uint64; + details: Cell; +} + +struct TokenPool_ChainAdded { + remoteChainSelector: uint64; + remoteTokenAddress: Cell; + // outboundRateLimiterConfig: RateLimiter.Config; + // inboundRateLimiterConfig: RateLimiter.Config; +} + +struct TokenPool_ChainRemoved { + remoteChainSelector: uint64; +} + +// TODO: make reply message +struct TokenPool_RemotePoolAdded { + remoteChainSelector: uint64; + remotePoolAddress: Cell; +} + +// TODO: make reply message +struct TokenPool_RemotePoolRemoved { + remoteChainSelector: uint64; + remotePoolAddress: Cell; +} + +// event DynamicConfigSet(address router, address rateLimitAdmin, address feeAdmin); +struct TokenPool_DynamicConfigSet { + router: address; + rateLimitAdmin: address?; + feeAdmin: address?; +} + +// TODO: make used +struct TokenPool_OutboundRateLimitConsumed { + remoteChainSelector: uint64; + token: address; + amount: uint256; +} + +// TODO: make used +struct TokenPool_InboundRateLimitConsumed { + remoteChainSelector: uint64; + token: address; + amount: uint256; +} + +// TODO: make used +struct TokenPool_TokenTransferFeeConfigUpdated { + remoteChainSelector: uint64; + tokenTransferFeeConfig: Cell; +} + +// TODO: make used +struct TokenPool_TokenTransferFeeConfigDeleted { + remoteChainSelector: uint64; +} + +// event FinalityConfigSet(bytes4 allowedFinality); +struct TokenPool_FinalityConfigSet { + allowedFinalityConfig: uint32; +} + +// event FastFinalityOutboundRateLimitConsumed(uint64 indexed remoteChainSelector, address token, uint256 amount); +// event FastFinalityInboundRateLimitConsumed(uint64 indexed remoteChainSelector, address token, uint256 amount); +// event RateLimitConfigured( +// uint64 indexed remoteChainSelector, +// bool fastFinality, +// RateLimiter.Config outboundRateLimiterConfig, +// RateLimiter.Config inboundRateLimiterConfig +// ); +// event AdvancedPoolHooksUpdated(IAdvancedPoolHooks oldHook, IAdvancedPoolHooks newHook); + +struct TokenPool_RampAccessUpdated { + remoteChainSelector: uint64; + onRamp: address? = null; + offRamp: address? = null; +} + +struct TokenPool_CursedSubjectsUpdated {} diff --git a/contracts/contracts/ccip/pool/lock_release_token_pool/contract.tolk b/contracts/contracts/ccip/pool/lock_release_token_pool/contract.tolk new file mode 100644 index 000000000..dfb1b7b6d --- /dev/null +++ b/contracts/contracts/ccip/pool/lock_release_token_pool/contract.tolk @@ -0,0 +1,266 @@ +// SPDX-License-Identifier: BUSL-1.1 +import "../../../lib/utils.tolk" +import "../../../lib/access/ownable_2step.tolk" +import "../../../lib/jetton/messages.tolk" +import "../../../lib/jetton/jetton-utils.tolk" +import "../../../lib/jetton/jetton_client.tolk" +import "../../rmn_remote/lib" +import "../token_pool.tolk" +import "../types" +import "../messages" +import "../events" +import "../errors" + +import "messages" +import "types" +import "errors" +import "storage" + +fun onInternalMessage(in: InMessage) { + var st = Storage.load(); + var pool = loadPool(st); + val handled = pool.onInternalMessage(in.senderAddress, in.valueCoins, in.body); + if (handled) { + st = pool.context != null ? pool.context! : st; + st.poolData = pool.data.toCell(); + st.store(); + return; + } + + val msg = lazy LockReleaseTokenPool_CustomInMessage.fromSlice(in.body); + match (msg) { + TransferNotificationForRecipient => { + onJettonTransferNotification(mutate st, msg, in.senderAddress); + st.store(); + } + ReturnExcessesBack => { + onReturnExcessesBack(mutate st, msg, in.senderAddress); + st.store(); + } + else => { + assert(in.body.isEmpty()) throw 0xFFFF; + } + } +} + +fun onBouncedMessage(in: InMessageBounced) { + val msg = lazy LockReleaseTokenPool_BouncedMessage.fromSlice(in.bouncedBody.skipBouncedPrefix()); + match (msg) { + AskToTransfer => { + var st = Storage.load(); + onReleaseTransferBounced(mutate st, msg, in.senderAddress); + st.store(); + } + } +} + +/// @notice Token pool used for tokens on their native chain. This uses a lock and release mechanism. +/// @dev One token per LockReleaseTokenPool. In this non-lockbox variant the pool contract's Jetton wallet holds custody directly. +fun onJettonTransferNotification( + mutate st: Storage, + msg: TransferNotificationForRecipient, + sender: address, +) { + val jettonClient = st.jettonClient.load(); + assert(jettonClient.isWallet(sender), Error.IncorrectJettonSender); + + val payload = loadForwardPayloadAsSlice(msg.forwardPayload); + assert(payload != null, Error.MissingForwardPayload); + + val requestMsg = TokenPool_LockOrBurn.fromSlice(payload!); + var request = requestMsg.request.load(); + assert(request.amount == msg.jettonAmount, Error.AmountMismatch); + assert(msg.transferInitiator != null, Error.MissingTransferInitiator); + val transferInitiator = msg.transferInitiator!; + + var pool = loadPool(st); + val prepared = pool.prepareLockOrBurn(transferInitiator, request, requestMsg.requestedFinalityConfig, requestMsg.tokenArgs); + st.poolData = pool.data.toCell(); + + emit(TOKEN_POOL_LOCKED_OR_BURNED_TOPIC, TokenPool_LockedOrBurned { + remoteChainSelector: request.remoteChainSelector, + details: TokenPool_LockedOrBurnedDetails { + token: request.localToken, + sender: transferInitiator, + amount: prepared.destTokenAmount, + }.toCell(), + }); + + if (requestMsg.replyTo != null) { + createMessage({ + bounce: true, + value: LockReleaseTokenPool_REPLY_VALUE, + dest: requestMsg.replyTo!, + body: TokenPool_LockOrBurnResponse { + queryId: requestMsg.queryId, + out: prepared.out.toCell(), + destTokenAmount: prepared.destTokenAmount, + }, + }).send(SEND_MODE_PAY_FEES_SEPARATELY | SEND_MODE_CARRY_ALL_REMAINING_MESSAGE_VALUE); + } +} + +fun hookHandleReleaseOrMintMessage( + ctx: Storage?, + sender: address, + msg: TokenPool_ReleaseOrMint, + prepared: TokenPool_ReleaseOrMintPrepared, +): Storage? { + assert(ctx != null, TokenPool_Error.UnsupportedOperation); + var st = ctx!; + assert(!st.pendingReleases.get(msg.queryId).isFound, Error.PendingReleaseAlreadyExists); + val jettonClient = st.jettonClient.load(); + + val recipientWallet = calcAddressOfJettonWallet( + prepared.request.receiver, + jettonClient.masterAddress, + jettonClient.jettonWalletCode, + ); + + st.pendingReleases.set(msg.queryId, LockReleaseTokenPool_PendingRelease { + replyTo: msg.replyTo, + request: prepared.request.toCell(), + out: prepared.out.toCell(), + expectedSender: recipientWallet, + }.toCell()); + + jettonClient.sendSimple( + JettonMessageOptions { + bounce: true, + value: LockReleaseTokenPool_RELEASE_TRANSFER_VALUE, + }, + SEND_MODE_PAY_FEES_SEPARATELY, + msg.queryId, + prepared.localAmount as coins, + prepared.request.receiver, + contract.getAddress(), + ); + + return st; +} + +fun onReturnExcessesBack( + mutate st: Storage, + msg: ReturnExcessesBack, + sender: address, +) { + val pendingEntry = st.pendingReleases.get(msg.queryId); + assert(pendingEntry.isFound, Error.PendingReleaseNotFound); + + val pending = pendingEntry.loadValue().load(); + assert(sender == pending.expectedSender, Error.UnexpectedReleaseConfirmationSender); + + st.pendingReleases.delete(msg.queryId); + val request = pending.request.load(); + val out = pending.out.load(); + + emit(TOKEN_POOL_RELEASED_OR_MINTED_TOPIC, TokenPool_ReleasedOrMinted { + remoteChainSelector: request.remoteChainSelector, + details: TokenPool_ReleasedOrMintedDetails { + token: request.localToken, + amount: out.destinationAmount, + participants: TokenPool_ReleasedOrMintedParticipants { + sender: contract.getAddress(), + recipient: request.receiver, + }.toCell(), + }.toCell(), + }); + + if (pending.replyTo != null) { + createMessage({ + bounce: true, + value: LockReleaseTokenPool_REPLY_VALUE, + dest: pending.replyTo!, + body: TokenPool_ReleaseOrMintResponse { + queryId: msg.queryId, + out: pending.out, + }, + }).send(SEND_MODE_PAY_FEES_SEPARATELY | SEND_MODE_CARRY_ALL_REMAINING_MESSAGE_VALUE); + } +} + +fun onReleaseTransferBounced( + mutate st: Storage, + msg: AskToTransfer, + sender: address, +) { + val jettonClient = st.jettonClient.load(); + assert(jettonClient.isWallet(sender), Error.UnexpectedReleaseBounce); + + val pendingEntry = st.pendingReleases.get(msg.queryId); + assert(pendingEntry.isFound, Error.PendingReleaseNotFound); + + val pending = pendingEntry.loadValue().load(); + st.pendingReleases.delete(msg.queryId); + + if (pending.replyTo != null) { + createMessage({ + bounce: true, + value: LockReleaseTokenPool_REPLY_VALUE, + dest: pending.replyTo!, + body: TokenPool_ReleaseOrMintFailure { + queryId: msg.queryId, + errorCode: Error.UnexpectedReleaseBounce as uint16, + }, + }).send(SEND_MODE_PAY_FEES_SEPARATELY | SEND_MODE_CARRY_ALL_REMAINING_MESSAGE_VALUE); + } +} + +fun loadPool(st: Storage): TokenPool { + return TokenPool { + data: st.poolData.load(), + context: st, + hooks: TokenPool_Hooks { + ensureOutboundAccess: null, + ensureInboundAccess: null, + ensureNotCursed: null, + preflightCheck: null, + postflightCheck: null, + applyLockOrBurn: null, + applyReleaseOrMint: null, + handleReleaseOrMintMessage: hookHandleReleaseOrMintMessage, + }, + }; +} + +get fun typeAndVersion(): (slice, slice) { + return (LockReleaseTokenPool_CONTRACT_NAME, LockReleaseTokenPool_CONTRACT_VERSION); +} + +get fun token(): address { + return Storage.load().poolData.load().token; +} + +get fun tokenDecimals(): uint8 { + return Storage.load().poolData.load().tokenDecimals; +} + +get fun isSupportedChain(remoteChainSelector: uint64): bool { + return Storage.load().poolData.load().remoteChainConfigs.get(remoteChainSelector).isFound; +} + +get fun onRamp(remoteChainSelector: uint64): address? { + val entry = Storage.load().poolData.load().mirroredPolicy.load().onRamps.get(remoteChainSelector); + return entry.isFound ? entry.loadValue() : null; +} + +get fun offRamp(remoteChainSelector: uint64): address? { + val entry = Storage.load().poolData.load().mirroredPolicy.load().offRamps.get(remoteChainSelector); + return entry.isFound ? entry.loadValue() : null; +} + +get fun hasPendingRelease(queryId: uint64): bool { + return Storage.load().pendingReleases.get(queryId).isFound; +} + +get fun verifyNotCursed(subject: uint128): bool { + return !Storage.load().poolData.load().mirroredPolicy.load().cursedSubjects.isCursed(subject); +} + +get fun owner(): address { + return Storage.load().poolData.load().adminConfig.load().ownable.load().get_owner(); +} + +get fun pendingOwner(): address? { + return Storage.load().poolData.load().adminConfig.load().ownable.load().get_pendingOwner(); +} \ No newline at end of file diff --git a/contracts/contracts/ccip/pool/lock_release_token_pool/errors.tolk b/contracts/contracts/ccip/pool/lock_release_token_pool/errors.tolk new file mode 100644 index 000000000..200f3e3d2 --- /dev/null +++ b/contracts/contracts/ccip/pool/lock_release_token_pool/errors.tolk @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: BUSL-1.1 +import "../../../lib/utils.tolk" + +const LockReleaseTokenPool_FACILITY_NAME = "link.chain.ton.ccip.LockReleaseTokenPool"; +const LockReleaseTokenPool_FACILITY_ID = 263; // (crc32() % 640) + 10 + +enum Error { + IncorrectJettonSender = LockReleaseTokenPool_FACILITY_ID * 100 + MissingTransferInitiator + MissingForwardPayload + AmountMismatch + PendingReleaseAlreadyExists + PendingReleaseNotFound + UnexpectedReleaseConfirmationSender + UnexpectedReleaseBounce +} diff --git a/contracts/contracts/ccip/pool/lock_release_token_pool/events.tolk b/contracts/contracts/ccip/pool/lock_release_token_pool/events.tolk new file mode 100644 index 000000000..198d01e41 --- /dev/null +++ b/contracts/contracts/ccip/pool/lock_release_token_pool/events.tolk @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: BUSL-1.1 + +const LOCKED_OR_BURNED_TOPIC = stringCrc32("LockReleaseTokenPool_LockedOrBurned"); +const RELEASED_OR_MINTED_TOPIC = stringCrc32("LockReleaseTokenPool_ReleasedOrMinted"); +const RAMP_ACCESS_UPDATED_TOPIC = stringCrc32("LockReleaseTokenPool_RampAccessUpdated"); +const CURSED_SUBJECTS_UPDATED_TOPIC = stringCrc32("LockReleaseTokenPool_CursedSubjectsUpdated"); + +struct LockedOrBurnedDetails { + token: address; + sender: address; + amount: uint256; +} + +struct LockedOrBurned { + remoteChainSelector: uint64; + details: Cell; +} + +struct ReleasedOrMintedDetails { + token: address; + amount: uint256; + participants: Cell; +} + +struct ReleasedOrMintedParticipants { + sender: address; + recipient: address; +} + +struct ReleasedOrMinted { + remoteChainSelector: uint64; + details: Cell; +} + +struct RampAccessUpdated { + remoteChainSelector: uint64; + onRamp: address? = null; + offRamp: address? = null; +} + +struct CursedSubjectsUpdated {} diff --git a/contracts/contracts/ccip/pool/lock_release_token_pool/messages.tolk b/contracts/contracts/ccip/pool/lock_release_token_pool/messages.tolk new file mode 100644 index 000000000..9248344b4 --- /dev/null +++ b/contracts/contracts/ccip/pool/lock_release_token_pool/messages.tolk @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: BUSL-1.1 +import "../messages" +import "../../../lib/jetton/messages.tolk" + +type LockReleaseTokenPool_CustomInMessage = + | TransferNotificationForRecipient + | ReturnExcessesBack; + +type LockReleaseTokenPool_BouncedMessage = AskToTransfer; diff --git a/contracts/contracts/ccip/pool/lock_release_token_pool/storage.tolk b/contracts/contracts/ccip/pool/lock_release_token_pool/storage.tolk new file mode 100644 index 000000000..9b482d808 --- /dev/null +++ b/contracts/contracts/ccip/pool/lock_release_token_pool/storage.tolk @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: BUSL-1.1 +import "../token_pool.tolk" +import "../types" +import "../../rmn_remote/lib" +import "../../../lib/jetton/jetton_client.tolk" +import "../../../lib/access/ownable_2step.tolk" +import "types" + +struct Storage { + poolData: Cell; + jettonClient: Cell; + pendingReleases: map>; +} + +fun Storage.load(): Storage { + return Storage.fromCell(contract.getData()); +} + +fun Storage.store(self) { + contract.setData(self.toCell()); +} + +fun LockReleaseTokenPool_initialStorage(config: LockReleaseTokenPool_Config): Storage { + return Storage { + poolData: TokenPool_Data { + adminConfig: TokenPool_AdminConfig { + ownable: Ownable2Step { + owner: config.owner, + pendingOwner: null, + }.toCell(), + rmnProxy: config.rmnProxy, + dynamicConfig: TokenPool_DynamicConfig { + router: config.router, + rateLimitAdmin: null, + feeAdmin: null, + }.toCell(), + allowedFinalityConfig: TOKEN_POOL_DEFAULT_FINALITY, + }.toCell(), + mirroredPolicy: TokenPool_MirroredPolicy { + onRamps: createEmptyMap(), + offRamps: createEmptyMap(), + cursedSubjects: CursedSubjects { + data: createEmptyMap(), + }, + }.toCell(), + token: config.token, + tokenDecimals: config.tokenDecimals, + remoteChainConfigs: createEmptyMap(), + tokenTransferFeeConfigs: createEmptyMap(), + }.toCell(), + jettonClient: config.jettonClient.toCell(), + pendingReleases: createEmptyMap(), + }; +} diff --git a/contracts/contracts/ccip/pool/lock_release_token_pool/types.tolk b/contracts/contracts/ccip/pool/lock_release_token_pool/types.tolk new file mode 100644 index 000000000..603eed16e --- /dev/null +++ b/contracts/contracts/ccip/pool/lock_release_token_pool/types.tolk @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: BUSL-1.1 +import "../../../lib/jetton/jetton_client.tolk" +import "../types" + +const LockReleaseTokenPool_CONTRACT_NAME = "LockReleaseTokenPool".literalSlice(); +const LockReleaseTokenPool_CONTRACT_VERSION = "0.1.0".literalSlice(); +const LockReleaseTokenPool_RELEASE_TRANSFER_VALUE = ton("0.05"); +const LockReleaseTokenPool_REPLY_VALUE = ton("0.01"); + +struct LockReleaseTokenPool_PendingRelease { + replyTo: address? = null; + request: Cell; + out: Cell; + expectedSender: address; +} + +struct LockReleaseTokenPool_Config { + owner: address; + token: address; + tokenDecimals: uint8; + rmnProxy: address; + router: address; + jettonClient: JettonClient; +} diff --git a/contracts/contracts/ccip/pool/messages.tolk b/contracts/contracts/ccip/pool/messages.tolk new file mode 100644 index 000000000..b55c75728 --- /dev/null +++ b/contracts/contracts/ccip/pool/messages.tolk @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: BUSL-1.1 +import "../../lib/utils" +import "../common/types" +import "../rmn_remote/lib" +import "types" + +struct (0xdc0b6ff5) TokenPool_ApplyChainUpdates { + queryId: uint64; + remoteChainSelectorsToRemove: SnakedCell; + chainsToAdd: SnakedCell; +} + +struct (0x5fd2c8b6) TokenPool_AddRemotePool { + queryId: uint64; + remoteChainSelector: uint64; + remotePoolAddress: Cell; +} + +struct (0xdbf0a2df) TokenPool_RemoveRemotePool { + queryId: uint64; + remoteChainSelector: uint64; + remotePoolAddress: Cell; +} + +struct (0x4eea060b) TokenPool_SetDynamicConfig { + queryId: uint64; + router: address; + rateLimitAdmin: address? = null; + feeAdmin: address? = null; +} + +struct (0x29b46fc6) TokenPool_SetAllowedFinalityConfig { + queryId: uint64; + allowedFinalityConfig: uint32; +} + +struct (0x3a028da2) TokenPool_SetRateLimitConfig { + queryId: uint64; + updates: SnakedCell; +} + +struct (0x10c4b4a1) TokenPool_ApplyTokenTransferFeeConfigUpdates { + queryId: uint64; + updates: SnakedCell; + disableChainSelectors: SnakedCell; +} + +struct (0x7a9c4aa5) TokenPool_UpdateRampAccess { + queryId: uint64; + updates: SnakedCell; +} + +struct (0x823dadf2) TokenPool_UpdateCursedSubjects { + cursedSubjects: CursedSubjects; +} + +/// Lock tokens into the pool or burn the tokens. +/// @param lockOrBurnIn Encoded data fields for the processing of tokens on the source chain. +/// @param requestedFinalityConfig Requested finality encoding (see `FinalityCodec`). +/// @param tokenArgs Additional token arguments. +struct (0x1161516e) TokenPool_LockOrBurn { + queryId: uint64; + lockOrBurnIn: Cell; + requestedFinalityConfig: uint32; + tokenArgs: cell?; + replyTo: address?; +} + +struct (0x19e65bea) TokenPool_LockOrBurnResponse { + queryId: uint64; + // TODO: unwrap and inline this type + out: Cell; + destTokenAmount: uint256; +} + +/// @Releases or mints tokens on the destination chain. +/// @param releaseOrMintIn Encoded data fields for the processing of tokens on the destination chain. +/// @param requestedFinalityConfig Requested finality encoding (see `FinalityCodec`). +struct (0x7d0ffd89) TokenPool_ReleaseOrMint { + queryId: uint64; + request: Cell; + requestedFinalityConfig: uint32; + replyTo: address? = null; +} + +struct (0x7ec43aee) TokenPool_ReleaseOrMintResponse { + queryId: uint64; + out: Cell; +} + +struct (0x41a1702b) TokenPool_ReleaseOrMintFailure { + queryId: uint64; + errorCode: uint16; +} + +type TokenPool_InMessage = + | TokenPool_ApplyChainUpdates + | TokenPool_AddRemotePool + | TokenPool_RemoveRemotePool + | TokenPool_SetDynamicConfig + | TokenPool_SetAllowedFinalityConfig + | TokenPool_SetRateLimitConfig + | TokenPool_ApplyTokenTransferFeeConfigUpdates + | TokenPool_UpdateRampAccess + | TokenPool_UpdateCursedSubjects + | TokenPool_LockOrBurn + | TokenPool_ReleaseOrMint; diff --git a/contracts/contracts/ccip/pool/rate_limiter.tolk b/contracts/contracts/ccip/pool/rate_limiter.tolk new file mode 100644 index 000000000..edd97e5b0 --- /dev/null +++ b/contracts/contracts/ccip/pool/rate_limiter.tolk @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: BUSL-1.1 + +struct RateLimiter_Config { + isEnabled: bool; + capacity: uint256; + rate: uint256; +} + +struct RateLimiter_TokenBucket { + tokens: uint256; + lastUpdated: uint64; + isEnabled: bool; + capacity: uint256; + rate: uint256; +} + +fun RateLimiter_tokenBucketFromConfig(config: RateLimiter_Config): RateLimiter_TokenBucket { + return RateLimiter_TokenBucket { + tokens: config.capacity, + lastUpdated: blockchain.now(), + isEnabled: config.isEnabled, + capacity: config.capacity, + rate: config.rate, + }; +} + +fun RateLimiter_consumeBucket(mutate bucket: RateLimiter_TokenBucket, amount: uint256) { + if (!bucket.isEnabled) { + return; + } + + RateLimiter_refillBucket(mutate bucket); + assert(bucket.tokens >= amount, TokenPool_Error.RateLimitExceeded); + bucket.tokens -= amount; +} + +fun RateLimiter_rateLimitConfigFromCell(data: cell): RateLimiter_Config { + var cs = data.beginParse(); + val isEnabled = cs.loadUint(1) != 0; + val capacity = cs.loadUint(256); + val rate = cs.loadUint(256); + cs.assertEnd(); + return RateLimiter_Config { + isEnabled, + capacity, + rate, + }; +} + +fun RateLimiter_refillBucket(mutate bucket: RateLimiter_TokenBucket) { + if (!bucket.isEnabled) { + return; + } + + val nowTs = blockchain.now(); + if (nowTs <= bucket.lastUpdated) { + return; + } + + val elapsed = nowTs - bucket.lastUpdated; + val refill = (elapsed as uint256) * bucket.rate; + if (refill == 0) { + bucket.lastUpdated = nowTs; + return; + } + + val nextTokens = bucket.tokens + refill; + bucket.tokens = nextTokens > bucket.capacity ? bucket.capacity : nextTokens; + bucket.lastUpdated = nowTs; +} diff --git a/contracts/contracts/ccip/pool/token_pool.tolk b/contracts/contracts/ccip/pool/token_pool.tolk new file mode 100644 index 000000000..6a9024323 --- /dev/null +++ b/contracts/contracts/ccip/pool/token_pool.tolk @@ -0,0 +1,1008 @@ +// SPDX-License-Identifier: BUSL-1.1 +import "@stdlib/lisp-lists" + +import "../../lib/utils" +import "../../lib/access/ownable_2step.tolk" +import "../common/types" +import "../rmn_remote/lib" + +import "types" +import "errors" +import "messages" +import "events" +import "rate_limiter" + +struct TokenPool_AdminConfig { + ownable: Cell; + rmnProxy: address; + dynamicConfig: Cell; + allowedFinalityConfig: uint32 = TOKEN_POOL_DEFAULT_FINALITY; +} + +struct TokenPool_Data { + adminConfig: Cell; + mirroredPolicy: Cell; + token: address; + tokenDecimals: uint8; + remoteChainConfigs: map; + tokenTransferFeeConfigs: map; +} + +@inline +fun TokenPool_Data.fromContractData() { + return TokenPool_Data.fromCell(contract.getData()); +} + +@inline +fun TokenPool_Data.storeAsContractData(self) { + contract.setData(self.toCell()); +} + +// --- Hooks struct (extensions) --- + +/// Hook extensions exposed by the TokenPool contract. +struct TokenPool_Hooks { + ensureOutboundAccess: ((T?, address, uint64) -> void)?; + ensureInboundAccess: ((T?, address, uint64) -> void)?; + ensureNotCursed: ((T?, uint64) -> void)?; + preflightCheck: ((T?, TokenPool_LockOrBurnInV1, uint32, cell?, uint256) -> void)?; + postflightCheck: ((T?, TokenPool_ReleaseOrMintInV1, uint256, uint32) -> void)?; + applyLockOrBurn: ((T?, TokenPool_LockOrBurnPrepared) -> void)?; + applyReleaseOrMint: ((T?, TokenPool_ReleaseOrMintPrepared) -> void)?; + handleReleaseOrMintMessage: ((T?, address, TokenPool_ReleaseOrMint, TokenPool_ReleaseOrMintPrepared) -> T?)?; +} + +struct TokenPool { + data: TokenPool_Data; + context: T? = null; + hooks: TokenPool_Hooks? = null; +} + +@inline +fun TokenPool.load(context: T? = null, hooks: TokenPool_Hooks? = null): TokenPool { + return TokenPool { + data: TokenPool_Data.fromContractData(), + context, + hooks, + }; +} + +fun TokenPool.store(self) { + self.data.storeAsContractData(); +} + +/// Returns if the token pool supports the given token. +/// @param token The address of the token. +@inline +fun TokenPool.isSupportedToken(self, token: address): bool { + return self.data.token == token; +} + +/// Gets the Jetton token that this pool can lock or burn. +/// @return token The Jetton token representation. +@inline +fun TokenPool.getToken(self): address { + return self.data.token; +} + +/// Gets the Jetton token decimals on the local chain. +@inline +fun TokenPool.getTokenDecimals(self): uint8 { + return self.data.tokenDecimals; +} + +@inline +fun TokenPool.getRmnProxy(self): address { + return self.data.adminConfig.load().rmnProxy; +} + +/// Gets the pools dynamic configuration. +@inline +fun TokenPool.getDynamicConfig(self): TokenPool_DynamicConfig { + return self.data.adminConfig.load().dynamicConfig.load(); +} + +/// Gets the finality config as defined in the FinalityCodec library. This value does NOT 1:1 translate to +/// a block depth. The finality config contains special flags and should only be encoded/decoded using the +/// FinalityCodec library. Checks must happen by calling `FinalityCodec._ensureRequestedFinalityAllowed`. +@inline +fun TokenPool.getAllowedFinalityConfig(self): uint32 { + return self.data.adminConfig.load().allowedFinalityConfig; +} + +// TODO: implement me +/// Gets the advanced pool hook contract address used by this pool. +@inline +fun TokenPool.getAdvancedPoolHooks(self): address? { + return null; +} + +@inline +fun TokenPool.getOnRamp(self, remoteChainSelector: uint64): address? { + val entry = self.data.mirroredPolicy.load().onRamps.get(remoteChainSelector); + return entry.isFound ? entry.loadValue() : null; +} + +@inline +fun TokenPool.getOffRamp(self, remoteChainSelector: uint64): address? { + val entry = self.data.mirroredPolicy.load().offRamps.get(remoteChainSelector); + return entry.isFound ? entry.loadValue() : null; +} + +@inline +fun TokenPool.verifyNotCursed(self, subject: uint128): bool { + return !self.data.mirroredPolicy.load().cursedSubjects.isCursed(subject); +} + +/// Checks whether a remote chain is supported in the token pool. +/// @param remoteChainSelector The remote chain selector to check. +@inline +fun TokenPool.isSupportedChain(self, remoteChainSelector: uint64): bool { + return self.data.remoteChainConfigs.get(remoteChainSelector).isFound; +} + +/// Checks if the pool address is configured on the remote chain. +/// @param remoteChainSelector Remote chain selector. +/// @param remotePoolAddress The address of the remote pool. +fun TokenPool.isRemotePool(self, remoteChainSelector: uint64, remotePoolAddress: Cell): bool { + val entry = self.data.remoteChainConfigs.get(remoteChainSelector); + if (!entry.isFound) { + return false; + } + + val config = entry.loadValue(); + return config.remotePools.get(TokenPool_hashCrossChainAddress(remotePoolAddress)).isFound; +} + +/// Gets the token address on the remote chain. +/// @param remoteChainSelector Remote chain selector. +fun TokenPool.getRemoteToken(self, remoteChainSelector: uint64): Cell { + val config = self.data.remoteChainConfigs.mustGet(remoteChainSelector, TokenPool_Error.NonExistentChain as int); + return config.remoteTokenAddress; +} + +/// Gets the pool address on the remote chain. +/// @param remoteChainSelector Remote chain selector. +fun TokenPool.getRemotePools(self, remoteChainSelector: uint64): lisp_list> { + val config = self.data.remoteChainConfigs.mustGet(remoteChainSelector, TokenPool_Error.NonExistentChain as int); + var list: lisp_list> = []; + var entry = config.remotePools.findFirst(); + while (entry.isFound) { + list.prependHead(entry.loadValue()); + entry = config.remotePools.iterateNext(entry); + } + return list; +} + +/// Sets the dynamic configuration for the pool. +/// @param router The address of the router contract. +/// @param rateLimitAdmin The address of the rate limiter admin. +/// @param feeAdmin An additional address that can withdraw fees from this contract. +/// @dev FeeTokenHandler will revert if feeAdmin is zero when withdrawing fees. +/// @dev If only the owner can withdraw fees, set feeAdmin to address(0). +fun TokenPool.setDynamicConfig( + mutate self, + sender: address, + router: address, + rateLimitAdmin: address?, + feeAdmin: address?, +) { + var adminConfig = self.data.adminConfig.load(); + adminConfig.ownable.load().requireOwner(sender); + + assert(!router.isNone(), TokenPool_Error.ZeroAddressInvalid); + adminConfig.dynamicConfig = TokenPool_DynamicConfig { + router, + rateLimitAdmin, + feeAdmin, + }.toCell(); + self.data.adminConfig = adminConfig.toCell(); + + // TODO: reply back to sender with excess + emit(TOKEN_POOL_DYNAMIC_CONFIG_SET_TOPIC, TokenPool_DynamicConfigSet { + router, + rateLimitAdmin, + feeAdmin, + }); +} + +/// Sets the finality config according to the FinalityCodec library encoding. +/// @param allowedFinality The finality settings allowed in this pool, according to the FinalityCodec encoding. +fun TokenPool.setAllowedFinalityConfig(mutate self, sender: address, allowedFinalityConfig: uint32) { + var adminConfig = self.data.adminConfig.load(); + adminConfig.ownable.load().requireOwner(sender); + // Any bytes4 value is accepted as allowedFinality; the FinalityCodec semantics are enforced when requests are + // checked against this value via FinalityCodec._ensureRequestedFinalityAllowed. + adminConfig.allowedFinalityConfig = allowedFinalityConfig; + self.data.adminConfig = adminConfig.toCell(); + + // TODO: reply back to sender with excess + emit(TOKEN_POOL_FINALITY_CONFIG_SET_TOPIC, TokenPool_FinalityConfigSet { + allowedFinalityConfig, + }); +} + +// TODO: add updateAdvancedPoolHooks + +/// Adds a remote pool for a given chain selector. This could be due to a pool being upgraded on the remote +/// chain. We don't simply want to replace the old pool as there could still be valid inflight messages from the old +/// pool. This function allows for multiple pools to be added for a single chain selector. +/// @param remoteChainSelector The remote chain selector for which the remote pool address is being added. +/// @param remotePoolAddress The address of the new remote pool. +fun TokenPool.addRemotePool( + mutate self, + sender: address, + remoteChainSelector: uint64, + remotePoolAddress: Cell, +) { + self.data.adminConfig.load().ownable.load().requireOwner(sender); + assert(self.isSupportedChain(remoteChainSelector), TokenPool_Error.NonExistentChain); + + var config = self.data.remoteChainConfigs.mustGet(remoteChainSelector, TokenPool_Error.NonExistentChain as int); + self._setRemotePool(mutate config, remotePoolAddress); + self.data.remoteChainConfigs.set(remoteChainSelector, config); + + // TODO: reply back to sender with excess + emit(TOKEN_POOL_REMOTE_POOL_ADDED_TOPIC, TokenPool_RemotePoolAdded { + remoteChainSelector, + remotePoolAddress, + }); +} + +/// Removes the remote pool address for a given chain selector. +/// @dev All inflight txs from the remote pool will be rejected after it is removed. To ensure no loss of funds, there +/// should be no inflight txs from the given pool. +/// @param remoteChainSelector The remote chain selector. +/// @param remotePoolAddress The remote pool address to remove. +fun TokenPool.removeRemotePool( + mutate self, + sender: address, + remoteChainSelector: uint64, + remotePoolAddress: Cell, +) { + self.data.adminConfig.load().ownable.load().requireOwner(sender); + assert(self.isSupportedChain(remoteChainSelector), TokenPool_Error.NonExistentChain); + + var config = self.data.remoteChainConfigs.mustGet(remoteChainSelector, TokenPool_Error.NonExistentChain as int); + val deleted = config.remotePools.delete(TokenPool_hashCrossChainAddress(remotePoolAddress)); + assert(deleted, TokenPool_Error.InvalidRemotePoolForChain); + self.data.remoteChainConfigs.set(remoteChainSelector, config); + + // TODO: reply back to sender with excess + emit(TOKEN_POOL_REMOTE_POOL_REMOVED_TOPIC, TokenPool_RemotePoolRemoved { + remoteChainSelector, + remotePoolAddress, + }); +} + +fun TokenPool.applyChainUpdates( + mutate self, + sender: address, + remoteChainSelectorsToRemove: cell, + chainsToAdd: cell, +) { + self.data.adminConfig.load().ownable.load().requireOwner(sender); + + var removeSlice = remoteChainSelectorsToRemove.beginParse(); + var removeDone = false; + while (!removeDone) { + while (removeSlice.remainingBitsCount() > 0) { + val remoteChainSelector = removeSlice.loadUint(64); + val deleted = self.data.remoteChainConfigs.delete(remoteChainSelector); + assert(deleted, TokenPool_Error.NonExistentChain); + + emit(TOKEN_POOL_CHAIN_REMOVED_TOPIC, TokenPool_ChainRemoved { + remoteChainSelector, + }); + } + + if (removeSlice.remainingRefsCount() == 0) { + removeDone = true; + } else { + removeSlice = removeSlice.loadRef().beginParse(); + } + } + + var addSlice = chainsToAdd.beginParse(); + var addDone = false; + while (!addDone) { + while (addSlice.remainingBitsCount() > 0) { + val remoteChainSelector = addSlice.loadUint(64); + val remotePoolAddresses = addSlice.loadRef(); + val remoteTokenAddress = addSlice.loadRef() as Cell; + var rateLimitConfigs = addSlice.loadRef().beginParse(); + val outboundRateLimiterConfig = RateLimiter_rateLimitConfigFromCell(rateLimitConfigs.loadRef()); + val inboundRateLimiterConfig = RateLimiter_rateLimitConfigFromCell(rateLimitConfigs.loadRef()); + rateLimitConfigs.assertEnd(); + + assert(!TokenPool_isEmptyCrossChainAddress(remoteTokenAddress), TokenPool_Error.ZeroAddressInvalid); + assert(!self.data.remoteChainConfigs.get(remoteChainSelector).isFound, TokenPool_Error.ChainAlreadyExists); + + var remotePools: map> = createEmptyMap(); + var config = TokenPool_RemoteChainConfig { + remoteTokenAddress, + remotePools, + rateLimiters: TokenPool_RateLimiterPair { + outbound: RateLimiter_tokenBucketFromConfig(outboundRateLimiterConfig).toCell(), + inbound: RateLimiter_tokenBucketFromConfig(inboundRateLimiterConfig).toCell(), + }.toCell(), + fastFinalityRateLimiters: TokenPool_RateLimiterPair { + outbound: RateLimiter_tokenBucketFromConfig(RateLimiter_Config { + isEnabled: false, + capacity: 0, + rate: 0, + }).toCell(), + inbound: RateLimiter_tokenBucketFromConfig(RateLimiter_Config { + isEnabled: false, + capacity: 0, + rate: 0, + }).toCell(), + }.toCell(), + }; + + var remotePoolsSlice = remotePoolAddresses.beginParse(); + var remotePoolsDone = false; + while (!remotePoolsDone) { + while (remotePoolsSlice.remainingBitsCount() > 0) { + val remotePoolAddress = TokenPool_boxCrossChainAddress(CrossChainAddress.unpackFromSlice(mutate remotePoolsSlice)); + self._setRemotePool(mutate config, remotePoolAddress); + + emit(TOKEN_POOL_REMOTE_POOL_ADDED_TOPIC, TokenPool_RemotePoolAdded { + remoteChainSelector, + remotePoolAddress, + }); + } + + if (remotePoolsSlice.remainingRefsCount() == 0) { + remotePoolsDone = true; + } else { + remotePoolsSlice = remotePoolsSlice.loadRef().beginParse(); + } + } + + emit(TOKEN_POOL_CHAIN_ADDED_TOPIC, TokenPool_ChainAdded { + remoteChainSelector, + remoteTokenAddress, + }); + + self.data.remoteChainConfigs.set(remoteChainSelector, config); + } + + if (addSlice.remainingRefsCount() == 0) { + addDone = true; + } else { + addSlice = addSlice.loadRef().beginParse(); + } + } +} + +fun TokenPool.applyRampAccessUpdates( + mutate self, + sender: address, + updates: cell, +) { + var adminConfig = self.data.adminConfig.load(); + var ownable = adminConfig.ownable.load(); + ownable.requireOwner(sender); + adminConfig.ownable = ownable.toCell(); + self.data.adminConfig = adminConfig.toCell(); + + var mirroredPolicy = self.data.mirroredPolicy.load(); + var updatesSlice = updates.beginParse(); + var updatesDone = false; + while (!updatesDone) { + while (updatesSlice.remainingBitsCount() > 0) { + val update = TokenPool_RampUpdate.fromSlice(mutate updatesSlice); + + if (update.onRamp != null) { + mirroredPolicy.onRamps.set(update.remoteChainSelector, update.onRamp!); + } else { + mirroredPolicy.onRamps.delete(update.remoteChainSelector); + } + + if (update.offRamp != null) { + mirroredPolicy.offRamps.set(update.remoteChainSelector, update.offRamp!); + } else { + mirroredPolicy.offRamps.delete(update.remoteChainSelector); + } + + emit(TOKEN_POOL_RAMP_ACCESS_UPDATED_TOPIC, TokenPool_RampAccessUpdated { + remoteChainSelector: update.remoteChainSelector, + onRamp: update.onRamp, + offRamp: update.offRamp, + }); + } + + if (updatesSlice.remainingRefsCount() == 0) { + updatesDone = true; + } else { + updatesSlice = updatesSlice.loadRef().beginParse(); + } + } + + self.data.mirroredPolicy = mirroredPolicy.toCell(); +} + +fun TokenPool.setCursedSubjects( + mutate self, + sender: address, + cursedSubjects: CursedSubjects, +) { + assert(sender == self.data.adminConfig.load().rmnProxy, TokenPool_Error.Unauthorized); + + var mirroredPolicy = self.data.mirroredPolicy.load(); + mirroredPolicy.cursedSubjects = cursedSubjects; + self.data.mirroredPolicy = mirroredPolicy.toCell(); + + emit(TOKEN_POOL_CURSED_SUBJECTS_UPDATED_TOPIC, TokenPool_CursedSubjectsUpdated {}); +} + +fun TokenPool.onInternalMessage(mutate self, msgSender: address, msgValue: coins, msgBody: slice): bool { + val msg = lazy TokenPool_InMessage.fromSlice(msgBody); + + match (msg) { + TokenPool_ApplyChainUpdates => { + self.applyChainUpdates(msgSender, msg.remoteChainSelectorsToRemove, msg.chainsToAdd); + return true; + } + TokenPool_AddRemotePool => { + self.addRemotePool(msgSender, msg.remoteChainSelector, msg.remotePoolAddress); + return true; + } + TokenPool_RemoveRemotePool => { + self.removeRemotePool(msgSender, msg.remoteChainSelector, msg.remotePoolAddress); + return true; + } + TokenPool_SetDynamicConfig => { + self.setDynamicConfig(msgSender, msg.router, msg.rateLimitAdmin, msg.feeAdmin); + return true; + } + TokenPool_SetAllowedFinalityConfig => { + self.setAllowedFinalityConfig(msgSender, msg.allowedFinalityConfig); + return true; + } + TokenPool_SetRateLimitConfig => { + self.setRateLimitConfig(msgSender, msg.updates.load()); + return true; + } + TokenPool_ApplyTokenTransferFeeConfigUpdates => { + self.applyTokenTransferFeeConfigUpdates(msgSender, msg.updates.load(), msg.disableChainSelectors.load()); + return true; + } + TokenPool_UpdateRampAccess => { + self.applyRampAccessUpdates(msgSender, msg.updates); + return true; + } + TokenPool_UpdateCursedSubjects => { + self.setCursedSubjects(msgSender, msg.cursedSubjects); + return true; + } + TokenPool_ReleaseOrMint => { + val prepared = self.prepareReleaseOrMint(msgSender, msg.request.load(), msg.requestedFinalityConfig); + assert(self.hooks != null && self.hooks.handleReleaseOrMintMessage != null, TokenPool_Error.UnsupportedOperation); + self.context = self.hooks.handleReleaseOrMintMessage(self.context, msgSender, msg, prepared); + return true; + } + else => { + var adminConfig = self.data.adminConfig.load(); + var ownable = adminConfig.ownable.load(); + val handled = ownable.onInternalMessage(msgSender, msgBody); + if (handled) { + adminConfig.ownable = ownable.toCell(); + self.data.adminConfig = adminConfig.toCell(); + return true; + } + + return msgBody.isEmpty(); + } + } +} + +fun TokenPool.applyTokenTransferFeeConfigUpdates( + mutate self, + sender: address, + updates: SnakedCell, + disableChainSelectors: SnakedCell, +) { + self.data.adminConfig.load().ownable.load().requireOwner(sender); + + var iter = updates.iter(); + while (!iter.empty()) { + val update = iter.next(); + assert(self.isSupportedChain(update.destChainSelector), TokenPool_Error.NonExistentChain); + assert(update.tokenTransferFeeConfig.isEnabled, TokenPool_Error.InvalidTokenTransferFeeConfig); + assert((update.tokenTransferFeeConfig.finalityTransferFeeBps as uint256) < TOKEN_POOL_BPS_DIVIDER, TokenPool_Error.InvalidTransferFeeBps); + assert((update.tokenTransferFeeConfig.fastFinalityTransferFeeBps as uint256) < TOKEN_POOL_BPS_DIVIDER, TokenPool_Error.InvalidTransferFeeBps); + assert(update.tokenTransferFeeConfig.destGasOverhead > 0, TokenPool_Error.InvalidTokenTransferFeeConfig); + self.data.tokenTransferFeeConfigs.set(update.destChainSelector, update.tokenTransferFeeConfig); + } + + var disableIter = disableChainSelectors.iter(); + while (!disableIter.empty()) { + self.data.tokenTransferFeeConfigs.delete(disableIter.next()); + } +} + +fun TokenPool.getTokenTransferFeeConfig(self, destChainSelector: uint64): TokenPool_TokenTransferFeeConfig? { + val entry = self.data.tokenTransferFeeConfigs.get(destChainSelector); + return entry.isFound ? entry.loadValue() : null; +} + +fun TokenPool.getFee( + self, + destChainSelector: uint64, + requestedFinalityConfig: uint32, +): (uint256, uint32, uint32, uint16, bool) { + TokenPool_ensureRequestedFinalityAllowed(requestedFinalityConfig, self.data.adminConfig.load().allowedFinalityConfig); + + val entry = self.data.tokenTransferFeeConfigs.get(destChainSelector); + if (!entry.isFound) { + return (0, 0, 0, 0, false); + } + + val feeConfig = entry.loadValue(); + if (!feeConfig.isEnabled) { + return (0, 0, 0, 0, false); + } + + if (requestedFinalityConfig != TOKEN_POOL_WAIT_FOR_FINALITY_FLAG) { + return ( + feeConfig.fastFinalityFeeUSDCents, + feeConfig.destGasOverhead, + feeConfig.destBytesOverhead, + feeConfig.fastFinalityTransferFeeBps, + true, + ); + } + + return ( + feeConfig.finalityFeeUSDCents, + feeConfig.destGasOverhead, + feeConfig.destBytesOverhead, + feeConfig.finalityTransferFeeBps, + true, + ); +} + +fun TokenPool.prepareLockOrBurn( + mutate self, + sender: address, + request: TokenPool_LockOrBurnInV1, + requestedFinalityConfig: uint32 = TOKEN_POOL_DEFAULT_FINALITY, + tokenArgs: cell? = null, +): TokenPool_LockOrBurnPrepared { + assert(self.isSupportedToken(request.localToken), TokenPool_Error.InvalidToken); + self.requireSupportedChain(request.remoteChainSelector); + self.ensureNotCursed(request.remoteChainSelector); + self.ensureOutboundAccess(sender, request.remoteChainSelector); + + val feeAmount = self.getFeeAmount(request, requestedFinalityConfig); + val destTokenAmount = request.amount - feeAmount; + val usingFastFinality = requestedFinalityConfig != TOKEN_POOL_WAIT_FOR_FINALITY_FLAG; + if (usingFastFinality) { + TokenPool_ensureRequestedFinalityAllowed(requestedFinalityConfig, self.data.adminConfig.load().allowedFinalityConfig); + self.consumeFastFinalityOutboundRateLimit(request.remoteChainSelector, destTokenAmount); + } else { + self.consumeOutboundRateLimit(request.remoteChainSelector, destTokenAmount); + } + + self.preflightCheck(request, requestedFinalityConfig, tokenArgs, destTokenAmount); + + return TokenPool_LockOrBurnPrepared { + request, + requestedFinalityConfig, + tokenArgs, + feeAmount, + destTokenAmount, + usingFastFinality, + out: TokenPool_LockOrBurnOutV1 { + destTokenAddress: self.getRemoteToken(request.remoteChainSelector), + destPoolData: self.encodeLocalDecimals(), + }, + }; +} + +fun TokenPool.lockOrBurn( + mutate self, + sender: address, + request: TokenPool_LockOrBurnInV1, + requestedFinalityConfig: uint32 = TOKEN_POOL_DEFAULT_FINALITY, + tokenArgs: cell? = null, +): TokenPool_LockOrBurnPrepared { + val prepared = self.prepareLockOrBurn(sender, request, requestedFinalityConfig, tokenArgs); + if (self.hooks != null && self.hooks.applyLockOrBurn != null) { + self.hooks.applyLockOrBurn(self.context, prepared); + } + return prepared; +} + +fun TokenPool.prepareReleaseOrMint( + mutate self, + sender: address, + request: TokenPool_ReleaseOrMintInV1, + requestedFinalityConfig: uint32 = TOKEN_POOL_DEFAULT_FINALITY, +): TokenPool_ReleaseOrMintPrepared { + assert(self.isSupportedToken(request.localToken), TokenPool_Error.InvalidToken); + self.requireSupportedChain(request.remoteChainSelector); + self.ensureNotCursed(request.remoteChainSelector); + self.ensureInboundAccess(sender, request.remoteChainSelector); + assert(self.isRemotePool(request.remoteChainSelector, request.sourcePoolAddress), TokenPool_Error.InvalidRemotePoolForChain); + + val remoteDecimals = self.parseRemoteDecimals(request.sourcePoolData); + val localAmount = self.calculateLocalAmount(request.sourceDenominatedAmount, remoteDecimals); + val usingFastFinality = requestedFinalityConfig != TOKEN_POOL_WAIT_FOR_FINALITY_FLAG; + if (usingFastFinality) { + TokenPool_ensureRequestedFinalityAllowed(requestedFinalityConfig, self.data.adminConfig.load().allowedFinalityConfig); + self.consumeFastFinalityInboundRateLimit(request.remoteChainSelector, localAmount); + } else { + self.consumeInboundRateLimit(request.remoteChainSelector, localAmount); + } + + self.postflightCheck(request, localAmount, requestedFinalityConfig); + + return TokenPool_ReleaseOrMintPrepared { + request, + requestedFinalityConfig, + localAmount, + usingFastFinality, + out: TokenPool_ReleaseOrMintOutV1 { + destinationAmount: localAmount, + }, + }; +} + +fun TokenPool.releaseOrMint( + mutate self, + sender: address, + request: TokenPool_ReleaseOrMintInV1, + requestedFinalityConfig: uint32 = TOKEN_POOL_DEFAULT_FINALITY, +): TokenPool_ReleaseOrMintPrepared { + val prepared = self.prepareReleaseOrMint(sender, request, requestedFinalityConfig); + if (self.hooks != null && self.hooks.applyReleaseOrMint != null) { + self.hooks.applyReleaseOrMint(self.context, prepared); + } + return prepared; +} + +fun TokenPool.encodeLocalDecimals(self): cell { + return beginCell().storeUint(self.data.tokenDecimals as uint256, 256).endCell(); +} + +fun TokenPool.parseRemoteDecimals(self, sourcePoolData: cell?): uint8 { + if (sourcePoolData == null) { + return self.data.tokenDecimals; + } + + var cs = sourcePoolData!.beginParse(); + assert(cs.remainingBitsCount() == 256 && cs.remainingRefsCount() == 0, TokenPool_Error.InvalidRemoteChainDecimals); + val remoteDecimals = cs.loadUint(256); + cs.assertEnd(); + assert(remoteDecimals <= 255, TokenPool_Error.InvalidRemoteChainDecimals); + return remoteDecimals as uint8; +} + +fun TokenPool.calculateLocalAmount(self, remoteAmount: uint256, remoteDecimals: uint8): uint256 { + if (remoteDecimals == self.data.tokenDecimals) { + return remoteAmount; + } + + if (remoteDecimals > self.data.tokenDecimals) { + val decimalsDiff = remoteDecimals - self.data.tokenDecimals; + assert(decimalsDiff <= TOKEN_POOL_MAX_EXP10, TokenPool_Error.OverflowDetected); + return remoteAmount / TokenPool_pow10(decimalsDiff); + } + + val decimalsDiff = self.data.tokenDecimals - remoteDecimals; + assert(decimalsDiff <= TOKEN_POOL_MAX_EXP10, TokenPool_Error.OverflowDetected); + val scale = TokenPool_pow10(decimalsDiff); + assert(scale == 0 || remoteAmount <= TOKEN_POOL_MAX_UINT256 / scale, TokenPool_Error.OverflowDetected); + return remoteAmount * scale; +} + +fun TokenPool.getFeeAmount( + self, + request: TokenPool_LockOrBurnInV1, + requestedFinalityConfig: uint32, +): uint256 { + val entry = self.data.tokenTransferFeeConfigs.get(request.remoteChainSelector); + if (!entry.isFound) { + return 0; + } + + val feeConfig = entry.loadValue(); + if (!feeConfig.isEnabled) { + return 0; + } + + if (requestedFinalityConfig != TOKEN_POOL_WAIT_FOR_FINALITY_FLAG) { + return (request.amount * (feeConfig.fastFinalityTransferFeeBps as uint256)) / TOKEN_POOL_BPS_DIVIDER; + } + return (request.amount * (feeConfig.finalityTransferFeeBps as uint256)) / TOKEN_POOL_BPS_DIVIDER; +} + +fun TokenPool.requireSupportedChain(self, remoteChainSelector: uint64) { + assert(self.isSupportedChain(remoteChainSelector), TokenPool_Error.ChainNotAllowed); +} + +fun TokenPool.requireOwnerOrRateLimitAdmin(self, sender: address) { + val adminConfig = self.data.adminConfig.load(); + val ownable = adminConfig.ownable.load(); + if (sender == ownable.owner) { + return; + } + val dynamicConfig = adminConfig.dynamicConfig.load(); + assert(dynamicConfig.rateLimitAdmin != null && sender == dynamicConfig.rateLimitAdmin, TokenPool_Error.Unauthorized); +} + +fun TokenPool.ensureNotCursed(self, remoteChainSelector: uint64) { + assert(self.verifyNotCursed(remoteChainSelector as uint128), TokenPool_Error.CursedByRMN); + if (self.hooks != null && self.hooks.ensureNotCursed != null) { + self.hooks.ensureNotCursed(self.context, remoteChainSelector); + } +} + +fun TokenPool.ensureOutboundAccess(self, sender: address, remoteChainSelector: uint64) { + val onRamp = self.getOnRamp(remoteChainSelector); + assert(onRamp != null, TokenPool_Error.Unauthorized); + assert(onRamp! == sender, TokenPool_Error.Unauthorized); + if (self.hooks != null && self.hooks.ensureOutboundAccess != null) { + self.hooks.ensureOutboundAccess(self.context, sender, remoteChainSelector); + } +} + +fun TokenPool.ensureInboundAccess(self, sender: address, remoteChainSelector: uint64) { + val offRamp = self.getOffRamp(remoteChainSelector); + assert(offRamp != null, TokenPool_Error.Unauthorized); + assert(offRamp! == sender, TokenPool_Error.Unauthorized); + if (self.hooks != null && self.hooks.ensureInboundAccess != null) { + self.hooks.ensureInboundAccess(self.context, sender, remoteChainSelector); + } +} + +fun TokenPool.preflightCheck( + self, + request: TokenPool_LockOrBurnInV1, + requestedFinalityConfig: uint32, + tokenArgs: cell?, + amountPostFee: uint256, +) { + if (self.hooks != null && self.hooks.preflightCheck != null) { + self.hooks.preflightCheck(self.context, request, requestedFinalityConfig, tokenArgs, amountPostFee); + } +} + +fun TokenPool.postflightCheck( + self, + request: TokenPool_ReleaseOrMintInV1, + localAmount: uint256, + requestedFinalityConfig: uint32, +) { + if (self.hooks != null && self.hooks.postflightCheck != null) { + self.hooks.postflightCheck(self.context, request, localAmount, requestedFinalityConfig); + } +} + +// ================================================================ +// │ Rate limiting │ +// ================================================================ + +/// @dev The inbound rate limits should be slightly higher than the outbound rate limits. This is because many chains +/// finalize blocks in batches. CCIP also commits messages in batches: the commit plugin bundles multiple messages in +/// a single merkle root. +/// Imagine the following scenario. +/// - Chain A has an inbound and outbound rate limit of 100 tokens capacity and 1 token per second refill rate. +/// - Chain B has an inbound and outbound rate limit of 100 tokens capacity and 1 token per second refill rate. +/// +/// At time 0: +/// - Chain A sends 100 tokens to Chain B. +/// At time 5: +/// - Chain A sends 5 tokens to Chain B. +/// At time 6: +/// The epoch that contains blocks [0-5] is finalized. +/// Both transactions will be included in the same merkle root and become executable at the same time. This means +/// the token pool on chain B requires a capacity of 105 to successfully execute both messages at the same time. +/// The exact additional capacity required depends on the refill rate and the size of the source chain epochs and the +/// CCIP round time. For simplicity, a 5-10% buffer should be sufficient in most cases. + +/// Consumes outbound rate limiting capacity in this pool. +/// @param remoteChainSelector The remote chain selector. +/// @param amount The amount of tokens consumed. +fun TokenPool.consumeOutboundRateLimit(mutate self, remoteChainSelector: uint64, amount: uint256) { + var config = self.data.remoteChainConfigs.mustGet(remoteChainSelector, TokenPool_Error.NonExistentChain as int); + var rateLimiters = config.rateLimiters.load(); + var bucket = rateLimiters.outbound.load(); + RateLimiter_consumeBucket(mutate bucket, amount); + rateLimiters.outbound = bucket.toCell(); + config.rateLimiters = rateLimiters.toCell(); + self.data.remoteChainConfigs.set(remoteChainSelector, config); + + // TODO: emit event with updated rate limiter state + // emit OutboundRateLimitConsumed({token: token, remoteChainSelector: remoteChainSelector, amount: amount}); +} + +/// Consumes inbound rate limiting capacity in this pool. +/// @param remoteChainSelector The remote chain selector. +/// @param amount The amount of tokens consumed. +fun TokenPool.consumeInboundRateLimit(mutate self, remoteChainSelector: uint64, amount: uint256) { + var config = self.data.remoteChainConfigs.mustGet(remoteChainSelector, TokenPool_Error.NonExistentChain as int); + var rateLimiters = config.rateLimiters.load(); + var bucket = rateLimiters.inbound.load(); + RateLimiter_consumeBucket(mutate bucket, amount); + rateLimiters.inbound = bucket.toCell(); + config.rateLimiters = rateLimiters.toCell(); + self.data.remoteChainConfigs.set(remoteChainSelector, config); + + // TODO: emit event with updated rate limiter state + // emit InboundRateLimitConsumed({token: token, remoteChainSelector: remoteChainSelector, amount: amount}); +} + +/// Consumes fast finality outbound rate limiting capacity in this pool. +/// @dev If fast finality rate limiter is not enabled for the chain, it will fallback to the default +/// rate limiter. +/// @param remoteChainSelector The remote chain selector. +/// @param amount The amount of tokens consumed. +fun TokenPool.consumeFastFinalityOutboundRateLimit(mutate self, remoteChainSelector: uint64, amount: uint256) { + var config = self.data.remoteChainConfigs.mustGet(remoteChainSelector, TokenPool_Error.NonExistentChain as int); + var fastRateLimiters = config.fastFinalityRateLimiters.load(); + var fastBucket = fastRateLimiters.outbound.load(); + if (!fastBucket.isEnabled) { + var rateLimiters = config.rateLimiters.load(); + var bucket = rateLimiters.outbound.load(); + RateLimiter_consumeBucket(mutate bucket, amount); + rateLimiters.outbound = bucket.toCell(); + config.rateLimiters = rateLimiters.toCell(); + } else { + RateLimiter_consumeBucket(mutate fastBucket, amount); + fastRateLimiters.outbound = fastBucket.toCell(); + config.fastFinalityRateLimiters = fastRateLimiters.toCell(); + } + self.data.remoteChainConfigs.set(remoteChainSelector, config); + + // TODO: emit event with updated rate limiter state + // emit FastFinalityOutboundRateLimitConsumed({token: token, remoteChainSelector: remoteChainSelector, amount: amount}); +} + +/// Consumes fast finality inbound rate limiting capacity in this pool. +/// @dev If fast finality rate limiter is not enabled for the chain, it will fallback to the default +/// rate limiter. +/// @param remoteChainSelector The remote chain selector. +/// @param amount The amount of tokens consumed. +fun TokenPool.consumeFastFinalityInboundRateLimit(mutate self, remoteChainSelector: uint64, amount: uint256) { + var config = self.data.remoteChainConfigs.mustGet(remoteChainSelector, TokenPool_Error.NonExistentChain as int); + var fastRateLimiters = config.fastFinalityRateLimiters.load(); + var fastBucket = fastRateLimiters.inbound.load(); + if (!fastBucket.isEnabled) { + var rateLimiters = config.rateLimiters.load(); + var bucket = rateLimiters.inbound.load(); + RateLimiter_consumeBucket(mutate bucket, amount); + rateLimiters.inbound = bucket.toCell(); + config.rateLimiters = rateLimiters.toCell(); + } else { + RateLimiter_consumeBucket(mutate fastBucket, amount); + fastRateLimiters.inbound = fastBucket.toCell(); + config.fastFinalityRateLimiters = fastRateLimiters.toCell(); + } + self.data.remoteChainConfigs.set(remoteChainSelector, config); + + // TODO: emit event with updated rate limiter state + // emit FastFinalityInboundRateLimitConsumed({token: token, remoteChainSelector: remoteChainSelector, amount: amount}); +} + +/// Returns the outbound and inbound rate limiter state for the given remote chain at the time of the call. +/// @param remoteChainSelector The remote chain selector. +/// @param fastFinality Whether to get the fast finality rate limiter state. +fun TokenPool.getCurrentRateLimiterState( + self, + remoteChainSelector: uint64, + fastFinality: bool, +): TokenPool_RateLimiterPair { + val config = self.data.remoteChainConfigs.mustGet(remoteChainSelector, TokenPool_Error.NonExistentChain as int); + if (fastFinality) { + val rateLimiters = config.fastFinalityRateLimiters.load(); + // TODO: recompute with _currentTokenBucketState + return TokenPool_RateLimiterPair { + outbound: rateLimiters.outbound, + inbound: rateLimiters.inbound, + }; + } + + val rateLimiters = config.rateLimiters.load(); + // TODO: recompute with _currentTokenBucketState + return TokenPool_RateLimiterPair { + outbound: rateLimiters.outbound, + inbound: rateLimiters.inbound, + }; +} + +/// Sets the rate limit configurations for specified remote chains. +/// @param rateLimitConfigArgs Array of structs containing remote chain selectors and their rate limiter configs. +fun TokenPool.setRateLimitConfig( + mutate self, + sender: address, + updates: SnakedCell, +) { + self.requireOwnerOrRateLimitAdmin(sender); + + var iter = updates.iter(); + while (!iter.empty()) { + val update = iter.next(); + var config = self.data.remoteChainConfigs.mustGet(update.remoteChainSelector, TokenPool_Error.NonExistentChain as int); + if (update.fastFinality) { + var fastRateLimiters = config.fastFinalityRateLimiters.load(); + // TODO: use setter RateLimiter._setTokenBucketConfig + fastRateLimiters.outbound = RateLimiter_tokenBucketFromConfig(update.outboundRateLimiterConfig.load()).toCell(); + fastRateLimiters.inbound = RateLimiter_tokenBucketFromConfig(update.inboundRateLimiterConfig.load()).toCell(); + config.fastFinalityRateLimiters = fastRateLimiters.toCell(); + } else { + var rateLimiters = config.rateLimiters.load(); + // TODO: use setter RateLimiter._setTokenBucketConfig + rateLimiters.outbound = RateLimiter_tokenBucketFromConfig(update.outboundRateLimiterConfig.load()).toCell(); + rateLimiters.inbound = RateLimiter_tokenBucketFromConfig(update.inboundRateLimiterConfig.load()).toCell(); + config.rateLimiters = rateLimiters.toCell(); + } + self.data.remoteChainConfigs.set(update.remoteChainSelector, config); + + // TODO: emit event with updated rate limiter config + // emit RateLimitConfigured( + // remoteChainSelector, + // configArgs.fastFinality, + // configArgs.outboundRateLimiterConfig, + // configArgs.inboundRateLimiterConfig + // ); + } + + // TODO: reply back to sender with excess +} + +/// Adds a pool address to the allowed remote token pools for a particular chain. +/// @param remoteChainSelector The remote chain selector for which the remote pool address is being added. +/// @param remotePoolAddress The address of the new remote pool. +fun TokenPool._setRemotePool(mutate self, mutate config: TokenPool_RemoteChainConfig, remotePoolAddress: Cell) { + assert(!TokenPool_isEmptyCrossChainAddress(remotePoolAddress), TokenPool_Error.ZeroAddressInvalid); + val poolHash = TokenPool_hashCrossChainAddress(remotePoolAddress); + assert(!config.remotePools.get(poolHash).isFound, TokenPool_Error.PoolAlreadyAdded); + // Add the pool to the mapping to be able to un-hash it later. + config.remotePools.set(poolHash, remotePoolAddress); +} + +fun TokenPool_ensureRequestedFinalityAllowed(requestedFinalityConfig: uint32, allowedFinalityConfig: uint32) { + if (requestedFinalityConfig == TOKEN_POOL_WAIT_FOR_FINALITY_FLAG) { + return; + } + assert(allowedFinalityConfig != TOKEN_POOL_WAIT_FOR_FINALITY_FLAG && requestedFinalityConfig == allowedFinalityConfig, TokenPool_Error.InvalidRequestedFinality); +} + +fun TokenPool_hashCrossChainAddress(value: Cell): uint256 { + var cs = value.beginParse(); + val addressBytes = CrossChainAddress.unpackFromSlice(mutate cs); + cs.assertEnd(); + return keccak256(beginCell().storeSlice(addressBytes)); +} + +fun TokenPool_isEmptyCrossChainAddress(value: Cell): bool { + var cs = value.beginParse(); + val addressBytes = CrossChainAddress.unpackFromSlice(mutate cs); + cs.assertEnd(); + return addressBytes.remainingBitsCount() == 0; +} + +fun TokenPool_boxCrossChainAddress(addressBytes: CrossChainAddress): Cell { + var addressSlice = addressBytes; + val bits = addressSlice.remainingBitsCount(); + assert(bits % 8 == 0, TokenPool_Error.OverflowDetected); + val pureAddressBits = addressSlice.loadBits(bits); + return beginCell() + .storeUint(bits / 8, 8) + .storeSlice(pureAddressBits) + .endCell() as Cell; +} + +fun TokenPool_pow10(exponent: uint8): uint256 { + var i: uint8 = 0; + var result: uint256 = 1; + while (i < exponent) { + result *= 10; + i += 1; + } + return result; +} diff --git a/contracts/contracts/ccip/pool/tolk-1.4-docs.md b/contracts/contracts/ccip/pool/tolk-1.4-docs.md new file mode 100644 index 000000000..598af4886 --- /dev/null +++ b/contracts/contracts/ccip/pool/tolk-1.4-docs.md @@ -0,0 +1,987 @@ +This update is mostly about making Tolk contracts understandable not only by humans, but also by all **tools around the ecosystem**. + +Tolk already has a rich type system, auto-serialization, TON-specific concepts deeply integrated, and all the language features needed for smart contracts. In v1.4, we expose this knowledge outside the compiler: + +1. ABI export — for toolchain, explorers, UI +2. TypeScript wrappers for Tolk contracts +3. Source maps that map TVM execution back to Tolk source, variables, stack layout, and call frames +4. Debugger marks that enable step-by-step debugging of fully-optimized production contracts +5. Several language enhancements (continue the direction of a general-purpose language) + +ABI and source maps are the final pieces of my initial vision — exactly as I saw how all branches merge together, more than a year ago. So, let's explore how it looks like. + + + +# The `contract` keyword + +A contract file can now start with a `contract` declaration: + +```tolk +contract Counter { + author: "Tolk Team" + version: "0.1" + description: "A small counter contract" + + storage: ContractStorage + incomingMessages: Increment | Reset +} + +// ... all the rest of code unchanged: +// - types and declarations +// - onInternalMessage +// - get methods +``` + +## What does `contract` mean + +The directive is not a runtime thing, it does not affect bytecode at all. It is a declaration for tooling: "this source file is a contract, and these are the public shapes that describe it." + +You place `contract` in the same file with entrypoints: `onInternalMessage`, get methods, etc. If you have several contracts in a project (say, `JettonMinter` and `JettonWallet`) — you have several files with `onInternalMessage`, and you precede every file with a `contract` directive. + +For example. File `JettonMinter.tolk` (it's now the preferred PascalCase naming: a contract's filename is equal to its name): + +```tolk +import "..." +import "..." + +contract JettonMinter { + author: "..." + storage: MinterStorage + incomingMessages: MinterMessages +} + +// you still declare internal types, as earlier +// think of it like "implementation" + +struct MinterStorage { + ... +} + +type MinterMessages = Message1 | Message2 | Message3 + +// you still declare entrypoints, as earlier +// think of it like "public interface" + +fun onInternalMessage(in: InMessage) { ... } +fun onExternalMessage(body: slice) { ... } + +get fun minterMethod1() { ... } +get fun minterMethod2() { ... } +``` + +So, is it a breaking change? No! Everything still works without `contract` — and with it. If you add `contract`: +- you emphasize that it's a contract file +- you get ABI support and TypeScript wrappers +- all the tooling can interact with your contract via ABI +- some importing rules become more strict, read below + +## Declare ALL `get fun` in the same file + +Before Tolk v1.4, it was possible (and somebody used it) to split `get fun` across multiple files: + +``` +// file: separate-getter.tolk +get fun method1() { ... } + +// file: main.tolk +import "separate-getter" + +get fun method2() { ... } +``` + +The `contract` prohibits this: all entrypoints must exist in the same file, they cannot be imported. This is for clarity: when you explore a contract file, you should see all its "interface" as a whole. + +``` +// file: MyContract.tolk +import "separate-getter" // compilation error + +contract MyContract { ... } +``` + +You'll see an error to place all entrypoints in `MyContract.tolk`. + +So, rule1: keep `contract`, `onInternalMessage`, `onExternalMessage`, and `get fun` together — one file to expose the entire "interface". + +## `import "MyContract"` does NOT import its entrypoints + +Before Tolk v1.4, when you import a file with `get fun`, they become available implicitly. That's why managing multiple contracts in one project required accuracy: from "JettonMinter" you couldn't just import "JettonWallet", because it conflicted on `onInternalMessage` duplicate. You had to extract common parts to separate files (e.g. MinterStorage and WalletStorage in `storage.tolk`, all available messages, etc.). + +With Tolk v1.4, this becomes simpler: `import "MyContract"` with `contract MyContract` inside does NOT expose entrypoints. User-defined types work as earlier, but `onInternalMessage` and `get fun` are logically "part of a contract" and are not visible outside. + +This enables two interesting patterns. + +Pattern 1. You have a contract, and you write scripts or tests as standalone files: + +``` +import "Counter" // with `contract Counter` + +// tests are written as get methods, +// they do not conflict with `get fun` of Counter.tolk + +get fun `test increase does not overflow`() { + // use symbols from "Counter.tolk" as expected + val initial = Storage { + value: 0 + }; +} + +// you can even declare `main` (TVM method_id=0), +// it does not conflict with `onInternalMessage` +fun main() { + createMessage({ + body: CounterIncrement { + // ... + } + }) +} +``` + +Pattern 2. You have multiple contracts, and you can import one from another — you see all declarations, but entrypoints do not conflict, they "belong" to each `contract` specifically. + +``` +// file: JettonWallet.tolk + +contract JettonWallet { ... } + +struct WalletStorage { ... } + +struct MsgA { ... } +struct MsgB { ... } +type WalletMessages = MsgA | MsgB + +fun onInternalMessage() { ... } + +get fun walletMethod1() { ... } +``` + +``` +// file: JettonMinter.tolk +import "JettonWallet" + +contract JettonMinter { ... } + +// use WalletStorage, MsgA, etc. + +fun deployJW() { + val initial = WalletStorage { ... }; + // ... +} + +// and declare minter's entrypoints + +fun onInternalMessage() { ... } + +get fun minterMethod1() { ... } +``` + +All in all, `contract` specifier tells: +1. This file is a contract file, all its "public interface" exists solely in this file +2. This file, being imported, does not pollute outer scope with "public interface" + +## What properties can be specified in `contract` + +In practice, you'll specify `author`, `storage`, and `incomingMessages`. But generally, there are other fields which may also be useful: + +``` +contract SomeName { + /// arbitrary string, exported to ABI as-is + author: "Tolk team" + + /// arbitrary string (preferably semver), exported as-is + version: "1.0" + + /// arbitrary string, exported as-is + description: "..." + + /// tells what shape persistent on-chain data has + storage: MyStorage + + /// specified if storage has another shape AT DEPLOYMENT + /// (when calculating initial address); + /// example: NFT, when at deployment it's {itemIndex,collectionAddr}, + /// and after initialization it's enriched with {owner,content}; + /// then PartialStruct has 2 fields, and MyStorage has 4 + storageAtDeployment: PartialStruct + + /// internal messages that are accepted by this contract; + /// typically you use the same union as for `lazy` match + incomingMessages: UnionOfStructs + + /// if your contract has `onExternalMessage`, + /// you can specify which shape of a `slice` you expect; + /// typically use that struct/union for `lazy` fromSlice + incomingExternal: SomeStructOrUnion + + /// (rarely used, to override auto-calculated) + /// outgoing internal messages that a contract may send; + /// if not set, calculated by `createMessage` calls + outgoingMessages: UnionOfStructs + + /// (rarely used, to override auto-calculated) + /// outgoing external messages (aka "events") that may be emitted; + /// if not set, calculated by `createExternalLogMessage` calls + emittedEvents: UnionOfStructs + + /// (rarely used, to override auto-calculated) + /// exception codes that may be thrown (should be a enum); + /// if not set, calculated by `throw` / `assert` / etc. + thrownErrors: SomeEnum + + /// additional types that should appear in ABI even if + /// they are not reachable from storage/messages/getters; + /// for example, to use them in TypeScript unit tests + forceAbiExport: (type1, type2, ...) +} +``` + +As a conclusion, `contract` specifies some properties that cannot be inferred from source code — and combined with source code, are exported as a public ABI. + +
+ +# Contract ABI export + +Before, Tolk code was compiled into Fift and TVM bytecode, but external tools still had to guess a lot: what messages the contract accepts, what storage shape it uses, what get methods exist, and how client-side values should be represented. + +Tolk v1.4 emits a machine-readable ABI JSON directly from Tolk sources. + +## Goals of having ABI + +ABI of a contract gives all necessary information for the following purposes: + +```text +Tolk -> ABI -> TypeScript wrappers + dynamic serialization + stack layout info + print any Tolk object to console + render a contract in explorer + build UI to send a message + build UI to invoke a get method + ... +``` + +## ABI JSON artifact + +Being invoked from a command-line, + +```bash +tolk -o out.fif Counter.tolk +``` + +The compiler outputs `out.abi.json` next to `out.fif`. + +**This ABI contains:** + +* contract name, author, version, description +* internal messages a contract accepts +* external messages, if any +* outgoing messages a contract sends by `createMessage` +* emitted events a contract writes by `createExternalLogMessage` +* storage shape a contract has +* storage at deployment for address calculation, if differs +* contract getters with parameters and returns +* exceptions a contract may throw +* user-defined declarations (structs, aliases, enums) +* a list of unique types where declarations point to +* Tolk compiler version + +## Example of abi.json + +`out.abi.json` looks like this: + +```json +{ + "abi_schema_version": "1.0", + "contract_name": "TolkCounter", + "unique_types": [ + {"kind":"void"}, + {"kind":"int"}, + {"kind":"slice"}, + {"kind":"cell"}, + {"kind":"builder"}, + {"kind":"bool"}, + {"kind":"coins"}, + {"kind":"address"}, + {"kind":"intN","n":32}, + {"kind":"uintN","n":32}, + {"kind":"intN","n":64}, + {"kind":"uintN","n":64}, + {"kind":"StructRef","struct_name":"IncreaseCounter"}, + {"kind":"StructRef","struct_name":"ResetCounter"}, + {"kind":"StructRef","struct_name":"Storage"} + ], + "struct_instantiations": [ + ], + "alias_instantiations": [ + ], + "declarations": [ + { + "kind": "struct", + "name": "Storage", + "ty_idx": 14, + "fields": [ + { + "name": "id", + "ty_idx": 9 + }, + { + "name": "counter", + "ty_idx": 9 + } + ] + }, + { + "kind": "struct", + "name": "IncreaseCounter", + "ty_idx": 12, + "prefix": { + "prefix_num": 2122802415, + "prefix_len": 32 + }, + "fields": [ + { + "name": "queryId", + "ty_idx": 11 + }, + { + "name": "increaseBy", + "ty_idx": 9 + } + ] + }, + { + "kind": "struct", + "name": "ResetCounter", + "ty_idx": 13, + "prefix": { + "prefix_num": 980758278, + "prefix_len": 32 + }, + "fields": [ + { + "name": "queryId", + "ty_idx": 11 + } + ] + } + ], + "storage": { + "storage_ty_idx": 14 + }, + "incoming_messages": [ + { + "body_ty_idx": 12 + }, + { + "body_ty_idx": 13 + } + ], + "incoming_external": [ + ], + "outgoing_messages": [ + ], + "emitted_events": [ + ], + "get_methods": [ + { + "tvm_method_id": 117456, + "name": "currentCounter", + "parameters": [ + ], + "return_ty_idx": 1 + }, + { + "tvm_method_id": 71937, + "name": "initialId", + "parameters": [ + ], + "return_ty_idx": 1 + } + ], + "thrown_errors": [ + { + "kind": "plain_int", + "err_code": 65535 + } + ], + "compiler_name": "tolk", + "compiler_version": "1.4.0" +} +``` + +Note: ABI is hard to read. For instance, it contains `unique_types`, which are referenced by indexes: `body_ty_idx`, `return_ty_idx`, etc. But JSON is not targeted to be read by eye: it's targeted for machine parsing. + +## How the compiler calculates all these fields + +Almost everything can be calculated automatically by contract's source code. For example: + +* outgoing messages — by inspecting `createMessage` and `TBody` within it +* exceptions — by inspecting `throw` and `assert` with constants/enums +* getters — by `get fun` +* etc. + +But some fields can NOT be automatically detected — those are provided in `contract` manually: + +* author, description +* incoming messages +* shape of storage + +A reasonable question: **why can't the compiler detect incoming messages**? The answer is: contract's code is not declarative, it's imperative. Yes, most likely, you use a union with `lazy` match. But generally, you can split this union into several; use manual parsing and opcodes; want to hide admin messages from ABI; etc. Same goes for storage: from the compiler's perspective, `MyStorage` is a regular struct, you call `fromCell` and `toCell` in arbitrary places, it does not differ from any other struct. That's why, instead of fragile heuristics, I decided to always require specifying those fields from the user's side. And it's also better for the reader. + +## Doc comments as description + +Place `/// doc comment` over every struct/field/enum — they go as "description" to ABI, and therefore will be rendered as TypeScript comments, in UI, etc. + +```tolk +/// Persistent contract data +struct (0x12345678) ContractStorage { + /// Current counter value + counter: int32 + + /// Contract owner + owner: address +} + +/// Reads current counter. +/// @param verbose whether to include debug info +get fun currentCounter(verbose: bool): (int32, cell?) { + ... +} +``` + +The compiler parses only `///` comments. They must be placed strictly above declarations, they are not allowed to be inside regular code — use simple `//` comments there. + +For the example above, ABI will contain descriptions: + +``` + declarations: [ + { + "kind": "struct", + "name": "ContractStorage", + "fields": [ + { + "name": "counter", + "ty_idx": 123, + "description": "Current counter value" + }, + { + "name": "owner", + "ty_idx": 124, + "description": "Contract owner" + } + ] + } + ], + "get_methods": [ + { + "tvm_method_id": 117456, + "name": "currentCounter", + "parameters": [ + { + "name": "verbose", + "ty_idx": 125, + "description": "whether to include debug info" + } + ], + "return_ty_idx": 126, + "description": "Reads current counter." + } + ], +``` + +A good manner is also to use descriptions for error codes. Then, in case of exceptions, UI and IDE will be able to provide details from a comment. + +``` +enum ErrCode { + /// Sender is not allowed to perform this action. + NotOwner = 401 +} +``` + +## Special annotation `@abi.clientType` + +Sometimes the on-chain type is intentionally low-level, but client tools should see a more convenient shape. + +For example, `forwardPayload` in jettons is often just `slice`: we don't want to waste gas on validation and carrying a union. But for external clients (TypeScript, explorers, etc.) we want to expose it "inline payload or ref payload": + +```tolk +struct AskToTransfer { + // ... + @abi.clientType(PayloadInline | PayloadInRef) + forwardPayload: RemainingBitsAndRefs +} +``` + +The compiler still type-checks and serializes the real field as `RemainingBitsAndRefs`, but ABI emits it as a union (`client_ty_idx` in a field). + +This is a way to hide "implementation details" while exposing schema-described public contract interface. + +## Defining ABI for existing FunC contracts + +Imagine, you have an existing FunC contract (deployed to mainnet, so you are not going to rewrite it), and you want to use TypeScript generator. What are required steps? + +One might think, that he should write a JSON manually. But it's an incorrect path. + +The answer is: **decribe FunC's interfaces in Tolk** and generate ABI from that fake contract. + +``` +contract SwapalkaInFunC { + incomingMessages: A | B | C + outgoingMessages: D | E | F + storage: S + thrownErrors: ErrCodes +} + +// declare types mentioned in `contract` + +struct (0x12345600) A { ... } +struct (0x12345601) B { ... } +// ... + +enum ErrCodes { + NotAdmin = 401, + InsufficientBalance = 402, + ... +} + +// declare get methods and their types + +struct CalcSwapCostReply { + from: address + to: address + cost: coins +} + +get fun calc_swap_cost(from: address): CalcSwapCostReply { + // to satisfy the type system, we need to return something; + // not very beautiful, but let it be this way for now + return { + from: FAKE_ADDR, + to: FAKE_ADDR, + cost: 0, + } +} + +// and an empty entrypoint + +fun onInternalMessage() { +} +``` + +It's also a valid contract — without any body — and sufficient for ABI generation. Using `///` comments will enrich ABI with descriptions. + +You might also notice why `outgoingMessages` and `thrownErrors` are useful. In practice, they are auto-calculated by `createMessage`, `throw`, etc. But in case you are "just describing ABI" they are the key. Also they are helpful if you are writing a proxy contract that does not `createMessage` itself — it sends an already composed message cell. Then you can describe types of those implicit messages for explorers/UI/etc. + +## ABI in tonscan / tonviewer / TON Center / TonAPI / etc. + +In the near future, we'll work with other teams to bring ABI support across TON ecosystem. + +For instance, explorers have lots of heuristics and implicit conventions to render messages and transactions in UI. Ideally, this layer should be standartized and be fully based on ABI standard. ABI for existing contracts may be described in a way shown above. + +## Side note: ABI is based on Tolk types, NOT on TL-B + +Experienced FunC developers tend to ask questions like "How to generate a TL-B schema for a Tolk structure?". Or — alternatively — "we already have a TL-B codegenerator, so ABI should probably reuse TL-B tooling". + +Such reasoning leads in the wrong direction — because the Tolk **type system** is designed as a **replacement for TL-B**. + +There is no need to "provide a TL-B schema for a contract". Every Tolk `struct` **is already a schema**. + +**TL-B and the Tolk type system are not equivalent**, even if they look similar at first glance. + +Similarities include: + +- `intN`, `uintN`, `bitsN` +- `Maybe` (nullable), `Either` (a two-component union) +- multiple constructors (declared structs + prefixes + unions) +- cells and typed cells + +But the differences are essential. + +TL-B supports the following (not expressible in Tolk): + +- `~tilde` +- `{conditions}` +- dynamic `## n` + +Tolk supports the following (not expressible in TL-B): + +- type aliases +- enums +- inline unions (auto-generated prefix trees) +- tensors +- custom `packToBuilder` and `unpackFromSlice` +- `address?` as "internal or none" (not "maybe T") + +Moreover: ABI is not only about serialization, but also about stack layout, because get methods work via the stack. + +The conclusion is simple: to make ABI sufficient for all scenarios, **it must rely on the type system, not on TL-B**. + +## How exactly types are represented in ABI + +Type representation in ABI covers all nuances of the type system. Even though it might seem simple, there are lots of corner cases. For example: + +- how are typed cells represented? +- how are generic structs and aliases described? +- how to serialize unions with prefix trees? +- how to read a union from a TVM stack? +- how to deal with `packToBuilder` and `unpackFromSlice`? + +ABI gives extensive information to answer all these questions and do any interaction with a contract solely having its ABI. + +Since this piece of information is very big, I will not include it in this description. Instead, I'll provide a comprehensive README in a separate repo, where ABI is used on the client side: in a TypeScript wrappers generator. + + + +# TypeScript wrappers for Tolk contracts + +Aside from the `ton-blockchain` repo, I have implemented a TypeScript generator based on ABI. The compiler emits ABI, the only source of truth: + +``` +Tolk -> ABI -> TypeScript wrappers + -> Go wrappers + -> Rust wrappers + -> Python wrappers + -> JSON marshalling + -> Tolk declarations +``` + +Currently, only TypeScript generator is ready, but others are only a matter of time. + +## Why TypeScript wrappers are needed + +A contract in a blockchain is "the backend" layer. In practice, you have a dApp — frontend — that somehow interacts with a contract: sends messages, calls get methods, etc. In order to compose message cells and properly manipulate a TVM stack, you manually had to mirror your contract's "interface" in TypeScript — a boring and error-prone work. Now it's fully automated. + +All in all, you use TypeScript for +- frontend and UI, to interact with contracts +- end-to-end tests, involving offchain and onchain +- cumbersome on-chain scripting + +## What TypeScript wrappers contain + +For every `contract`, a single `ContractName.gen.ts` file contains: + +- all structs exposed as TS interfaces; each can be serialized to a builder and deserialized from a slice, identically to how Tolk compiler does it +- all type aliases as TS type aliases +- all enums exposed as TS enum-like objects (not TS enums, they don't support bigint) +- private helpers to compose address, StateInit, and sharding +- private helpers to manipulate TVM stack +- a class `ContractName` with high-level methods: send messages, compose message cells, call get methods + +TypeScript generator supports all nuances of the Tolk type system, even generics and unions. This sounds simple, but when you think deeper, it becomes absolutely unobvious. For example, `int64` in Tolk translates to `bigint` in TypeScript. But how `int64 | int128` should look like? `bigint | bigint` makes no sense, then how? + +Anyway, since I managed to solve all issues at the border between Tolk (statically typed, compiled) and TypeScript (dynamically typed, interpreted), wrappers for other languages look promising. + +## How to use the TypeScript generator + +Proceed to a dedicated repo: + +https://github.com/ton-blockchain/tolk-abi-to-typescript + +
+ +# Source maps and debugger + +Tolk v1.4 introduces compiler-side **source maps**. For the end user, they are the foundation of: +- debugger +- coverage +- unwinding on TVM exception + +All these features are released together with v1.4 in the toolchain (read below). + +The goal is simple to say and very hard to implement: + +*"Given a TVM execution point, determine the original Tolk source location, current function, call stack, initialized variables, and their values."* + +The most curious thing about source maps: they work for **for fully-optimized production Tolk contracts**. No "disable optimizations" mode, no bytecode modification. + +Tolk still inlines functions, folds constants, performs lazy deserialization, and emits optimized bytecode. Nevertheless, source maps provide all info to remap execution state back. + +## Where source maps are useful + +For example, a contract fails with exit code 9. Earlier, you had to manually explore TVM logs, study generated assembler, manually mapping assembler code to original Tolk sources (which is a very hard task), trying to reconstruct the original trace and what *actually* happened. + +Now, you automatically have: + +- an exact location of the exception +- call stack (including inlined functions!) +- all local variables in every call frame (including already disappeared from a stack!) +- all TVM registers +- all global variables +- all deserialized contents of typed cells + +And again — this all works WITHOUT bytecode modification. + +## Step-by-step debugger + +Since we have an ability to calculate TVM state at every asm instruction (due to source maps), we introduce a real step-by-step debugger, working via DAP — Debugger Adapter Protocol — supported by all major IDEs. + +You can just click "debug" in VS Code or JetBrains, and evaluate a request step by step: + +- see all variables and how they change +- all `lazy` objects (even if their fields were not loaded yet!) +- step over, step into, step out (even into inlined functions!) +- use breakpoints and run to cursor +- stop on uncaught exception +- and more, exactly as you expect from a debugger + +This provides awesome experience, compared to modern Web2 languages — but working inside TVM. + +Moreover — you can take a transaction hash from a real mainnet, and debug it step-by-step — from a real network. A transaction failed in mainnet? No problem, just debug it in IDE (if you have sources of that contract, of course). That would be impossible if we used "disable optimizations" for debugging — but we do not, that's why it works. + +## How exactly source maps and debugger work + +The architecture of debugging fully-optimized contracts is very complicated. It involves tricks in the compiler, ABI core, patched Fift, patched TVM, and a standalone replayer that combines all artifacts and literally *emulates* (replays) transaction flow. + +I will not explain this machinery here, in MR's description — otherwise, the description will become too large to be analyzed. Instead, I'll provide a dedicated document "How the debugger works" in the near future. + +## How to try the debugger + +The debugger comes a part of Acton toolchain. Read below. + + + + +# Several language enhancements + +In Tolk v1.3 I introduced many new language features that are primarily not for contracts, but for libraries and frameworks. In a way, Tolk becomes more general-purpose language. + +Tolk v1.4 also brings some improvements in this direction. + +### Closures (lambdas with captures) + +Lambdas without capturing already existed in Tolk. Now they can capture outer variables and really become first-class functions: + +```tolk +fun makeAdder(delta: int): int -> int { + return fun(value) { + return value + delta; + }; +} + +fun demo() { + val add3 = makeAdder(3); + return add3(10); // 13 +} +``` + +There is no special `use` or `[&]` syntax: capturing is done automatically. + +Variables are captured by value, at the exact point where a lambda is created. Mutations become independent: + +```tolk +fun demo() { + var x = 10; + + val cb = fun() { + return x + 1; + }; + + x = 20; + return cb(); // 11, not 21 +} +``` + +Lambdas and capturing work with generics, nesting, and smart casts. For instance, if `v` is smart-casted at the point where the lambda is created, the closure captures that narrowed type. + +### Optional `void` parameters + +Tolk already allowed `void` fields to be omitted in object literals: + +```tolk +struct S { + x: int + marker: void +} + +val s = S { x: 10 }; // marker is omitted +``` + +For instance, `body` of `createMessage` can be omitted, because its type defaults to `TBody = void`. + +Now the same convention applies to function parameters. + +If a trailing parameter has type `void`, it may be omitted: + +```tolk +fun format(msg: string, arg1: T1, arg2: T2) { + ... +} + +format("hello"); +format("value is {}", 42); +format("pair is {} and {}", "str", beginCell()); +``` + +This is especially convenient for generic helpers where "no argument" is represented by `void`, not by an artificial nullable wrapper or a pile of overloads. + +### `void` inside unions for serialization + +`T | void` is a valid union now, and it also can be (de)serialized. `void` here means "empty slice". + +This allows to express "maybe zero bits" in serialization. Unlike `T | null`, which requires at least one bit (0 or 1+T), `T | void` means NOTHING or T. + +For example: +- `int32 | void` — either int32 or nothing +- `A | B | C | void` — either empty slice, or some of those variants +- `int8 | null | void` — empty / 0 / 1+int8 + +In other words, `void` does not participate in prefix tree. On deserialization, it's a special case: if a slice is empty, `void` is saved. On serialization, if active variant is `void`, nothing is written. + +Since it's a regular type, after deserialization, it can be tested with `someVar is void`, or `match (v) { int32 => ... void => ... }`, etc. + +Using `Cell | void` we can describe an imperative chain of wallet-v5 payload "parse cells until refs exist" that is unrepresentable with TL-B. + +### Numeric separators + +Integer literals can now contain `_` separators: + +```tolk +const A = 1_000_000; +const B = 0x_ABCD_EF01; +const C = 0b_1010_1011_0000; +``` + +### Enums are assignable to integers + +Enums are distinct types, but enum values can now be assigned to integer variables without `as` cast: + +```tolk +var x: int = Color.Red; +var y: int32 = VmExitCode.OutOfGasError; +``` + +This looks a bit strange for decorative enums like `Color`, but it is very convenient for enums that represent TVM exit codes, operation ids, modes, and other numeric constants. + +This does not mean that enums silently become integers everywhere. For example: + +```tolk +1 + Color.Blue; // still an error +``` + +### Breaking change: only `bool` in conditions + +This is the biggest language-level breaking change in v1.4. + +Before, Tolk allowed integers in conditions: + +```tolk +if (x) { ... } +while (coinsAmount) { ... } +assert (flags) throw 123; +``` + +Now conditions must be `bool`. Write explicitly: + +```tolk +if (x != 0) { ... } +while (coinsAmount != 0) { ... } +assert (flags != 0) throw 123; +``` + +This applies to: `if`, `while`, `do while`, ternary condition, and `assert`. + +Similarly, unary `!` accepts only `bool` now: use not `if (!num)`, but `if (num == 0)`. + +While using integers as conditions is common in C-like languages, we decided to make it stricter. + +Note: there is **no gas overhead**. Writing `x != 0` does not mean that the compiler blindly emits `0 NEQINT`. The lowering detects this pattern and strips the comparison off. The source code becomes more explicit, while bytecode stays efficient. + +## `do while` scope is now conventional + +The `do while` scoping has been aligned with other languages. + +Before, the condition could see variables declared inside the loop body: + +```tolk +do { + var found = ... +} while (found); +``` + +Now this is an error: + +```text +undefined symbol `found` +``` + +Declare the variable before the loop: + +```tolk +var found: bool; +do { + found = ... +} while (found); +``` + +To be honest, I changed this behavior due to AI agents: they argue on non-standard scoping while reading Tolk contracts, thinking it's an error. No languages (except FunC, and Tolk consequently) allow "leaking" loop's body to condition. So, this change removes this exception and makes `do while` consistent with block scopes everywhere else. + +## Several bug fixes found through LLM fuzzing + +Traditionally, we had some research and bug bounty reports targeting invalid compiler behavior in corner cases. Most of the findings are false positives, but some of them make sense and should be fixed. None of them could appear in real straightforward code, only in artificial scenarios you'd very unlikely face with. + +For instance: + +- tricky recursive generics leading to infinite stack size +- more accurate handling of `never` type +- smart casts in loops up to a fixed control flow point +- mixture of generics and asm functions +- and similar + +## Migrating from v1.3 to v1.4 + +As a conclusion, a quick migration guide: + +1. Add `contract` directive above each `onInternalMessage`. If `get fun` are implicitly imported, you'll get an error. Then place them below: `contract` requires the whole public interface to be visible in one file. You can leave common implementation shared, but each contract must declare `get fun` independently. + +2. Facing an error "can not use `int` as a boolean condition", replace `if (someNumber)` with `if (someNumber != 0)`. This applies to `if`, `while`, `assert`, and ternary. + +3. Facing an error "undefined symbol `x`" in condition of `do while` body, move `x` lateinit declaration before the loop, as shown above. + + +
+ +# Acton: a unified toolchain for TON + +Together with Tolk v1.4, we are releasing a **TON toolchain** named Acton. + +## Modern replacement for blueprint + +When Tolk appeared, it made FunC feel like the old world. Tolk is not just "a bit better" — it feels like a different era. + +Now we are doing the same for the entire on-chain development stack. + +We are releasing Acton — all-in-one toolchain for project management, testing, scripting, debugging, deployment, and more. Not a bunch of utilites — a full development environment built as one coherent system around Tolk. + +## What features are bundled into Acton + +* Project management. Contracts, unit tests, integration tests, and ready-to-use templates. + +* Native tests in Tolk — not in TypeScript. Not only unit tests — but chains of transactions. 50x faster than the current JS sandbox. Mutation testing, fuzzing testing, and even fork testing — loading account states from mainnet on demand. + +* A real debugger. Test failed with exit code 9? Stop exactly at the exception, inspect the call stack, local variables, lazy fields, and more. + +* Faucet and deployment. Work with wallets locally, top-up on testnet with embedded faucet. On-chain scripts are also written in Tolk. + +* Transaction visualization. Inspect transaction trees, messages, fees, storage changes — for every test, in a clean dev-oriented UI. + +* IDE integration, linter, formatter, code coverage, gas profiling. + +* AI-friendly. Skills and manuals available out of the box. Acton is a modern CLI tool that becomes an agent's runtime. + +Note that everything became possible, because Tolk is not limited by contracts — it's now a general-purpose language. The type system, ABI, and source maps join together to provide the kernel. All other pieces — 100k+ lines of Rust code — were carefully written by my teammates. + +## How to try Acton + +**https://ton-blockchain.github.io/acton/** + + + +# Related pull requests + +- https://github.com/ton-blockchain/tolk-js/pull/19 +- https://github.com/ton-blockchain/tolk-bench/pull/6 +- https://github.com/ton-org/docs/pull/2150 +- TypeScript generator: https://github.com/ton-blockchain/tolk-abi-to-typescript +- Agent skills: https://github.com/ton-blockchain/skills +- Acton contracts repo: https://github.com/ton-blockchain/acton-contracts +- Acton: https://ton-blockchain.github.io/acton/ + diff --git a/contracts/contracts/ccip/pool/types.tolk b/contracts/contracts/ccip/pool/types.tolk new file mode 100644 index 000000000..120b4bf06 --- /dev/null +++ b/contracts/contracts/ccip/pool/types.tolk @@ -0,0 +1,166 @@ +// SPDX-License-Identifier: BUSL-1.1 +import "rate_limiter" +import "../common/types" +import "../rmn_remote/lib" +import "../../lib/utils" + +const TOKEN_POOL_WAIT_FOR_FINALITY_FLAG: uint32 = 0; +const TOKEN_POOL_DEFAULT_FINALITY: uint32 = TOKEN_POOL_WAIT_FOR_FINALITY_FLAG; +const TOKEN_POOL_BPS_DIVIDER: uint256 = 10000; +const TOKEN_POOL_MAX_UINT256: uint256 = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; +const TOKEN_POOL_MAX_EXP10: uint8 = 77; + +// The number of bytes in the return data for a pool v1 releaseOrMint call. +// This should match the size of the ReleaseOrMintOutV1 struct. +const CCIP_POOL_V1_RET_BYTES = 32; + +// The default max number of bytes in the return data for a pool v1 lockOrBurn call. +// This data can be used to send information to the destination chain token pool. Can be overwritten +// in the TokenTransferFeeConfig.destBytesOverhead if more data is required. +const CCIP_LOCK_OR_BURN_V1_RET_BYTES = 32; + +struct TokenPool_DynamicConfig { + router: address; + rateLimitAdmin: address?; + feeAdmin: address?; +} + +struct TokenPool_MirroredPolicy { + onRamps: map; + offRamps: map; + cursedSubjects: CursedSubjects; +} + +struct TokenPool_RampUpdate { + remoteChainSelector: uint64; + onRamp: address? = null; + offRamp: address? = null; +} + +struct TokenPool_RateLimiterPair { + outbound: Cell; + inbound: Cell; +} + +struct TokenPool_RateLimitConfigPair { + outbound: Cell; // Outbound rate limited config, meaning the rate limits for all of the onRamps for the given chain. + inbound: Cell; // Inbound rate limited config, meaning the rate limits for all of the offRamps for the given chain. +} + +struct TokenPool_ChainUpdate { + remoteChainSelector: uint64; // Remote chain selector. + remotePoolAddresses: SnakedCell; // Address of the remote pool, ABI encoded in the case of a remote EVM chain. + remoteTokenAddress: Cell; // Address of the remote token, ABI encoded in the case of a remote EVM chain. + rateLimitConfigs: Cell; // Rate limiter configs. +} + +struct TokenPool_RemoteChainConfig { + remoteTokenAddress: Cell; // Address of the remote token, ABI encoded in the case of a remote EVM chain. + // TODO: EnumerableSet.Bytes32Set remotePools; + remotePools: map>; // Set of remote pool hashes, ABI encoded in the case of a remote EVM chain. + rateLimiters: Cell; // Rate limiter configs. + + // TODO: N/A in EVM RemoteChainConfig + fastFinalityRateLimiters: Cell; +} + +struct TokenPool_RateLimitConfigArgs { + remoteChainSelector: uint64; // Remote chain selector. + fastFinality: bool; // Whether the rate limit config is for fast finality transfers. + outboundRateLimiterConfig: Cell; // Outbound rate limiter configuration. + inboundRateLimiterConfig: Cell; // Inbound rate limiter configuration. +} + +/// Struct with args for setting the token transfer fee configurations for a destination chain and a set of tokens. +struct TokenPool_TokenTransferFeeConfigArgs { + destChainSelector: uint64; // Destination chain selector. + tokenTransferFeeConfig: TokenPool_TokenTransferFeeConfig; // Token transfer fee configuration. +} + +// TODO: triage new types below + +struct TokenPool_LockOrBurnPrepared { + request: TokenPool_LockOrBurnInV1; + requestedFinalityConfig: uint32; + tokenArgs: cell?; + feeAmount: uint256; + destTokenAmount: uint256; + usingFastFinality: bool; + out: TokenPool_LockOrBurnOutV1; +} + +struct TokenPool_ReleaseOrMintPrepared { + request: TokenPool_ReleaseOrMintInV1; + requestedFinalityConfig: uint32; + localAmount: uint256; + usingFastFinality: bool; + out: TokenPool_ReleaseOrMintOutV1; +} + +// IPoolV2 + +// TODO: reorder the fields in the struct +// struct TokenTransferFeeConfig { +// uint32 destGasOverhead; // ──────────╮ Gas charged to execute the token transfer on the destination chain. +// uint32 destBytesOverhead; // │ Data availability bytes. +// uint32 finalityFeeUSDCents; // │ Fee to charge for token transfer with default (wait-for-finality) finality, multiples of 0.01 USD. +// uint32 fastFinalityFeeUSDCents; // │ Fee to charge for token transfer with fast finality (FTF), multiples of 0.01 USD. +// // │ The following two fee is deducted from the transferred asset, not added on top. +// uint16 finalityTransferFeeBps; // │ Fee in basis points for default finality transfers [0-10_000]. +// uint16 fastFinalityTransferFeeBps; //│ Fee in basis points for custom finality transfers [0-10_000]. +// bool isEnabled; // ──────────────────╯ Whether this config is enabled. +// } + +struct TokenPool_TokenTransferFeeConfig { + isEnabled: bool; + finalityFeeUSDCents: uint256; + fastFinalityFeeUSDCents: uint256; + destGasOverhead: uint32; + destBytesOverhead: uint32; + finalityTransferFeeBps: uint16; + fastFinalityTransferFeeBps: uint16; +} + +enum TokenPool_MessageDirection: uint8 { + Outbound = 0 + Inbound = 1 +} + +struct TokenPool_LockOrBurnInV1 { + receiver: Cell; // The recipient of the tokens on the destination chain. For EVM source chains, this is abi-encoded (32 bytes). + remoteChainSelector: uint64; // ─╮The chain ID of the destination chain. + originalSender: address; // ─╯The original sender of the tx on the source chain. + amount: uint256; // The amount of tokens to lock or burn, denominated in the source token's decimals. + localToken: address; // The address on this chain of the token to lock or burn. +} + +struct TokenPool_LockOrBurnOutV1 { + // The address of the destination token, abi encoded in the case of EVM chains. + // This value is UNTRUSTED as any pool owner can return whatever value they want. + destTokenAddress: Cell; + // Optional pool data to be transferred to the destination chain. Be default this is capped at + // CCIP_LOCK_OR_BURN_V1_RET_BYTES bytes. If more data is required, the TokenTransferFeeConfig.destBytesOverhead + // has to be set for the specific token. + destPoolData: cell; +} + +struct TokenPool_ReleaseOrMintInV1 { + originalSender: Cell; // The original sender of the tx on the source chain, abi encoded in the case of EVM chains. + remoteChainSelector: uint64; // ──╮ The chain ID of the source chain. + receiver: address; // -─╯ The recipient of the tokens on the destination chain. + sourceDenominatedAmount: uint256; // The amount of tokens to release or mint, denominated in the source token's decimals. + localToken: address; // The address on this chain of the token to release or mint. + /// @dev WARNING: sourcePoolAddress should be checked prior to any processing of funds. Make sure it matches the + /// expected pool address for the given remoteChainSelector. + sourcePoolAddress: Cell; // The address of the source pool, abi encoded in the case of EVM chains. + sourcePoolData: cell?; // The data received from the source pool to process the release or mint. + /// @dev WARNING: offchainTokenData is untrusted data. + offchainTokenData: cell?; // The offchain data to process the release or mint. +} + +struct TokenPool_ReleaseOrMintOutV1 { + // The number of tokens released or minted on the destination chain, denominated in the local token's decimals. + // This value is expected to be equal to the ReleaseOrMintInV1.amount in the case where the source and destination + // chain have the same number of decimals. + destinationAmount: uint256; +} diff --git a/contracts/tests/ccip/pool/BurnMintTokenPool.spec.ts b/contracts/tests/ccip/pool/BurnMintTokenPool.spec.ts new file mode 100644 index 000000000..b7327d9b4 --- /dev/null +++ b/contracts/tests/ccip/pool/BurnMintTokenPool.spec.ts @@ -0,0 +1,397 @@ +import '@ton/test-utils' +import { Blockchain, SandboxContract, TreasuryContract } from '@ton/sandbox' +import { Address, Cell, beginCell, toNano } from '@ton/core' +import { JettonMinter, JettonWallet } from '../../../wrappers/examples/jetton' +import { BurnMintTokenPool, codec as poolCodec, opcodes as poolOpcodes } from '../../../wrappers/ccip/BurnMintTokenPool' +import { CCTJettonMinter } from '../../../wrappers/ccip/CCTJettonMinter' +import { CCTJettonMinterCode, CCTJettonWalletCode } from '../../../wrappers/ccip/CCTJettonCode' +import { runTokenPoolBehaviorTests } from './TokenPool.behavior' + +describe('BurnMintTokenPool', () => { + let blockchain: Blockchain + let deployer: SandboxContract + let offRamp: SandboxContract + let unauthorized: SandboxContract + let recipient: SandboxContract + + let cctMinter: SandboxContract + let cctMinterRuntime: SandboxContract + let burnMintPool: SandboxContract + let cctWalletCode: Cell + + let userWallet: (address: Address) => Promise> + + const remoteChainSelector = 91000001n + const sourcePoolAddress = poolCodec.crossChainAddressFromBuffer(Buffer.from('source-pool')) + const destTokenAddress = poolCodec.crossChainAddressFromBuffer(Buffer.from('dest-token')) + const receiverAddress = poolCodec.crossChainAddressFromBuffer(Buffer.from('receiver')) + + beforeEach(async () => { + blockchain = await Blockchain.create() + deployer = await blockchain.treasury('deployer') + offRamp = await blockchain.treasury('offramp') + unauthorized = await blockchain.treasury('unauthorized') + recipient = await blockchain.treasury('recipient') + + cctWalletCode = await CCTJettonWalletCode() + const cctMinterCode = await CCTJettonMinterCode() + + cctMinter = blockchain.openContract( + CCTJettonMinter.createFromConfig( + { + totalSupply: 0n, + adminAddress: deployer.address, + nextAdminAddress: null, + jettonWalletCode: cctWalletCode, + metadataUri: 'cct-test', + }, + cctMinterCode, + ), + ) + await cctMinter.sendDeploy(deployer.getSender(), toNano('1')) + cctMinterRuntime = blockchain.openContract(JettonMinter.createFromAddress(cctMinter.address)) + + const poolCode = await BurnMintTokenPool.code() + burnMintPool = blockchain.openContract( + BurnMintTokenPool.createFromConfig( + { + owner: deployer.address, + token: cctMinter.address, + tokenDecimals: 9, + rmnProxy: deployer.address, + router: deployer.address, + jettonClient: { + masterAddress: cctMinter.address, + jettonWalletCode: cctWalletCode, + }, + }, + poolCode, + ), + ) + await burnMintPool.sendDeploy(deployer.getSender(), toNano('2')) + + await burnMintPool.sendApplyChainUpdates(deployer.getSender(), toNano('0.2'), { + queryId: 1n, + remove: [], + add: [ + { + remoteChainSelector, + remotePoolAddresses: [sourcePoolAddress], + remoteTokenAddress: destTokenAddress, + outboundRateLimiterConfig: { isEnabled: true, capacity: toNano('100'), rate: 1n }, + inboundRateLimiterConfig: { isEnabled: true, capacity: toNano('100'), rate: 1n }, + }, + ], + }) + + await burnMintPool.sendUpdateRampAccess(deployer.getSender(), toNano('0.2'), { + queryId: 2n, + updates: [ + { + remoteChainSelector, + onRamp: deployer.address, + offRamp: offRamp.address, + }, + ], + }) + + // Mint user-side test balance before handing minter admin to the pool. + const mintToOnRamp = await cctMinterRuntime.sendMint(deployer.getSender(), { + value: toNano('1'), + mintOpcode: 0x00000015, + message: { + queryId: 101n, + destination: deployer.address, + tonAmount: toNano('0.05'), + jettonAmount: toNano('10'), + from: deployer.address, + responseDestination: deployer.address, + forwardTonAmount: 0n, + }, + }) + expect(mintToOnRamp.transactions).toHaveTransaction({ + from: deployer.address, + to: cctMinter.address, + success: true, + }) + + await cctMinterRuntime.sendMint(deployer.getSender(), { + value: toNano('1'), + mintOpcode: 0x00000015, + message: { + queryId: 102n, + destination: unauthorized.address, + tonAmount: toNano('0.05'), + jettonAmount: toNano('2'), + from: deployer.address, + responseDestination: deployer.address, + forwardTonAmount: 0n, + }, + }) + + // Admin handoff: deployer sets pending admin to pool, pool claims ownership itself. + const changeAdminResult = await cctMinterRuntime.sendChangeAdmin(deployer.getSender(), { + value: toNano('0.2'), + message: { + queryId: 201n, + newAdmin: burnMintPool.address, + }, + }) + expect(changeAdminResult.transactions).toHaveTransaction({ + from: deployer.address, + to: cctMinter.address, + success: true, + }) + + const claimAdminResult = await burnMintPool.sendClaimMinterAdmin(deployer.getSender(), toNano('0.2'), 202n) + expect(claimAdminResult.transactions).toHaveTransaction({ + from: burnMintPool.address, + to: cctMinter.address, + success: true, + }) + + const jettonData = await cctMinterRuntime.getJettonData() + expect(jettonData.admin).toEqualAddress(burnMintPool.address) + expect(await cctMinterRuntime.getNextAdminAddress()).toBeNull() + + userWallet = async (address: Address) => { + return blockchain.openContract(JettonWallet.createFromAddress(await cctMinterRuntime.getWalletAddress(address))) + } + }) + + runTokenPoolBehaviorTests('BurnMintTokenPool', async () => ({ + pool: burnMintPool, + deployer, + offRamp, + altOffRamp: deployer, + unauthorized, + recipient, + remoteChainSelector, + unsupportedChainSelector: remoteChainSelector + 1n, + unknownSourcePoolAddress: poolCodec.crossChainAddressFromBuffer(Buffer.from('unknown-source-pool')), + remoteTokenAddress: destTokenAddress, + onRampAddress: deployer.address, + destTokenAddress, + sourcePoolAddress, + localToken: cctMinter.address, + })) + + it('has no pending burn or mint by default', async () => { + expect(await burnMintPool.getHasPendingBurn(300n)).toBe(false) + expect(await burnMintPool.getHasPendingMint(301n)).toBe(false) + }) + + it('rejects claim-minter-admin from non-owner sender', async () => { + const result = await burnMintPool.sendClaimMinterAdmin(unauthorized.getSender(), toNano('0.2'), 302n) + + expect(result.transactions).toHaveTransaction({ + from: unauthorized.address, + to: burnMintPool.address, + success: false, + }) + }) + + it('reverts lockOrBurn when caller is not configured on-ramp', async () => { + const unauthorizedWallet = await userWallet(unauthorized.address) + const poolWallet = await userWallet(burnMintPool.address) + const result = await unauthorizedWallet.sendTransfer(unauthorized.getSender(), { + value: toNano('2'), + message: { + queryId: 303, + jettonAmount: toNano('1'), + destination: burnMintPool.address, + responseDestination: unauthorized.address, + customPayload: null, + forwardTonAmount: toNano('0.2'), + forwardPayload: poolCodec.lockOrBurnPayload + .encode({ + queryId: 303n, + request: { + receiver: receiverAddress, + remoteChainSelector, + originalSender: unauthorized.address, + amount: toNano('1'), + localToken: cctMinter.address, + }, + requestedFinalityConfig: 0, + tokenArgs: null, + replyTo: unauthorized.address, + }) + .endCell(), + }, + }) + + expect(result.transactions).toHaveTransaction({ + from: poolWallet.address, + to: burnMintPool.address, + success: false, + }) + }) + + it('reverts lockOrBurn when payload amount does not match transferred amount', async () => { + const onRampWallet = await userWallet(deployer.address) + const poolWallet = await userWallet(burnMintPool.address) + const result = await onRampWallet.sendTransfer(deployer.getSender(), { + value: toNano('2'), + message: { + queryId: 304, + jettonAmount: toNano('2'), + destination: burnMintPool.address, + responseDestination: deployer.address, + customPayload: null, + forwardTonAmount: toNano('0.2'), + forwardPayload: poolCodec.lockOrBurnPayload + .encode({ + queryId: 304n, + request: { + receiver: receiverAddress, + remoteChainSelector, + originalSender: deployer.address, + amount: toNano('1'), + localToken: cctMinter.address, + }, + requestedFinalityConfig: 0, + tokenArgs: null, + replyTo: deployer.address, + }) + .endCell(), + }, + }) + + expect(result.transactions).toHaveTransaction({ + from: poolWallet.address, + to: burnMintPool.address, + success: false, + }) + }) + + it('burns tokens on lockOrBurn path and clears pending burn on confirmation', async () => { + const onRampWallet = await userWallet(deployer.address) + const poolWallet = await userWallet(burnMintPool.address) + + const result = await onRampWallet.sendTransfer(deployer.getSender(), { + value: toNano('2'), + message: { + queryId: 11, + jettonAmount: toNano('3'), + destination: burnMintPool.address, + responseDestination: deployer.address, + customPayload: null, + forwardTonAmount: toNano('0.2'), + forwardPayload: poolCodec.lockOrBurnPayload + .encode({ + queryId: 11n, + request: { + receiver: receiverAddress, + remoteChainSelector, + originalSender: deployer.address, + amount: toNano('3'), + localToken: cctMinter.address, + }, + requestedFinalityConfig: 0, + tokenArgs: null, + replyTo: deployer.address, + }) + .endCell(), + }, + }) + + expect(result.transactions).toHaveTransaction({ + from: deployer.address, + to: onRampWallet.address, + success: true, + }) + + expect(await burnMintPool.getHasPendingBurn(11n)).toBe(false) + expect(await poolWallet.getJettonBalance()).toEqual(0n) + + expect(result.transactions).toHaveTransaction({ + from: burnMintPool.address, + to: deployer.address, + success: true, + op: poolOpcodes.out.lockOrBurnResponse, + }) + }) + + it('mints tokens on releaseOrMint path and clears pending mint on confirmation', async () => { + const result = await burnMintPool.sendReleaseOrMint(offRamp.getSender(), toNano('0.6'), { + queryId: 22n, + request: { + originalSender: sourcePoolAddress, + remoteChainSelector, + receiver: recipient.address, + sourceDenominatedAmount: toNano('2'), + localToken: cctMinter.address, + sourcePoolAddress, + sourcePoolData: null, + offchainTokenData: null, + }, + requestedFinalityConfig: 0, + replyTo: deployer.address, + }) + + expect(result.transactions).toHaveTransaction({ + from: offRamp.address, + to: burnMintPool.address, + success: true, + }) + + expect(result.transactions).toHaveTransaction({ + from: burnMintPool.address, + to: cctMinter.address, + success: true, + }) + + expect(await burnMintPool.getHasPendingMint(22n)).toBe(false) + + expect(result.transactions).toHaveTransaction({ + from: burnMintPool.address, + to: deployer.address, + success: true, + op: poolOpcodes.out.releaseOrMintResponse, + body(body) { + if (!body) return false + const response = poolCodec.releaseOrMintResponse.load(body.beginParse()) + return response.queryId === 22n && response.destinationAmount === toNano('2') + }, + }) + }) + + it('mints on releaseOrMint with null replyTo without emitting response message', async () => { + const result = await burnMintPool.sendReleaseOrMint(offRamp.getSender(), toNano('0.6'), { + queryId: 305n, + request: { + originalSender: sourcePoolAddress, + remoteChainSelector, + receiver: recipient.address, + sourceDenominatedAmount: toNano('1'), + localToken: cctMinter.address, + sourcePoolAddress, + sourcePoolData: null, + offchainTokenData: null, + }, + requestedFinalityConfig: 0, + replyTo: null, + }) + + expect(result.transactions).toHaveTransaction({ + from: offRamp.address, + to: burnMintPool.address, + success: true, + }) + expect(result.transactions).toHaveTransaction({ + from: burnMintPool.address, + to: cctMinter.address, + success: true, + }) + + const releaseResponses = result.transactions.filter((tx: any) => { + return ( + tx.inMessage?.info?.src?.equals?.(burnMintPool.address) && + tx.inMessage?.body?.beginParse?.().preloadUint?.(32) === poolOpcodes.out.releaseOrMintResponse + ) + }) + expect(releaseResponses.length).toBe(0) + expect(await burnMintPool.getHasPendingMint(305n)).toBe(false) + }) +}) diff --git a/contracts/tests/ccip/pool/LockReleaseTokenPool.spec.ts b/contracts/tests/ccip/pool/LockReleaseTokenPool.spec.ts new file mode 100644 index 000000000..1cfabe092 --- /dev/null +++ b/contracts/tests/ccip/pool/LockReleaseTokenPool.spec.ts @@ -0,0 +1,381 @@ +import '@ton/test-utils' +import { Blockchain, SandboxContract, TreasuryContract } from '@ton/sandbox' +import { Address, Cell, Message, beginCell, toNano } from '@ton/core' +import { JettonMinter, JettonSender, JettonWallet } from '../../../wrappers/examples/jetton' +import { LockReleaseTokenPool, codec as poolCodec, opcodes as poolOpcodes } from '../../../wrappers/ccip/LockReleaseTokenPool' +import * as jetton from '../../../wrappers/jetton/JettonCode' +import { runTokenPoolBehaviorTests } from './TokenPool.behavior' + +describe('LockReleaseTokenPool', () => { + let blockchain: Blockchain + let deployer: SandboxContract + let offRamp: SandboxContract + let recipient: SandboxContract + + let jettonMinter: SandboxContract + let jettonSender: SandboxContract + let lockReleasePool: SandboxContract + let jettonWalletCode: Cell + + let userWallet: (address: Address) => Promise> + + const remoteChainSelector = 90000001n + const sourcePoolAddress = poolCodec.crossChainAddressFromBuffer(Buffer.from('source-pool')) + const destTokenAddress = poolCodec.crossChainAddressFromBuffer(Buffer.from('dest-token')) + const receiverAddress = poolCodec.crossChainAddressFromBuffer(Buffer.from('receiver')) + + beforeEach(async () => { + blockchain = await Blockchain.create() + deployer = await blockchain.treasury('deployer') + offRamp = await blockchain.treasury('offramp') + recipient = await blockchain.treasury('recipient') + + jettonWalletCode = await jetton.JettonWalletCode() + const jettonMinterCode = await jetton.JettonMinterCode() + + jettonMinter = blockchain.openContract( + JettonMinter.createFromConfig( + { + admin: deployer.address, + transferAdmin: null, + walletCode: jettonWalletCode, + jettonContent: beginCell().storeStringTail('pool-test').endCell(), + totalSupply: 0n, + }, + jettonMinterCode, + ), + ) + await jettonMinter.sendDeploy(deployer.getSender(), toNano('1')) + + const jettonSenderCode = await JettonSender.code() + jettonSender = blockchain.openContract( + JettonSender.createFromConfig( + { + jettonClient: { + masterAddress: jettonMinter.address, + jettonWalletCode, + }, + }, + jettonSenderCode, + ), + ) + await jettonSender.sendDeploy(deployer.getSender(), toNano('1')) + + const poolCode = await LockReleaseTokenPool.code() + lockReleasePool = blockchain.openContract( + LockReleaseTokenPool.createFromConfig( + { + owner: deployer.address, + token: jettonMinter.address, + tokenDecimals: 9, + rmnProxy: deployer.address, + router: deployer.address, + jettonClient: { + masterAddress: jettonMinter.address, + jettonWalletCode, + }, + }, + poolCode, + ), + ) + await lockReleasePool.sendDeploy(deployer.getSender(), toNano('2')) + + const applyChains = await lockReleasePool.sendApplyChainUpdates(deployer.getSender(), toNano('0.2'), { + queryId: 1n, + remove: [], + add: [ + { + remoteChainSelector, + remotePoolAddresses: [sourcePoolAddress], + remoteTokenAddress: destTokenAddress, + outboundRateLimiterConfig: { isEnabled: true, capacity: toNano('100'), rate: 1n }, + inboundRateLimiterConfig: { isEnabled: true, capacity: toNano('100'), rate: 1n }, + }, + ], + }) + + expect(applyChains.transactions).toHaveTransaction({ + from: deployer.address, + to: lockReleasePool.address, + success: true, + }) + + const updateRampAccess = await lockReleasePool.sendUpdateRampAccess(deployer.getSender(), toNano('0.2'), { + queryId: 2n, + updates: [ + { + remoteChainSelector, + onRamp: jettonSender.address, + offRamp: offRamp.address, + }, + ], + }) + + expect(updateRampAccess.transactions).toHaveTransaction({ + from: deployer.address, + to: lockReleasePool.address, + success: true, + }) + + const mintToOnRamp = await jettonMinter.sendMint(deployer.getSender(), { + value: toNano('1'), + message: { + queryId: 0n, + destination: jettonSender.address, + tonAmount: toNano('0.05'), + jettonAmount: toNano('10'), + from: deployer.address, + responseDestination: deployer.address, + forwardTonAmount: 0n, + }, + }) + expect(mintToOnRamp.transactions).toHaveTransaction({ + from: deployer.address, + to: jettonMinter.address, + success: true, + }) + + userWallet = async (address: Address) => { + return blockchain.openContract( + JettonWallet.createFromAddress(await jettonMinter.getWalletAddress(address)), + ) + } + }) + + runTokenPoolBehaviorTests('LockReleaseTokenPool', async () => ({ + pool: lockReleasePool, + deployer, + offRamp, + altOffRamp: deployer, + unauthorized: recipient, + recipient, + remoteChainSelector, + unsupportedChainSelector: remoteChainSelector + 1n, + unknownSourcePoolAddress: poolCodec.crossChainAddressFromBuffer(Buffer.from('unknown-source-pool')), + remoteTokenAddress: destTokenAddress, + onRampAddress: jettonSender.address, + destTokenAddress, + sourcePoolAddress, + localToken: jettonMinter.address, + })) + + it('has no pending release by default', async () => { + expect(await lockReleasePool.getHasPendingRelease(999n)).toBe(false) + }) + + it('reverts lockOrBurn when forwarded amount does not match transfer amount', async () => { + const onRampWallet = await userWallet(jettonSender.address) + const poolWallet = await userWallet(lockReleasePool.address) + + const result = await jettonSender.sendJettonsExtended(deployer.getSender(), { + value: toNano('2'), + message: { + queryId: 44n, + amount: toNano('3'), + destination: lockReleasePool.address, + customPayload: beginCell().storeBit(1).endCell(), + forwardTonAmount: toNano('0.2'), + forwardPayload: poolCodec.lockOrBurnPayload + .encode({ + queryId: 44n, + request: { + receiver: receiverAddress, + remoteChainSelector, + originalSender: deployer.address, + amount: toNano('2'), + localToken: jettonMinter.address, + }, + requestedFinalityConfig: 0, + tokenArgs: null, + replyTo: deployer.address, + }) + .endCell(), + }, + }) + + expect(result.transactions).toHaveTransaction({ + from: poolWallet.address, + to: lockReleasePool.address, + success: false, + }) + }) + + it('reverts lockOrBurn when forward payload is malformed', async () => { + const onRampWallet = await userWallet(jettonSender.address) + const poolWallet = await userWallet(lockReleasePool.address) + + const result = await jettonSender.sendJettonsExtended(deployer.getSender(), { + value: toNano('2'), + message: { + queryId: 45n, + amount: toNano('1'), + destination: lockReleasePool.address, + customPayload: beginCell().storeBit(1).endCell(), + forwardTonAmount: toNano('0.2'), + forwardPayload: beginCell().storeUint(0, 32).endCell(), + }, + }) + + expect(result.transactions).toHaveTransaction({ + from: poolWallet.address, + to: lockReleasePool.address, + success: false, + }) + }) + + it('reverts releaseOrMint when requested amount exceeds pool liquidity', async () => { + const result = await lockReleasePool.sendReleaseOrMint(offRamp.getSender(), toNano('0.4'), { + queryId: 46n, + request: { + originalSender: sourcePoolAddress, + remoteChainSelector, + receiver: recipient.address, + sourceDenominatedAmount: toNano('999999'), + localToken: jettonMinter.address, + sourcePoolAddress, + sourcePoolData: null, + offchainTokenData: null, + }, + requestedFinalityConfig: 0, + replyTo: deployer.address, + }) + + expect(result.transactions).toHaveTransaction({ + from: offRamp.address, + to: lockReleasePool.address, + success: false, + }) + expect(await lockReleasePool.getHasPendingRelease(46n)).toBe(false) + }) + + it('locks tokens through a jetton transfer notification and credits the pool wallet', async () => { + const onRampWallet = await userWallet(jettonSender.address) + const poolWallet = await userWallet(lockReleasePool.address) + + const result = await jettonSender.sendJettonsExtended(deployer.getSender(), { + value: toNano('2'), + message: { + queryId: 11n, + amount: toNano('3'), + destination: lockReleasePool.address, + customPayload: beginCell().storeBit(1).endCell(), + forwardTonAmount: toNano('0.2'), + forwardPayload: poolCodec.lockOrBurnPayload + .encode({ + queryId: 11n, + request: { + receiver: receiverAddress, + remoteChainSelector, + originalSender: deployer.address, + amount: toNano('3'), + localToken: jettonMinter.address, + }, + requestedFinalityConfig: 0, + tokenArgs: null, + replyTo: deployer.address, + }) + .endCell(), + }, + }) + + expect(result.transactions).toHaveTransaction({ + from: jettonSender.address, + to: onRampWallet.address, + success: true, + }) + + expect(await poolWallet.getJettonBalance()).toEqual(toNano('3')) + }) + + it('releases tokens from pool custody after off-ramp request and clears pending state on confirmation', async () => { + const poolWallet = await userWallet(lockReleasePool.address) + const recipientWallet = await userWallet(recipient.address) + + await jettonMinter.sendMint(deployer.getSender(), { + value: toNano('1'), + message: { + queryId: 0n, + destination: lockReleasePool.address, + tonAmount: toNano('0.05'), + jettonAmount: toNano('5'), + from: deployer.address, + responseDestination: deployer.address, + forwardTonAmount: 0n, + }, + }) + + const result = await lockReleasePool.sendReleaseOrMint(offRamp.getSender(), toNano('0.4'), { + queryId: 22n, + request: { + originalSender: sourcePoolAddress, + remoteChainSelector, + receiver: recipient.address, + sourceDenominatedAmount: toNano('2'), + localToken: jettonMinter.address, + sourcePoolAddress, + sourcePoolData: null, + offchainTokenData: null, + }, + requestedFinalityConfig: 0, + replyTo: deployer.address, + }) + + expect(result.transactions).toHaveTransaction({ + from: offRamp.address, + to: lockReleasePool.address, + success: true, + }) + + expect(await recipientWallet.getJettonBalance()).toEqual(toNano('2')) + expect(await poolWallet.getJettonBalance()).toEqual(toNano('3')) + expect(await lockReleasePool.getHasPendingRelease(22n)).toBe(false) + + expect(result.transactions).toHaveTransaction({ + from: lockReleasePool.address, + to: deployer.address, + success: true, + op: poolOpcodes.out.releaseOrMintResponse, + body(body) { + if (!body) return false + const response = poolCodec.releaseOrMintResponse.load(body.beginParse()) + return response.queryId === 22n && response.destinationAmount === toNano('2') + }, + }) + }) + + it('mirrors cursed state locally and blocks release while cursed', async () => { + const curseUpdate = await lockReleasePool.sendUpdateCursedSubjects(deployer.getSender(), toNano('0.2'), [ + remoteChainSelector, + ]) + + expect(curseUpdate.transactions).toHaveTransaction({ + from: deployer.address, + to: lockReleasePool.address, + success: true, + }) + + expect(await lockReleasePool.getVerifyNotCursed(remoteChainSelector)).toBe(false) + + const result = await lockReleasePool.sendReleaseOrMint(offRamp.getSender(), toNano('0.3'), { + queryId: 33n, + request: { + originalSender: sourcePoolAddress, + remoteChainSelector, + receiver: recipient.address, + sourceDenominatedAmount: 1n, + localToken: jettonMinter.address, + sourcePoolAddress, + sourcePoolData: null, + offchainTokenData: null, + }, + requestedFinalityConfig: 0, + replyTo: deployer.address, + }) + + expect(result.transactions).toHaveTransaction({ + from: offRamp.address, + to: lockReleasePool.address, + success: false, + }) + }) +}) \ No newline at end of file diff --git a/contracts/tests/ccip/pool/TokenPool.behavior.ts b/contracts/tests/ccip/pool/TokenPool.behavior.ts new file mode 100644 index 000000000..9bfccff97 --- /dev/null +++ b/contracts/tests/ccip/pool/TokenPool.behavior.ts @@ -0,0 +1,415 @@ +import '@ton/test-utils' +import { SandboxContract, TreasuryContract } from '@ton/sandbox' +import { Address, beginCell, Cell, Sender, toNano } from '@ton/core' +import { ReleaseOrMintInV1 } from '../../../wrappers/ccip/TokenPool' + +export type TokenPoolBehaviorContext = { + pool: { + sendApplyChainUpdates: ( + via: Sender, + value: bigint, + body: { queryId: bigint; remove: bigint[]; add: ChainUpdateInput[] }, + ) => Promise<{ transactions: unknown[] }> + sendUpdateRampAccess: ( + via: Sender, + value: bigint, + body: { + queryId: bigint + updates: { + remoteChainSelector: bigint + onRamp: Address | null + offRamp: Address | null + }[] + }, + ) => Promise<{ transactions: unknown[] }> + sendUpdateCursedSubjects: ( + via: Sender, + value: bigint, + cursedSubjects: bigint[], + ) => Promise<{ transactions: unknown[] }> + sendReleaseOrMint: ( + via: Sender, + value: bigint, + body: { + queryId: bigint + request: ReleaseOrMintInV1 + requestedFinalityConfig?: number + replyTo?: Address | null + }, + ) => Promise<{ transactions: unknown[] }> + getVerifyNotCursed: (subject: bigint) => Promise + getOnRamp: (remoteChainSelector: bigint) => Promise
+ getOffRamp: (remoteChainSelector: bigint) => Promise
+ getIsSupportedChain: (remoteChainSelector: bigint) => Promise + address: Address + } + deployer: SandboxContract + offRamp: SandboxContract + unauthorized: SandboxContract + recipient: SandboxContract + onRampAddress: Address + remoteChainSelector: bigint + destTokenAddress: Cell + sourcePoolAddress: Cell + localToken: Address +} + +type ChainUpdateInput = { + remoteChainSelector: bigint + remotePoolAddresses: Cell[] + remoteTokenAddress: Cell + outboundRateLimiterConfig: { isEnabled: boolean; capacity: bigint; rate: bigint } + inboundRateLimiterConfig: { isEnabled: boolean; capacity: bigint; rate: bigint } +} + +function releaseRequest( + ctx: TokenPoolBehaviorContext, + overrides: Partial = {}, +): ReleaseOrMintInV1 { + return { + originalSender: ctx.sourcePoolAddress, + remoteChainSelector: ctx.remoteChainSelector, + receiver: ctx.recipient.address, + sourceDenominatedAmount: 1n, + localToken: ctx.localToken, + sourcePoolAddress: ctx.sourcePoolAddress, + sourcePoolData: null, + offchainTokenData: null, + ...overrides, + } +} + +export function runTokenPoolBehaviorTests( + name: string, + setup: () => Promise, +) { + describe(`${name} TokenPool behavior`, () => { + it('mirrors ramp access and supported chain state after setup', async () => { + const ctx = await setup() + + expect(await ctx.pool.getIsSupportedChain(ctx.remoteChainSelector)).toBe(true) + expect(await ctx.pool.getOnRamp(ctx.remoteChainSelector)).not.toBeNull() + expect(await ctx.pool.getOffRamp(ctx.remoteChainSelector)).toEqualAddress(ctx.offRamp.address) + }) + + it('reverts releaseOrMint when caller is not configured off-ramp', async () => { + const ctx = await setup() + + const result = await ctx.pool.sendReleaseOrMint(ctx.unauthorized.getSender(), toNano('0.3'), { + queryId: 901n, + request: releaseRequest(ctx), + requestedFinalityConfig: 0, + replyTo: ctx.deployer.address, + }) + + expect(result.transactions).toHaveTransaction({ + from: ctx.unauthorized.address, + to: ctx.pool.address, + success: false, + }) + }) + + it('reverts releaseOrMint while chain is cursed', async () => { + const ctx = await setup() + + await ctx.pool.sendUpdateCursedSubjects(ctx.deployer.getSender(), toNano('0.2'), [ctx.remoteChainSelector]) + expect(await ctx.pool.getVerifyNotCursed(ctx.remoteChainSelector)).toBe(false) + + const result = await ctx.pool.sendReleaseOrMint(ctx.offRamp.getSender(), toNano('0.3'), { + queryId: 902n, + request: releaseRequest(ctx), + requestedFinalityConfig: 0, + replyTo: ctx.deployer.address, + }) + + expect(result.transactions).toHaveTransaction({ + from: ctx.offRamp.address, + to: ctx.pool.address, + success: false, + }) + }) + + it('starts with chain not cursed', async () => { + const ctx = await setup() + expect(await ctx.pool.getVerifyNotCursed(ctx.remoteChainSelector)).toBe(true) + }) + + it('returns null ramps for unknown chain', async () => { + const ctx = await setup() + const unknownChainSelector = ctx.remoteChainSelector + 1n + expect(await ctx.pool.getOnRamp(unknownChainSelector)).toBeNull() + expect(await ctx.pool.getOffRamp(unknownChainSelector)).toBeNull() + }) + + it('returns unsupported for unknown chain', async () => { + const ctx = await setup() + const unknownChainSelector = ctx.remoteChainSelector + 1n + expect(await ctx.pool.getIsSupportedChain(unknownChainSelector)).toBe(false) + }) + + it('rejects applyChainUpdates from non-owner', async () => { + const ctx = await setup() + const result = await ctx.pool.sendApplyChainUpdates(ctx.unauthorized.getSender(), toNano('0.2'), { + queryId: 903n, + remove: [], + add: [], + }) + + expect(result.transactions).toHaveTransaction({ + from: ctx.unauthorized.address, + to: ctx.pool.address, + success: false, + }) + }) + + it('rejects updateRampAccess from non-owner', async () => { + const ctx = await setup() + const result = await ctx.pool.sendUpdateRampAccess(ctx.unauthorized.getSender(), toNano('0.2'), { + queryId: 904n, + updates: [ + { + remoteChainSelector: ctx.remoteChainSelector, + onRamp: ctx.onRampAddress, + offRamp: ctx.unauthorized.address, + }, + ], + }) + + expect(result.transactions).toHaveTransaction({ + from: ctx.unauthorized.address, + to: ctx.pool.address, + success: false, + }) + }) + + it('rejects cursed-subject updates from non-rmn sender', async () => { + const ctx = await setup() + const result = await ctx.pool.sendUpdateCursedSubjects(ctx.unauthorized.getSender(), toNano('0.2'), [ + ctx.remoteChainSelector, + ]) + + expect(result.transactions).toHaveTransaction({ + from: ctx.unauthorized.address, + to: ctx.pool.address, + success: false, + }) + }) + + it('can clear cursed subject back to not cursed', async () => { + const ctx = await setup() + await ctx.pool.sendUpdateCursedSubjects(ctx.deployer.getSender(), toNano('0.2'), [ctx.remoteChainSelector]) + expect(await ctx.pool.getVerifyNotCursed(ctx.remoteChainSelector)).toBe(false) + + await ctx.pool.sendUpdateCursedSubjects(ctx.deployer.getSender(), toNano('0.2'), []) + expect(await ctx.pool.getVerifyNotCursed(ctx.remoteChainSelector)).toBe(true) + }) + + it('removes configured chain via applyChainUpdates', async () => { + const ctx = await setup() + const result = await ctx.pool.sendApplyChainUpdates(ctx.deployer.getSender(), toNano('0.2'), { + queryId: 905n, + remove: [ctx.remoteChainSelector], + add: [], + }) + + expect(result.transactions).toHaveTransaction({ + from: ctx.deployer.address, + to: ctx.pool.address, + success: true, + }) + expect(await ctx.pool.getIsSupportedChain(ctx.remoteChainSelector)).toBe(false) + }) + + it('reverts releaseOrMint after configured chain is removed', async () => { + const ctx = await setup() + await ctx.pool.sendApplyChainUpdates(ctx.deployer.getSender(), toNano('0.2'), { + queryId: 906n, + remove: [ctx.remoteChainSelector], + add: [], + }) + + const result = await ctx.pool.sendReleaseOrMint(ctx.offRamp.getSender(), toNano('0.3'), { + queryId: 907n, + request: releaseRequest(ctx), + requestedFinalityConfig: 0, + replyTo: ctx.deployer.address, + }) + + expect(result.transactions).toHaveTransaction({ + from: ctx.offRamp.address, + to: ctx.pool.address, + success: false, + }) + }) + + it('rejects removing a non-existent chain', async () => { + const ctx = await setup() + const result = await ctx.pool.sendApplyChainUpdates(ctx.deployer.getSender(), toNano('0.2'), { + queryId: 908n, + remove: [ctx.remoteChainSelector + 1n], + add: [], + }) + + expect(result.transactions).toHaveTransaction({ + from: ctx.deployer.address, + to: ctx.pool.address, + success: false, + }) + }) + + it('can replace off-ramp mapping via updateRampAccess', async () => { + const ctx = await setup() + const result = await ctx.pool.sendUpdateRampAccess(ctx.deployer.getSender(), toNano('0.2'), { + queryId: 909n, + updates: [ + { + remoteChainSelector: ctx.remoteChainSelector, + onRamp: ctx.onRampAddress, + offRamp: ctx.unauthorized.address, + }, + ], + }) + + expect(result.transactions).toHaveTransaction({ + from: ctx.deployer.address, + to: ctx.pool.address, + success: true, + }) + expect(await ctx.pool.getOffRamp(ctx.remoteChainSelector)).toEqualAddress(ctx.unauthorized.address) + }) + + it('rejects old off-ramp sender after remapping off-ramp', async () => { + const ctx = await setup() + await ctx.pool.sendUpdateRampAccess(ctx.deployer.getSender(), toNano('0.2'), { + queryId: 910n, + updates: [ + { + remoteChainSelector: ctx.remoteChainSelector, + onRamp: ctx.onRampAddress, + offRamp: ctx.unauthorized.address, + }, + ], + }) + + const result = await ctx.pool.sendReleaseOrMint(ctx.offRamp.getSender(), toNano('0.3'), { + queryId: 911n, + request: releaseRequest(ctx), + requestedFinalityConfig: 0, + replyTo: ctx.deployer.address, + }) + + expect(result.transactions).toHaveTransaction({ + from: ctx.offRamp.address, + to: ctx.pool.address, + success: false, + }) + }) + + it('rejects releaseOrMint when source pool is not configured', async () => { + const ctx = await setup() + const wrongSourcePoolAddress = beginCell().storeUint(4, 8).storeBuffer(Buffer.from('evil')).endCell() + const result = await ctx.pool.sendReleaseOrMint(ctx.offRamp.getSender(), toNano('0.3'), { + queryId: 912n, + request: releaseRequest(ctx, { sourcePoolAddress: wrongSourcePoolAddress }), + requestedFinalityConfig: 0, + replyTo: ctx.deployer.address, + }) + + expect(result.transactions).toHaveTransaction({ + from: ctx.offRamp.address, + to: ctx.pool.address, + success: false, + }) + }) + + it('rejects releaseOrMint when local token does not match pool token', async () => { + const ctx = await setup() + const wrongLocalToken = ctx.deployer.address + const result = await ctx.pool.sendReleaseOrMint(ctx.offRamp.getSender(), toNano('0.3'), { + queryId: 913n, + request: releaseRequest(ctx, { localToken: wrongLocalToken }), + requestedFinalityConfig: 0, + replyTo: ctx.deployer.address, + }) + + expect(result.transactions).toHaveTransaction({ + from: ctx.offRamp.address, + to: ctx.pool.address, + success: false, + }) + }) + + it('keeps existing off-ramp when update passes null off-ramp', async () => { + const ctx = await setup() + await ctx.pool.sendUpdateRampAccess(ctx.deployer.getSender(), toNano('0.2'), { + queryId: 914n, + updates: [ + { + remoteChainSelector: ctx.remoteChainSelector, + onRamp: ctx.onRampAddress, + offRamp: null, + }, + ], + }) + + expect(await ctx.pool.getOffRamp(ctx.remoteChainSelector)).toEqualAddress(ctx.offRamp.address) + }) + + it('still accepts existing off-ramp sender after null off-ramp update', async () => { + const ctx = await setup() + await ctx.pool.sendUpdateRampAccess(ctx.deployer.getSender(), toNano('0.2'), { + queryId: 915n, + updates: [ + { + remoteChainSelector: ctx.remoteChainSelector, + onRamp: ctx.onRampAddress, + offRamp: null, + }, + ], + }) + + const result = await ctx.pool.sendReleaseOrMint(ctx.offRamp.getSender(), toNano('0.3'), { + queryId: 916n, + request: releaseRequest(ctx), + requestedFinalityConfig: 0, + replyTo: ctx.deployer.address, + }) + + expect(result.transactions).toHaveTransaction({ + from: ctx.offRamp.address, + to: ctx.pool.address, + }) + }) + + it('can re-add chain after remove via applyChainUpdates', async () => { + const ctx = await setup() + + await ctx.pool.sendApplyChainUpdates(ctx.deployer.getSender(), toNano('0.2'), { + queryId: 917n, + remove: [ctx.remoteChainSelector], + add: [], + }) + + const addResult = await ctx.pool.sendApplyChainUpdates(ctx.deployer.getSender(), toNano('0.2'), { + queryId: 918n, + remove: [], + add: [ + { + remoteChainSelector: ctx.remoteChainSelector, + remotePoolAddresses: [ctx.sourcePoolAddress], + remoteTokenAddress: ctx.destTokenAddress, + outboundRateLimiterConfig: { isEnabled: true, capacity: toNano('100'), rate: 1n }, + inboundRateLimiterConfig: { isEnabled: true, capacity: toNano('100'), rate: 1n }, + }, + ], + }) + + expect(addResult.transactions).toHaveTransaction({ + from: ctx.deployer.address, + to: ctx.pool.address, + success: true, + }) + expect(await ctx.pool.getIsSupportedChain(ctx.remoteChainSelector)).toBe(true) + }) + }) +} diff --git a/contracts/wrappers/BurnMintTokenPool.compile.ts b/contracts/wrappers/BurnMintTokenPool.compile.ts new file mode 100644 index 000000000..15a841b42 --- /dev/null +++ b/contracts/wrappers/BurnMintTokenPool.compile.ts @@ -0,0 +1,7 @@ +import { CompilerConfig } from '@ton/blueprint' + +export const compile: CompilerConfig = { + lang: 'tolk', + entrypoint: 'contracts/ccip/pool/burn_mint_token_pool/contract.tolk', + withStackComments: true, +} \ No newline at end of file diff --git a/contracts/wrappers/LockReleaseTokenPool.compile.ts b/contracts/wrappers/LockReleaseTokenPool.compile.ts new file mode 100644 index 000000000..758af9f5e --- /dev/null +++ b/contracts/wrappers/LockReleaseTokenPool.compile.ts @@ -0,0 +1,7 @@ +import { CompilerConfig } from '@ton/blueprint' + +export const compile: CompilerConfig = { + lang: 'tolk', + entrypoint: 'contracts/ccip/pool/lock_release_token_pool/contract.tolk', + withStackComments: true, +} \ No newline at end of file diff --git a/contracts/wrappers/ccip.cct.JettonMinter.compile.ts b/contracts/wrappers/ccip.cct.JettonMinter.compile.ts new file mode 100644 index 000000000..0377bcaca --- /dev/null +++ b/contracts/wrappers/ccip.cct.JettonMinter.compile.ts @@ -0,0 +1,7 @@ +import { CompilerConfig } from '@ton/blueprint' + +export const compile: CompilerConfig = { + lang: 'tolk', + entrypoint: 'contracts/ccip/cct/JettonMinter.tolk', + withStackComments: true, +} \ No newline at end of file diff --git a/contracts/wrappers/ccip.cct.JettonWallet.compile.ts b/contracts/wrappers/ccip.cct.JettonWallet.compile.ts new file mode 100644 index 000000000..00584c349 --- /dev/null +++ b/contracts/wrappers/ccip.cct.JettonWallet.compile.ts @@ -0,0 +1,7 @@ +import { CompilerConfig } from '@ton/blueprint' + +export const compile: CompilerConfig = { + lang: 'tolk', + entrypoint: 'contracts/ccip/cct/JettonWallet.tolk', + withStackComments: true, +} \ No newline at end of file diff --git a/contracts/wrappers/ccip/BurnMintTokenPool.ts b/contracts/wrappers/ccip/BurnMintTokenPool.ts new file mode 100644 index 000000000..82ecf2985 --- /dev/null +++ b/contracts/wrappers/ccip/BurnMintTokenPool.ts @@ -0,0 +1,156 @@ +import { + Address, + beginCell, + Cell, + Contract, + contractAddress, + ContractProvider, + Sender, + SendMode, +} from '@ton/core' +import { crc32 } from 'zlib' +import { facilityId, errorCode } from '../utils' +import { contractCode } from '../codeLoader' +import { + codec, + createJettonClientData, + createTokenPoolData, + opcodes, + sendApplyChainUpdates, + sendReleaseOrMint, + sendUpdateCursedSubjects, + sendUpdateRampAccess, + type ChainUpdate, + type JettonClientConfig, + type RampAccess, + type TokenPoolConfig, + type ReleaseOrMintInV1, + type LockOrBurnInV1, + type LockOrBurnPayload, +} from './TokenPool' + +export const FACILITY_NAME = 'link.chain.ton.ccip.BurnMintTokenPool' +export const FACILITY_ID = facilityId(crc32(FACILITY_NAME)) +export const ERROR_CODE = errorCode(crc32(FACILITY_NAME)) +export const CONTRACT_VERSION = '0.1.0' +const BURN_MINT_CLAIM_MINTER_ADMIN_OPCODE = 0x93c174a1 + +export type Config = TokenPoolConfig & { + jettonClient: JettonClientConfig +} + +export class BurnMintTokenPool implements Contract { + constructor( + readonly address: Address, + readonly init?: { code: Cell; data: Cell }, + ) {} + + static createFromAddress(address: Address) { + return new BurnMintTokenPool(address) + } + + static createFromConfig(config: Config, code: Cell, workchain = 0) { + const data = beginCell() + .storeRef(createTokenPoolData(config)) + .storeRef(createJettonClientData(config.jettonClient)) + .storeDict(null) + .storeDict(null) + .endCell() + + const init = { code, data } + return new BurnMintTokenPool(contractAddress(workchain, init), init) + } + + static code(): Promise { + return contractCode.ccip.local('BurnMintTokenPool') + } + + async sendDeploy(provider: ContractProvider, via: Sender, value: bigint) { + await provider.internal(via, { + value, + sendMode: SendMode.PAY_GAS_SEPARATELY, + body: Cell.EMPTY, + }) + } + + async sendApplyChainUpdates( + provider: ContractProvider, + via: Sender, + value: bigint, + body: { queryId: bigint; remove: bigint[]; add: ChainUpdate[] }, + ) { + await sendApplyChainUpdates(provider, via, value, body) + } + + async sendUpdateRampAccess( + provider: ContractProvider, + via: Sender, + value: bigint, + body: { queryId: bigint; updates: RampAccess[] }, + ) { + await sendUpdateRampAccess(provider, via, value, body) + } + + async sendUpdateCursedSubjects( + provider: ContractProvider, + via: Sender, + value: bigint, + cursedSubjects: bigint[], + ) { + await sendUpdateCursedSubjects(provider, via, value, cursedSubjects) + } + + async sendReleaseOrMint( + provider: ContractProvider, + via: Sender, + value: bigint, + body: { + queryId: bigint + request: ReleaseOrMintInV1 + requestedFinalityConfig?: number + replyTo?: Address | null + }, + ) { + await sendReleaseOrMint(provider, via, value, body) + } + + async sendClaimMinterAdmin( + provider: ContractProvider, + via: Sender, + value: bigint, + queryId: bigint = 0n, + ) { + await provider.internal(via, { + value, + sendMode: SendMode.PAY_GAS_SEPARATELY, + body: beginCell().storeUint(BURN_MINT_CLAIM_MINTER_ADMIN_OPCODE, 32).storeUint(queryId, 64).endCell(), + }) + } + + async getHasPendingBurn(provider: ContractProvider, queryId: bigint) { + return provider.get('hasPendingBurn', [{ type: 'int', value: queryId }]).then((res) => res.stack.readBoolean()) + } + + async getHasPendingMint(provider: ContractProvider, queryId: bigint) { + return provider.get('hasPendingMint', [{ type: 'int', value: queryId }]).then((res) => res.stack.readBoolean()) + } + + async getVerifyNotCursed(provider: ContractProvider, subject: bigint) { + return provider.get('verifyNotCursed', [{ type: 'int', value: subject }]).then((res) => res.stack.readBoolean()) + } + + async getOnRamp(provider: ContractProvider, remoteChainSelector: bigint) { + return provider.get('onRamp', [{ type: 'int', value: remoteChainSelector }]).then((res) => res.stack.readAddressOpt()) + } + + async getOffRamp(provider: ContractProvider, remoteChainSelector: bigint) { + return provider.get('offRamp', [{ type: 'int', value: remoteChainSelector }]).then((res) => res.stack.readAddressOpt()) + } + + async getIsSupportedChain(provider: ContractProvider, remoteChainSelector: bigint) { + return provider.get('isSupportedChain', [{ type: 'int', value: remoteChainSelector }]).then((res) => res.stack.readBoolean()) + } +} + +export { codec, opcodes } +export type { ChainUpdate, JettonClientConfig, LockOrBurnInV1, LockOrBurnPayload, RampAccess, ReleaseOrMintInV1 } \ No newline at end of file diff --git a/contracts/wrappers/ccip/CCTJettonCode.ts b/contracts/wrappers/ccip/CCTJettonCode.ts new file mode 100644 index 000000000..1fffa93b7 --- /dev/null +++ b/contracts/wrappers/ccip/CCTJettonCode.ts @@ -0,0 +1,10 @@ +import { Cell } from '@ton/core' +import { contractCode } from '../codeLoader' + +export async function CCTJettonMinterCode(): Promise { + return contractCode.ccip.local('ccip.cct.JettonMinter') +} + +export async function CCTJettonWalletCode(): Promise { + return contractCode.ccip.local('ccip.cct.JettonWallet') +} \ No newline at end of file diff --git a/contracts/wrappers/ccip/CCTJettonMinter.ts b/contracts/wrappers/ccip/CCTJettonMinter.ts new file mode 100644 index 000000000..b23559b99 --- /dev/null +++ b/contracts/wrappers/ccip/CCTJettonMinter.ts @@ -0,0 +1,123 @@ +import { + Address, + beginCell, + Cell, + Contract, + contractAddress, + ContractProvider, + Sender, + SendMode, +} from '@ton/core' +import { contractCode } from '../codeLoader' +import { + builder as jettonMinterBuilder, +} from '../jetton/JettonMinter' + +export type CCTJettonMinterConfig = { + totalSupply: bigint + adminAddress: Address | null + nextAdminAddress: Address | null + jettonWalletCode: Cell + metadataUri: string +} + +export type CCTMintMessage = { + queryId: bigint + destination: Address + tonAmount: bigint + jettonAmount: bigint + from: Address | null + responseDestination: Address | null + forwardTonAmount?: bigint +} + +export class CCTJettonMinter implements Contract { + constructor( + readonly address: Address, + readonly init?: { code: Cell; data: Cell }, + ) {} + + static createFromAddress(address: Address) { + return new CCTJettonMinter(address) + } + + static createFromConfig(config: CCTJettonMinterConfig, code: Cell, workchain = 0) { + const data = beginCell() + .storeCoins(config.totalSupply) + .storeAddress(config.adminAddress) + .storeAddress(config.nextAdminAddress) + .storeRef(config.jettonWalletCode) + .storeStringRefTail(config.metadataUri) + .endCell() + + const init = { code, data } + return new CCTJettonMinter(contractAddress(workchain, init), init) + } + + static code(): Promise { + return contractCode.ccip.local('ccip.cct.JettonMinter') + } + + async sendDeploy(provider: ContractProvider, via: Sender, value: bigint) { + await provider.internal(via, { + value, + sendMode: SendMode.PAY_GAS_SEPARATELY, + body: Cell.EMPTY, + }) + } + + async sendMint( + provider: ContractProvider, + via: Sender, + opts: { + value: bigint + message: CCTMintMessage + }, + ) { + const internalTransferMsg = beginCell() + .storeUint(0x178d4519, 32) + .storeUint(opts.message.queryId, 64) + .storeCoins(opts.message.jettonAmount) + .storeAddress(opts.message.from) + .storeAddress(opts.message.responseDestination) + .storeCoins(opts.message.forwardTonAmount ?? 0n) + .storeSlice(beginCell().endCell().beginParse()) + .endCell() + + await provider.internal(via, { + value: opts.value, + sendMode: SendMode.PAY_GAS_SEPARATELY, + body: beginCell() + .storeUint(0x00000015, 32) + .storeUint(opts.message.queryId, 64) + .storeAddress(opts.message.destination) + .storeCoins(opts.message.tonAmount) + .storeRef(internalTransferMsg) + .endCell(), + }) + } + + async sendChangeMinterAdmin( + provider: ContractProvider, + via: Sender, + opts: { + value: bigint + queryId?: bigint + newAdminAddress: Address + }, + ) { + await provider.internal(via, { + value: opts.value, + sendMode: SendMode.PAY_GAS_SEPARATELY, + body: jettonMinterBuilder.messages.in + .changeMinterAdmin + .encode({ queryId: opts.queryId ?? 0n, newAdmin: opts.newAdminAddress }) + .asCell(), + }) + } + + async getWalletAddress(provider: ContractProvider, ownerAddress: Address): Promise
{ + const { stack } = await provider.get('get_wallet_address', [{ type: 'slice', cell: beginCell().storeAddress(ownerAddress).endCell() }]) + return stack.readAddress() + } +} diff --git a/contracts/wrappers/ccip/LockReleaseTokenPool.ts b/contracts/wrappers/ccip/LockReleaseTokenPool.ts new file mode 100644 index 000000000..ffb0b716c --- /dev/null +++ b/contracts/wrappers/ccip/LockReleaseTokenPool.ts @@ -0,0 +1,141 @@ +import { + Address, + beginCell, + Cell, + Contract, + contractAddress, + ContractProvider, + Sender, + SendMode, +} from '@ton/core' +import { crc32 } from 'zlib' +import { facilityId, errorCode } from '../utils' +import { contractCode } from '../codeLoader' +import { + codec, + createJettonClientData, + createTokenPoolData, + opcodes, + sendApplyChainUpdates, + sendReleaseOrMint, + sendUpdateCursedSubjects, + sendUpdateRampAccess, + type ChainUpdate, + type CrossChainAddress, + type JettonClientConfig, + type LockOrBurnInV1, + type LockOrBurnPayload, + type RampAccess, + type RateLimitConfig, + type ReleaseOrMintInV1, + type TokenPoolConfig, + type TokenPoolRateLimitConfigArgs, +} from './TokenPool' + +export const FACILITY_NAME = 'link.chain.ton.ccip.LockReleaseTokenPool' +export const FACILITY_ID = facilityId(crc32(FACILITY_NAME)) +export const ERROR_CODE = errorCode(crc32(FACILITY_NAME)) +export const CONTRACT_VERSION = '0.1.0' + +export type Config = TokenPoolConfig & { + jettonClient: JettonClientConfig +} + +export class LockReleaseTokenPool implements Contract { + constructor( + readonly address: Address, + readonly init?: { code: Cell; data: Cell }, + ) {} + + static createFromAddress(address: Address) { + return new LockReleaseTokenPool(address) + } + + static createFromConfig(config: Config, code: Cell, workchain = 0) { + const data = beginCell() + .storeRef(createTokenPoolData(config)) + .storeRef(createJettonClientData(config.jettonClient)) + .storeDict(null) + .endCell() + + const init = { code, data } + return new LockReleaseTokenPool(contractAddress(workchain, init), init) + } + + static code(): Promise { + return contractCode.ccip.local('LockReleaseTokenPool') + } + + async sendDeploy(provider: ContractProvider, via: Sender, value: bigint) { + await provider.internal(via, { + value, + sendMode: SendMode.PAY_GAS_SEPARATELY, + body: Cell.EMPTY, + }) + } + + async sendApplyChainUpdates( + provider: ContractProvider, + via: Sender, + value: bigint, + body: { queryId: bigint; remove: bigint[]; add: ChainUpdate[] }, + ) { + await sendApplyChainUpdates(provider, via, value, body) + } + + async sendUpdateRampAccess( + provider: ContractProvider, + via: Sender, + value: bigint, + body: { queryId: bigint; updates: RampAccess[] }, + ) { + await sendUpdateRampAccess(provider, via, value, body) + } + + async sendUpdateCursedSubjects( + provider: ContractProvider, + via: Sender, + value: bigint, + cursedSubjects: bigint[], + ) { + await sendUpdateCursedSubjects(provider, via, value, cursedSubjects) + } + + async sendReleaseOrMint( + provider: ContractProvider, + via: Sender, + value: bigint, + body: { + queryId: bigint + request: ReleaseOrMintInV1 + requestedFinalityConfig?: number + replyTo?: Address | null + }, + ) { + await sendReleaseOrMint(provider, via, value, body) + } + + async getHasPendingRelease(provider: ContractProvider, queryId: bigint) { + return provider + .get('hasPendingRelease', [{ type: 'int', value: queryId }]) + .then((res) => res.stack.readBoolean()) + } + + async getVerifyNotCursed(provider: ContractProvider, subject: bigint) { + return provider.get('verifyNotCursed', [{ type: 'int', value: subject }]).then((res) => res.stack.readBoolean()) + } + + async getOnRamp(provider: ContractProvider, remoteChainSelector: bigint) { + return provider.get('onRamp', [{ type: 'int', value: remoteChainSelector }]).then((res) => res.stack.readAddressOpt()) + } + + async getOffRamp(provider: ContractProvider, remoteChainSelector: bigint) { + return provider.get('offRamp', [{ type: 'int', value: remoteChainSelector }]).then((res) => res.stack.readAddressOpt()) + } + + async getIsSupportedChain(provider: ContractProvider, remoteChainSelector: bigint) { + return provider.get('isSupportedChain', [{ type: 'int', value: remoteChainSelector }]).then((res) => res.stack.readBoolean()) + } +} + +export { codec, opcodes } \ No newline at end of file diff --git a/contracts/wrappers/ccip/TokenPool.ts b/contracts/wrappers/ccip/TokenPool.ts new file mode 100644 index 000000000..59724674f --- /dev/null +++ b/contracts/wrappers/ccip/TokenPool.ts @@ -0,0 +1,346 @@ +import { + Address, + beginCell, + Builder, + Cell, + ContractProvider, + Dictionary, + Sender, + SendMode, + Slice, +} from '@ton/core' +import * as ownable2step from '../libraries/access/Ownable2Step' +import { asSnakedCell } from '../../src/utils' + +export const opcodes = { + in: { + applyChainUpdates: 0xdc0b6ff5, + addRemotePool: 0x5fd2c8b6, + removeRemotePool: 0xdbf0a2df, + setDynamicConfig: 0x4eea060b, + setAllowedFinalityConfig: 0x29b46fc6, + setRateLimitConfig: 0x3a028da2, + applyTokenTransferFeeConfigUpdates: 0x10c4b4a1, + updateRampAccess: 0x7a9c4aa5, + updateCursedSubjects: 0x823dadf2, + releaseOrMint: 0x7d0ffd89, + }, + payload: { + lockOrBurn: 0x1161516e, + }, + out: { + lockOrBurnResponse: 0x19e65bea, + releaseOrMintResponse: 0x7ec43aee, + releaseOrMintFailure: 0x41a1702b, + }, +} + +export type CrossChainAddress = Cell + +export type JettonClientConfig = { + masterAddress: Address + jettonWalletCode: Cell +} + +export type TokenPoolConfig = { + owner: Address + token: Address + tokenDecimals: number + rmnProxy: Address + router: Address +} + +export type TokenPoolJettonConfig = TokenPoolConfig & { + jettonClient: JettonClientConfig +} + +export type RateLimitConfig = { + isEnabled: boolean + capacity: bigint + rate: bigint +} + +export type ChainUpdate = { + remoteChainSelector: bigint + remotePoolAddresses: CrossChainAddress[] + remoteTokenAddress: CrossChainAddress + outboundRateLimiterConfig: RateLimitConfig + inboundRateLimiterConfig: RateLimitConfig +} + +export type RampAccess = { + remoteChainSelector: bigint + onRamp: Address | null + offRamp: Address | null +} + +export type LockOrBurnInV1 = { + receiver: CrossChainAddress + remoteChainSelector: bigint + originalSender: Address + amount: bigint + localToken: Address +} + +export type LockOrBurnPayload = { + queryId: bigint + request: LockOrBurnInV1 + requestedFinalityConfig: number + tokenArgs: Cell | null + replyTo: Address | null +} + +export type ReleaseOrMintInV1 = { + originalSender: CrossChainAddress + remoteChainSelector: bigint + receiver: Address + sourceDenominatedAmount: bigint + localToken: Address + sourcePoolAddress: CrossChainAddress + sourcePoolData: Cell | null + offchainTokenData: Cell | null +} + +export type TokenPoolRateLimitConfigArgs = { + remoteChainSelector: bigint + fastFinality: boolean + outboundRateLimiterConfig: RateLimitConfig + inboundRateLimiterConfig: RateLimitConfig +} + +export const codec = { + crossChainAddressFromBuffer(data: Buffer): Cell { + return beginCell().storeUint(data.length, 8).storeBuffer(data).endCell() + }, + + rateLimitConfig: { + encode(data: RateLimitConfig): Builder { + return beginCell().storeBit(data.isEnabled).storeUint(data.capacity, 256).storeUint(data.rate, 256) + }, + }, + + lockOrBurnInV1: { + encode(data: LockOrBurnInV1): Builder { + return beginCell() + .storeRef(data.receiver) + .storeUint(data.remoteChainSelector, 64) + .storeAddress(data.originalSender) + .storeUint(data.amount, 256) + .storeAddress(data.localToken) + }, + }, + + releaseOrMintInV1: { + encode(data: ReleaseOrMintInV1): Builder { + return beginCell() + .storeRef(data.originalSender) + .storeUint(data.remoteChainSelector, 64) + .storeAddress(data.receiver) + .storeUint(data.sourceDenominatedAmount, 256) + .storeAddress(data.localToken) + .storeRef(data.sourcePoolAddress) + .storeMaybeRef(data.sourcePoolData) + .storeMaybeRef(data.offchainTokenData) + }, + }, + + lockOrBurnPayload: { + encode(data: LockOrBurnPayload): Builder { + return beginCell() + .storeUint(opcodes.payload.lockOrBurn, 32) + .storeUint(data.queryId, 64) + .storeRef(codec.lockOrBurnInV1.encode(data.request).endCell()) + .storeUint(data.requestedFinalityConfig, 32) + .storeMaybeRef(data.tokenArgs) + .storeAddress(data.replyTo) + }, + }, + + releaseOrMintResponse: { + load(src: Slice): { queryId: bigint; destinationAmount: bigint } { + const op = src.loadUint(32) + if (op !== opcodes.out.releaseOrMintResponse) { + throw new Error('Unexpected opcode: ' + op) + } + const queryId = src.loadUintBig(64) + const out = src.loadRef().beginParse() + return { + queryId, + destinationAmount: out.loadUintBig(256), + } + }, + }, + + releaseOrMintFailure: { + load(src: Slice): { queryId: bigint; errorCode: number } { + const op = src.loadUint(32) + if (op !== opcodes.out.releaseOrMintFailure) { + throw new Error('Unexpected opcode: ' + op) + } + return { + queryId: src.loadUintBig(64), + errorCode: src.loadUint(16), + } + }, + }, + + lockOrBurnResponse: { + load(src: Slice): { queryId: bigint; destinationAmount: bigint } { + const op = src.loadUint(32) + if (op !== opcodes.out.lockOrBurnResponse) { + throw new Error('Unexpected opcode: ' + op) + } + const queryId = src.loadUintBig(64) + const out = src.loadRef().beginParse() + return { + queryId, + destinationAmount: out.loadUintBig(256), + } + }, + }, +} + +export function createTokenPoolData(config: TokenPoolConfig): Cell { + const dynamicConfig = beginCell() + .storeAddress(config.router) + .storeAddress(null) + .storeAddress(null) + .endCell() + + const adminConfig = beginCell() + .storeRef( + ownable2step.builder.data.traitData.encode({ + owner: config.owner, + pendingOwner: null, + }).asCell(), + ) + .storeAddress(config.rmnProxy) + .storeRef(dynamicConfig) + .storeUint(0, 32) + .endCell() + + return beginCell() + .storeRef(adminConfig) + .storeRef( + beginCell() + .storeDict(Dictionary.empty(Dictionary.Keys.BigUint(64), Dictionary.Values.Address())) + .storeDict(Dictionary.empty(Dictionary.Keys.BigUint(64), Dictionary.Values.Address())) + .storeDict(Dictionary.empty()) + .endCell(), + ) + .storeAddress(config.token) + .storeUint(config.tokenDecimals, 8) + .storeDict(Dictionary.empty(Dictionary.Keys.BigUint(64), Dictionary.Values.Cell())) + .storeDict(Dictionary.empty(Dictionary.Keys.BigUint(64), Dictionary.Values.Cell())) + .endCell() +} + +export function createJettonClientData(config: JettonClientConfig): Cell { + return beginCell() + .storeAddress(config.masterAddress) + .storeRef(config.jettonWalletCode) + .endCell() +} + +export async function sendApplyChainUpdates( + provider: ContractProvider, + via: Sender, + value: bigint, + body: { queryId: bigint; remove: bigint[]; add: ChainUpdate[] }, +) { + await provider.internal(via, { + value, + sendMode: SendMode.PAY_GAS_SEPARATELY, + body: beginCell() + .storeUint(opcodes.in.applyChainUpdates, 32) + .storeUint(body.queryId, 64) + .storeRef(asSnakeUint64(body.remove)) + .storeRef(asSnakeChainUpdates(body.add)) + .endCell(), + }) +} + +export async function sendUpdateRampAccess( + provider: ContractProvider, + via: Sender, + value: bigint, + body: { queryId: bigint; updates: RampAccess[] }, +) { + await provider.internal(via, { + value, + sendMode: SendMode.PAY_GAS_SEPARATELY, + body: beginCell() + .storeUint(opcodes.in.updateRampAccess, 32) + .storeUint(body.queryId, 64) + .storeRef(asSnakeRampAccess(body.updates)) + .endCell(), + }) +} + +export async function sendUpdateCursedSubjects( + provider: ContractProvider, + via: Sender, + value: bigint, + cursedSubjects: bigint[], +) { + const dict = Dictionary.empty(Dictionary.Keys.BigInt(128), Dictionary.Values.Bool()) + cursedSubjects.forEach((subject) => dict.set(subject, true)) + await provider.internal(via, { + value, + sendMode: SendMode.PAY_GAS_SEPARATELY, + body: beginCell().storeUint(opcodes.in.updateCursedSubjects, 32).storeDict(dict).endCell(), + }) +} + +export async function sendReleaseOrMint( + provider: ContractProvider, + via: Sender, + value: bigint, + body: { + queryId: bigint + request: ReleaseOrMintInV1 + requestedFinalityConfig?: number + replyTo?: Address | null + }, +) { + await provider.internal(via, { + value, + sendMode: SendMode.PAY_GAS_SEPARATELY, + body: beginCell() + .storeUint(opcodes.in.releaseOrMint, 32) + .storeUint(body.queryId, 64) + .storeRef(codec.releaseOrMintInV1.encode(body.request).endCell()) + .storeUint(body.requestedFinalityConfig ?? 0, 32) + .storeAddress(body.replyTo ?? null) + .endCell(), + }) +} + +function asSnakeUint64(items: bigint[]): Cell { + return asSnakedCell(items, (item) => beginCell().storeUint(item, 64)) +} + +function asSnakeCrossChainAddresses(items: Cell[]): Cell { + return asSnakedCell(items, (item) => beginCell().storeSlice(item.beginParse())) +} + +function asSnakeChainUpdates(items: ChainUpdate[]): Cell { + return asSnakedCell(items, (item) => + beginCell() + .storeUint(item.remoteChainSelector, 64) + .storeRef(asSnakeCrossChainAddresses(item.remotePoolAddresses)) + .storeRef(item.remoteTokenAddress) + .storeRef( + beginCell() + .storeRef(codec.rateLimitConfig.encode(item.outboundRateLimiterConfig).endCell()) + .storeRef(codec.rateLimitConfig.encode(item.inboundRateLimiterConfig).endCell()) + .endCell(), + ), + ) +} + +function asSnakeRampAccess(items: RampAccess[]): Cell { + return asSnakedCell(items, (item) => + beginCell().storeUint(item.remoteChainSelector, 64).storeAddress(item.onRamp).storeAddress(item.offRamp), + ) +} \ No newline at end of file From 1461c969825f157b5ed09a8cfbdd69556902cf1b Mon Sep 17 00:00:00 2001 From: Kristijan Date: Tue, 9 Jun 2026 12:39:59 +0200 Subject: [PATCH 02/16] Rename as ccip/pools, add gen wrappers --- contracts/Acton.toml | 18 + contracts/contracts/ccip/pool/TODO.md | 36 - .../contracts/ccip/pool/tolk-1.4-docs.md | 987 ------- .../burn_mint_token_pool/contract.tolk | 11 + .../burn_mint_token_pool/errors.tolk | 0 .../burn_mint_token_pool/messages.tolk | 0 .../burn_mint_token_pool/storage.tolk | 0 .../burn_mint_token_pool/types.tolk | 2 +- .../ccip/{pool => pools}/errors.tolk | 0 .../ccip/{pool => pools}/events.tolk | 1 + .../lock_release_token_pool/contract.tolk | 13 +- .../lock_release_token_pool/errors.tolk | 0 .../lock_release_token_pool/events.tolk | 0 .../lock_release_token_pool/messages.tolk | 0 .../lock_release_token_pool/storage.tolk | 0 .../lock_release_token_pool/types.tolk | 0 .../ccip/{pool => pools}/messages.tolk | 2 +- .../ccip/{pool => pools}/rate_limiter.tolk | 3 +- .../ccip/{pool => pools}/token_pool.tolk | 53 +- .../ccip/pools/token_pool_contract.tolk | 21 + .../contracts/ccip/{pool => pools}/types.tolk | 0 .../{pool => pools}/BurnMintTokenPool.spec.ts | 0 .../LockReleaseTokenPool.spec.ts | 0 .../{pool => pools}/TokenPool.behavior.ts | 7 +- ...> ccip.pools.BurnMintTokenPool.compile.ts} | 4 +- ...cip.pools.LockReleaseTokenPool.compile.ts} | 4 +- contracts/wrappers/ccip/BurnMintTokenPool.ts | 2 +- .../wrappers/ccip/LockReleaseTokenPool.ts | 2 +- .../gen/ccip/pools/BurnMintTokenPool.ts | 2345 +++++++++++++++++ .../gen/ccip/pools/LockReleaseTokenPool.ts | 2078 +++++++++++++++ .../wrappers/gen/ccip/pools/TokenPool.ts | 1885 +++++++++++++ 31 files changed, 6409 insertions(+), 1065 deletions(-) delete mode 100644 contracts/contracts/ccip/pool/TODO.md delete mode 100644 contracts/contracts/ccip/pool/tolk-1.4-docs.md rename contracts/contracts/ccip/{pool => pools}/burn_mint_token_pool/contract.tolk (97%) rename contracts/contracts/ccip/{pool => pools}/burn_mint_token_pool/errors.tolk (100%) rename contracts/contracts/ccip/{pool => pools}/burn_mint_token_pool/messages.tolk (100%) rename contracts/contracts/ccip/{pool => pools}/burn_mint_token_pool/storage.tolk (100%) rename contracts/contracts/ccip/{pool => pools}/burn_mint_token_pool/types.tolk (91%) rename contracts/contracts/ccip/{pool => pools}/errors.tolk (100%) rename contracts/contracts/ccip/{pool => pools}/events.tolk (99%) rename contracts/contracts/ccip/{pool => pools}/lock_release_token_pool/contract.tolk (96%) rename contracts/contracts/ccip/{pool => pools}/lock_release_token_pool/errors.tolk (100%) rename contracts/contracts/ccip/{pool => pools}/lock_release_token_pool/events.tolk (100%) rename contracts/contracts/ccip/{pool => pools}/lock_release_token_pool/messages.tolk (100%) rename contracts/contracts/ccip/{pool => pools}/lock_release_token_pool/storage.tolk (100%) rename contracts/contracts/ccip/{pool => pools}/lock_release_token_pool/types.tolk (100%) rename contracts/contracts/ccip/{pool => pools}/messages.tolk (97%) rename contracts/contracts/ccip/{pool => pools}/rate_limiter.tolk (93%) rename contracts/contracts/ccip/{pool => pools}/token_pool.tolk (96%) create mode 100644 contracts/contracts/ccip/pools/token_pool_contract.tolk rename contracts/contracts/ccip/{pool => pools}/types.tolk (100%) rename contracts/tests/ccip/{pool => pools}/BurnMintTokenPool.spec.ts (100%) rename contracts/tests/ccip/{pool => pools}/LockReleaseTokenPool.spec.ts (100%) rename contracts/tests/ccip/{pool => pools}/TokenPool.behavior.ts (98%) rename contracts/wrappers/{BurnMintTokenPool.compile.ts => ccip.pools.BurnMintTokenPool.compile.ts} (63%) rename contracts/wrappers/{LockReleaseTokenPool.compile.ts => ccip.pools.LockReleaseTokenPool.compile.ts} (63%) create mode 100644 contracts/wrappers/gen/ccip/pools/BurnMintTokenPool.ts create mode 100644 contracts/wrappers/gen/ccip/pools/LockReleaseTokenPool.ts create mode 100644 contracts/wrappers/gen/ccip/pools/TokenPool.ts diff --git a/contracts/Acton.toml b/contracts/Acton.toml index c7e03e988..c74440f7a 100644 --- a/contracts/Acton.toml +++ b/contracts/Acton.toml @@ -50,6 +50,24 @@ src = "contracts/ccip/merkle_root/contract.tolk" domain = "ccip" depends = [] +[contracts.TokenPool] +display-name = "link.chain.ton.ccip.TokenPool" +src = "contracts/ccip/pools/token_pool_contract.tolk" +domain = "ccip/pools" +depends = [] + +[contracts.LockReleaseTokenPool] +display-name = "link.chain.ton.ccip.LockReleaseTokenPool" +src = "contracts/ccip/pools/lock_release_token_pool/contract.tolk" +domain = "ccip/pools" +depends = [] + +[contracts.BurnMintTokenPool] +display-name = "link.chain.ton.ccip.BurnMintTokenPool" +src = "contracts/ccip/pools/burn_mint_token_pool/contract.tolk" +domain = "ccip/pools" +depends = [] + [contracts.Timelock] display-name = "link.chain.ton.mcms.Timelock" src = "contracts/mcms/rbac_timelock.tolk" diff --git a/contracts/contracts/ccip/pool/TODO.md b/contracts/contracts/ccip/pool/TODO.md deleted file mode 100644 index 258022be8..000000000 --- a/contracts/contracts/ccip/pool/TODO.md +++ /dev/null @@ -1,36 +0,0 @@ - -## Overview - -- Our goal is to translate token pool EVM implementation to TON/Tolk -- We will start with TokenPool.sol lib and the lock release pool -- The reimplementation in TON/Tolk should be as close as possible to EVM original, diviate only when required and where makes sense - - Can check translation as example: - - TVM: chainlink-ton/contracts/contracts/mcms/mcms.tolk - - EVM: ccip-owner-contracts/src/ManyChainMultiSig.sol -- We need to build same type of core token pool lib that different instances would extend and change behaviour - we used a hooks pattern for MCMS/RBACTimelock, but Tolk didn't have closures before 1.4, should have closures at 1.4: chainlink-ton/contracts/contracts/ccip/pool/TODO.md so this can be simplified in next version. -- We want to focus on resolving the async communication correctly, costs time and gas - - Need to authorise off/onramp calls via Router sync call on EVM - here we said we're going to authorise calls from executors, but how to support any - - Need to call advanced hooks, this can probably stay async - - Need to validate RMN curse, this can probably be propagated down from Router as it is with on/offramp - list of pools is going to be in pool registry, doesn't exist yet - - As we go we want to keep updating the documentation and design in llm-wiki, specifically the section on TokenPool like "### M1.4 Token Pool Core Library (IPoolV2, hardcoded defaultFinality)" in - - We might want to extract that into a separate (per-component) design page -- As we go along want to start building a basic test harness for token pools contracts (using wTON as Jetton), and add coverage as we move forward - we should use EVM available tests as inspiration to follow the spec, as we did for MCMS -- As we go along document issues, missing-components, todos, etc. with explicit enumerated comments so we can reference them as we iterate (e.g., TON-TP/16) - -## TODOs - -## Iterations progress notes - -1. Iteration 1 - - Added a first-pass generic TokenPool lib scaffold in `types.tolk`, `errors.tolk`, and `token_pool.tolk`. - - Scope is intentionally the shared core only: storage layout, EVM-parity request/response structs, decimals conversion, chain config management, fee config management, rate-limiter helpers, and MCMS-style runtime hooks for access checks and concrete token movement. - - Deliberately deferred in this pass: concrete contract entrypoints, async pending-operation state machines, lockbox integration, Jetton wallet hosting flow, Router/OnRamp/ReceiveExecutor wiring, and finality codec parity beyond the current default/single-fast-config check. - -2. Iteration 2 - - Added a first concrete non-lockbox `LockReleaseTokenPool` contract on top of the generic pool lib, plus a first sandbox harness. - - Async design choice for TVM: do not synchronously query Router or RMN from the pool. Instead, duplicate the minimum required auth/curse state locally in the pool and update it asynchronously through messages, analogous to `OffRamp_UpdateCursedSubjects`. - - Current concrete flow: - - outbound lock is triggered by `TransferNotificationForRecipient` on the pool wallet, not a synchronous pool call; - - inbound release starts from `LockReleaseTokenPool_ReleaseOrMint`, creates a pending operation keyed by `queryId`, and only resolves after `ReturnExcessesBack` from the expected recipient wallet; - - bounce handling currently covers the pool wallet transfer bounce path. - - Still deferred: executor integration, router-owned custody flow, lockbox-backed variant, richer failure taxonomy, and a generalized pending-op state machine shared across pool variants. \ No newline at end of file diff --git a/contracts/contracts/ccip/pool/tolk-1.4-docs.md b/contracts/contracts/ccip/pool/tolk-1.4-docs.md deleted file mode 100644 index 598af4886..000000000 --- a/contracts/contracts/ccip/pool/tolk-1.4-docs.md +++ /dev/null @@ -1,987 +0,0 @@ -This update is mostly about making Tolk contracts understandable not only by humans, but also by all **tools around the ecosystem**. - -Tolk already has a rich type system, auto-serialization, TON-specific concepts deeply integrated, and all the language features needed for smart contracts. In v1.4, we expose this knowledge outside the compiler: - -1. ABI export — for toolchain, explorers, UI -2. TypeScript wrappers for Tolk contracts -3. Source maps that map TVM execution back to Tolk source, variables, stack layout, and call frames -4. Debugger marks that enable step-by-step debugging of fully-optimized production contracts -5. Several language enhancements (continue the direction of a general-purpose language) - -ABI and source maps are the final pieces of my initial vision — exactly as I saw how all branches merge together, more than a year ago. So, let's explore how it looks like. - - - -# The `contract` keyword - -A contract file can now start with a `contract` declaration: - -```tolk -contract Counter { - author: "Tolk Team" - version: "0.1" - description: "A small counter contract" - - storage: ContractStorage - incomingMessages: Increment | Reset -} - -// ... all the rest of code unchanged: -// - types and declarations -// - onInternalMessage -// - get methods -``` - -## What does `contract` mean - -The directive is not a runtime thing, it does not affect bytecode at all. It is a declaration for tooling: "this source file is a contract, and these are the public shapes that describe it." - -You place `contract` in the same file with entrypoints: `onInternalMessage`, get methods, etc. If you have several contracts in a project (say, `JettonMinter` and `JettonWallet`) — you have several files with `onInternalMessage`, and you precede every file with a `contract` directive. - -For example. File `JettonMinter.tolk` (it's now the preferred PascalCase naming: a contract's filename is equal to its name): - -```tolk -import "..." -import "..." - -contract JettonMinter { - author: "..." - storage: MinterStorage - incomingMessages: MinterMessages -} - -// you still declare internal types, as earlier -// think of it like "implementation" - -struct MinterStorage { - ... -} - -type MinterMessages = Message1 | Message2 | Message3 - -// you still declare entrypoints, as earlier -// think of it like "public interface" - -fun onInternalMessage(in: InMessage) { ... } -fun onExternalMessage(body: slice) { ... } - -get fun minterMethod1() { ... } -get fun minterMethod2() { ... } -``` - -So, is it a breaking change? No! Everything still works without `contract` — and with it. If you add `contract`: -- you emphasize that it's a contract file -- you get ABI support and TypeScript wrappers -- all the tooling can interact with your contract via ABI -- some importing rules become more strict, read below - -## Declare ALL `get fun` in the same file - -Before Tolk v1.4, it was possible (and somebody used it) to split `get fun` across multiple files: - -``` -// file: separate-getter.tolk -get fun method1() { ... } - -// file: main.tolk -import "separate-getter" - -get fun method2() { ... } -``` - -The `contract` prohibits this: all entrypoints must exist in the same file, they cannot be imported. This is for clarity: when you explore a contract file, you should see all its "interface" as a whole. - -``` -// file: MyContract.tolk -import "separate-getter" // compilation error - -contract MyContract { ... } -``` - -You'll see an error to place all entrypoints in `MyContract.tolk`. - -So, rule1: keep `contract`, `onInternalMessage`, `onExternalMessage`, and `get fun` together — one file to expose the entire "interface". - -## `import "MyContract"` does NOT import its entrypoints - -Before Tolk v1.4, when you import a file with `get fun`, they become available implicitly. That's why managing multiple contracts in one project required accuracy: from "JettonMinter" you couldn't just import "JettonWallet", because it conflicted on `onInternalMessage` duplicate. You had to extract common parts to separate files (e.g. MinterStorage and WalletStorage in `storage.tolk`, all available messages, etc.). - -With Tolk v1.4, this becomes simpler: `import "MyContract"` with `contract MyContract` inside does NOT expose entrypoints. User-defined types work as earlier, but `onInternalMessage` and `get fun` are logically "part of a contract" and are not visible outside. - -This enables two interesting patterns. - -Pattern 1. You have a contract, and you write scripts or tests as standalone files: - -``` -import "Counter" // with `contract Counter` - -// tests are written as get methods, -// they do not conflict with `get fun` of Counter.tolk - -get fun `test increase does not overflow`() { - // use symbols from "Counter.tolk" as expected - val initial = Storage { - value: 0 - }; -} - -// you can even declare `main` (TVM method_id=0), -// it does not conflict with `onInternalMessage` -fun main() { - createMessage({ - body: CounterIncrement { - // ... - } - }) -} -``` - -Pattern 2. You have multiple contracts, and you can import one from another — you see all declarations, but entrypoints do not conflict, they "belong" to each `contract` specifically. - -``` -// file: JettonWallet.tolk - -contract JettonWallet { ... } - -struct WalletStorage { ... } - -struct MsgA { ... } -struct MsgB { ... } -type WalletMessages = MsgA | MsgB - -fun onInternalMessage() { ... } - -get fun walletMethod1() { ... } -``` - -``` -// file: JettonMinter.tolk -import "JettonWallet" - -contract JettonMinter { ... } - -// use WalletStorage, MsgA, etc. - -fun deployJW() { - val initial = WalletStorage { ... }; - // ... -} - -// and declare minter's entrypoints - -fun onInternalMessage() { ... } - -get fun minterMethod1() { ... } -``` - -All in all, `contract` specifier tells: -1. This file is a contract file, all its "public interface" exists solely in this file -2. This file, being imported, does not pollute outer scope with "public interface" - -## What properties can be specified in `contract` - -In practice, you'll specify `author`, `storage`, and `incomingMessages`. But generally, there are other fields which may also be useful: - -``` -contract SomeName { - /// arbitrary string, exported to ABI as-is - author: "Tolk team" - - /// arbitrary string (preferably semver), exported as-is - version: "1.0" - - /// arbitrary string, exported as-is - description: "..." - - /// tells what shape persistent on-chain data has - storage: MyStorage - - /// specified if storage has another shape AT DEPLOYMENT - /// (when calculating initial address); - /// example: NFT, when at deployment it's {itemIndex,collectionAddr}, - /// and after initialization it's enriched with {owner,content}; - /// then PartialStruct has 2 fields, and MyStorage has 4 - storageAtDeployment: PartialStruct - - /// internal messages that are accepted by this contract; - /// typically you use the same union as for `lazy` match - incomingMessages: UnionOfStructs - - /// if your contract has `onExternalMessage`, - /// you can specify which shape of a `slice` you expect; - /// typically use that struct/union for `lazy` fromSlice - incomingExternal: SomeStructOrUnion - - /// (rarely used, to override auto-calculated) - /// outgoing internal messages that a contract may send; - /// if not set, calculated by `createMessage` calls - outgoingMessages: UnionOfStructs - - /// (rarely used, to override auto-calculated) - /// outgoing external messages (aka "events") that may be emitted; - /// if not set, calculated by `createExternalLogMessage` calls - emittedEvents: UnionOfStructs - - /// (rarely used, to override auto-calculated) - /// exception codes that may be thrown (should be a enum); - /// if not set, calculated by `throw` / `assert` / etc. - thrownErrors: SomeEnum - - /// additional types that should appear in ABI even if - /// they are not reachable from storage/messages/getters; - /// for example, to use them in TypeScript unit tests - forceAbiExport: (type1, type2, ...) -} -``` - -As a conclusion, `contract` specifies some properties that cannot be inferred from source code — and combined with source code, are exported as a public ABI. - -
- -# Contract ABI export - -Before, Tolk code was compiled into Fift and TVM bytecode, but external tools still had to guess a lot: what messages the contract accepts, what storage shape it uses, what get methods exist, and how client-side values should be represented. - -Tolk v1.4 emits a machine-readable ABI JSON directly from Tolk sources. - -## Goals of having ABI - -ABI of a contract gives all necessary information for the following purposes: - -```text -Tolk -> ABI -> TypeScript wrappers - dynamic serialization - stack layout info - print any Tolk object to console - render a contract in explorer - build UI to send a message - build UI to invoke a get method - ... -``` - -## ABI JSON artifact - -Being invoked from a command-line, - -```bash -tolk -o out.fif Counter.tolk -``` - -The compiler outputs `out.abi.json` next to `out.fif`. - -**This ABI contains:** - -* contract name, author, version, description -* internal messages a contract accepts -* external messages, if any -* outgoing messages a contract sends by `createMessage` -* emitted events a contract writes by `createExternalLogMessage` -* storage shape a contract has -* storage at deployment for address calculation, if differs -* contract getters with parameters and returns -* exceptions a contract may throw -* user-defined declarations (structs, aliases, enums) -* a list of unique types where declarations point to -* Tolk compiler version - -## Example of abi.json - -`out.abi.json` looks like this: - -```json -{ - "abi_schema_version": "1.0", - "contract_name": "TolkCounter", - "unique_types": [ - {"kind":"void"}, - {"kind":"int"}, - {"kind":"slice"}, - {"kind":"cell"}, - {"kind":"builder"}, - {"kind":"bool"}, - {"kind":"coins"}, - {"kind":"address"}, - {"kind":"intN","n":32}, - {"kind":"uintN","n":32}, - {"kind":"intN","n":64}, - {"kind":"uintN","n":64}, - {"kind":"StructRef","struct_name":"IncreaseCounter"}, - {"kind":"StructRef","struct_name":"ResetCounter"}, - {"kind":"StructRef","struct_name":"Storage"} - ], - "struct_instantiations": [ - ], - "alias_instantiations": [ - ], - "declarations": [ - { - "kind": "struct", - "name": "Storage", - "ty_idx": 14, - "fields": [ - { - "name": "id", - "ty_idx": 9 - }, - { - "name": "counter", - "ty_idx": 9 - } - ] - }, - { - "kind": "struct", - "name": "IncreaseCounter", - "ty_idx": 12, - "prefix": { - "prefix_num": 2122802415, - "prefix_len": 32 - }, - "fields": [ - { - "name": "queryId", - "ty_idx": 11 - }, - { - "name": "increaseBy", - "ty_idx": 9 - } - ] - }, - { - "kind": "struct", - "name": "ResetCounter", - "ty_idx": 13, - "prefix": { - "prefix_num": 980758278, - "prefix_len": 32 - }, - "fields": [ - { - "name": "queryId", - "ty_idx": 11 - } - ] - } - ], - "storage": { - "storage_ty_idx": 14 - }, - "incoming_messages": [ - { - "body_ty_idx": 12 - }, - { - "body_ty_idx": 13 - } - ], - "incoming_external": [ - ], - "outgoing_messages": [ - ], - "emitted_events": [ - ], - "get_methods": [ - { - "tvm_method_id": 117456, - "name": "currentCounter", - "parameters": [ - ], - "return_ty_idx": 1 - }, - { - "tvm_method_id": 71937, - "name": "initialId", - "parameters": [ - ], - "return_ty_idx": 1 - } - ], - "thrown_errors": [ - { - "kind": "plain_int", - "err_code": 65535 - } - ], - "compiler_name": "tolk", - "compiler_version": "1.4.0" -} -``` - -Note: ABI is hard to read. For instance, it contains `unique_types`, which are referenced by indexes: `body_ty_idx`, `return_ty_idx`, etc. But JSON is not targeted to be read by eye: it's targeted for machine parsing. - -## How the compiler calculates all these fields - -Almost everything can be calculated automatically by contract's source code. For example: - -* outgoing messages — by inspecting `createMessage` and `TBody` within it -* exceptions — by inspecting `throw` and `assert` with constants/enums -* getters — by `get fun` -* etc. - -But some fields can NOT be automatically detected — those are provided in `contract` manually: - -* author, description -* incoming messages -* shape of storage - -A reasonable question: **why can't the compiler detect incoming messages**? The answer is: contract's code is not declarative, it's imperative. Yes, most likely, you use a union with `lazy` match. But generally, you can split this union into several; use manual parsing and opcodes; want to hide admin messages from ABI; etc. Same goes for storage: from the compiler's perspective, `MyStorage` is a regular struct, you call `fromCell` and `toCell` in arbitrary places, it does not differ from any other struct. That's why, instead of fragile heuristics, I decided to always require specifying those fields from the user's side. And it's also better for the reader. - -## Doc comments as description - -Place `/// doc comment` over every struct/field/enum — they go as "description" to ABI, and therefore will be rendered as TypeScript comments, in UI, etc. - -```tolk -/// Persistent contract data -struct (0x12345678) ContractStorage { - /// Current counter value - counter: int32 - - /// Contract owner - owner: address -} - -/// Reads current counter. -/// @param verbose whether to include debug info -get fun currentCounter(verbose: bool): (int32, cell?) { - ... -} -``` - -The compiler parses only `///` comments. They must be placed strictly above declarations, they are not allowed to be inside regular code — use simple `//` comments there. - -For the example above, ABI will contain descriptions: - -``` - declarations: [ - { - "kind": "struct", - "name": "ContractStorage", - "fields": [ - { - "name": "counter", - "ty_idx": 123, - "description": "Current counter value" - }, - { - "name": "owner", - "ty_idx": 124, - "description": "Contract owner" - } - ] - } - ], - "get_methods": [ - { - "tvm_method_id": 117456, - "name": "currentCounter", - "parameters": [ - { - "name": "verbose", - "ty_idx": 125, - "description": "whether to include debug info" - } - ], - "return_ty_idx": 126, - "description": "Reads current counter." - } - ], -``` - -A good manner is also to use descriptions for error codes. Then, in case of exceptions, UI and IDE will be able to provide details from a comment. - -``` -enum ErrCode { - /// Sender is not allowed to perform this action. - NotOwner = 401 -} -``` - -## Special annotation `@abi.clientType` - -Sometimes the on-chain type is intentionally low-level, but client tools should see a more convenient shape. - -For example, `forwardPayload` in jettons is often just `slice`: we don't want to waste gas on validation and carrying a union. But for external clients (TypeScript, explorers, etc.) we want to expose it "inline payload or ref payload": - -```tolk -struct AskToTransfer { - // ... - @abi.clientType(PayloadInline | PayloadInRef) - forwardPayload: RemainingBitsAndRefs -} -``` - -The compiler still type-checks and serializes the real field as `RemainingBitsAndRefs`, but ABI emits it as a union (`client_ty_idx` in a field). - -This is a way to hide "implementation details" while exposing schema-described public contract interface. - -## Defining ABI for existing FunC contracts - -Imagine, you have an existing FunC contract (deployed to mainnet, so you are not going to rewrite it), and you want to use TypeScript generator. What are required steps? - -One might think, that he should write a JSON manually. But it's an incorrect path. - -The answer is: **decribe FunC's interfaces in Tolk** and generate ABI from that fake contract. - -``` -contract SwapalkaInFunC { - incomingMessages: A | B | C - outgoingMessages: D | E | F - storage: S - thrownErrors: ErrCodes -} - -// declare types mentioned in `contract` - -struct (0x12345600) A { ... } -struct (0x12345601) B { ... } -// ... - -enum ErrCodes { - NotAdmin = 401, - InsufficientBalance = 402, - ... -} - -// declare get methods and their types - -struct CalcSwapCostReply { - from: address - to: address - cost: coins -} - -get fun calc_swap_cost(from: address): CalcSwapCostReply { - // to satisfy the type system, we need to return something; - // not very beautiful, but let it be this way for now - return { - from: FAKE_ADDR, - to: FAKE_ADDR, - cost: 0, - } -} - -// and an empty entrypoint - -fun onInternalMessage() { -} -``` - -It's also a valid contract — without any body — and sufficient for ABI generation. Using `///` comments will enrich ABI with descriptions. - -You might also notice why `outgoingMessages` and `thrownErrors` are useful. In practice, they are auto-calculated by `createMessage`, `throw`, etc. But in case you are "just describing ABI" they are the key. Also they are helpful if you are writing a proxy contract that does not `createMessage` itself — it sends an already composed message cell. Then you can describe types of those implicit messages for explorers/UI/etc. - -## ABI in tonscan / tonviewer / TON Center / TonAPI / etc. - -In the near future, we'll work with other teams to bring ABI support across TON ecosystem. - -For instance, explorers have lots of heuristics and implicit conventions to render messages and transactions in UI. Ideally, this layer should be standartized and be fully based on ABI standard. ABI for existing contracts may be described in a way shown above. - -## Side note: ABI is based on Tolk types, NOT on TL-B - -Experienced FunC developers tend to ask questions like "How to generate a TL-B schema for a Tolk structure?". Or — alternatively — "we already have a TL-B codegenerator, so ABI should probably reuse TL-B tooling". - -Such reasoning leads in the wrong direction — because the Tolk **type system** is designed as a **replacement for TL-B**. - -There is no need to "provide a TL-B schema for a contract". Every Tolk `struct` **is already a schema**. - -**TL-B and the Tolk type system are not equivalent**, even if they look similar at first glance. - -Similarities include: - -- `intN`, `uintN`, `bitsN` -- `Maybe` (nullable), `Either` (a two-component union) -- multiple constructors (declared structs + prefixes + unions) -- cells and typed cells - -But the differences are essential. - -TL-B supports the following (not expressible in Tolk): - -- `~tilde` -- `{conditions}` -- dynamic `## n` - -Tolk supports the following (not expressible in TL-B): - -- type aliases -- enums -- inline unions (auto-generated prefix trees) -- tensors -- custom `packToBuilder` and `unpackFromSlice` -- `address?` as "internal or none" (not "maybe T") - -Moreover: ABI is not only about serialization, but also about stack layout, because get methods work via the stack. - -The conclusion is simple: to make ABI sufficient for all scenarios, **it must rely on the type system, not on TL-B**. - -## How exactly types are represented in ABI - -Type representation in ABI covers all nuances of the type system. Even though it might seem simple, there are lots of corner cases. For example: - -- how are typed cells represented? -- how are generic structs and aliases described? -- how to serialize unions with prefix trees? -- how to read a union from a TVM stack? -- how to deal with `packToBuilder` and `unpackFromSlice`? - -ABI gives extensive information to answer all these questions and do any interaction with a contract solely having its ABI. - -Since this piece of information is very big, I will not include it in this description. Instead, I'll provide a comprehensive README in a separate repo, where ABI is used on the client side: in a TypeScript wrappers generator. - - - -# TypeScript wrappers for Tolk contracts - -Aside from the `ton-blockchain` repo, I have implemented a TypeScript generator based on ABI. The compiler emits ABI, the only source of truth: - -``` -Tolk -> ABI -> TypeScript wrappers - -> Go wrappers - -> Rust wrappers - -> Python wrappers - -> JSON marshalling - -> Tolk declarations -``` - -Currently, only TypeScript generator is ready, but others are only a matter of time. - -## Why TypeScript wrappers are needed - -A contract in a blockchain is "the backend" layer. In practice, you have a dApp — frontend — that somehow interacts with a contract: sends messages, calls get methods, etc. In order to compose message cells and properly manipulate a TVM stack, you manually had to mirror your contract's "interface" in TypeScript — a boring and error-prone work. Now it's fully automated. - -All in all, you use TypeScript for -- frontend and UI, to interact with contracts -- end-to-end tests, involving offchain and onchain -- cumbersome on-chain scripting - -## What TypeScript wrappers contain - -For every `contract`, a single `ContractName.gen.ts` file contains: - -- all structs exposed as TS interfaces; each can be serialized to a builder and deserialized from a slice, identically to how Tolk compiler does it -- all type aliases as TS type aliases -- all enums exposed as TS enum-like objects (not TS enums, they don't support bigint) -- private helpers to compose address, StateInit, and sharding -- private helpers to manipulate TVM stack -- a class `ContractName` with high-level methods: send messages, compose message cells, call get methods - -TypeScript generator supports all nuances of the Tolk type system, even generics and unions. This sounds simple, but when you think deeper, it becomes absolutely unobvious. For example, `int64` in Tolk translates to `bigint` in TypeScript. But how `int64 | int128` should look like? `bigint | bigint` makes no sense, then how? - -Anyway, since I managed to solve all issues at the border between Tolk (statically typed, compiled) and TypeScript (dynamically typed, interpreted), wrappers for other languages look promising. - -## How to use the TypeScript generator - -Proceed to a dedicated repo: - -https://github.com/ton-blockchain/tolk-abi-to-typescript - -
- -# Source maps and debugger - -Tolk v1.4 introduces compiler-side **source maps**. For the end user, they are the foundation of: -- debugger -- coverage -- unwinding on TVM exception - -All these features are released together with v1.4 in the toolchain (read below). - -The goal is simple to say and very hard to implement: - -*"Given a TVM execution point, determine the original Tolk source location, current function, call stack, initialized variables, and their values."* - -The most curious thing about source maps: they work for **for fully-optimized production Tolk contracts**. No "disable optimizations" mode, no bytecode modification. - -Tolk still inlines functions, folds constants, performs lazy deserialization, and emits optimized bytecode. Nevertheless, source maps provide all info to remap execution state back. - -## Where source maps are useful - -For example, a contract fails with exit code 9. Earlier, you had to manually explore TVM logs, study generated assembler, manually mapping assembler code to original Tolk sources (which is a very hard task), trying to reconstruct the original trace and what *actually* happened. - -Now, you automatically have: - -- an exact location of the exception -- call stack (including inlined functions!) -- all local variables in every call frame (including already disappeared from a stack!) -- all TVM registers -- all global variables -- all deserialized contents of typed cells - -And again — this all works WITHOUT bytecode modification. - -## Step-by-step debugger - -Since we have an ability to calculate TVM state at every asm instruction (due to source maps), we introduce a real step-by-step debugger, working via DAP — Debugger Adapter Protocol — supported by all major IDEs. - -You can just click "debug" in VS Code or JetBrains, and evaluate a request step by step: - -- see all variables and how they change -- all `lazy` objects (even if their fields were not loaded yet!) -- step over, step into, step out (even into inlined functions!) -- use breakpoints and run to cursor -- stop on uncaught exception -- and more, exactly as you expect from a debugger - -This provides awesome experience, compared to modern Web2 languages — but working inside TVM. - -Moreover — you can take a transaction hash from a real mainnet, and debug it step-by-step — from a real network. A transaction failed in mainnet? No problem, just debug it in IDE (if you have sources of that contract, of course). That would be impossible if we used "disable optimizations" for debugging — but we do not, that's why it works. - -## How exactly source maps and debugger work - -The architecture of debugging fully-optimized contracts is very complicated. It involves tricks in the compiler, ABI core, patched Fift, patched TVM, and a standalone replayer that combines all artifacts and literally *emulates* (replays) transaction flow. - -I will not explain this machinery here, in MR's description — otherwise, the description will become too large to be analyzed. Instead, I'll provide a dedicated document "How the debugger works" in the near future. - -## How to try the debugger - -The debugger comes a part of Acton toolchain. Read below. - - - - -# Several language enhancements - -In Tolk v1.3 I introduced many new language features that are primarily not for contracts, but for libraries and frameworks. In a way, Tolk becomes more general-purpose language. - -Tolk v1.4 also brings some improvements in this direction. - -### Closures (lambdas with captures) - -Lambdas without capturing already existed in Tolk. Now they can capture outer variables and really become first-class functions: - -```tolk -fun makeAdder(delta: int): int -> int { - return fun(value) { - return value + delta; - }; -} - -fun demo() { - val add3 = makeAdder(3); - return add3(10); // 13 -} -``` - -There is no special `use` or `[&]` syntax: capturing is done automatically. - -Variables are captured by value, at the exact point where a lambda is created. Mutations become independent: - -```tolk -fun demo() { - var x = 10; - - val cb = fun() { - return x + 1; - }; - - x = 20; - return cb(); // 11, not 21 -} -``` - -Lambdas and capturing work with generics, nesting, and smart casts. For instance, if `v` is smart-casted at the point where the lambda is created, the closure captures that narrowed type. - -### Optional `void` parameters - -Tolk already allowed `void` fields to be omitted in object literals: - -```tolk -struct S { - x: int - marker: void -} - -val s = S { x: 10 }; // marker is omitted -``` - -For instance, `body` of `createMessage` can be omitted, because its type defaults to `TBody = void`. - -Now the same convention applies to function parameters. - -If a trailing parameter has type `void`, it may be omitted: - -```tolk -fun format(msg: string, arg1: T1, arg2: T2) { - ... -} - -format("hello"); -format("value is {}", 42); -format("pair is {} and {}", "str", beginCell()); -``` - -This is especially convenient for generic helpers where "no argument" is represented by `void`, not by an artificial nullable wrapper or a pile of overloads. - -### `void` inside unions for serialization - -`T | void` is a valid union now, and it also can be (de)serialized. `void` here means "empty slice". - -This allows to express "maybe zero bits" in serialization. Unlike `T | null`, which requires at least one bit (0 or 1+T), `T | void` means NOTHING or T. - -For example: -- `int32 | void` — either int32 or nothing -- `A | B | C | void` — either empty slice, or some of those variants -- `int8 | null | void` — empty / 0 / 1+int8 - -In other words, `void` does not participate in prefix tree. On deserialization, it's a special case: if a slice is empty, `void` is saved. On serialization, if active variant is `void`, nothing is written. - -Since it's a regular type, after deserialization, it can be tested with `someVar is void`, or `match (v) { int32 => ... void => ... }`, etc. - -Using `Cell | void` we can describe an imperative chain of wallet-v5 payload "parse cells until refs exist" that is unrepresentable with TL-B. - -### Numeric separators - -Integer literals can now contain `_` separators: - -```tolk -const A = 1_000_000; -const B = 0x_ABCD_EF01; -const C = 0b_1010_1011_0000; -``` - -### Enums are assignable to integers - -Enums are distinct types, but enum values can now be assigned to integer variables without `as` cast: - -```tolk -var x: int = Color.Red; -var y: int32 = VmExitCode.OutOfGasError; -``` - -This looks a bit strange for decorative enums like `Color`, but it is very convenient for enums that represent TVM exit codes, operation ids, modes, and other numeric constants. - -This does not mean that enums silently become integers everywhere. For example: - -```tolk -1 + Color.Blue; // still an error -``` - -### Breaking change: only `bool` in conditions - -This is the biggest language-level breaking change in v1.4. - -Before, Tolk allowed integers in conditions: - -```tolk -if (x) { ... } -while (coinsAmount) { ... } -assert (flags) throw 123; -``` - -Now conditions must be `bool`. Write explicitly: - -```tolk -if (x != 0) { ... } -while (coinsAmount != 0) { ... } -assert (flags != 0) throw 123; -``` - -This applies to: `if`, `while`, `do while`, ternary condition, and `assert`. - -Similarly, unary `!` accepts only `bool` now: use not `if (!num)`, but `if (num == 0)`. - -While using integers as conditions is common in C-like languages, we decided to make it stricter. - -Note: there is **no gas overhead**. Writing `x != 0` does not mean that the compiler blindly emits `0 NEQINT`. The lowering detects this pattern and strips the comparison off. The source code becomes more explicit, while bytecode stays efficient. - -## `do while` scope is now conventional - -The `do while` scoping has been aligned with other languages. - -Before, the condition could see variables declared inside the loop body: - -```tolk -do { - var found = ... -} while (found); -``` - -Now this is an error: - -```text -undefined symbol `found` -``` - -Declare the variable before the loop: - -```tolk -var found: bool; -do { - found = ... -} while (found); -``` - -To be honest, I changed this behavior due to AI agents: they argue on non-standard scoping while reading Tolk contracts, thinking it's an error. No languages (except FunC, and Tolk consequently) allow "leaking" loop's body to condition. So, this change removes this exception and makes `do while` consistent with block scopes everywhere else. - -## Several bug fixes found through LLM fuzzing - -Traditionally, we had some research and bug bounty reports targeting invalid compiler behavior in corner cases. Most of the findings are false positives, but some of them make sense and should be fixed. None of them could appear in real straightforward code, only in artificial scenarios you'd very unlikely face with. - -For instance: - -- tricky recursive generics leading to infinite stack size -- more accurate handling of `never` type -- smart casts in loops up to a fixed control flow point -- mixture of generics and asm functions -- and similar - -## Migrating from v1.3 to v1.4 - -As a conclusion, a quick migration guide: - -1. Add `contract` directive above each `onInternalMessage`. If `get fun` are implicitly imported, you'll get an error. Then place them below: `contract` requires the whole public interface to be visible in one file. You can leave common implementation shared, but each contract must declare `get fun` independently. - -2. Facing an error "can not use `int` as a boolean condition", replace `if (someNumber)` with `if (someNumber != 0)`. This applies to `if`, `while`, `assert`, and ternary. - -3. Facing an error "undefined symbol `x`" in condition of `do while` body, move `x` lateinit declaration before the loop, as shown above. - - -
- -# Acton: a unified toolchain for TON - -Together with Tolk v1.4, we are releasing a **TON toolchain** named Acton. - -## Modern replacement for blueprint - -When Tolk appeared, it made FunC feel like the old world. Tolk is not just "a bit better" — it feels like a different era. - -Now we are doing the same for the entire on-chain development stack. - -We are releasing Acton — all-in-one toolchain for project management, testing, scripting, debugging, deployment, and more. Not a bunch of utilites — a full development environment built as one coherent system around Tolk. - -## What features are bundled into Acton - -* Project management. Contracts, unit tests, integration tests, and ready-to-use templates. - -* Native tests in Tolk — not in TypeScript. Not only unit tests — but chains of transactions. 50x faster than the current JS sandbox. Mutation testing, fuzzing testing, and even fork testing — loading account states from mainnet on demand. - -* A real debugger. Test failed with exit code 9? Stop exactly at the exception, inspect the call stack, local variables, lazy fields, and more. - -* Faucet and deployment. Work with wallets locally, top-up on testnet with embedded faucet. On-chain scripts are also written in Tolk. - -* Transaction visualization. Inspect transaction trees, messages, fees, storage changes — for every test, in a clean dev-oriented UI. - -* IDE integration, linter, formatter, code coverage, gas profiling. - -* AI-friendly. Skills and manuals available out of the box. Acton is a modern CLI tool that becomes an agent's runtime. - -Note that everything became possible, because Tolk is not limited by contracts — it's now a general-purpose language. The type system, ABI, and source maps join together to provide the kernel. All other pieces — 100k+ lines of Rust code — were carefully written by my teammates. - -## How to try Acton - -**https://ton-blockchain.github.io/acton/** - - - -# Related pull requests - -- https://github.com/ton-blockchain/tolk-js/pull/19 -- https://github.com/ton-blockchain/tolk-bench/pull/6 -- https://github.com/ton-org/docs/pull/2150 -- TypeScript generator: https://github.com/ton-blockchain/tolk-abi-to-typescript -- Agent skills: https://github.com/ton-blockchain/skills -- Acton contracts repo: https://github.com/ton-blockchain/acton-contracts -- Acton: https://ton-blockchain.github.io/acton/ - diff --git a/contracts/contracts/ccip/pool/burn_mint_token_pool/contract.tolk b/contracts/contracts/ccip/pools/burn_mint_token_pool/contract.tolk similarity index 97% rename from contracts/contracts/ccip/pool/burn_mint_token_pool/contract.tolk rename to contracts/contracts/ccip/pools/burn_mint_token_pool/contract.tolk index 8c5620343..6680c2706 100644 --- a/contracts/contracts/ccip/pool/burn_mint_token_pool/contract.tolk +++ b/contracts/contracts/ccip/pools/burn_mint_token_pool/contract.tolk @@ -1,4 +1,6 @@ // SPDX-License-Identifier: BUSL-1.1 +tolk 1.4.1 + import "../../../lib/utils.tolk" import "../../../lib/access/ownable_2step.tolk" import "../../../lib/jetton/jetton_client.tolk" @@ -16,6 +18,15 @@ import "types" import "errors" import "storage" +contract BurnMintTokenPool { + author: "SmartContract Chainlink Limited SEZC" + version: "0.1.0" + description: "link.chain.ton.ccip.BurnMintTokenPool" + + storage: Storage + incomingMessages: BurnMintTokenPool_CustomInMessage // TODO: all incoming messages should be registered +} + fun onInternalMessage(in: InMessage) { var st = Storage.load(); var pool = loadPool(st); diff --git a/contracts/contracts/ccip/pool/burn_mint_token_pool/errors.tolk b/contracts/contracts/ccip/pools/burn_mint_token_pool/errors.tolk similarity index 100% rename from contracts/contracts/ccip/pool/burn_mint_token_pool/errors.tolk rename to contracts/contracts/ccip/pools/burn_mint_token_pool/errors.tolk diff --git a/contracts/contracts/ccip/pool/burn_mint_token_pool/messages.tolk b/contracts/contracts/ccip/pools/burn_mint_token_pool/messages.tolk similarity index 100% rename from contracts/contracts/ccip/pool/burn_mint_token_pool/messages.tolk rename to contracts/contracts/ccip/pools/burn_mint_token_pool/messages.tolk diff --git a/contracts/contracts/ccip/pool/burn_mint_token_pool/storage.tolk b/contracts/contracts/ccip/pools/burn_mint_token_pool/storage.tolk similarity index 100% rename from contracts/contracts/ccip/pool/burn_mint_token_pool/storage.tolk rename to contracts/contracts/ccip/pools/burn_mint_token_pool/storage.tolk diff --git a/contracts/contracts/ccip/pool/burn_mint_token_pool/types.tolk b/contracts/contracts/ccip/pools/burn_mint_token_pool/types.tolk similarity index 91% rename from contracts/contracts/ccip/pool/burn_mint_token_pool/types.tolk rename to contracts/contracts/ccip/pools/burn_mint_token_pool/types.tolk index 25771ecae..f4c7fb8aa 100644 --- a/contracts/contracts/ccip/pool/burn_mint_token_pool/types.tolk +++ b/contracts/contracts/ccip/pools/burn_mint_token_pool/types.tolk @@ -3,7 +3,7 @@ import "../../../lib/jetton/jetton_client.tolk" import "../../rmn_remote/lib" import "../types" -const BurnMintTokenPool_CONTRACT_NAME = "BurnMintTokenPool".literalSlice(); +const BurnMintTokenPool_CONTRACT_NAME = "link.chain.ton.ccip.BurnMintTokenPool".literalSlice(); const BurnMintTokenPool_CONTRACT_VERSION = "0.1.0".literalSlice(); const BurnMintTokenPool_CLAIM_ADMIN_VALUE = ton("0.05"); const BurnMintTokenPool_BURN_VALUE = ton("0.05"); diff --git a/contracts/contracts/ccip/pool/errors.tolk b/contracts/contracts/ccip/pools/errors.tolk similarity index 100% rename from contracts/contracts/ccip/pool/errors.tolk rename to contracts/contracts/ccip/pools/errors.tolk diff --git a/contracts/contracts/ccip/pool/events.tolk b/contracts/contracts/ccip/pools/events.tolk similarity index 99% rename from contracts/contracts/ccip/pool/events.tolk rename to contracts/contracts/ccip/pools/events.tolk index 8bc8d656e..dff934d73 100644 --- a/contracts/contracts/ccip/pool/events.tolk +++ b/contracts/contracts/ccip/pools/events.tolk @@ -1,5 +1,6 @@ // SPDX-License-Identifier: BUSL-1.1 import "../common/types" +import "types" const TOKEN_POOL_LOCKED_OR_BURNED_TOPIC = stringCrc32("TokenPool_LockedOrBurned"); const TOKEN_POOL_RELEASED_OR_MINTED_TOPIC = stringCrc32("TokenPool_ReleasedOrMinted"); diff --git a/contracts/contracts/ccip/pool/lock_release_token_pool/contract.tolk b/contracts/contracts/ccip/pools/lock_release_token_pool/contract.tolk similarity index 96% rename from contracts/contracts/ccip/pool/lock_release_token_pool/contract.tolk rename to contracts/contracts/ccip/pools/lock_release_token_pool/contract.tolk index dfb1b7b6d..f17da4a2c 100644 --- a/contracts/contracts/ccip/pool/lock_release_token_pool/contract.tolk +++ b/contracts/contracts/ccip/pools/lock_release_token_pool/contract.tolk @@ -1,4 +1,6 @@ // SPDX-License-Identifier: BUSL-1.1 +tolk 1.4.1 + import "../../../lib/utils.tolk" import "../../../lib/access/ownable_2step.tolk" import "../../../lib/jetton/messages.tolk" @@ -16,6 +18,15 @@ import "types" import "errors" import "storage" +contract LockReleaseTokenPool { + author: "SmartContract Chainlink Limited SEZC" + version: "0.1.0" + description: "link.chain.ton.ccip.LockReleaseTokenPool" + + storage: Storage + incomingMessages: LockReleaseTokenPool_CustomInMessage // TODO: all incoming messages should be registered +} + fun onInternalMessage(in: InMessage) { var st = Storage.load(); var pool = loadPool(st); @@ -263,4 +274,4 @@ get fun owner(): address { get fun pendingOwner(): address? { return Storage.load().poolData.load().adminConfig.load().ownable.load().get_pendingOwner(); -} \ No newline at end of file +} diff --git a/contracts/contracts/ccip/pool/lock_release_token_pool/errors.tolk b/contracts/contracts/ccip/pools/lock_release_token_pool/errors.tolk similarity index 100% rename from contracts/contracts/ccip/pool/lock_release_token_pool/errors.tolk rename to contracts/contracts/ccip/pools/lock_release_token_pool/errors.tolk diff --git a/contracts/contracts/ccip/pool/lock_release_token_pool/events.tolk b/contracts/contracts/ccip/pools/lock_release_token_pool/events.tolk similarity index 100% rename from contracts/contracts/ccip/pool/lock_release_token_pool/events.tolk rename to contracts/contracts/ccip/pools/lock_release_token_pool/events.tolk diff --git a/contracts/contracts/ccip/pool/lock_release_token_pool/messages.tolk b/contracts/contracts/ccip/pools/lock_release_token_pool/messages.tolk similarity index 100% rename from contracts/contracts/ccip/pool/lock_release_token_pool/messages.tolk rename to contracts/contracts/ccip/pools/lock_release_token_pool/messages.tolk diff --git a/contracts/contracts/ccip/pool/lock_release_token_pool/storage.tolk b/contracts/contracts/ccip/pools/lock_release_token_pool/storage.tolk similarity index 100% rename from contracts/contracts/ccip/pool/lock_release_token_pool/storage.tolk rename to contracts/contracts/ccip/pools/lock_release_token_pool/storage.tolk diff --git a/contracts/contracts/ccip/pool/lock_release_token_pool/types.tolk b/contracts/contracts/ccip/pools/lock_release_token_pool/types.tolk similarity index 100% rename from contracts/contracts/ccip/pool/lock_release_token_pool/types.tolk rename to contracts/contracts/ccip/pools/lock_release_token_pool/types.tolk diff --git a/contracts/contracts/ccip/pool/messages.tolk b/contracts/contracts/ccip/pools/messages.tolk similarity index 97% rename from contracts/contracts/ccip/pool/messages.tolk rename to contracts/contracts/ccip/pools/messages.tolk index b55c75728..c6250edc5 100644 --- a/contracts/contracts/ccip/pool/messages.tolk +++ b/contracts/contracts/ccip/pools/messages.tolk @@ -60,7 +60,7 @@ struct (0x823dadf2) TokenPool_UpdateCursedSubjects { /// @param tokenArgs Additional token arguments. struct (0x1161516e) TokenPool_LockOrBurn { queryId: uint64; - lockOrBurnIn: Cell; + request: Cell; // TODO: consider renaming requestedFinalityConfig: uint32; tokenArgs: cell?; replyTo: address?; diff --git a/contracts/contracts/ccip/pool/rate_limiter.tolk b/contracts/contracts/ccip/pools/rate_limiter.tolk similarity index 93% rename from contracts/contracts/ccip/pool/rate_limiter.tolk rename to contracts/contracts/ccip/pools/rate_limiter.tolk index edd97e5b0..2ddf8b6f1 100644 --- a/contracts/contracts/ccip/pool/rate_limiter.tolk +++ b/contracts/contracts/ccip/pools/rate_limiter.tolk @@ -30,7 +30,8 @@ fun RateLimiter_consumeBucket(mutate bucket: RateLimiter_TokenBucket, amount: ui } RateLimiter_refillBucket(mutate bucket); - assert(bucket.tokens >= amount, TokenPool_Error.RateLimitExceeded); + // TODO: should be RateLimiter error + // assert(bucket.tokens >= amount, TokenPool_Error.RateLimitExceeded); bucket.tokens -= amount; } diff --git a/contracts/contracts/ccip/pool/token_pool.tolk b/contracts/contracts/ccip/pools/token_pool.tolk similarity index 96% rename from contracts/contracts/ccip/pool/token_pool.tolk rename to contracts/contracts/ccip/pools/token_pool.tolk index 6a9024323..4bec6c970 100644 --- a/contracts/contracts/ccip/pool/token_pool.tolk +++ b/contracts/contracts/ccip/pools/token_pool.tolk @@ -190,7 +190,8 @@ fun TokenPool.setDynamicConfig( var adminConfig = self.data.adminConfig.load(); adminConfig.ownable.load().requireOwner(sender); - assert(!router.isNone(), TokenPool_Error.ZeroAddressInvalid); + // TODO: check if address is valid (not zero) + // assert(!router.isNone(), TokenPool_Error.ZeroAddressInvalid); adminConfig.dynamicConfig = TokenPool_DynamicConfig { router, rateLimitAdmin, @@ -379,7 +380,7 @@ fun TokenPool.applyChainUpdates( fun TokenPool.applyRampAccessUpdates( mutate self, sender: address, - updates: cell, + updates: SnakedCell, ) { var adminConfig = self.data.adminConfig.load(); var ownable = adminConfig.ownable.load(); @@ -388,36 +389,27 @@ fun TokenPool.applyRampAccessUpdates( self.data.adminConfig = adminConfig.toCell(); var mirroredPolicy = self.data.mirroredPolicy.load(); - var updatesSlice = updates.beginParse(); - var updatesDone = false; - while (!updatesDone) { - while (updatesSlice.remainingBitsCount() > 0) { - val update = TokenPool_RampUpdate.fromSlice(mutate updatesSlice); - - if (update.onRamp != null) { - mirroredPolicy.onRamps.set(update.remoteChainSelector, update.onRamp!); - } else { - mirroredPolicy.onRamps.delete(update.remoteChainSelector); - } - - if (update.offRamp != null) { - mirroredPolicy.offRamps.set(update.remoteChainSelector, update.offRamp!); - } else { - mirroredPolicy.offRamps.delete(update.remoteChainSelector); - } + var iter = updates.iter(); + while (!iter.empty()) { + val update = iter.next(); - emit(TOKEN_POOL_RAMP_ACCESS_UPDATED_TOPIC, TokenPool_RampAccessUpdated { - remoteChainSelector: update.remoteChainSelector, - onRamp: update.onRamp, - offRamp: update.offRamp, - }); + if (update.onRamp != null) { + mirroredPolicy.onRamps.set(update.remoteChainSelector, update.onRamp!); + } else { + mirroredPolicy.onRamps.delete(update.remoteChainSelector); } - if (updatesSlice.remainingRefsCount() == 0) { - updatesDone = true; + if (update.offRamp != null) { + mirroredPolicy.offRamps.set(update.remoteChainSelector, update.offRamp!); } else { - updatesSlice = updatesSlice.loadRef().beginParse(); + mirroredPolicy.offRamps.delete(update.remoteChainSelector); } + + emit(TOKEN_POOL_RAMP_ACCESS_UPDATED_TOPIC, TokenPool_RampAccessUpdated { + remoteChainSelector: update.remoteChainSelector, + onRamp: update.onRamp, + offRamp: update.offRamp, + }); } self.data.mirroredPolicy = mirroredPolicy.toCell(); @@ -462,11 +454,11 @@ fun TokenPool.onInternalMessage(mutate self, msgSender: address, msgValue: co return true; } TokenPool_SetRateLimitConfig => { - self.setRateLimitConfig(msgSender, msg.updates.load()); + self.setRateLimitConfig(msgSender, msg.updates); return true; } TokenPool_ApplyTokenTransferFeeConfigUpdates => { - self.applyTokenTransferFeeConfigUpdates(msgSender, msg.updates.load(), msg.disableChainSelectors.load()); + self.applyTokenTransferFeeConfigUpdates(msgSender, msg.updates, msg.disableChainSelectors); return true; } TokenPool_UpdateRampAccess => { @@ -483,6 +475,9 @@ fun TokenPool.onInternalMessage(mutate self, msgSender: address, msgValue: co self.context = self.hooks.handleReleaseOrMintMessage(self.context, msgSender, msg, prepared); return true; } + TokenPool_LockOrBurn => { + return false; // TODO: handle me, should be JettonNitification payload + } else => { var adminConfig = self.data.adminConfig.load(); var ownable = adminConfig.ownable.load(); diff --git a/contracts/contracts/ccip/pools/token_pool_contract.tolk b/contracts/contracts/ccip/pools/token_pool_contract.tolk new file mode 100644 index 000000000..ae5d054d1 --- /dev/null +++ b/contracts/contracts/ccip/pools/token_pool_contract.tolk @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: BUSL-1.1 +import "@stdlib/lisp-lists" + +import "types" +import "errors" +import "messages" +import "events" +import "token_pool" + +contract TokenPool { + author: "SmartContract Chainlink Limited SEZC" + version: "0.1.0" + description: "link.chain.ton.ccip.TokenPool" + + storage: TokenPool_Data + incomingMessages: TokenPool_InMessage // TODO: all incoming messages should be registered +} + +fun onInternalMessage(in: InMessage) { + throw 0xFFFF; // template for bindings, should not be deployed +} diff --git a/contracts/contracts/ccip/pool/types.tolk b/contracts/contracts/ccip/pools/types.tolk similarity index 100% rename from contracts/contracts/ccip/pool/types.tolk rename to contracts/contracts/ccip/pools/types.tolk diff --git a/contracts/tests/ccip/pool/BurnMintTokenPool.spec.ts b/contracts/tests/ccip/pools/BurnMintTokenPool.spec.ts similarity index 100% rename from contracts/tests/ccip/pool/BurnMintTokenPool.spec.ts rename to contracts/tests/ccip/pools/BurnMintTokenPool.spec.ts diff --git a/contracts/tests/ccip/pool/LockReleaseTokenPool.spec.ts b/contracts/tests/ccip/pools/LockReleaseTokenPool.spec.ts similarity index 100% rename from contracts/tests/ccip/pool/LockReleaseTokenPool.spec.ts rename to contracts/tests/ccip/pools/LockReleaseTokenPool.spec.ts diff --git a/contracts/tests/ccip/pool/TokenPool.behavior.ts b/contracts/tests/ccip/pools/TokenPool.behavior.ts similarity index 98% rename from contracts/tests/ccip/pool/TokenPool.behavior.ts rename to contracts/tests/ccip/pools/TokenPool.behavior.ts index 9bfccff97..4e206e311 100644 --- a/contracts/tests/ccip/pool/TokenPool.behavior.ts +++ b/contracts/tests/ccip/pools/TokenPool.behavior.ts @@ -339,7 +339,7 @@ export function runTokenPoolBehaviorTests( }) }) - it('keeps existing off-ramp when update passes null off-ramp', async () => { + it('clears existing off-ramp when update passes null off-ramp', async () => { const ctx = await setup() await ctx.pool.sendUpdateRampAccess(ctx.deployer.getSender(), toNano('0.2'), { queryId: 914n, @@ -352,10 +352,10 @@ export function runTokenPoolBehaviorTests( ], }) - expect(await ctx.pool.getOffRamp(ctx.remoteChainSelector)).toEqualAddress(ctx.offRamp.address) + expect(await ctx.pool.getOffRamp(ctx.remoteChainSelector)).toBeNull() }) - it('still accepts existing off-ramp sender after null off-ramp update', async () => { + it('rejects existing off-ramp sender after null off-ramp update', async () => { const ctx = await setup() await ctx.pool.sendUpdateRampAccess(ctx.deployer.getSender(), toNano('0.2'), { queryId: 915n, @@ -378,6 +378,7 @@ export function runTokenPoolBehaviorTests( expect(result.transactions).toHaveTransaction({ from: ctx.offRamp.address, to: ctx.pool.address, + success: false, }) }) diff --git a/contracts/wrappers/BurnMintTokenPool.compile.ts b/contracts/wrappers/ccip.pools.BurnMintTokenPool.compile.ts similarity index 63% rename from contracts/wrappers/BurnMintTokenPool.compile.ts rename to contracts/wrappers/ccip.pools.BurnMintTokenPool.compile.ts index 15a841b42..dca1ee093 100644 --- a/contracts/wrappers/BurnMintTokenPool.compile.ts +++ b/contracts/wrappers/ccip.pools.BurnMintTokenPool.compile.ts @@ -2,6 +2,6 @@ import { CompilerConfig } from '@ton/blueprint' export const compile: CompilerConfig = { lang: 'tolk', - entrypoint: 'contracts/ccip/pool/burn_mint_token_pool/contract.tolk', + entrypoint: 'contracts/ccip/pools/burn_mint_token_pool/contract.tolk', withStackComments: true, -} \ No newline at end of file +} diff --git a/contracts/wrappers/LockReleaseTokenPool.compile.ts b/contracts/wrappers/ccip.pools.LockReleaseTokenPool.compile.ts similarity index 63% rename from contracts/wrappers/LockReleaseTokenPool.compile.ts rename to contracts/wrappers/ccip.pools.LockReleaseTokenPool.compile.ts index 758af9f5e..84b478484 100644 --- a/contracts/wrappers/LockReleaseTokenPool.compile.ts +++ b/contracts/wrappers/ccip.pools.LockReleaseTokenPool.compile.ts @@ -2,6 +2,6 @@ import { CompilerConfig } from '@ton/blueprint' export const compile: CompilerConfig = { lang: 'tolk', - entrypoint: 'contracts/ccip/pool/lock_release_token_pool/contract.tolk', + entrypoint: 'contracts/ccip/pools/lock_release_token_pool/contract.tolk', withStackComments: true, -} \ No newline at end of file +} diff --git a/contracts/wrappers/ccip/BurnMintTokenPool.ts b/contracts/wrappers/ccip/BurnMintTokenPool.ts index 82ecf2985..2212e6c2b 100644 --- a/contracts/wrappers/ccip/BurnMintTokenPool.ts +++ b/contracts/wrappers/ccip/BurnMintTokenPool.ts @@ -62,7 +62,7 @@ export class BurnMintTokenPool implements Contract { } static code(): Promise { - return contractCode.ccip.local('BurnMintTokenPool') + return contractCode.ccip.local('ccip.pools.BurnMintTokenPool') } async sendDeploy(provider: ContractProvider, via: Sender, value: bigint) { diff --git a/contracts/wrappers/ccip/LockReleaseTokenPool.ts b/contracts/wrappers/ccip/LockReleaseTokenPool.ts index ffb0b716c..61930489d 100644 --- a/contracts/wrappers/ccip/LockReleaseTokenPool.ts +++ b/contracts/wrappers/ccip/LockReleaseTokenPool.ts @@ -63,7 +63,7 @@ export class LockReleaseTokenPool implements Contract { } static code(): Promise { - return contractCode.ccip.local('LockReleaseTokenPool') + return contractCode.ccip.local('ccip.pools.LockReleaseTokenPool') } async sendDeploy(provider: ContractProvider, via: Sender, value: bigint) { diff --git a/contracts/wrappers/gen/ccip/pools/BurnMintTokenPool.ts b/contracts/wrappers/gen/ccip/pools/BurnMintTokenPool.ts new file mode 100644 index 000000000..d6377e4dc --- /dev/null +++ b/contracts/wrappers/gen/ccip/pools/BurnMintTokenPool.ts @@ -0,0 +1,2345 @@ +// AUTO-GENERATED, do not edit +// It's a TypeScript wrapper for a BurnMintTokenPool contract in Tolk. +/* eslint-disable */ + +import * as c from '@ton/core'; +import { beginCell, ContractProvider, Sender, SendMode } from '@ton/core'; + +// ———————————————————————————————————————————— +// predefined types and functions +// + +type RemainingBitsAndRefs = c.Slice + +type StoreCallback = (obj: T, b: c.Builder) => void +type LoadCallback = (s: c.Slice) => T + +export type CellRef = { + ref: T +} + +function makeCellFrom(self: T, storeFn_T: StoreCallback): c.Cell { + let b = beginCell(); + storeFn_T(self, b); + return b.endCell(); +} + +function loadAndCheckPrefix32(s: c.Slice, expected: number, structName: string): void { + let prefix = s.loadUint(32); + if (prefix !== expected) { + throw new Error(`Incorrect prefix for '${structName}': expected 0x${expected.toString(16).padStart(8, '0')}, got 0x${prefix.toString(16).padStart(8, '0')}`); + } +} + +function lookupPrefix(s: c.Slice, expected: number, prefixLen: number): boolean { + return s.remainingBits >= prefixLen && s.preloadUint(prefixLen) === expected; +} + +function throwNonePrefixMatch(fieldPath: string): never { + throw new Error(`Incorrect prefix for '${fieldPath}': none of variants matched`); +} + +function storeCellRef(cell: CellRef, b: c.Builder, storeFn_T: StoreCallback): void { + let b_ref = c.beginCell(); + storeFn_T(cell.ref, b_ref); + b.storeRef(b_ref.endCell()); +} + +function loadCellRef(s: c.Slice, loadFn_T: LoadCallback): CellRef { + let s_ref = s.loadRef().beginParse(); + return { ref: loadFn_T(s_ref) }; +} + +function storeTolkRemaining(v: RemainingBitsAndRefs, b: c.Builder): void { + b.storeSlice(v); +} + +function loadTolkRemaining(s: c.Slice): RemainingBitsAndRefs { + let rest = s.clone(); + s.loadBits(s.remainingBits); + while (s.remainingRefs) { + s.loadRef(); + } + return rest; +} + +function storeTolkNullable(v: T | null, b: c.Builder, storeFn_T: StoreCallback): void { + if (v === null) { + b.storeUint(0, 1); + } else { + b.storeUint(1, 1); + storeFn_T(v, b); + } +} + +function createDictionaryValue(loadFn_V: LoadCallback, storeFn_V: StoreCallback): c.DictionaryValue { + return { + serialize(self: V, b: c.Builder) { + storeFn_V(self, b); + }, + parse(s: c.Slice): V { + const value = loadFn_V(s); + s.endParse(); + return value; + } + } +} + +// ———————————————————————————————————————————— +// parse get methods result from a TVM stack +// + +class StackReader { + constructor(private tuple: c.TupleItem[]) { + } + + static fromGetMethod(expectedN: number, getMethodResult: { stack: c.TupleReader }): StackReader { + let tuple = [] as c.TupleItem[]; + while (getMethodResult.stack.remaining) { + tuple.push(getMethodResult.stack.pop()); + } + if (tuple.length !== expectedN) { + throw new Error(`expected ${expectedN} stack width, got ${tuple.length}`); + } + return new StackReader(tuple); + } + + private popExpecting(itemType: string): ItemT { + const item = this.tuple.shift(); + if (item?.type === itemType) { + return item as ItemT; + } + throw new Error(`not '${itemType}' on a stack`); + } + + private popCellLike(): c.Cell { + const item = this.tuple.shift(); + if (item && (item.type === 'cell' || item.type === 'slice' || item.type === 'builder')) { + return item.cell; + } + throw new Error(`not cell/slice on a stack`); + } + + readBigInt(): bigint { + return this.popExpecting('int').value; + } + + readBoolean(): boolean { + return this.popExpecting('int').value !== 0n; + } + + readCell(): c.Cell { + return this.popCellLike(); + } + + readSlice(): c.Slice { + return this.popCellLike().beginParse(); + } + + readNullable(readFn_T: (r: StackReader) => T): T | null { + if (this.tuple[0].type === 'null') { + this.tuple.shift(); + return null; + } + return readFn_T(this); + } +} + +// ———————————————————————————————————————————— +// custom packToBuilder and unpackFromSlice +// + +type CustomPackToBuilderFn = (self: T, b: c.Builder) => void +type CustomUnpackFromSliceFn = (s: c.Slice) => T + +let customSerializersRegistry: Map | null, CustomUnpackFromSliceFn | null]> = new Map; + +function ensureCustomSerializerRegistered(typeName: string) { + if (!customSerializersRegistry.has(typeName)) { + throw new Error(`Custom packToBuilder/unpackFromSlice was not registered for type 'BurnMintTokenPool.${typeName}'.\n(in Tolk code, they have custom logic \`fun ${typeName}__packToBuilder\`)\nSteps to fix:\n1) in your code, create and implement\n > function ${typeName}__packToBuilder(self: ${typeName}, b: Builder): void { ... }\n > function ${typeName}__unpackFromSlice(s: Slice): ${typeName} { ... }\n2) register them in advance by calling\n > BurnMintTokenPool.registerCustomPackUnpack('${typeName}', ${typeName}__packToBuilder, ${typeName}__unpackFromSlice);`); + } +} + +function invokeCustomPackToBuilder(typeName: string, self: T, b: c.Builder) { + ensureCustomSerializerRegistered(typeName); + customSerializersRegistry.get(typeName)![0]!(self, b); +} + +function invokeCustomUnpackFromSlice(typeName: string, s: c.Slice): T { + ensureCustomSerializerRegistered(typeName); + return customSerializersRegistry.get(typeName)![1]!(s); +} + +// ———————————————————————————————————————————— +// auto-generated serializers to/from cells +// + +type coins = bigint + +type uint8 = bigint +type uint16 = bigint +type uint32 = bigint +type uint64 = bigint +type uint128 = bigint +type uint256 = bigint + +/** + > struct Ownable2Step { + > owner: address + > pendingOwner: address? + > } + */ +export interface Ownable2Step { + readonly $: 'Ownable2Step' + owner: c.Address + pendingOwner: c.Address | null +} + +export const Ownable2Step = { + create(args: { + owner: c.Address + pendingOwner: c.Address | null + }): Ownable2Step { + return { + $: 'Ownable2Step', + ...args + } + }, + fromSlice(s: c.Slice): Ownable2Step { + return { + $: 'Ownable2Step', + owner: s.loadAddress(), + pendingOwner: s.loadMaybeAddress(), + } + }, + store(self: Ownable2Step, b: c.Builder): void { + b.storeAddress(self.owner); + b.storeAddress(self.pendingOwner); + }, + toCell(self: Ownable2Step): c.Cell { + return makeCellFrom(self, Ownable2Step.store); + } +} + +/** + > struct Ownable2Step_OwnershipTransferRequested { + > queryId: uint64 + > newOwner: address + > } + */ +export interface Ownable2Step_OwnershipTransferRequested { + readonly $: 'Ownable2Step_OwnershipTransferRequested' + queryId: uint64 + newOwner: c.Address +} + +export const Ownable2Step_OwnershipTransferRequested = { + create(args: { + queryId: uint64 + newOwner: c.Address + }): Ownable2Step_OwnershipTransferRequested { + return { + $: 'Ownable2Step_OwnershipTransferRequested', + ...args + } + }, + fromSlice(s: c.Slice): Ownable2Step_OwnershipTransferRequested { + return { + $: 'Ownable2Step_OwnershipTransferRequested', + queryId: s.loadUintBig(64), + newOwner: s.loadAddress(), + } + }, + store(self: Ownable2Step_OwnershipTransferRequested, b: c.Builder): void { + b.storeUint(self.queryId, 64); + b.storeAddress(self.newOwner); + }, + toCell(self: Ownable2Step_OwnershipTransferRequested): c.Cell { + return makeCellFrom(self, Ownable2Step_OwnershipTransferRequested.store); + } +} + +/** + > struct Ownable2Step_OwnershipTransferred { + > queryId: uint64 + > oldOwner: address + > newOwner: address + > } + */ +export interface Ownable2Step_OwnershipTransferred { + readonly $: 'Ownable2Step_OwnershipTransferred' + queryId: uint64 + oldOwner: c.Address + newOwner: c.Address +} + +export const Ownable2Step_OwnershipTransferred = { + create(args: { + queryId: uint64 + oldOwner: c.Address + newOwner: c.Address + }): Ownable2Step_OwnershipTransferred { + return { + $: 'Ownable2Step_OwnershipTransferred', + ...args + } + }, + fromSlice(s: c.Slice): Ownable2Step_OwnershipTransferred { + return { + $: 'Ownable2Step_OwnershipTransferred', + queryId: s.loadUintBig(64), + oldOwner: s.loadAddress(), + newOwner: s.loadAddress(), + } + }, + store(self: Ownable2Step_OwnershipTransferred, b: c.Builder): void { + b.storeUint(self.queryId, 64); + b.storeAddress(self.oldOwner); + b.storeAddress(self.newOwner); + }, + toCell(self: Ownable2Step_OwnershipTransferred): c.Cell { + return makeCellFrom(self, Ownable2Step_OwnershipTransferred.store); + } +} + +/** + > struct JettonClient { + > masterAddress: address + > jettonWalletCode: cell + > } + */ +export interface JettonClient { + readonly $: 'JettonClient' + masterAddress: c.Address + jettonWalletCode: c.Cell +} + +export const JettonClient = { + create(args: { + masterAddress: c.Address + jettonWalletCode: c.Cell + }): JettonClient { + return { + $: 'JettonClient', + ...args + } + }, + fromSlice(s: c.Slice): JettonClient { + return { + $: 'JettonClient', + masterAddress: s.loadAddress(), + jettonWalletCode: s.loadRef(), + } + }, + store(self: JettonClient, b: c.Builder): void { + b.storeAddress(self.masterAddress); + b.storeRef(self.jettonWalletCode); + }, + toCell(self: JettonClient): c.Cell { + return makeCellFrom(self, JettonClient.store); + } +} + +/** + > type ForwardPayloadRemainder = RemainingBitsAndRefs + */ +export type ForwardPayloadRemainder = RemainingBitsAndRefs + +export const ForwardPayloadRemainder = { + fromSlice(s: c.Slice): ForwardPayloadRemainder { + return loadTolkRemaining(s); + }, + store(self: ForwardPayloadRemainder, b: c.Builder): void { + storeTolkRemaining(self, b); + }, + toCell(self: ForwardPayloadRemainder): c.Cell { + return makeCellFrom(self, ForwardPayloadRemainder.store); + } +} + +/** + > struct (0x7362d09c) TransferNotificationForRecipient { + > queryId: uint64 + > jettonAmount: coins + > transferInitiator: address? + > forwardPayload: ForwardPayloadRemainder + > } + */ +export interface TransferNotificationForRecipient { + readonly $: 'TransferNotificationForRecipient' + queryId: uint64 + jettonAmount: coins + transferInitiator: c.Address | null + forwardPayload: ForwardPayloadRemainder +} + +export const TransferNotificationForRecipient = { + PREFIX: 0x7362d09c, + + create(args: { + queryId: uint64 + jettonAmount: coins + transferInitiator: c.Address | null + forwardPayload: ForwardPayloadRemainder + }): TransferNotificationForRecipient { + return { + $: 'TransferNotificationForRecipient', + ...args + } + }, + fromSlice(s: c.Slice): TransferNotificationForRecipient { + loadAndCheckPrefix32(s, 0x7362d09c, 'TransferNotificationForRecipient'); + return { + $: 'TransferNotificationForRecipient', + queryId: s.loadUintBig(64), + jettonAmount: s.loadCoins(), + transferInitiator: s.loadMaybeAddress(), + forwardPayload: ForwardPayloadRemainder.fromSlice(s), + } + }, + store(self: TransferNotificationForRecipient, b: c.Builder): void { + b.storeUint(0x7362d09c, 32); + b.storeUint(self.queryId, 64); + b.storeCoins(self.jettonAmount); + b.storeAddress(self.transferInitiator); + ForwardPayloadRemainder.store(self.forwardPayload, b); + }, + toCell(self: TransferNotificationForRecipient): c.Cell { + return makeCellFrom(self, TransferNotificationForRecipient.store); + } +} + +/** + > struct (0x178d4519) InternalTransferStep { + > queryId: uint64 + > jettonAmount: coins + > transferInitiator: address? + > sendExcessesTo: address? + > forwardTonAmount: coins + > forwardPayload: ForwardPayloadRemainder + > } + */ +export interface InternalTransferStep { + readonly $: 'InternalTransferStep' + queryId: uint64 + jettonAmount: coins + transferInitiator: c.Address | null + sendExcessesTo: c.Address | null + forwardTonAmount: coins + forwardPayload: ForwardPayloadRemainder +} + +export const InternalTransferStep = { + PREFIX: 0x178d4519, + + create(args: { + queryId: uint64 + jettonAmount: coins + transferInitiator: c.Address | null + sendExcessesTo: c.Address | null + forwardTonAmount: coins + forwardPayload: ForwardPayloadRemainder + }): InternalTransferStep { + return { + $: 'InternalTransferStep', + ...args + } + }, + fromSlice(s: c.Slice): InternalTransferStep { + loadAndCheckPrefix32(s, 0x178d4519, 'InternalTransferStep'); + return { + $: 'InternalTransferStep', + queryId: s.loadUintBig(64), + jettonAmount: s.loadCoins(), + transferInitiator: s.loadMaybeAddress(), + sendExcessesTo: s.loadMaybeAddress(), + forwardTonAmount: s.loadCoins(), + forwardPayload: ForwardPayloadRemainder.fromSlice(s), + } + }, + store(self: InternalTransferStep, b: c.Builder): void { + b.storeUint(0x178d4519, 32); + b.storeUint(self.queryId, 64); + b.storeCoins(self.jettonAmount); + b.storeAddress(self.transferInitiator); + b.storeAddress(self.sendExcessesTo); + b.storeCoins(self.forwardTonAmount); + ForwardPayloadRemainder.store(self.forwardPayload, b); + }, + toCell(self: InternalTransferStep): c.Cell { + return makeCellFrom(self, InternalTransferStep.store); + } +} + +/** + > struct (0xd53276db) ReturnExcessesBack { + > queryId: uint64 + > } + */ +export interface ReturnExcessesBack { + readonly $: 'ReturnExcessesBack' + queryId: uint64 +} + +export const ReturnExcessesBack = { + PREFIX: 0xd53276db, + + create(args: { + queryId: uint64 + }): ReturnExcessesBack { + return { + $: 'ReturnExcessesBack', + ...args + } + }, + fromSlice(s: c.Slice): ReturnExcessesBack { + loadAndCheckPrefix32(s, 0xd53276db, 'ReturnExcessesBack'); + return { + $: 'ReturnExcessesBack', + queryId: s.loadUintBig(64), + } + }, + store(self: ReturnExcessesBack, b: c.Builder): void { + b.storeUint(0xd53276db, 32); + b.storeUint(self.queryId, 64); + }, + toCell(self: ReturnExcessesBack): c.Cell { + return makeCellFrom(self, ReturnExcessesBack.store); + } +} + +/** + > struct (0x595f07bc) AskToBurn { + > queryId: uint64 + > jettonAmount: coins + > sendExcessesTo: address? + > customPayload: cell? + > } + */ +export interface AskToBurn { + readonly $: 'AskToBurn' + queryId: uint64 + jettonAmount: coins + sendExcessesTo: c.Address | null + customPayload: c.Cell | null +} + +export const AskToBurn = { + PREFIX: 0x595f07bc, + + create(args: { + queryId: uint64 + jettonAmount: coins + sendExcessesTo: c.Address | null + customPayload: c.Cell | null + }): AskToBurn { + return { + $: 'AskToBurn', + ...args + } + }, + fromSlice(s: c.Slice): AskToBurn { + loadAndCheckPrefix32(s, 0x595f07bc, 'AskToBurn'); + return { + $: 'AskToBurn', + queryId: s.loadUintBig(64), + jettonAmount: s.loadCoins(), + sendExcessesTo: s.loadMaybeAddress(), + customPayload: s.loadBoolean() ? s.loadRef() : null, + } + }, + store(self: AskToBurn, b: c.Builder): void { + b.storeUint(0x595f07bc, 32); + b.storeUint(self.queryId, 64); + b.storeCoins(self.jettonAmount); + b.storeAddress(self.sendExcessesTo); + storeTolkNullable(self.customPayload, b, + (v,b) => b.storeRef(v) + ); + }, + toCell(self: AskToBurn): c.Cell { + return makeCellFrom(self, AskToBurn.store); + } +} + +/** + > struct (0x00000015) MintNewJettons { + > queryId: uint64 + > mintRecipient: address + > tonAmount: coins + > internalTransferMsg: Cell + > } + */ +export interface MintNewJettons { + readonly $: 'MintNewJettons' + queryId: uint64 + mintRecipient: c.Address + tonAmount: coins + internalTransferMsg: CellRef +} + +export const MintNewJettons = { + PREFIX: 0x00000015, + + create(args: { + queryId: uint64 + mintRecipient: c.Address + tonAmount: coins + internalTransferMsg: CellRef + }): MintNewJettons { + return { + $: 'MintNewJettons', + ...args + } + }, + fromSlice(s: c.Slice): MintNewJettons { + loadAndCheckPrefix32(s, 0x00000015, 'MintNewJettons'); + return { + $: 'MintNewJettons', + queryId: s.loadUintBig(64), + mintRecipient: s.loadAddress(), + tonAmount: s.loadCoins(), + internalTransferMsg: loadCellRef(s, InternalTransferStep.fromSlice), + } + }, + store(self: MintNewJettons, b: c.Builder): void { + b.storeUint(0x00000015, 32); + b.storeUint(self.queryId, 64); + b.storeAddress(self.mintRecipient); + b.storeCoins(self.tonAmount); + storeCellRef(self.internalTransferMsg, b, InternalTransferStep.store); + }, + toCell(self: MintNewJettons): c.Cell { + return makeCellFrom(self, MintNewJettons.store); + } +} + +/** + > struct (0xfb88e119) ClaimMinterAdmin { + > queryId: uint64 + > } + */ +export interface ClaimMinterAdmin { + readonly $: 'ClaimMinterAdmin' + queryId: uint64 +} + +export const ClaimMinterAdmin = { + PREFIX: 0xfb88e119, + + create(args: { + queryId: uint64 + }): ClaimMinterAdmin { + return { + $: 'ClaimMinterAdmin', + ...args + } + }, + fromSlice(s: c.Slice): ClaimMinterAdmin { + loadAndCheckPrefix32(s, 0xfb88e119, 'ClaimMinterAdmin'); + return { + $: 'ClaimMinterAdmin', + queryId: s.loadUintBig(64), + } + }, + store(self: ClaimMinterAdmin, b: c.Builder): void { + b.storeUint(0xfb88e119, 32); + b.storeUint(self.queryId, 64); + }, + toCell(self: ClaimMinterAdmin): c.Cell { + return makeCellFrom(self, ClaimMinterAdmin.store); + } +} + +/** + > struct CursedSubjects { + > data: map + > } + */ +export interface CursedSubjects { + readonly $: 'CursedSubjects' + data: c.Dictionary +} + +export const CursedSubjects = { + create(args: { + data: c.Dictionary + }): CursedSubjects { + return { + $: 'CursedSubjects', + ...args + } + }, + fromSlice(s: c.Slice): CursedSubjects { + return { + $: 'CursedSubjects', + data: c.Dictionary.load(c.Dictionary.Keys.BigUint(128), createDictionaryValue<[]>( + (s) => [], + (v,b) => { {} } + ), s), + } + }, + store(self: CursedSubjects, b: c.Builder): void { + b.storeDict(self.data, c.Dictionary.Keys.BigUint(128), createDictionaryValue<[]>( + (s) => [], + (v,b) => { {} } + )); + }, + toCell(self: CursedSubjects): c.Cell { + return makeCellFrom(self, CursedSubjects.store); + } +} + +/** + > struct TokenPool_AdminConfig { + > ownable: Cell + > rmnProxy: address + > dynamicConfig: Cell + > allowedFinalityConfig: uint32 + > } + */ +export interface TokenPool_AdminConfig { + readonly $: 'TokenPool_AdminConfig' + ownable: CellRef + rmnProxy: c.Address + dynamicConfig: CellRef + allowedFinalityConfig: uint32 /* = 0 as uint32 */ +} + +export const TokenPool_AdminConfig = { + create(args: { + ownable: CellRef + rmnProxy: c.Address + dynamicConfig: CellRef + allowedFinalityConfig?: uint32 /* = 0 as uint32 */ + }): TokenPool_AdminConfig { + return { + $: 'TokenPool_AdminConfig', + allowedFinalityConfig: 0n, + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_AdminConfig { + return { + $: 'TokenPool_AdminConfig', + ownable: loadCellRef(s, Ownable2Step.fromSlice), + rmnProxy: s.loadAddress(), + dynamicConfig: loadCellRef(s, TokenPool_DynamicConfig.fromSlice), + allowedFinalityConfig: s.loadUintBig(32), + } + }, + store(self: TokenPool_AdminConfig, b: c.Builder): void { + storeCellRef(self.ownable, b, Ownable2Step.store); + b.storeAddress(self.rmnProxy); + storeCellRef(self.dynamicConfig, b, TokenPool_DynamicConfig.store); + b.storeUint(self.allowedFinalityConfig, 32); + }, + toCell(self: TokenPool_AdminConfig): c.Cell { + return makeCellFrom(self, TokenPool_AdminConfig.store); + } +} + +/** + > struct TokenPool_Data { + > adminConfig: Cell + > mirroredPolicy: Cell + > token: address + > tokenDecimals: uint8 + > remoteChainConfigs: map + > tokenTransferFeeConfigs: map + > } + */ +export interface TokenPool_Data { + readonly $: 'TokenPool_Data' + adminConfig: CellRef + mirroredPolicy: CellRef + token: c.Address + tokenDecimals: uint8 + remoteChainConfigs: c.Dictionary + tokenTransferFeeConfigs: c.Dictionary +} + +export const TokenPool_Data = { + create(args: { + adminConfig: CellRef + mirroredPolicy: CellRef + token: c.Address + tokenDecimals: uint8 + remoteChainConfigs: c.Dictionary + tokenTransferFeeConfigs: c.Dictionary + }): TokenPool_Data { + return { + $: 'TokenPool_Data', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_Data { + return { + $: 'TokenPool_Data', + adminConfig: loadCellRef(s, TokenPool_AdminConfig.fromSlice), + mirroredPolicy: loadCellRef(s, TokenPool_MirroredPolicy.fromSlice), + token: s.loadAddress(), + tokenDecimals: s.loadUintBig(8), + remoteChainConfigs: c.Dictionary.load(c.Dictionary.Keys.BigUint(64), createDictionaryValue(TokenPool_RemoteChainConfig.fromSlice, TokenPool_RemoteChainConfig.store), s), + tokenTransferFeeConfigs: c.Dictionary.load(c.Dictionary.Keys.BigUint(64), createDictionaryValue(TokenPool_TokenTransferFeeConfig.fromSlice, TokenPool_TokenTransferFeeConfig.store), s), + } + }, + store(self: TokenPool_Data, b: c.Builder): void { + storeCellRef(self.adminConfig, b, TokenPool_AdminConfig.store); + storeCellRef(self.mirroredPolicy, b, TokenPool_MirroredPolicy.store); + b.storeAddress(self.token); + b.storeUint(self.tokenDecimals, 8); + b.storeDict(self.remoteChainConfigs, c.Dictionary.Keys.BigUint(64), createDictionaryValue(TokenPool_RemoteChainConfig.fromSlice, TokenPool_RemoteChainConfig.store)); + b.storeDict(self.tokenTransferFeeConfigs, c.Dictionary.Keys.BigUint(64), createDictionaryValue(TokenPool_TokenTransferFeeConfig.fromSlice, TokenPool_TokenTransferFeeConfig.store)); + }, + toCell(self: TokenPool_Data): c.Cell { + return makeCellFrom(self, TokenPool_Data.store); + } +} + +/** + > struct TokenPool_DynamicConfig { + > router: address + > rateLimitAdmin: address? + > feeAdmin: address? + > } + */ +export interface TokenPool_DynamicConfig { + readonly $: 'TokenPool_DynamicConfig' + router: c.Address + rateLimitAdmin: c.Address | null + feeAdmin: c.Address | null +} + +export const TokenPool_DynamicConfig = { + create(args: { + router: c.Address + rateLimitAdmin: c.Address | null + feeAdmin: c.Address | null + }): TokenPool_DynamicConfig { + return { + $: 'TokenPool_DynamicConfig', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_DynamicConfig { + return { + $: 'TokenPool_DynamicConfig', + router: s.loadAddress(), + rateLimitAdmin: s.loadMaybeAddress(), + feeAdmin: s.loadMaybeAddress(), + } + }, + store(self: TokenPool_DynamicConfig, b: c.Builder): void { + b.storeAddress(self.router); + b.storeAddress(self.rateLimitAdmin); + b.storeAddress(self.feeAdmin); + }, + toCell(self: TokenPool_DynamicConfig): c.Cell { + return makeCellFrom(self, TokenPool_DynamicConfig.store); + } +} + +/** + > struct TokenPool_MirroredPolicy { + > onRamps: map + > offRamps: map + > cursedSubjects: CursedSubjects + > } + */ +export interface TokenPool_MirroredPolicy { + readonly $: 'TokenPool_MirroredPolicy' + onRamps: c.Dictionary + offRamps: c.Dictionary + cursedSubjects: CursedSubjects +} + +export const TokenPool_MirroredPolicy = { + create(args: { + onRamps: c.Dictionary + offRamps: c.Dictionary + cursedSubjects: CursedSubjects + }): TokenPool_MirroredPolicy { + return { + $: 'TokenPool_MirroredPolicy', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_MirroredPolicy { + return { + $: 'TokenPool_MirroredPolicy', + onRamps: c.Dictionary.load(c.Dictionary.Keys.BigUint(64), createDictionaryValue( + (s) => s.loadAddress(), + (v,b) => b.storeAddress(v) + ), s), + offRamps: c.Dictionary.load(c.Dictionary.Keys.BigUint(64), createDictionaryValue( + (s) => s.loadAddress(), + (v,b) => b.storeAddress(v) + ), s), + cursedSubjects: CursedSubjects.fromSlice(s), + } + }, + store(self: TokenPool_MirroredPolicy, b: c.Builder): void { + b.storeDict(self.onRamps, c.Dictionary.Keys.BigUint(64), createDictionaryValue( + (s) => s.loadAddress(), + (v,b) => b.storeAddress(v) + )); + b.storeDict(self.offRamps, c.Dictionary.Keys.BigUint(64), createDictionaryValue( + (s) => s.loadAddress(), + (v,b) => b.storeAddress(v) + )); + CursedSubjects.store(self.cursedSubjects, b); + }, + toCell(self: TokenPool_MirroredPolicy): c.Cell { + return makeCellFrom(self, TokenPool_MirroredPolicy.store); + } +} + +/** + > struct TokenPool_RateLimiterPair { + > outbound: Cell + > inbound: Cell + > } + */ +export interface TokenPool_RateLimiterPair { + readonly $: 'TokenPool_RateLimiterPair' + outbound: CellRef + inbound: CellRef +} + +export const TokenPool_RateLimiterPair = { + create(args: { + outbound: CellRef + inbound: CellRef + }): TokenPool_RateLimiterPair { + return { + $: 'TokenPool_RateLimiterPair', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_RateLimiterPair { + return { + $: 'TokenPool_RateLimiterPair', + outbound: loadCellRef(s, RateLimiter_TokenBucket.fromSlice), + inbound: loadCellRef(s, RateLimiter_TokenBucket.fromSlice), + } + }, + store(self: TokenPool_RateLimiterPair, b: c.Builder): void { + storeCellRef(self.outbound, b, RateLimiter_TokenBucket.store); + storeCellRef(self.inbound, b, RateLimiter_TokenBucket.store); + }, + toCell(self: TokenPool_RateLimiterPair): c.Cell { + return makeCellFrom(self, TokenPool_RateLimiterPair.store); + } +} + +/** + > struct TokenPool_RemoteChainConfig { + > remoteTokenAddress: Cell + > remotePools: map> + > rateLimiters: Cell + > fastFinalityRateLimiters: Cell + > } + */ +export interface TokenPool_RemoteChainConfig { + readonly $: 'TokenPool_RemoteChainConfig' + remoteTokenAddress: CellRef + remotePools: c.Dictionary> + rateLimiters: CellRef + fastFinalityRateLimiters: CellRef +} + +export const TokenPool_RemoteChainConfig = { + create(args: { + remoteTokenAddress: CellRef + remotePools: c.Dictionary> + rateLimiters: CellRef + fastFinalityRateLimiters: CellRef + }): TokenPool_RemoteChainConfig { + return { + $: 'TokenPool_RemoteChainConfig', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_RemoteChainConfig { + return { + $: 'TokenPool_RemoteChainConfig', + remoteTokenAddress: loadCellRef(s, CrossChainAddress.fromSlice), + remotePools: c.Dictionary.load>(c.Dictionary.Keys.BigUint(256), createDictionaryValue>( + (s) => loadCellRef(s, CrossChainAddress.fromSlice), + (v,b) => storeCellRef(v, b, CrossChainAddress.store) + ), s), + rateLimiters: loadCellRef(s, TokenPool_RateLimiterPair.fromSlice), + fastFinalityRateLimiters: loadCellRef(s, TokenPool_RateLimiterPair.fromSlice), + } + }, + store(self: TokenPool_RemoteChainConfig, b: c.Builder): void { + storeCellRef(self.remoteTokenAddress, b, CrossChainAddress.store); + b.storeDict>(self.remotePools, c.Dictionary.Keys.BigUint(256), createDictionaryValue>( + (s) => loadCellRef(s, CrossChainAddress.fromSlice), + (v,b) => storeCellRef(v, b, CrossChainAddress.store) + )); + storeCellRef(self.rateLimiters, b, TokenPool_RateLimiterPair.store); + storeCellRef(self.fastFinalityRateLimiters, b, TokenPool_RateLimiterPair.store); + }, + toCell(self: TokenPool_RemoteChainConfig): c.Cell { + return makeCellFrom(self, TokenPool_RemoteChainConfig.store); + } +} + +/** + > struct TokenPool_TokenTransferFeeConfig { + > isEnabled: bool + > finalityFeeUSDCents: uint256 + > fastFinalityFeeUSDCents: uint256 + > destGasOverhead: uint32 + > destBytesOverhead: uint32 + > finalityTransferFeeBps: uint16 + > fastFinalityTransferFeeBps: uint16 + > } + */ +export interface TokenPool_TokenTransferFeeConfig { + readonly $: 'TokenPool_TokenTransferFeeConfig' + isEnabled: boolean + finalityFeeUSDCents: uint256 + fastFinalityFeeUSDCents: uint256 + destGasOverhead: uint32 + destBytesOverhead: uint32 + finalityTransferFeeBps: uint16 + fastFinalityTransferFeeBps: uint16 +} + +export const TokenPool_TokenTransferFeeConfig = { + create(args: { + isEnabled: boolean + finalityFeeUSDCents: uint256 + fastFinalityFeeUSDCents: uint256 + destGasOverhead: uint32 + destBytesOverhead: uint32 + finalityTransferFeeBps: uint16 + fastFinalityTransferFeeBps: uint16 + }): TokenPool_TokenTransferFeeConfig { + return { + $: 'TokenPool_TokenTransferFeeConfig', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_TokenTransferFeeConfig { + return { + $: 'TokenPool_TokenTransferFeeConfig', + isEnabled: s.loadBoolean(), + finalityFeeUSDCents: s.loadUintBig(256), + fastFinalityFeeUSDCents: s.loadUintBig(256), + destGasOverhead: s.loadUintBig(32), + destBytesOverhead: s.loadUintBig(32), + finalityTransferFeeBps: s.loadUintBig(16), + fastFinalityTransferFeeBps: s.loadUintBig(16), + } + }, + store(self: TokenPool_TokenTransferFeeConfig, b: c.Builder): void { + b.storeBit(self.isEnabled); + b.storeUint(self.finalityFeeUSDCents, 256); + b.storeUint(self.fastFinalityFeeUSDCents, 256); + b.storeUint(self.destGasOverhead, 32); + b.storeUint(self.destBytesOverhead, 32); + b.storeUint(self.finalityTransferFeeBps, 16); + b.storeUint(self.fastFinalityTransferFeeBps, 16); + }, + toCell(self: TokenPool_TokenTransferFeeConfig): c.Cell { + return makeCellFrom(self, TokenPool_TokenTransferFeeConfig.store); + } +} + +/** + > struct TokenPool_LockOrBurnInV1 { + > receiver: Cell + > remoteChainSelector: uint64 + > originalSender: address + > amount: uint256 + > localToken: address + > } + */ +export interface TokenPool_LockOrBurnInV1 { + readonly $: 'TokenPool_LockOrBurnInV1' + receiver: CellRef + remoteChainSelector: uint64 + originalSender: c.Address + amount: uint256 + localToken: c.Address +} + +export const TokenPool_LockOrBurnInV1 = { + create(args: { + receiver: CellRef + remoteChainSelector: uint64 + originalSender: c.Address + amount: uint256 + localToken: c.Address + }): TokenPool_LockOrBurnInV1 { + return { + $: 'TokenPool_LockOrBurnInV1', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_LockOrBurnInV1 { + return { + $: 'TokenPool_LockOrBurnInV1', + receiver: loadCellRef(s, CrossChainAddress.fromSlice), + remoteChainSelector: s.loadUintBig(64), + originalSender: s.loadAddress(), + amount: s.loadUintBig(256), + localToken: s.loadAddress(), + } + }, + store(self: TokenPool_LockOrBurnInV1, b: c.Builder): void { + storeCellRef(self.receiver, b, CrossChainAddress.store); + b.storeUint(self.remoteChainSelector, 64); + b.storeAddress(self.originalSender); + b.storeUint(self.amount, 256); + b.storeAddress(self.localToken); + }, + toCell(self: TokenPool_LockOrBurnInV1): c.Cell { + return makeCellFrom(self, TokenPool_LockOrBurnInV1.store); + } +} + +/** + > struct TokenPool_LockOrBurnOutV1 { + > destTokenAddress: Cell + > destPoolData: cell + > } + */ +export interface TokenPool_LockOrBurnOutV1 { + readonly $: 'TokenPool_LockOrBurnOutV1' + destTokenAddress: CellRef + destPoolData: c.Cell +} + +export const TokenPool_LockOrBurnOutV1 = { + create(args: { + destTokenAddress: CellRef + destPoolData: c.Cell + }): TokenPool_LockOrBurnOutV1 { + return { + $: 'TokenPool_LockOrBurnOutV1', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_LockOrBurnOutV1 { + return { + $: 'TokenPool_LockOrBurnOutV1', + destTokenAddress: loadCellRef(s, CrossChainAddress.fromSlice), + destPoolData: s.loadRef(), + } + }, + store(self: TokenPool_LockOrBurnOutV1, b: c.Builder): void { + storeCellRef(self.destTokenAddress, b, CrossChainAddress.store); + b.storeRef(self.destPoolData); + }, + toCell(self: TokenPool_LockOrBurnOutV1): c.Cell { + return makeCellFrom(self, TokenPool_LockOrBurnOutV1.store); + } +} + +/** + > struct TokenPool_ReleaseOrMintInV1 { + > originalSender: Cell + > remoteChainSelector: uint64 + > receiver: address + > sourceDenominatedAmount: uint256 + > localToken: address + > sourcePoolAddress: Cell + > sourcePoolData: cell? + > offchainTokenData: cell? + > } + */ +export interface TokenPool_ReleaseOrMintInV1 { + readonly $: 'TokenPool_ReleaseOrMintInV1' + originalSender: CellRef + remoteChainSelector: uint64 + receiver: c.Address + sourceDenominatedAmount: uint256 + localToken: c.Address + sourcePoolAddress: CellRef + sourcePoolData: c.Cell | null + offchainTokenData: c.Cell | null +} + +export const TokenPool_ReleaseOrMintInV1 = { + create(args: { + originalSender: CellRef + remoteChainSelector: uint64 + receiver: c.Address + sourceDenominatedAmount: uint256 + localToken: c.Address + sourcePoolAddress: CellRef + sourcePoolData: c.Cell | null + offchainTokenData: c.Cell | null + }): TokenPool_ReleaseOrMintInV1 { + return { + $: 'TokenPool_ReleaseOrMintInV1', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_ReleaseOrMintInV1 { + return { + $: 'TokenPool_ReleaseOrMintInV1', + originalSender: loadCellRef(s, CrossChainAddress.fromSlice), + remoteChainSelector: s.loadUintBig(64), + receiver: s.loadAddress(), + sourceDenominatedAmount: s.loadUintBig(256), + localToken: s.loadAddress(), + sourcePoolAddress: loadCellRef(s, CrossChainAddress.fromSlice), + sourcePoolData: s.loadBoolean() ? s.loadRef() : null, + offchainTokenData: s.loadBoolean() ? s.loadRef() : null, + } + }, + store(self: TokenPool_ReleaseOrMintInV1, b: c.Builder): void { + storeCellRef(self.originalSender, b, CrossChainAddress.store); + b.storeUint(self.remoteChainSelector, 64); + b.storeAddress(self.receiver); + b.storeUint(self.sourceDenominatedAmount, 256); + b.storeAddress(self.localToken); + storeCellRef(self.sourcePoolAddress, b, CrossChainAddress.store); + storeTolkNullable(self.sourcePoolData, b, + (v,b) => b.storeRef(v) + ); + storeTolkNullable(self.offchainTokenData, b, + (v,b) => b.storeRef(v) + ); + }, + toCell(self: TokenPool_ReleaseOrMintInV1): c.Cell { + return makeCellFrom(self, TokenPool_ReleaseOrMintInV1.store); + } +} + +/** + > struct TokenPool_ReleaseOrMintOutV1 { + > destinationAmount: uint256 + > } + */ +export interface TokenPool_ReleaseOrMintOutV1 { + readonly $: 'TokenPool_ReleaseOrMintOutV1' + destinationAmount: uint256 +} + +export const TokenPool_ReleaseOrMintOutV1 = { + create(args: { + destinationAmount: uint256 + }): TokenPool_ReleaseOrMintOutV1 { + return { + $: 'TokenPool_ReleaseOrMintOutV1', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_ReleaseOrMintOutV1 { + return { + $: 'TokenPool_ReleaseOrMintOutV1', + destinationAmount: s.loadUintBig(256), + } + }, + store(self: TokenPool_ReleaseOrMintOutV1, b: c.Builder): void { + b.storeUint(self.destinationAmount, 256); + }, + toCell(self: TokenPool_ReleaseOrMintOutV1): c.Cell { + return makeCellFrom(self, TokenPool_ReleaseOrMintOutV1.store); + } +} + +/** + > struct (0x19e65bea) TokenPool_LockOrBurnResponse { + > queryId: uint64 + > out: Cell + > destTokenAmount: uint256 + > } + */ +export interface TokenPool_LockOrBurnResponse { + readonly $: 'TokenPool_LockOrBurnResponse' + queryId: uint64 + out: CellRef + destTokenAmount: uint256 +} + +export const TokenPool_LockOrBurnResponse = { + PREFIX: 0x19e65bea, + + create(args: { + queryId: uint64 + out: CellRef + destTokenAmount: uint256 + }): TokenPool_LockOrBurnResponse { + return { + $: 'TokenPool_LockOrBurnResponse', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_LockOrBurnResponse { + loadAndCheckPrefix32(s, 0x19e65bea, 'TokenPool_LockOrBurnResponse'); + return { + $: 'TokenPool_LockOrBurnResponse', + queryId: s.loadUintBig(64), + out: loadCellRef(s, TokenPool_LockOrBurnOutV1.fromSlice), + destTokenAmount: s.loadUintBig(256), + } + }, + store(self: TokenPool_LockOrBurnResponse, b: c.Builder): void { + b.storeUint(0x19e65bea, 32); + b.storeUint(self.queryId, 64); + storeCellRef(self.out, b, TokenPool_LockOrBurnOutV1.store); + b.storeUint(self.destTokenAmount, 256); + }, + toCell(self: TokenPool_LockOrBurnResponse): c.Cell { + return makeCellFrom(self, TokenPool_LockOrBurnResponse.store); + } +} + +/** + > struct (0x7ec43aee) TokenPool_ReleaseOrMintResponse { + > queryId: uint64 + > out: Cell + > } + */ +export interface TokenPool_ReleaseOrMintResponse { + readonly $: 'TokenPool_ReleaseOrMintResponse' + queryId: uint64 + out: CellRef +} + +export const TokenPool_ReleaseOrMintResponse = { + PREFIX: 0x7ec43aee, + + create(args: { + queryId: uint64 + out: CellRef + }): TokenPool_ReleaseOrMintResponse { + return { + $: 'TokenPool_ReleaseOrMintResponse', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_ReleaseOrMintResponse { + loadAndCheckPrefix32(s, 0x7ec43aee, 'TokenPool_ReleaseOrMintResponse'); + return { + $: 'TokenPool_ReleaseOrMintResponse', + queryId: s.loadUintBig(64), + out: loadCellRef(s, TokenPool_ReleaseOrMintOutV1.fromSlice), + } + }, + store(self: TokenPool_ReleaseOrMintResponse, b: c.Builder): void { + b.storeUint(0x7ec43aee, 32); + b.storeUint(self.queryId, 64); + storeCellRef(self.out, b, TokenPool_ReleaseOrMintOutV1.store); + }, + toCell(self: TokenPool_ReleaseOrMintResponse): c.Cell { + return makeCellFrom(self, TokenPool_ReleaseOrMintResponse.store); + } +} + +/** + > struct TokenPool_LockedOrBurnedDetails { + > token: address + > sender: address + > amount: uint256 + > } + */ +export interface TokenPool_LockedOrBurnedDetails { + readonly $: 'TokenPool_LockedOrBurnedDetails' + token: c.Address + sender: c.Address + amount: uint256 +} + +export const TokenPool_LockedOrBurnedDetails = { + create(args: { + token: c.Address + sender: c.Address + amount: uint256 + }): TokenPool_LockedOrBurnedDetails { + return { + $: 'TokenPool_LockedOrBurnedDetails', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_LockedOrBurnedDetails { + return { + $: 'TokenPool_LockedOrBurnedDetails', + token: s.loadAddress(), + sender: s.loadAddress(), + amount: s.loadUintBig(256), + } + }, + store(self: TokenPool_LockedOrBurnedDetails, b: c.Builder): void { + b.storeAddress(self.token); + b.storeAddress(self.sender); + b.storeUint(self.amount, 256); + }, + toCell(self: TokenPool_LockedOrBurnedDetails): c.Cell { + return makeCellFrom(self, TokenPool_LockedOrBurnedDetails.store); + } +} + +/** + > struct TokenPool_LockedOrBurned { + > remoteChainSelector: uint64 + > details: Cell + > } + */ +export interface TokenPool_LockedOrBurned { + readonly $: 'TokenPool_LockedOrBurned' + remoteChainSelector: uint64 + details: CellRef +} + +export const TokenPool_LockedOrBurned = { + create(args: { + remoteChainSelector: uint64 + details: CellRef + }): TokenPool_LockedOrBurned { + return { + $: 'TokenPool_LockedOrBurned', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_LockedOrBurned { + return { + $: 'TokenPool_LockedOrBurned', + remoteChainSelector: s.loadUintBig(64), + details: loadCellRef(s, TokenPool_LockedOrBurnedDetails.fromSlice), + } + }, + store(self: TokenPool_LockedOrBurned, b: c.Builder): void { + b.storeUint(self.remoteChainSelector, 64); + storeCellRef(self.details, b, TokenPool_LockedOrBurnedDetails.store); + }, + toCell(self: TokenPool_LockedOrBurned): c.Cell { + return makeCellFrom(self, TokenPool_LockedOrBurned.store); + } +} + +/** + > struct TokenPool_ReleasedOrMintedParticipants { + > sender: address + > recipient: address + > } + */ +export interface TokenPool_ReleasedOrMintedParticipants { + readonly $: 'TokenPool_ReleasedOrMintedParticipants' + sender: c.Address + recipient: c.Address +} + +export const TokenPool_ReleasedOrMintedParticipants = { + create(args: { + sender: c.Address + recipient: c.Address + }): TokenPool_ReleasedOrMintedParticipants { + return { + $: 'TokenPool_ReleasedOrMintedParticipants', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_ReleasedOrMintedParticipants { + return { + $: 'TokenPool_ReleasedOrMintedParticipants', + sender: s.loadAddress(), + recipient: s.loadAddress(), + } + }, + store(self: TokenPool_ReleasedOrMintedParticipants, b: c.Builder): void { + b.storeAddress(self.sender); + b.storeAddress(self.recipient); + }, + toCell(self: TokenPool_ReleasedOrMintedParticipants): c.Cell { + return makeCellFrom(self, TokenPool_ReleasedOrMintedParticipants.store); + } +} + +/** + > struct TokenPool_ReleasedOrMintedDetails { + > token: address + > amount: uint256 + > participants: Cell + > } + */ +export interface TokenPool_ReleasedOrMintedDetails { + readonly $: 'TokenPool_ReleasedOrMintedDetails' + token: c.Address + amount: uint256 + participants: CellRef +} + +export const TokenPool_ReleasedOrMintedDetails = { + create(args: { + token: c.Address + amount: uint256 + participants: CellRef + }): TokenPool_ReleasedOrMintedDetails { + return { + $: 'TokenPool_ReleasedOrMintedDetails', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_ReleasedOrMintedDetails { + return { + $: 'TokenPool_ReleasedOrMintedDetails', + token: s.loadAddress(), + amount: s.loadUintBig(256), + participants: loadCellRef(s, TokenPool_ReleasedOrMintedParticipants.fromSlice), + } + }, + store(self: TokenPool_ReleasedOrMintedDetails, b: c.Builder): void { + b.storeAddress(self.token); + b.storeUint(self.amount, 256); + storeCellRef(self.participants, b, TokenPool_ReleasedOrMintedParticipants.store); + }, + toCell(self: TokenPool_ReleasedOrMintedDetails): c.Cell { + return makeCellFrom(self, TokenPool_ReleasedOrMintedDetails.store); + } +} + +/** + > struct TokenPool_ReleasedOrMinted { + > remoteChainSelector: uint64 + > details: Cell + > } + */ +export interface TokenPool_ReleasedOrMinted { + readonly $: 'TokenPool_ReleasedOrMinted' + remoteChainSelector: uint64 + details: CellRef +} + +export const TokenPool_ReleasedOrMinted = { + create(args: { + remoteChainSelector: uint64 + details: CellRef + }): TokenPool_ReleasedOrMinted { + return { + $: 'TokenPool_ReleasedOrMinted', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_ReleasedOrMinted { + return { + $: 'TokenPool_ReleasedOrMinted', + remoteChainSelector: s.loadUintBig(64), + details: loadCellRef(s, TokenPool_ReleasedOrMintedDetails.fromSlice), + } + }, + store(self: TokenPool_ReleasedOrMinted, b: c.Builder): void { + b.storeUint(self.remoteChainSelector, 64); + storeCellRef(self.details, b, TokenPool_ReleasedOrMintedDetails.store); + }, + toCell(self: TokenPool_ReleasedOrMinted): c.Cell { + return makeCellFrom(self, TokenPool_ReleasedOrMinted.store); + } +} + +/** + > struct TokenPool_ChainAdded { + > remoteChainSelector: uint64 + > remoteTokenAddress: Cell + > } + */ +export interface TokenPool_ChainAdded { + readonly $: 'TokenPool_ChainAdded' + remoteChainSelector: uint64 + remoteTokenAddress: CellRef +} + +export const TokenPool_ChainAdded = { + create(args: { + remoteChainSelector: uint64 + remoteTokenAddress: CellRef + }): TokenPool_ChainAdded { + return { + $: 'TokenPool_ChainAdded', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_ChainAdded { + return { + $: 'TokenPool_ChainAdded', + remoteChainSelector: s.loadUintBig(64), + remoteTokenAddress: loadCellRef(s, CrossChainAddress.fromSlice), + } + }, + store(self: TokenPool_ChainAdded, b: c.Builder): void { + b.storeUint(self.remoteChainSelector, 64); + storeCellRef(self.remoteTokenAddress, b, CrossChainAddress.store); + }, + toCell(self: TokenPool_ChainAdded): c.Cell { + return makeCellFrom(self, TokenPool_ChainAdded.store); + } +} + +/** + > struct TokenPool_ChainRemoved { + > remoteChainSelector: uint64 + > } + */ +export interface TokenPool_ChainRemoved { + readonly $: 'TokenPool_ChainRemoved' + remoteChainSelector: uint64 +} + +export const TokenPool_ChainRemoved = { + create(args: { + remoteChainSelector: uint64 + }): TokenPool_ChainRemoved { + return { + $: 'TokenPool_ChainRemoved', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_ChainRemoved { + return { + $: 'TokenPool_ChainRemoved', + remoteChainSelector: s.loadUintBig(64), + } + }, + store(self: TokenPool_ChainRemoved, b: c.Builder): void { + b.storeUint(self.remoteChainSelector, 64); + }, + toCell(self: TokenPool_ChainRemoved): c.Cell { + return makeCellFrom(self, TokenPool_ChainRemoved.store); + } +} + +/** + > struct TokenPool_RemotePoolAdded { + > remoteChainSelector: uint64 + > remotePoolAddress: Cell + > } + */ +export interface TokenPool_RemotePoolAdded { + readonly $: 'TokenPool_RemotePoolAdded' + remoteChainSelector: uint64 + remotePoolAddress: CellRef +} + +export const TokenPool_RemotePoolAdded = { + create(args: { + remoteChainSelector: uint64 + remotePoolAddress: CellRef + }): TokenPool_RemotePoolAdded { + return { + $: 'TokenPool_RemotePoolAdded', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_RemotePoolAdded { + return { + $: 'TokenPool_RemotePoolAdded', + remoteChainSelector: s.loadUintBig(64), + remotePoolAddress: loadCellRef(s, CrossChainAddress.fromSlice), + } + }, + store(self: TokenPool_RemotePoolAdded, b: c.Builder): void { + b.storeUint(self.remoteChainSelector, 64); + storeCellRef(self.remotePoolAddress, b, CrossChainAddress.store); + }, + toCell(self: TokenPool_RemotePoolAdded): c.Cell { + return makeCellFrom(self, TokenPool_RemotePoolAdded.store); + } +} + +/** + > struct TokenPool_RemotePoolRemoved { + > remoteChainSelector: uint64 + > remotePoolAddress: Cell + > } + */ +export interface TokenPool_RemotePoolRemoved { + readonly $: 'TokenPool_RemotePoolRemoved' + remoteChainSelector: uint64 + remotePoolAddress: CellRef +} + +export const TokenPool_RemotePoolRemoved = { + create(args: { + remoteChainSelector: uint64 + remotePoolAddress: CellRef + }): TokenPool_RemotePoolRemoved { + return { + $: 'TokenPool_RemotePoolRemoved', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_RemotePoolRemoved { + return { + $: 'TokenPool_RemotePoolRemoved', + remoteChainSelector: s.loadUintBig(64), + remotePoolAddress: loadCellRef(s, CrossChainAddress.fromSlice), + } + }, + store(self: TokenPool_RemotePoolRemoved, b: c.Builder): void { + b.storeUint(self.remoteChainSelector, 64); + storeCellRef(self.remotePoolAddress, b, CrossChainAddress.store); + }, + toCell(self: TokenPool_RemotePoolRemoved): c.Cell { + return makeCellFrom(self, TokenPool_RemotePoolRemoved.store); + } +} + +/** + > struct TokenPool_DynamicConfigSet { + > router: address + > rateLimitAdmin: address? + > feeAdmin: address? + > } + */ +export interface TokenPool_DynamicConfigSet { + readonly $: 'TokenPool_DynamicConfigSet' + router: c.Address + rateLimitAdmin: c.Address | null + feeAdmin: c.Address | null +} + +export const TokenPool_DynamicConfigSet = { + create(args: { + router: c.Address + rateLimitAdmin: c.Address | null + feeAdmin: c.Address | null + }): TokenPool_DynamicConfigSet { + return { + $: 'TokenPool_DynamicConfigSet', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_DynamicConfigSet { + return { + $: 'TokenPool_DynamicConfigSet', + router: s.loadAddress(), + rateLimitAdmin: s.loadMaybeAddress(), + feeAdmin: s.loadMaybeAddress(), + } + }, + store(self: TokenPool_DynamicConfigSet, b: c.Builder): void { + b.storeAddress(self.router); + b.storeAddress(self.rateLimitAdmin); + b.storeAddress(self.feeAdmin); + }, + toCell(self: TokenPool_DynamicConfigSet): c.Cell { + return makeCellFrom(self, TokenPool_DynamicConfigSet.store); + } +} + +/** + > struct TokenPool_FinalityConfigSet { + > allowedFinalityConfig: uint32 + > } + */ +export interface TokenPool_FinalityConfigSet { + readonly $: 'TokenPool_FinalityConfigSet' + allowedFinalityConfig: uint32 +} + +export const TokenPool_FinalityConfigSet = { + create(args: { + allowedFinalityConfig: uint32 + }): TokenPool_FinalityConfigSet { + return { + $: 'TokenPool_FinalityConfigSet', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_FinalityConfigSet { + return { + $: 'TokenPool_FinalityConfigSet', + allowedFinalityConfig: s.loadUintBig(32), + } + }, + store(self: TokenPool_FinalityConfigSet, b: c.Builder): void { + b.storeUint(self.allowedFinalityConfig, 32); + }, + toCell(self: TokenPool_FinalityConfigSet): c.Cell { + return makeCellFrom(self, TokenPool_FinalityConfigSet.store); + } +} + +/** + > struct TokenPool_RampAccessUpdated { + > remoteChainSelector: uint64 + > onRamp: address? + > offRamp: address? + > } + */ +export interface TokenPool_RampAccessUpdated { + readonly $: 'TokenPool_RampAccessUpdated' + remoteChainSelector: uint64 + onRamp: c.Address | null /* = null */ + offRamp: c.Address | null /* = null */ +} + +export const TokenPool_RampAccessUpdated = { + create(args: { + remoteChainSelector: uint64 + onRamp?: c.Address | null /* = null */ + offRamp?: c.Address | null /* = null */ + }): TokenPool_RampAccessUpdated { + return { + $: 'TokenPool_RampAccessUpdated', + onRamp: null, + offRamp: null, + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_RampAccessUpdated { + return { + $: 'TokenPool_RampAccessUpdated', + remoteChainSelector: s.loadUintBig(64), + onRamp: s.loadMaybeAddress(), + offRamp: s.loadMaybeAddress(), + } + }, + store(self: TokenPool_RampAccessUpdated, b: c.Builder): void { + b.storeUint(self.remoteChainSelector, 64); + b.storeAddress(self.onRamp); + b.storeAddress(self.offRamp); + }, + toCell(self: TokenPool_RampAccessUpdated): c.Cell { + return makeCellFrom(self, TokenPool_RampAccessUpdated.store); + } +} + +/** + > struct TokenPool_CursedSubjectsUpdated { + > } + */ +export interface TokenPool_CursedSubjectsUpdated { + readonly $: 'TokenPool_CursedSubjectsUpdated' +} + +export const TokenPool_CursedSubjectsUpdated = { + create(): TokenPool_CursedSubjectsUpdated { + return { + $: 'TokenPool_CursedSubjectsUpdated', + } + }, + fromSlice(s: c.Slice): TokenPool_CursedSubjectsUpdated { + return { + $: 'TokenPool_CursedSubjectsUpdated', + } + }, + store(self: TokenPool_CursedSubjectsUpdated, b: c.Builder): void { + }, + toCell(self: TokenPool_CursedSubjectsUpdated): c.Cell { + return makeCellFrom(self, TokenPool_CursedSubjectsUpdated.store); + } +} + +/** + > struct (0x93c174a1) BurnMintTokenPool_ClaimMinterAdmin { + > queryId: uint64 + > } + */ +export interface BurnMintTokenPool_ClaimMinterAdmin { + readonly $: 'BurnMintTokenPool_ClaimMinterAdmin' + queryId: uint64 +} + +export const BurnMintTokenPool_ClaimMinterAdmin = { + PREFIX: 0x93c174a1, + + create(args: { + queryId: uint64 + }): BurnMintTokenPool_ClaimMinterAdmin { + return { + $: 'BurnMintTokenPool_ClaimMinterAdmin', + ...args + } + }, + fromSlice(s: c.Slice): BurnMintTokenPool_ClaimMinterAdmin { + loadAndCheckPrefix32(s, 0x93c174a1, 'BurnMintTokenPool_ClaimMinterAdmin'); + return { + $: 'BurnMintTokenPool_ClaimMinterAdmin', + queryId: s.loadUintBig(64), + } + }, + store(self: BurnMintTokenPool_ClaimMinterAdmin, b: c.Builder): void { + b.storeUint(0x93c174a1, 32); + b.storeUint(self.queryId, 64); + }, + toCell(self: BurnMintTokenPool_ClaimMinterAdmin): c.Cell { + return makeCellFrom(self, BurnMintTokenPool_ClaimMinterAdmin.store); + } +} + +/** + > struct BurnMintTokenPool_PendingBurn { + > replyTo: address? + > request: Cell + > out: Cell + > destTokenAmount: uint256 + > expectedSender: address + > } + */ +export interface BurnMintTokenPool_PendingBurn { + readonly $: 'BurnMintTokenPool_PendingBurn' + replyTo: c.Address | null /* = null */ + request: CellRef + out: CellRef + destTokenAmount: uint256 + expectedSender: c.Address +} + +export const BurnMintTokenPool_PendingBurn = { + create(args: { + replyTo?: c.Address | null /* = null */ + request: CellRef + out: CellRef + destTokenAmount: uint256 + expectedSender: c.Address + }): BurnMintTokenPool_PendingBurn { + return { + $: 'BurnMintTokenPool_PendingBurn', + replyTo: null, + ...args + } + }, + fromSlice(s: c.Slice): BurnMintTokenPool_PendingBurn { + return { + $: 'BurnMintTokenPool_PendingBurn', + replyTo: s.loadMaybeAddress(), + request: loadCellRef(s, TokenPool_LockOrBurnInV1.fromSlice), + out: loadCellRef(s, TokenPool_LockOrBurnOutV1.fromSlice), + destTokenAmount: s.loadUintBig(256), + expectedSender: s.loadAddress(), + } + }, + store(self: BurnMintTokenPool_PendingBurn, b: c.Builder): void { + b.storeAddress(self.replyTo); + storeCellRef(self.request, b, TokenPool_LockOrBurnInV1.store); + storeCellRef(self.out, b, TokenPool_LockOrBurnOutV1.store); + b.storeUint(self.destTokenAmount, 256); + b.storeAddress(self.expectedSender); + }, + toCell(self: BurnMintTokenPool_PendingBurn): c.Cell { + return makeCellFrom(self, BurnMintTokenPool_PendingBurn.store); + } +} + +/** + > struct BurnMintTokenPool_PendingMint { + > replyTo: address? + > request: Cell + > out: Cell + > expectedSender: address + > } + */ +export interface BurnMintTokenPool_PendingMint { + readonly $: 'BurnMintTokenPool_PendingMint' + replyTo: c.Address | null /* = null */ + request: CellRef + out: CellRef + expectedSender: c.Address +} + +export const BurnMintTokenPool_PendingMint = { + create(args: { + replyTo?: c.Address | null /* = null */ + request: CellRef + out: CellRef + expectedSender: c.Address + }): BurnMintTokenPool_PendingMint { + return { + $: 'BurnMintTokenPool_PendingMint', + replyTo: null, + ...args + } + }, + fromSlice(s: c.Slice): BurnMintTokenPool_PendingMint { + return { + $: 'BurnMintTokenPool_PendingMint', + replyTo: s.loadMaybeAddress(), + request: loadCellRef(s, TokenPool_ReleaseOrMintInV1.fromSlice), + out: loadCellRef(s, TokenPool_ReleaseOrMintOutV1.fromSlice), + expectedSender: s.loadAddress(), + } + }, + store(self: BurnMintTokenPool_PendingMint, b: c.Builder): void { + b.storeAddress(self.replyTo); + storeCellRef(self.request, b, TokenPool_ReleaseOrMintInV1.store); + storeCellRef(self.out, b, TokenPool_ReleaseOrMintOutV1.store); + b.storeAddress(self.expectedSender); + }, + toCell(self: BurnMintTokenPool_PendingMint): c.Cell { + return makeCellFrom(self, BurnMintTokenPool_PendingMint.store); + } +} + +/** + > struct Storage { + > poolData: Cell + > jettonClient: Cell + > pendingBurns: map> + > pendingMints: map> + > } + */ +export interface Storage { + readonly $: 'Storage' + poolData: CellRef + jettonClient: CellRef + pendingBurns: c.Dictionary> + pendingMints: c.Dictionary> +} + +export const Storage = { + create(args: { + poolData: CellRef + jettonClient: CellRef + pendingBurns: c.Dictionary> + pendingMints: c.Dictionary> + }): Storage { + return { + $: 'Storage', + ...args + } + }, + fromSlice(s: c.Slice): Storage { + return { + $: 'Storage', + poolData: loadCellRef(s, TokenPool_Data.fromSlice), + jettonClient: loadCellRef(s, JettonClient.fromSlice), + pendingBurns: c.Dictionary.load>(c.Dictionary.Keys.BigUint(64), createDictionaryValue>( + (s) => loadCellRef(s, BurnMintTokenPool_PendingBurn.fromSlice), + (v,b) => storeCellRef(v, b, BurnMintTokenPool_PendingBurn.store) + ), s), + pendingMints: c.Dictionary.load>(c.Dictionary.Keys.BigUint(64), createDictionaryValue>( + (s) => loadCellRef(s, BurnMintTokenPool_PendingMint.fromSlice), + (v,b) => storeCellRef(v, b, BurnMintTokenPool_PendingMint.store) + ), s), + } + }, + store(self: Storage, b: c.Builder): void { + storeCellRef(self.poolData, b, TokenPool_Data.store); + storeCellRef(self.jettonClient, b, JettonClient.store); + b.storeDict>(self.pendingBurns, c.Dictionary.Keys.BigUint(64), createDictionaryValue>( + (s) => loadCellRef(s, BurnMintTokenPool_PendingBurn.fromSlice), + (v,b) => storeCellRef(v, b, BurnMintTokenPool_PendingBurn.store) + )); + b.storeDict>(self.pendingMints, c.Dictionary.Keys.BigUint(64), createDictionaryValue>( + (s) => loadCellRef(s, BurnMintTokenPool_PendingMint.fromSlice), + (v,b) => storeCellRef(v, b, BurnMintTokenPool_PendingMint.store) + )); + }, + toCell(self: Storage): c.Cell { + return makeCellFrom(self, Storage.store); + } +} + +/** + > type CrossChainAddress = slice + */ +export type CrossChainAddress = c.Slice + +export const CrossChainAddress = { + fromSlice(s: c.Slice): CrossChainAddress { + return invokeCustomUnpackFromSlice('CrossChainAddress', s); + }, + store(self: CrossChainAddress, b: c.Builder): void { + invokeCustomPackToBuilder('CrossChainAddress', self, b); + }, + toCell(self: CrossChainAddress): c.Cell { + return makeCellFrom(self, CrossChainAddress.store); + } +} + +/** + > struct RateLimiter_TokenBucket { + > tokens: uint256 + > lastUpdated: uint64 + > isEnabled: bool + > capacity: uint256 + > rate: uint256 + > } + */ +export interface RateLimiter_TokenBucket { + readonly $: 'RateLimiter_TokenBucket' + tokens: uint256 + lastUpdated: uint64 + isEnabled: boolean + capacity: uint256 + rate: uint256 +} + +export const RateLimiter_TokenBucket = { + create(args: { + tokens: uint256 + lastUpdated: uint64 + isEnabled: boolean + capacity: uint256 + rate: uint256 + }): RateLimiter_TokenBucket { + return { + $: 'RateLimiter_TokenBucket', + ...args + } + }, + fromSlice(s: c.Slice): RateLimiter_TokenBucket { + return { + $: 'RateLimiter_TokenBucket', + tokens: s.loadUintBig(256), + lastUpdated: s.loadUintBig(64), + isEnabled: s.loadBoolean(), + capacity: s.loadUintBig(256), + rate: s.loadUintBig(256), + } + }, + store(self: RateLimiter_TokenBucket, b: c.Builder): void { + b.storeUint(self.tokens, 256); + b.storeUint(self.lastUpdated, 64); + b.storeBit(self.isEnabled); + b.storeUint(self.capacity, 256); + b.storeUint(self.rate, 256); + }, + toCell(self: RateLimiter_TokenBucket): c.Cell { + return makeCellFrom(self, RateLimiter_TokenBucket.store); + } +} + +// ———————————————————————————————————————————— +// class BurnMintTokenPool +// + +interface ExtraSendOptions { + bounce?: boolean // default: false + sendMode?: SendMode // default: SendMode.PAY_GAS_SEPARATELY + extraCurrencies?: c.ExtraCurrency // default: empty dict +} + +interface DeployedAddrOptions { + workchain?: number // default: 0 (basechain) + toShard?: { fixedPrefixLength: number; closeTo: c.Address } + overrideContractCode?: c.Cell +} + +function calculateDeployedAddress(code: c.Cell, data: c.Cell, options: DeployedAddrOptions): c.Address { + const stateInitCell = beginCell().store(c.storeStateInit({ + code, + data, + splitDepth: options.toShard?.fixedPrefixLength, + special: null, + libraries: null, + })).endCell(); + + let addrHash = stateInitCell.hash(); + if (options.toShard) { + const shardDepth = options.toShard.fixedPrefixLength; + addrHash = beginCell() + .storeBits(new c.BitString(options.toShard.closeTo.hash, 0, shardDepth)) + .storeBits(new c.BitString(stateInitCell.hash(), shardDepth, 256 - shardDepth)) + .endCell() + .beginParse().loadBuffer(32); + } + + return new c.Address(options.workchain ?? 0, addrHash); +} + +export class BurnMintTokenPool implements c.Contract { + static CodeCell = c.Cell.fromBase64('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'); + + static Errors = { + 'Common_Error.CrossChainAddressOutOfRange': 5, + 'Utils_Error.InvalidData': 13500, + 'TokenPool_Error.InvalidTransferFeeBps': 14900, + 'TokenPool_Error.InvalidTokenTransferFeeConfig': 14901, + 'TokenPool_Error.ZeroAddressInvalid': 14903, + 'TokenPool_Error.NonExistentChain': 14904, + 'TokenPool_Error.ChainNotAllowed': 14905, + 'TokenPool_Error.CursedByRMN': 14906, + 'TokenPool_Error.ChainAlreadyExists': 14907, + 'TokenPool_Error.InvalidToken': 14909, + 'TokenPool_Error.Unauthorized': 14910, + 'TokenPool_Error.PoolAlreadyAdded': 14911, + 'TokenPool_Error.InvalidRemotePoolForChain': 14912, + 'TokenPool_Error.InvalidRemoteChainDecimals': 14913, + 'TokenPool_Error.OverflowDetected': 14914, + 'TokenPool_Error.UnsupportedOperation': 14917, + 'TokenPool_Error.InvalidRequestedFinality': 14918, + 'Error.IncorrectJettonSender': 41200, + 'Error.MissingTransferInitiator': 41201, + 'Error.MissingForwardPayload': 41202, + 'Error.AmountMismatch': 41203, + 'Error.PendingBurnAlreadyExists': 41204, + 'Error.PendingMintAlreadyExists': 41206, + 'Error.PendingMintNotFound': 41207, + 'Error.UnexpectedBurnConfirmationSender': 41208, + 'Error.UnexpectedMintConfirmationSender': 41209, + 'Ownable2Step_Error.OnlyCallableByOwner': 49800, + 'Ownable2Step_Error.CannotTransferToSelf': 49801, + 'Ownable2Step_Error.MustBeProposedOwner': 49802, + } + + readonly address: c.Address + readonly init: { code: c.Cell, data: c.Cell } | undefined + + protected constructor(address: c.Address, init?: { code: c.Cell, data: c.Cell }) { + this.address = address; + this.init = init; + } + + static registerCustomPackUnpack( + typeName: string, + packToBuilderFn: CustomPackToBuilderFn | null, + unpackFromSliceFn: CustomUnpackFromSliceFn | null, + ) { + if (customSerializersRegistry.has(typeName)) { + throw new Error(`Custom pack/unpack for 'BurnMintTokenPool.${typeName}' already registered`); + } + customSerializersRegistry.set(typeName, [packToBuilderFn, unpackFromSliceFn]); + } + + static fromAddress(address: c.Address) { + return new BurnMintTokenPool(address); + } + + static fromStorage(emptyStorage: { + poolData: CellRef + jettonClient: CellRef + pendingBurns: c.Dictionary> + pendingMints: c.Dictionary> + }, deployedOptions?: DeployedAddrOptions) { + const initialState = { + code: deployedOptions?.overrideContractCode ?? BurnMintTokenPool.CodeCell, + data: Storage.toCell(Storage.create(emptyStorage)), + }; + const address = calculateDeployedAddress(initialState.code, initialState.data, deployedOptions ?? {}); + return new BurnMintTokenPool(address, initialState); + } + + static createCellOfBurnMintTokenPoolClaimMinterAdmin(body: { + queryId: uint64 + }) { + return BurnMintTokenPool_ClaimMinterAdmin.toCell(BurnMintTokenPool_ClaimMinterAdmin.create(body)); + } + + static createCellOfTransferNotificationForRecipient(body: { + queryId: uint64 + jettonAmount: coins + transferInitiator: c.Address | null + forwardPayload: ForwardPayloadRemainder + }) { + return TransferNotificationForRecipient.toCell(TransferNotificationForRecipient.create(body)); + } + + static createCellOfReturnExcessesBack(body: { + queryId: uint64 + }) { + return ReturnExcessesBack.toCell(ReturnExcessesBack.create(body)); + } + + async sendDeploy(provider: ContractProvider, via: Sender, msgValue: coins, extraOptions?: ExtraSendOptions) { + return provider.internal(via, { + value: msgValue, + body: c.Cell.EMPTY, + ...extraOptions + }); + } + + async sendBurnMintTokenPoolClaimMinterAdmin(provider: ContractProvider, via: Sender, msgValue: coins, body: { + queryId: uint64 + }, extraOptions?: ExtraSendOptions) { + return provider.internal(via, { + value: msgValue, + body: BurnMintTokenPool_ClaimMinterAdmin.toCell(BurnMintTokenPool_ClaimMinterAdmin.create(body)), + ...extraOptions + }); + } + + async sendTransferNotificationForRecipient(provider: ContractProvider, via: Sender, msgValue: coins, body: { + queryId: uint64 + jettonAmount: coins + transferInitiator: c.Address | null + forwardPayload: ForwardPayloadRemainder + }, extraOptions?: ExtraSendOptions) { + return provider.internal(via, { + value: msgValue, + body: TransferNotificationForRecipient.toCell(TransferNotificationForRecipient.create(body)), + ...extraOptions + }); + } + + async sendReturnExcessesBack(provider: ContractProvider, via: Sender, msgValue: coins, body: { + queryId: uint64 + }, extraOptions?: ExtraSendOptions) { + return provider.internal(via, { + value: msgValue, + body: ReturnExcessesBack.toCell(ReturnExcessesBack.create(body)), + ...extraOptions + }); + } + + async getTypeAndVersion(provider: ContractProvider): Promise<[ + c.Slice, + c.Slice, + ]> { + const r = StackReader.fromGetMethod(2, await provider.get('typeAndVersion', [])); + return [ + r.readSlice(), + r.readSlice(), + ]; + } + + async getToken(provider: ContractProvider): Promise { + const r = StackReader.fromGetMethod(1, await provider.get('token', [])); + return r.readSlice().loadAddress(); + } + + async getTokenDecimals(provider: ContractProvider): Promise { + const r = StackReader.fromGetMethod(1, await provider.get('tokenDecimals', [])); + return r.readBigInt(); + } + + async getIsSupportedChain(provider: ContractProvider, remoteChainSelector: uint64): Promise { + const r = StackReader.fromGetMethod(1, await provider.get('isSupportedChain', [ + { type: 'int', value: remoteChainSelector }, + ])); + return r.readBoolean(); + } + + async getOnRamp(provider: ContractProvider, remoteChainSelector: uint64): Promise { + const r = StackReader.fromGetMethod(1, await provider.get('onRamp', [ + { type: 'int', value: remoteChainSelector }, + ])); + return r.readNullable( + (r) => r.readSlice().loadAddress() + ); + } + + async getOffRamp(provider: ContractProvider, remoteChainSelector: uint64): Promise { + const r = StackReader.fromGetMethod(1, await provider.get('offRamp', [ + { type: 'int', value: remoteChainSelector }, + ])); + return r.readNullable( + (r) => r.readSlice().loadAddress() + ); + } + + async getHasPendingBurn(provider: ContractProvider, queryId: uint64): Promise { + const r = StackReader.fromGetMethod(1, await provider.get('hasPendingBurn', [ + { type: 'int', value: queryId }, + ])); + return r.readBoolean(); + } + + async getHasPendingMint(provider: ContractProvider, queryId: uint64): Promise { + const r = StackReader.fromGetMethod(1, await provider.get('hasPendingMint', [ + { type: 'int', value: queryId }, + ])); + return r.readBoolean(); + } + + async getVerifyNotCursed(provider: ContractProvider, subject: uint128): Promise { + const r = StackReader.fromGetMethod(1, await provider.get('verifyNotCursed', [ + { type: 'int', value: subject }, + ])); + return r.readBoolean(); + } + + async getOwner(provider: ContractProvider): Promise { + const r = StackReader.fromGetMethod(1, await provider.get('owner', [])); + return r.readSlice().loadAddress(); + } +} diff --git a/contracts/wrappers/gen/ccip/pools/LockReleaseTokenPool.ts b/contracts/wrappers/gen/ccip/pools/LockReleaseTokenPool.ts new file mode 100644 index 000000000..4fba812bc --- /dev/null +++ b/contracts/wrappers/gen/ccip/pools/LockReleaseTokenPool.ts @@ -0,0 +1,2078 @@ +// AUTO-GENERATED, do not edit +// It's a TypeScript wrapper for a LockReleaseTokenPool contract in Tolk. +/* eslint-disable */ + +import * as c from '@ton/core'; +import { beginCell, ContractProvider, Sender, SendMode } from '@ton/core'; + +// ———————————————————————————————————————————— +// predefined types and functions +// + +type RemainingBitsAndRefs = c.Slice + +type StoreCallback = (obj: T, b: c.Builder) => void +type LoadCallback = (s: c.Slice) => T + +export type CellRef = { + ref: T +} + +function makeCellFrom(self: T, storeFn_T: StoreCallback): c.Cell { + let b = beginCell(); + storeFn_T(self, b); + return b.endCell(); +} + +function loadAndCheckPrefix32(s: c.Slice, expected: number, structName: string): void { + let prefix = s.loadUint(32); + if (prefix !== expected) { + throw new Error(`Incorrect prefix for '${structName}': expected 0x${expected.toString(16).padStart(8, '0')}, got 0x${prefix.toString(16).padStart(8, '0')}`); + } +} + +function lookupPrefix(s: c.Slice, expected: number, prefixLen: number): boolean { + return s.remainingBits >= prefixLen && s.preloadUint(prefixLen) === expected; +} + +function throwNonePrefixMatch(fieldPath: string): never { + throw new Error(`Incorrect prefix for '${fieldPath}': none of variants matched`); +} + +function storeCellRef(cell: CellRef, b: c.Builder, storeFn_T: StoreCallback): void { + let b_ref = c.beginCell(); + storeFn_T(cell.ref, b_ref); + b.storeRef(b_ref.endCell()); +} + +function loadCellRef(s: c.Slice, loadFn_T: LoadCallback): CellRef { + let s_ref = s.loadRef().beginParse(); + return { ref: loadFn_T(s_ref) }; +} + +function storeTolkRemaining(v: RemainingBitsAndRefs, b: c.Builder): void { + b.storeSlice(v); +} + +function loadTolkRemaining(s: c.Slice): RemainingBitsAndRefs { + let rest = s.clone(); + s.loadBits(s.remainingBits); + while (s.remainingRefs) { + s.loadRef(); + } + return rest; +} + +function storeTolkNullable(v: T | null, b: c.Builder, storeFn_T: StoreCallback): void { + if (v === null) { + b.storeUint(0, 1); + } else { + b.storeUint(1, 1); + storeFn_T(v, b); + } +} + +function createDictionaryValue(loadFn_V: LoadCallback, storeFn_V: StoreCallback): c.DictionaryValue { + return { + serialize(self: V, b: c.Builder) { + storeFn_V(self, b); + }, + parse(s: c.Slice): V { + const value = loadFn_V(s); + s.endParse(); + return value; + } + } +} + +// ———————————————————————————————————————————— +// parse get methods result from a TVM stack +// + +class StackReader { + constructor(private tuple: c.TupleItem[]) { + } + + static fromGetMethod(expectedN: number, getMethodResult: { stack: c.TupleReader }): StackReader { + let tuple = [] as c.TupleItem[]; + while (getMethodResult.stack.remaining) { + tuple.push(getMethodResult.stack.pop()); + } + if (tuple.length !== expectedN) { + throw new Error(`expected ${expectedN} stack width, got ${tuple.length}`); + } + return new StackReader(tuple); + } + + private popExpecting(itemType: string): ItemT { + const item = this.tuple.shift(); + if (item?.type === itemType) { + return item as ItemT; + } + throw new Error(`not '${itemType}' on a stack`); + } + + private popCellLike(): c.Cell { + const item = this.tuple.shift(); + if (item && (item.type === 'cell' || item.type === 'slice' || item.type === 'builder')) { + return item.cell; + } + throw new Error(`not cell/slice on a stack`); + } + + readBigInt(): bigint { + return this.popExpecting('int').value; + } + + readBoolean(): boolean { + return this.popExpecting('int').value !== 0n; + } + + readCell(): c.Cell { + return this.popCellLike(); + } + + readSlice(): c.Slice { + return this.popCellLike().beginParse(); + } + + readNullable(readFn_T: (r: StackReader) => T): T | null { + if (this.tuple[0].type === 'null') { + this.tuple.shift(); + return null; + } + return readFn_T(this); + } +} + +// ———————————————————————————————————————————— +// custom packToBuilder and unpackFromSlice +// + +type CustomPackToBuilderFn = (self: T, b: c.Builder) => void +type CustomUnpackFromSliceFn = (s: c.Slice) => T + +let customSerializersRegistry: Map | null, CustomUnpackFromSliceFn | null]> = new Map; + +function ensureCustomSerializerRegistered(typeName: string) { + if (!customSerializersRegistry.has(typeName)) { + throw new Error(`Custom packToBuilder/unpackFromSlice was not registered for type 'LockReleaseTokenPool.${typeName}'.\n(in Tolk code, they have custom logic \`fun ${typeName}__packToBuilder\`)\nSteps to fix:\n1) in your code, create and implement\n > function ${typeName}__packToBuilder(self: ${typeName}, b: Builder): void { ... }\n > function ${typeName}__unpackFromSlice(s: Slice): ${typeName} { ... }\n2) register them in advance by calling\n > LockReleaseTokenPool.registerCustomPackUnpack('${typeName}', ${typeName}__packToBuilder, ${typeName}__unpackFromSlice);`); + } +} + +function invokeCustomPackToBuilder(typeName: string, self: T, b: c.Builder) { + ensureCustomSerializerRegistered(typeName); + customSerializersRegistry.get(typeName)![0]!(self, b); +} + +function invokeCustomUnpackFromSlice(typeName: string, s: c.Slice): T { + ensureCustomSerializerRegistered(typeName); + return customSerializersRegistry.get(typeName)![1]!(s); +} + +// ———————————————————————————————————————————— +// auto-generated serializers to/from cells +// + +type coins = bigint + +type uint8 = bigint +type uint16 = bigint +type uint32 = bigint +type uint64 = bigint +type uint128 = bigint +type uint256 = bigint + +/** + > struct Ownable2Step { + > owner: address + > pendingOwner: address? + > } + */ +export interface Ownable2Step { + readonly $: 'Ownable2Step' + owner: c.Address + pendingOwner: c.Address | null +} + +export const Ownable2Step = { + create(args: { + owner: c.Address + pendingOwner: c.Address | null + }): Ownable2Step { + return { + $: 'Ownable2Step', + ...args + } + }, + fromSlice(s: c.Slice): Ownable2Step { + return { + $: 'Ownable2Step', + owner: s.loadAddress(), + pendingOwner: s.loadMaybeAddress(), + } + }, + store(self: Ownable2Step, b: c.Builder): void { + b.storeAddress(self.owner); + b.storeAddress(self.pendingOwner); + }, + toCell(self: Ownable2Step): c.Cell { + return makeCellFrom(self, Ownable2Step.store); + } +} + +/** + > struct Ownable2Step_OwnershipTransferRequested { + > queryId: uint64 + > newOwner: address + > } + */ +export interface Ownable2Step_OwnershipTransferRequested { + readonly $: 'Ownable2Step_OwnershipTransferRequested' + queryId: uint64 + newOwner: c.Address +} + +export const Ownable2Step_OwnershipTransferRequested = { + create(args: { + queryId: uint64 + newOwner: c.Address + }): Ownable2Step_OwnershipTransferRequested { + return { + $: 'Ownable2Step_OwnershipTransferRequested', + ...args + } + }, + fromSlice(s: c.Slice): Ownable2Step_OwnershipTransferRequested { + return { + $: 'Ownable2Step_OwnershipTransferRequested', + queryId: s.loadUintBig(64), + newOwner: s.loadAddress(), + } + }, + store(self: Ownable2Step_OwnershipTransferRequested, b: c.Builder): void { + b.storeUint(self.queryId, 64); + b.storeAddress(self.newOwner); + }, + toCell(self: Ownable2Step_OwnershipTransferRequested): c.Cell { + return makeCellFrom(self, Ownable2Step_OwnershipTransferRequested.store); + } +} + +/** + > struct Ownable2Step_OwnershipTransferred { + > queryId: uint64 + > oldOwner: address + > newOwner: address + > } + */ +export interface Ownable2Step_OwnershipTransferred { + readonly $: 'Ownable2Step_OwnershipTransferred' + queryId: uint64 + oldOwner: c.Address + newOwner: c.Address +} + +export const Ownable2Step_OwnershipTransferred = { + create(args: { + queryId: uint64 + oldOwner: c.Address + newOwner: c.Address + }): Ownable2Step_OwnershipTransferred { + return { + $: 'Ownable2Step_OwnershipTransferred', + ...args + } + }, + fromSlice(s: c.Slice): Ownable2Step_OwnershipTransferred { + return { + $: 'Ownable2Step_OwnershipTransferred', + queryId: s.loadUintBig(64), + oldOwner: s.loadAddress(), + newOwner: s.loadAddress(), + } + }, + store(self: Ownable2Step_OwnershipTransferred, b: c.Builder): void { + b.storeUint(self.queryId, 64); + b.storeAddress(self.oldOwner); + b.storeAddress(self.newOwner); + }, + toCell(self: Ownable2Step_OwnershipTransferred): c.Cell { + return makeCellFrom(self, Ownable2Step_OwnershipTransferred.store); + } +} + +/** + > type ForwardPayloadRemainder = RemainingBitsAndRefs + */ +export type ForwardPayloadRemainder = RemainingBitsAndRefs + +export const ForwardPayloadRemainder = { + fromSlice(s: c.Slice): ForwardPayloadRemainder { + return loadTolkRemaining(s); + }, + store(self: ForwardPayloadRemainder, b: c.Builder): void { + storeTolkRemaining(self, b); + }, + toCell(self: ForwardPayloadRemainder): c.Cell { + return makeCellFrom(self, ForwardPayloadRemainder.store); + } +} + +/** + > struct (0x0f8a7ea5) AskToTransfer { + > queryId: uint64 + > jettonAmount: coins + > transferRecipient: address + > sendExcessesTo: address? + > customPayload: cell? + > forwardTonAmount: coins + > forwardPayload: ForwardPayloadRemainder + > } + */ +export interface AskToTransfer { + readonly $: 'AskToTransfer' + queryId: uint64 + jettonAmount: coins + transferRecipient: c.Address + sendExcessesTo: c.Address | null + customPayload: c.Cell | null + forwardTonAmount: coins + forwardPayload: ForwardPayloadRemainder +} + +export const AskToTransfer = { + PREFIX: 0x0f8a7ea5, + + create(args: { + queryId: uint64 + jettonAmount: coins + transferRecipient: c.Address + sendExcessesTo: c.Address | null + customPayload: c.Cell | null + forwardTonAmount: coins + forwardPayload: ForwardPayloadRemainder + }): AskToTransfer { + return { + $: 'AskToTransfer', + ...args + } + }, + fromSlice(s: c.Slice): AskToTransfer { + loadAndCheckPrefix32(s, 0x0f8a7ea5, 'AskToTransfer'); + return { + $: 'AskToTransfer', + queryId: s.loadUintBig(64), + jettonAmount: s.loadCoins(), + transferRecipient: s.loadAddress(), + sendExcessesTo: s.loadMaybeAddress(), + customPayload: s.loadBoolean() ? s.loadRef() : null, + forwardTonAmount: s.loadCoins(), + forwardPayload: ForwardPayloadRemainder.fromSlice(s), + } + }, + store(self: AskToTransfer, b: c.Builder): void { + b.storeUint(0x0f8a7ea5, 32); + b.storeUint(self.queryId, 64); + b.storeCoins(self.jettonAmount); + b.storeAddress(self.transferRecipient); + b.storeAddress(self.sendExcessesTo); + storeTolkNullable(self.customPayload, b, + (v,b) => b.storeRef(v) + ); + b.storeCoins(self.forwardTonAmount); + ForwardPayloadRemainder.store(self.forwardPayload, b); + }, + toCell(self: AskToTransfer): c.Cell { + return makeCellFrom(self, AskToTransfer.store); + } +} + +/** + > struct (0x7362d09c) TransferNotificationForRecipient { + > queryId: uint64 + > jettonAmount: coins + > transferInitiator: address? + > forwardPayload: ForwardPayloadRemainder + > } + */ +export interface TransferNotificationForRecipient { + readonly $: 'TransferNotificationForRecipient' + queryId: uint64 + jettonAmount: coins + transferInitiator: c.Address | null + forwardPayload: ForwardPayloadRemainder +} + +export const TransferNotificationForRecipient = { + PREFIX: 0x7362d09c, + + create(args: { + queryId: uint64 + jettonAmount: coins + transferInitiator: c.Address | null + forwardPayload: ForwardPayloadRemainder + }): TransferNotificationForRecipient { + return { + $: 'TransferNotificationForRecipient', + ...args + } + }, + fromSlice(s: c.Slice): TransferNotificationForRecipient { + loadAndCheckPrefix32(s, 0x7362d09c, 'TransferNotificationForRecipient'); + return { + $: 'TransferNotificationForRecipient', + queryId: s.loadUintBig(64), + jettonAmount: s.loadCoins(), + transferInitiator: s.loadMaybeAddress(), + forwardPayload: ForwardPayloadRemainder.fromSlice(s), + } + }, + store(self: TransferNotificationForRecipient, b: c.Builder): void { + b.storeUint(0x7362d09c, 32); + b.storeUint(self.queryId, 64); + b.storeCoins(self.jettonAmount); + b.storeAddress(self.transferInitiator); + ForwardPayloadRemainder.store(self.forwardPayload, b); + }, + toCell(self: TransferNotificationForRecipient): c.Cell { + return makeCellFrom(self, TransferNotificationForRecipient.store); + } +} + +/** + > struct (0xd53276db) ReturnExcessesBack { + > queryId: uint64 + > } + */ +export interface ReturnExcessesBack { + readonly $: 'ReturnExcessesBack' + queryId: uint64 +} + +export const ReturnExcessesBack = { + PREFIX: 0xd53276db, + + create(args: { + queryId: uint64 + }): ReturnExcessesBack { + return { + $: 'ReturnExcessesBack', + ...args + } + }, + fromSlice(s: c.Slice): ReturnExcessesBack { + loadAndCheckPrefix32(s, 0xd53276db, 'ReturnExcessesBack'); + return { + $: 'ReturnExcessesBack', + queryId: s.loadUintBig(64), + } + }, + store(self: ReturnExcessesBack, b: c.Builder): void { + b.storeUint(0xd53276db, 32); + b.storeUint(self.queryId, 64); + }, + toCell(self: ReturnExcessesBack): c.Cell { + return makeCellFrom(self, ReturnExcessesBack.store); + } +} + +/** + > struct JettonClient { + > masterAddress: address + > jettonWalletCode: cell + > } + */ +export interface JettonClient { + readonly $: 'JettonClient' + masterAddress: c.Address + jettonWalletCode: c.Cell +} + +export const JettonClient = { + create(args: { + masterAddress: c.Address + jettonWalletCode: c.Cell + }): JettonClient { + return { + $: 'JettonClient', + ...args + } + }, + fromSlice(s: c.Slice): JettonClient { + return { + $: 'JettonClient', + masterAddress: s.loadAddress(), + jettonWalletCode: s.loadRef(), + } + }, + store(self: JettonClient, b: c.Builder): void { + b.storeAddress(self.masterAddress); + b.storeRef(self.jettonWalletCode); + }, + toCell(self: JettonClient): c.Cell { + return makeCellFrom(self, JettonClient.store); + } +} + +/** + > struct CursedSubjects { + > data: map + > } + */ +export interface CursedSubjects { + readonly $: 'CursedSubjects' + data: c.Dictionary +} + +export const CursedSubjects = { + create(args: { + data: c.Dictionary + }): CursedSubjects { + return { + $: 'CursedSubjects', + ...args + } + }, + fromSlice(s: c.Slice): CursedSubjects { + return { + $: 'CursedSubjects', + data: c.Dictionary.load(c.Dictionary.Keys.BigUint(128), createDictionaryValue<[]>( + (s) => [], + (v,b) => { {} } + ), s), + } + }, + store(self: CursedSubjects, b: c.Builder): void { + b.storeDict(self.data, c.Dictionary.Keys.BigUint(128), createDictionaryValue<[]>( + (s) => [], + (v,b) => { {} } + )); + }, + toCell(self: CursedSubjects): c.Cell { + return makeCellFrom(self, CursedSubjects.store); + } +} + +/** + > struct TokenPool_AdminConfig { + > ownable: Cell + > rmnProxy: address + > dynamicConfig: Cell + > allowedFinalityConfig: uint32 + > } + */ +export interface TokenPool_AdminConfig { + readonly $: 'TokenPool_AdminConfig' + ownable: CellRef + rmnProxy: c.Address + dynamicConfig: CellRef + allowedFinalityConfig: uint32 /* = 0 as uint32 */ +} + +export const TokenPool_AdminConfig = { + create(args: { + ownable: CellRef + rmnProxy: c.Address + dynamicConfig: CellRef + allowedFinalityConfig?: uint32 /* = 0 as uint32 */ + }): TokenPool_AdminConfig { + return { + $: 'TokenPool_AdminConfig', + allowedFinalityConfig: 0n, + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_AdminConfig { + return { + $: 'TokenPool_AdminConfig', + ownable: loadCellRef(s, Ownable2Step.fromSlice), + rmnProxy: s.loadAddress(), + dynamicConfig: loadCellRef(s, TokenPool_DynamicConfig.fromSlice), + allowedFinalityConfig: s.loadUintBig(32), + } + }, + store(self: TokenPool_AdminConfig, b: c.Builder): void { + storeCellRef(self.ownable, b, Ownable2Step.store); + b.storeAddress(self.rmnProxy); + storeCellRef(self.dynamicConfig, b, TokenPool_DynamicConfig.store); + b.storeUint(self.allowedFinalityConfig, 32); + }, + toCell(self: TokenPool_AdminConfig): c.Cell { + return makeCellFrom(self, TokenPool_AdminConfig.store); + } +} + +/** + > struct TokenPool_Data { + > adminConfig: Cell + > mirroredPolicy: Cell + > token: address + > tokenDecimals: uint8 + > remoteChainConfigs: map + > tokenTransferFeeConfigs: map + > } + */ +export interface TokenPool_Data { + readonly $: 'TokenPool_Data' + adminConfig: CellRef + mirroredPolicy: CellRef + token: c.Address + tokenDecimals: uint8 + remoteChainConfigs: c.Dictionary + tokenTransferFeeConfigs: c.Dictionary +} + +export const TokenPool_Data = { + create(args: { + adminConfig: CellRef + mirroredPolicy: CellRef + token: c.Address + tokenDecimals: uint8 + remoteChainConfigs: c.Dictionary + tokenTransferFeeConfigs: c.Dictionary + }): TokenPool_Data { + return { + $: 'TokenPool_Data', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_Data { + return { + $: 'TokenPool_Data', + adminConfig: loadCellRef(s, TokenPool_AdminConfig.fromSlice), + mirroredPolicy: loadCellRef(s, TokenPool_MirroredPolicy.fromSlice), + token: s.loadAddress(), + tokenDecimals: s.loadUintBig(8), + remoteChainConfigs: c.Dictionary.load(c.Dictionary.Keys.BigUint(64), createDictionaryValue(TokenPool_RemoteChainConfig.fromSlice, TokenPool_RemoteChainConfig.store), s), + tokenTransferFeeConfigs: c.Dictionary.load(c.Dictionary.Keys.BigUint(64), createDictionaryValue(TokenPool_TokenTransferFeeConfig.fromSlice, TokenPool_TokenTransferFeeConfig.store), s), + } + }, + store(self: TokenPool_Data, b: c.Builder): void { + storeCellRef(self.adminConfig, b, TokenPool_AdminConfig.store); + storeCellRef(self.mirroredPolicy, b, TokenPool_MirroredPolicy.store); + b.storeAddress(self.token); + b.storeUint(self.tokenDecimals, 8); + b.storeDict(self.remoteChainConfigs, c.Dictionary.Keys.BigUint(64), createDictionaryValue(TokenPool_RemoteChainConfig.fromSlice, TokenPool_RemoteChainConfig.store)); + b.storeDict(self.tokenTransferFeeConfigs, c.Dictionary.Keys.BigUint(64), createDictionaryValue(TokenPool_TokenTransferFeeConfig.fromSlice, TokenPool_TokenTransferFeeConfig.store)); + }, + toCell(self: TokenPool_Data): c.Cell { + return makeCellFrom(self, TokenPool_Data.store); + } +} + +/** + > struct TokenPool_DynamicConfig { + > router: address + > rateLimitAdmin: address? + > feeAdmin: address? + > } + */ +export interface TokenPool_DynamicConfig { + readonly $: 'TokenPool_DynamicConfig' + router: c.Address + rateLimitAdmin: c.Address | null + feeAdmin: c.Address | null +} + +export const TokenPool_DynamicConfig = { + create(args: { + router: c.Address + rateLimitAdmin: c.Address | null + feeAdmin: c.Address | null + }): TokenPool_DynamicConfig { + return { + $: 'TokenPool_DynamicConfig', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_DynamicConfig { + return { + $: 'TokenPool_DynamicConfig', + router: s.loadAddress(), + rateLimitAdmin: s.loadMaybeAddress(), + feeAdmin: s.loadMaybeAddress(), + } + }, + store(self: TokenPool_DynamicConfig, b: c.Builder): void { + b.storeAddress(self.router); + b.storeAddress(self.rateLimitAdmin); + b.storeAddress(self.feeAdmin); + }, + toCell(self: TokenPool_DynamicConfig): c.Cell { + return makeCellFrom(self, TokenPool_DynamicConfig.store); + } +} + +/** + > struct TokenPool_MirroredPolicy { + > onRamps: map + > offRamps: map + > cursedSubjects: CursedSubjects + > } + */ +export interface TokenPool_MirroredPolicy { + readonly $: 'TokenPool_MirroredPolicy' + onRamps: c.Dictionary + offRamps: c.Dictionary + cursedSubjects: CursedSubjects +} + +export const TokenPool_MirroredPolicy = { + create(args: { + onRamps: c.Dictionary + offRamps: c.Dictionary + cursedSubjects: CursedSubjects + }): TokenPool_MirroredPolicy { + return { + $: 'TokenPool_MirroredPolicy', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_MirroredPolicy { + return { + $: 'TokenPool_MirroredPolicy', + onRamps: c.Dictionary.load(c.Dictionary.Keys.BigUint(64), createDictionaryValue( + (s) => s.loadAddress(), + (v,b) => b.storeAddress(v) + ), s), + offRamps: c.Dictionary.load(c.Dictionary.Keys.BigUint(64), createDictionaryValue( + (s) => s.loadAddress(), + (v,b) => b.storeAddress(v) + ), s), + cursedSubjects: CursedSubjects.fromSlice(s), + } + }, + store(self: TokenPool_MirroredPolicy, b: c.Builder): void { + b.storeDict(self.onRamps, c.Dictionary.Keys.BigUint(64), createDictionaryValue( + (s) => s.loadAddress(), + (v,b) => b.storeAddress(v) + )); + b.storeDict(self.offRamps, c.Dictionary.Keys.BigUint(64), createDictionaryValue( + (s) => s.loadAddress(), + (v,b) => b.storeAddress(v) + )); + CursedSubjects.store(self.cursedSubjects, b); + }, + toCell(self: TokenPool_MirroredPolicy): c.Cell { + return makeCellFrom(self, TokenPool_MirroredPolicy.store); + } +} + +/** + > struct TokenPool_RateLimiterPair { + > outbound: Cell + > inbound: Cell + > } + */ +export interface TokenPool_RateLimiterPair { + readonly $: 'TokenPool_RateLimiterPair' + outbound: CellRef + inbound: CellRef +} + +export const TokenPool_RateLimiterPair = { + create(args: { + outbound: CellRef + inbound: CellRef + }): TokenPool_RateLimiterPair { + return { + $: 'TokenPool_RateLimiterPair', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_RateLimiterPair { + return { + $: 'TokenPool_RateLimiterPair', + outbound: loadCellRef(s, RateLimiter_TokenBucket.fromSlice), + inbound: loadCellRef(s, RateLimiter_TokenBucket.fromSlice), + } + }, + store(self: TokenPool_RateLimiterPair, b: c.Builder): void { + storeCellRef(self.outbound, b, RateLimiter_TokenBucket.store); + storeCellRef(self.inbound, b, RateLimiter_TokenBucket.store); + }, + toCell(self: TokenPool_RateLimiterPair): c.Cell { + return makeCellFrom(self, TokenPool_RateLimiterPair.store); + } +} + +/** + > struct TokenPool_RemoteChainConfig { + > remoteTokenAddress: Cell + > remotePools: map> + > rateLimiters: Cell + > fastFinalityRateLimiters: Cell + > } + */ +export interface TokenPool_RemoteChainConfig { + readonly $: 'TokenPool_RemoteChainConfig' + remoteTokenAddress: CellRef + remotePools: c.Dictionary> + rateLimiters: CellRef + fastFinalityRateLimiters: CellRef +} + +export const TokenPool_RemoteChainConfig = { + create(args: { + remoteTokenAddress: CellRef + remotePools: c.Dictionary> + rateLimiters: CellRef + fastFinalityRateLimiters: CellRef + }): TokenPool_RemoteChainConfig { + return { + $: 'TokenPool_RemoteChainConfig', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_RemoteChainConfig { + return { + $: 'TokenPool_RemoteChainConfig', + remoteTokenAddress: loadCellRef(s, CrossChainAddress.fromSlice), + remotePools: c.Dictionary.load>(c.Dictionary.Keys.BigUint(256), createDictionaryValue>( + (s) => loadCellRef(s, CrossChainAddress.fromSlice), + (v,b) => storeCellRef(v, b, CrossChainAddress.store) + ), s), + rateLimiters: loadCellRef(s, TokenPool_RateLimiterPair.fromSlice), + fastFinalityRateLimiters: loadCellRef(s, TokenPool_RateLimiterPair.fromSlice), + } + }, + store(self: TokenPool_RemoteChainConfig, b: c.Builder): void { + storeCellRef(self.remoteTokenAddress, b, CrossChainAddress.store); + b.storeDict>(self.remotePools, c.Dictionary.Keys.BigUint(256), createDictionaryValue>( + (s) => loadCellRef(s, CrossChainAddress.fromSlice), + (v,b) => storeCellRef(v, b, CrossChainAddress.store) + )); + storeCellRef(self.rateLimiters, b, TokenPool_RateLimiterPair.store); + storeCellRef(self.fastFinalityRateLimiters, b, TokenPool_RateLimiterPair.store); + }, + toCell(self: TokenPool_RemoteChainConfig): c.Cell { + return makeCellFrom(self, TokenPool_RemoteChainConfig.store); + } +} + +/** + > struct TokenPool_TokenTransferFeeConfig { + > isEnabled: bool + > finalityFeeUSDCents: uint256 + > fastFinalityFeeUSDCents: uint256 + > destGasOverhead: uint32 + > destBytesOverhead: uint32 + > finalityTransferFeeBps: uint16 + > fastFinalityTransferFeeBps: uint16 + > } + */ +export interface TokenPool_TokenTransferFeeConfig { + readonly $: 'TokenPool_TokenTransferFeeConfig' + isEnabled: boolean + finalityFeeUSDCents: uint256 + fastFinalityFeeUSDCents: uint256 + destGasOverhead: uint32 + destBytesOverhead: uint32 + finalityTransferFeeBps: uint16 + fastFinalityTransferFeeBps: uint16 +} + +export const TokenPool_TokenTransferFeeConfig = { + create(args: { + isEnabled: boolean + finalityFeeUSDCents: uint256 + fastFinalityFeeUSDCents: uint256 + destGasOverhead: uint32 + destBytesOverhead: uint32 + finalityTransferFeeBps: uint16 + fastFinalityTransferFeeBps: uint16 + }): TokenPool_TokenTransferFeeConfig { + return { + $: 'TokenPool_TokenTransferFeeConfig', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_TokenTransferFeeConfig { + return { + $: 'TokenPool_TokenTransferFeeConfig', + isEnabled: s.loadBoolean(), + finalityFeeUSDCents: s.loadUintBig(256), + fastFinalityFeeUSDCents: s.loadUintBig(256), + destGasOverhead: s.loadUintBig(32), + destBytesOverhead: s.loadUintBig(32), + finalityTransferFeeBps: s.loadUintBig(16), + fastFinalityTransferFeeBps: s.loadUintBig(16), + } + }, + store(self: TokenPool_TokenTransferFeeConfig, b: c.Builder): void { + b.storeBit(self.isEnabled); + b.storeUint(self.finalityFeeUSDCents, 256); + b.storeUint(self.fastFinalityFeeUSDCents, 256); + b.storeUint(self.destGasOverhead, 32); + b.storeUint(self.destBytesOverhead, 32); + b.storeUint(self.finalityTransferFeeBps, 16); + b.storeUint(self.fastFinalityTransferFeeBps, 16); + }, + toCell(self: TokenPool_TokenTransferFeeConfig): c.Cell { + return makeCellFrom(self, TokenPool_TokenTransferFeeConfig.store); + } +} + +/** + > struct TokenPool_LockOrBurnOutV1 { + > destTokenAddress: Cell + > destPoolData: cell + > } + */ +export interface TokenPool_LockOrBurnOutV1 { + readonly $: 'TokenPool_LockOrBurnOutV1' + destTokenAddress: CellRef + destPoolData: c.Cell +} + +export const TokenPool_LockOrBurnOutV1 = { + create(args: { + destTokenAddress: CellRef + destPoolData: c.Cell + }): TokenPool_LockOrBurnOutV1 { + return { + $: 'TokenPool_LockOrBurnOutV1', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_LockOrBurnOutV1 { + return { + $: 'TokenPool_LockOrBurnOutV1', + destTokenAddress: loadCellRef(s, CrossChainAddress.fromSlice), + destPoolData: s.loadRef(), + } + }, + store(self: TokenPool_LockOrBurnOutV1, b: c.Builder): void { + storeCellRef(self.destTokenAddress, b, CrossChainAddress.store); + b.storeRef(self.destPoolData); + }, + toCell(self: TokenPool_LockOrBurnOutV1): c.Cell { + return makeCellFrom(self, TokenPool_LockOrBurnOutV1.store); + } +} + +/** + > struct TokenPool_ReleaseOrMintInV1 { + > originalSender: Cell + > remoteChainSelector: uint64 + > receiver: address + > sourceDenominatedAmount: uint256 + > localToken: address + > sourcePoolAddress: Cell + > sourcePoolData: cell? + > offchainTokenData: cell? + > } + */ +export interface TokenPool_ReleaseOrMintInV1 { + readonly $: 'TokenPool_ReleaseOrMintInV1' + originalSender: CellRef + remoteChainSelector: uint64 + receiver: c.Address + sourceDenominatedAmount: uint256 + localToken: c.Address + sourcePoolAddress: CellRef + sourcePoolData: c.Cell | null + offchainTokenData: c.Cell | null +} + +export const TokenPool_ReleaseOrMintInV1 = { + create(args: { + originalSender: CellRef + remoteChainSelector: uint64 + receiver: c.Address + sourceDenominatedAmount: uint256 + localToken: c.Address + sourcePoolAddress: CellRef + sourcePoolData: c.Cell | null + offchainTokenData: c.Cell | null + }): TokenPool_ReleaseOrMintInV1 { + return { + $: 'TokenPool_ReleaseOrMintInV1', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_ReleaseOrMintInV1 { + return { + $: 'TokenPool_ReleaseOrMintInV1', + originalSender: loadCellRef(s, CrossChainAddress.fromSlice), + remoteChainSelector: s.loadUintBig(64), + receiver: s.loadAddress(), + sourceDenominatedAmount: s.loadUintBig(256), + localToken: s.loadAddress(), + sourcePoolAddress: loadCellRef(s, CrossChainAddress.fromSlice), + sourcePoolData: s.loadBoolean() ? s.loadRef() : null, + offchainTokenData: s.loadBoolean() ? s.loadRef() : null, + } + }, + store(self: TokenPool_ReleaseOrMintInV1, b: c.Builder): void { + storeCellRef(self.originalSender, b, CrossChainAddress.store); + b.storeUint(self.remoteChainSelector, 64); + b.storeAddress(self.receiver); + b.storeUint(self.sourceDenominatedAmount, 256); + b.storeAddress(self.localToken); + storeCellRef(self.sourcePoolAddress, b, CrossChainAddress.store); + storeTolkNullable(self.sourcePoolData, b, + (v,b) => b.storeRef(v) + ); + storeTolkNullable(self.offchainTokenData, b, + (v,b) => b.storeRef(v) + ); + }, + toCell(self: TokenPool_ReleaseOrMintInV1): c.Cell { + return makeCellFrom(self, TokenPool_ReleaseOrMintInV1.store); + } +} + +/** + > struct TokenPool_ReleaseOrMintOutV1 { + > destinationAmount: uint256 + > } + */ +export interface TokenPool_ReleaseOrMintOutV1 { + readonly $: 'TokenPool_ReleaseOrMintOutV1' + destinationAmount: uint256 +} + +export const TokenPool_ReleaseOrMintOutV1 = { + create(args: { + destinationAmount: uint256 + }): TokenPool_ReleaseOrMintOutV1 { + return { + $: 'TokenPool_ReleaseOrMintOutV1', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_ReleaseOrMintOutV1 { + return { + $: 'TokenPool_ReleaseOrMintOutV1', + destinationAmount: s.loadUintBig(256), + } + }, + store(self: TokenPool_ReleaseOrMintOutV1, b: c.Builder): void { + b.storeUint(self.destinationAmount, 256); + }, + toCell(self: TokenPool_ReleaseOrMintOutV1): c.Cell { + return makeCellFrom(self, TokenPool_ReleaseOrMintOutV1.store); + } +} + +/** + > struct (0x19e65bea) TokenPool_LockOrBurnResponse { + > queryId: uint64 + > out: Cell + > destTokenAmount: uint256 + > } + */ +export interface TokenPool_LockOrBurnResponse { + readonly $: 'TokenPool_LockOrBurnResponse' + queryId: uint64 + out: CellRef + destTokenAmount: uint256 +} + +export const TokenPool_LockOrBurnResponse = { + PREFIX: 0x19e65bea, + + create(args: { + queryId: uint64 + out: CellRef + destTokenAmount: uint256 + }): TokenPool_LockOrBurnResponse { + return { + $: 'TokenPool_LockOrBurnResponse', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_LockOrBurnResponse { + loadAndCheckPrefix32(s, 0x19e65bea, 'TokenPool_LockOrBurnResponse'); + return { + $: 'TokenPool_LockOrBurnResponse', + queryId: s.loadUintBig(64), + out: loadCellRef(s, TokenPool_LockOrBurnOutV1.fromSlice), + destTokenAmount: s.loadUintBig(256), + } + }, + store(self: TokenPool_LockOrBurnResponse, b: c.Builder): void { + b.storeUint(0x19e65bea, 32); + b.storeUint(self.queryId, 64); + storeCellRef(self.out, b, TokenPool_LockOrBurnOutV1.store); + b.storeUint(self.destTokenAmount, 256); + }, + toCell(self: TokenPool_LockOrBurnResponse): c.Cell { + return makeCellFrom(self, TokenPool_LockOrBurnResponse.store); + } +} + +/** + > struct (0x7ec43aee) TokenPool_ReleaseOrMintResponse { + > queryId: uint64 + > out: Cell + > } + */ +export interface TokenPool_ReleaseOrMintResponse { + readonly $: 'TokenPool_ReleaseOrMintResponse' + queryId: uint64 + out: CellRef +} + +export const TokenPool_ReleaseOrMintResponse = { + PREFIX: 0x7ec43aee, + + create(args: { + queryId: uint64 + out: CellRef + }): TokenPool_ReleaseOrMintResponse { + return { + $: 'TokenPool_ReleaseOrMintResponse', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_ReleaseOrMintResponse { + loadAndCheckPrefix32(s, 0x7ec43aee, 'TokenPool_ReleaseOrMintResponse'); + return { + $: 'TokenPool_ReleaseOrMintResponse', + queryId: s.loadUintBig(64), + out: loadCellRef(s, TokenPool_ReleaseOrMintOutV1.fromSlice), + } + }, + store(self: TokenPool_ReleaseOrMintResponse, b: c.Builder): void { + b.storeUint(0x7ec43aee, 32); + b.storeUint(self.queryId, 64); + storeCellRef(self.out, b, TokenPool_ReleaseOrMintOutV1.store); + }, + toCell(self: TokenPool_ReleaseOrMintResponse): c.Cell { + return makeCellFrom(self, TokenPool_ReleaseOrMintResponse.store); + } +} + +/** + > struct (0x41a1702b) TokenPool_ReleaseOrMintFailure { + > queryId: uint64 + > errorCode: uint16 + > } + */ +export interface TokenPool_ReleaseOrMintFailure { + readonly $: 'TokenPool_ReleaseOrMintFailure' + queryId: uint64 + errorCode: uint16 +} + +export const TokenPool_ReleaseOrMintFailure = { + PREFIX: 0x41a1702b, + + create(args: { + queryId: uint64 + errorCode: uint16 + }): TokenPool_ReleaseOrMintFailure { + return { + $: 'TokenPool_ReleaseOrMintFailure', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_ReleaseOrMintFailure { + loadAndCheckPrefix32(s, 0x41a1702b, 'TokenPool_ReleaseOrMintFailure'); + return { + $: 'TokenPool_ReleaseOrMintFailure', + queryId: s.loadUintBig(64), + errorCode: s.loadUintBig(16), + } + }, + store(self: TokenPool_ReleaseOrMintFailure, b: c.Builder): void { + b.storeUint(0x41a1702b, 32); + b.storeUint(self.queryId, 64); + b.storeUint(self.errorCode, 16); + }, + toCell(self: TokenPool_ReleaseOrMintFailure): c.Cell { + return makeCellFrom(self, TokenPool_ReleaseOrMintFailure.store); + } +} + +/** + > struct TokenPool_LockedOrBurnedDetails { + > token: address + > sender: address + > amount: uint256 + > } + */ +export interface TokenPool_LockedOrBurnedDetails { + readonly $: 'TokenPool_LockedOrBurnedDetails' + token: c.Address + sender: c.Address + amount: uint256 +} + +export const TokenPool_LockedOrBurnedDetails = { + create(args: { + token: c.Address + sender: c.Address + amount: uint256 + }): TokenPool_LockedOrBurnedDetails { + return { + $: 'TokenPool_LockedOrBurnedDetails', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_LockedOrBurnedDetails { + return { + $: 'TokenPool_LockedOrBurnedDetails', + token: s.loadAddress(), + sender: s.loadAddress(), + amount: s.loadUintBig(256), + } + }, + store(self: TokenPool_LockedOrBurnedDetails, b: c.Builder): void { + b.storeAddress(self.token); + b.storeAddress(self.sender); + b.storeUint(self.amount, 256); + }, + toCell(self: TokenPool_LockedOrBurnedDetails): c.Cell { + return makeCellFrom(self, TokenPool_LockedOrBurnedDetails.store); + } +} + +/** + > struct TokenPool_LockedOrBurned { + > remoteChainSelector: uint64 + > details: Cell + > } + */ +export interface TokenPool_LockedOrBurned { + readonly $: 'TokenPool_LockedOrBurned' + remoteChainSelector: uint64 + details: CellRef +} + +export const TokenPool_LockedOrBurned = { + create(args: { + remoteChainSelector: uint64 + details: CellRef + }): TokenPool_LockedOrBurned { + return { + $: 'TokenPool_LockedOrBurned', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_LockedOrBurned { + return { + $: 'TokenPool_LockedOrBurned', + remoteChainSelector: s.loadUintBig(64), + details: loadCellRef(s, TokenPool_LockedOrBurnedDetails.fromSlice), + } + }, + store(self: TokenPool_LockedOrBurned, b: c.Builder): void { + b.storeUint(self.remoteChainSelector, 64); + storeCellRef(self.details, b, TokenPool_LockedOrBurnedDetails.store); + }, + toCell(self: TokenPool_LockedOrBurned): c.Cell { + return makeCellFrom(self, TokenPool_LockedOrBurned.store); + } +} + +/** + > struct TokenPool_ReleasedOrMintedParticipants { + > sender: address + > recipient: address + > } + */ +export interface TokenPool_ReleasedOrMintedParticipants { + readonly $: 'TokenPool_ReleasedOrMintedParticipants' + sender: c.Address + recipient: c.Address +} + +export const TokenPool_ReleasedOrMintedParticipants = { + create(args: { + sender: c.Address + recipient: c.Address + }): TokenPool_ReleasedOrMintedParticipants { + return { + $: 'TokenPool_ReleasedOrMintedParticipants', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_ReleasedOrMintedParticipants { + return { + $: 'TokenPool_ReleasedOrMintedParticipants', + sender: s.loadAddress(), + recipient: s.loadAddress(), + } + }, + store(self: TokenPool_ReleasedOrMintedParticipants, b: c.Builder): void { + b.storeAddress(self.sender); + b.storeAddress(self.recipient); + }, + toCell(self: TokenPool_ReleasedOrMintedParticipants): c.Cell { + return makeCellFrom(self, TokenPool_ReleasedOrMintedParticipants.store); + } +} + +/** + > struct TokenPool_ReleasedOrMintedDetails { + > token: address + > amount: uint256 + > participants: Cell + > } + */ +export interface TokenPool_ReleasedOrMintedDetails { + readonly $: 'TokenPool_ReleasedOrMintedDetails' + token: c.Address + amount: uint256 + participants: CellRef +} + +export const TokenPool_ReleasedOrMintedDetails = { + create(args: { + token: c.Address + amount: uint256 + participants: CellRef + }): TokenPool_ReleasedOrMintedDetails { + return { + $: 'TokenPool_ReleasedOrMintedDetails', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_ReleasedOrMintedDetails { + return { + $: 'TokenPool_ReleasedOrMintedDetails', + token: s.loadAddress(), + amount: s.loadUintBig(256), + participants: loadCellRef(s, TokenPool_ReleasedOrMintedParticipants.fromSlice), + } + }, + store(self: TokenPool_ReleasedOrMintedDetails, b: c.Builder): void { + b.storeAddress(self.token); + b.storeUint(self.amount, 256); + storeCellRef(self.participants, b, TokenPool_ReleasedOrMintedParticipants.store); + }, + toCell(self: TokenPool_ReleasedOrMintedDetails): c.Cell { + return makeCellFrom(self, TokenPool_ReleasedOrMintedDetails.store); + } +} + +/** + > struct TokenPool_ReleasedOrMinted { + > remoteChainSelector: uint64 + > details: Cell + > } + */ +export interface TokenPool_ReleasedOrMinted { + readonly $: 'TokenPool_ReleasedOrMinted' + remoteChainSelector: uint64 + details: CellRef +} + +export const TokenPool_ReleasedOrMinted = { + create(args: { + remoteChainSelector: uint64 + details: CellRef + }): TokenPool_ReleasedOrMinted { + return { + $: 'TokenPool_ReleasedOrMinted', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_ReleasedOrMinted { + return { + $: 'TokenPool_ReleasedOrMinted', + remoteChainSelector: s.loadUintBig(64), + details: loadCellRef(s, TokenPool_ReleasedOrMintedDetails.fromSlice), + } + }, + store(self: TokenPool_ReleasedOrMinted, b: c.Builder): void { + b.storeUint(self.remoteChainSelector, 64); + storeCellRef(self.details, b, TokenPool_ReleasedOrMintedDetails.store); + }, + toCell(self: TokenPool_ReleasedOrMinted): c.Cell { + return makeCellFrom(self, TokenPool_ReleasedOrMinted.store); + } +} + +/** + > struct TokenPool_ChainAdded { + > remoteChainSelector: uint64 + > remoteTokenAddress: Cell + > } + */ +export interface TokenPool_ChainAdded { + readonly $: 'TokenPool_ChainAdded' + remoteChainSelector: uint64 + remoteTokenAddress: CellRef +} + +export const TokenPool_ChainAdded = { + create(args: { + remoteChainSelector: uint64 + remoteTokenAddress: CellRef + }): TokenPool_ChainAdded { + return { + $: 'TokenPool_ChainAdded', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_ChainAdded { + return { + $: 'TokenPool_ChainAdded', + remoteChainSelector: s.loadUintBig(64), + remoteTokenAddress: loadCellRef(s, CrossChainAddress.fromSlice), + } + }, + store(self: TokenPool_ChainAdded, b: c.Builder): void { + b.storeUint(self.remoteChainSelector, 64); + storeCellRef(self.remoteTokenAddress, b, CrossChainAddress.store); + }, + toCell(self: TokenPool_ChainAdded): c.Cell { + return makeCellFrom(self, TokenPool_ChainAdded.store); + } +} + +/** + > struct TokenPool_ChainRemoved { + > remoteChainSelector: uint64 + > } + */ +export interface TokenPool_ChainRemoved { + readonly $: 'TokenPool_ChainRemoved' + remoteChainSelector: uint64 +} + +export const TokenPool_ChainRemoved = { + create(args: { + remoteChainSelector: uint64 + }): TokenPool_ChainRemoved { + return { + $: 'TokenPool_ChainRemoved', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_ChainRemoved { + return { + $: 'TokenPool_ChainRemoved', + remoteChainSelector: s.loadUintBig(64), + } + }, + store(self: TokenPool_ChainRemoved, b: c.Builder): void { + b.storeUint(self.remoteChainSelector, 64); + }, + toCell(self: TokenPool_ChainRemoved): c.Cell { + return makeCellFrom(self, TokenPool_ChainRemoved.store); + } +} + +/** + > struct TokenPool_RemotePoolAdded { + > remoteChainSelector: uint64 + > remotePoolAddress: Cell + > } + */ +export interface TokenPool_RemotePoolAdded { + readonly $: 'TokenPool_RemotePoolAdded' + remoteChainSelector: uint64 + remotePoolAddress: CellRef +} + +export const TokenPool_RemotePoolAdded = { + create(args: { + remoteChainSelector: uint64 + remotePoolAddress: CellRef + }): TokenPool_RemotePoolAdded { + return { + $: 'TokenPool_RemotePoolAdded', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_RemotePoolAdded { + return { + $: 'TokenPool_RemotePoolAdded', + remoteChainSelector: s.loadUintBig(64), + remotePoolAddress: loadCellRef(s, CrossChainAddress.fromSlice), + } + }, + store(self: TokenPool_RemotePoolAdded, b: c.Builder): void { + b.storeUint(self.remoteChainSelector, 64); + storeCellRef(self.remotePoolAddress, b, CrossChainAddress.store); + }, + toCell(self: TokenPool_RemotePoolAdded): c.Cell { + return makeCellFrom(self, TokenPool_RemotePoolAdded.store); + } +} + +/** + > struct TokenPool_RemotePoolRemoved { + > remoteChainSelector: uint64 + > remotePoolAddress: Cell + > } + */ +export interface TokenPool_RemotePoolRemoved { + readonly $: 'TokenPool_RemotePoolRemoved' + remoteChainSelector: uint64 + remotePoolAddress: CellRef +} + +export const TokenPool_RemotePoolRemoved = { + create(args: { + remoteChainSelector: uint64 + remotePoolAddress: CellRef + }): TokenPool_RemotePoolRemoved { + return { + $: 'TokenPool_RemotePoolRemoved', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_RemotePoolRemoved { + return { + $: 'TokenPool_RemotePoolRemoved', + remoteChainSelector: s.loadUintBig(64), + remotePoolAddress: loadCellRef(s, CrossChainAddress.fromSlice), + } + }, + store(self: TokenPool_RemotePoolRemoved, b: c.Builder): void { + b.storeUint(self.remoteChainSelector, 64); + storeCellRef(self.remotePoolAddress, b, CrossChainAddress.store); + }, + toCell(self: TokenPool_RemotePoolRemoved): c.Cell { + return makeCellFrom(self, TokenPool_RemotePoolRemoved.store); + } +} + +/** + > struct TokenPool_DynamicConfigSet { + > router: address + > rateLimitAdmin: address? + > feeAdmin: address? + > } + */ +export interface TokenPool_DynamicConfigSet { + readonly $: 'TokenPool_DynamicConfigSet' + router: c.Address + rateLimitAdmin: c.Address | null + feeAdmin: c.Address | null +} + +export const TokenPool_DynamicConfigSet = { + create(args: { + router: c.Address + rateLimitAdmin: c.Address | null + feeAdmin: c.Address | null + }): TokenPool_DynamicConfigSet { + return { + $: 'TokenPool_DynamicConfigSet', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_DynamicConfigSet { + return { + $: 'TokenPool_DynamicConfigSet', + router: s.loadAddress(), + rateLimitAdmin: s.loadMaybeAddress(), + feeAdmin: s.loadMaybeAddress(), + } + }, + store(self: TokenPool_DynamicConfigSet, b: c.Builder): void { + b.storeAddress(self.router); + b.storeAddress(self.rateLimitAdmin); + b.storeAddress(self.feeAdmin); + }, + toCell(self: TokenPool_DynamicConfigSet): c.Cell { + return makeCellFrom(self, TokenPool_DynamicConfigSet.store); + } +} + +/** + > struct TokenPool_FinalityConfigSet { + > allowedFinalityConfig: uint32 + > } + */ +export interface TokenPool_FinalityConfigSet { + readonly $: 'TokenPool_FinalityConfigSet' + allowedFinalityConfig: uint32 +} + +export const TokenPool_FinalityConfigSet = { + create(args: { + allowedFinalityConfig: uint32 + }): TokenPool_FinalityConfigSet { + return { + $: 'TokenPool_FinalityConfigSet', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_FinalityConfigSet { + return { + $: 'TokenPool_FinalityConfigSet', + allowedFinalityConfig: s.loadUintBig(32), + } + }, + store(self: TokenPool_FinalityConfigSet, b: c.Builder): void { + b.storeUint(self.allowedFinalityConfig, 32); + }, + toCell(self: TokenPool_FinalityConfigSet): c.Cell { + return makeCellFrom(self, TokenPool_FinalityConfigSet.store); + } +} + +/** + > struct TokenPool_RampAccessUpdated { + > remoteChainSelector: uint64 + > onRamp: address? + > offRamp: address? + > } + */ +export interface TokenPool_RampAccessUpdated { + readonly $: 'TokenPool_RampAccessUpdated' + remoteChainSelector: uint64 + onRamp: c.Address | null /* = null */ + offRamp: c.Address | null /* = null */ +} + +export const TokenPool_RampAccessUpdated = { + create(args: { + remoteChainSelector: uint64 + onRamp?: c.Address | null /* = null */ + offRamp?: c.Address | null /* = null */ + }): TokenPool_RampAccessUpdated { + return { + $: 'TokenPool_RampAccessUpdated', + onRamp: null, + offRamp: null, + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_RampAccessUpdated { + return { + $: 'TokenPool_RampAccessUpdated', + remoteChainSelector: s.loadUintBig(64), + onRamp: s.loadMaybeAddress(), + offRamp: s.loadMaybeAddress(), + } + }, + store(self: TokenPool_RampAccessUpdated, b: c.Builder): void { + b.storeUint(self.remoteChainSelector, 64); + b.storeAddress(self.onRamp); + b.storeAddress(self.offRamp); + }, + toCell(self: TokenPool_RampAccessUpdated): c.Cell { + return makeCellFrom(self, TokenPool_RampAccessUpdated.store); + } +} + +/** + > struct TokenPool_CursedSubjectsUpdated { + > } + */ +export interface TokenPool_CursedSubjectsUpdated { + readonly $: 'TokenPool_CursedSubjectsUpdated' +} + +export const TokenPool_CursedSubjectsUpdated = { + create(): TokenPool_CursedSubjectsUpdated { + return { + $: 'TokenPool_CursedSubjectsUpdated', + } + }, + fromSlice(s: c.Slice): TokenPool_CursedSubjectsUpdated { + return { + $: 'TokenPool_CursedSubjectsUpdated', + } + }, + store(self: TokenPool_CursedSubjectsUpdated, b: c.Builder): void { + }, + toCell(self: TokenPool_CursedSubjectsUpdated): c.Cell { + return makeCellFrom(self, TokenPool_CursedSubjectsUpdated.store); + } +} + +/** + > struct LockReleaseTokenPool_PendingRelease { + > replyTo: address? + > request: Cell + > out: Cell + > expectedSender: address + > } + */ +export interface LockReleaseTokenPool_PendingRelease { + readonly $: 'LockReleaseTokenPool_PendingRelease' + replyTo: c.Address | null /* = null */ + request: CellRef + out: CellRef + expectedSender: c.Address +} + +export const LockReleaseTokenPool_PendingRelease = { + create(args: { + replyTo?: c.Address | null /* = null */ + request: CellRef + out: CellRef + expectedSender: c.Address + }): LockReleaseTokenPool_PendingRelease { + return { + $: 'LockReleaseTokenPool_PendingRelease', + replyTo: null, + ...args + } + }, + fromSlice(s: c.Slice): LockReleaseTokenPool_PendingRelease { + return { + $: 'LockReleaseTokenPool_PendingRelease', + replyTo: s.loadMaybeAddress(), + request: loadCellRef(s, TokenPool_ReleaseOrMintInV1.fromSlice), + out: loadCellRef(s, TokenPool_ReleaseOrMintOutV1.fromSlice), + expectedSender: s.loadAddress(), + } + }, + store(self: LockReleaseTokenPool_PendingRelease, b: c.Builder): void { + b.storeAddress(self.replyTo); + storeCellRef(self.request, b, TokenPool_ReleaseOrMintInV1.store); + storeCellRef(self.out, b, TokenPool_ReleaseOrMintOutV1.store); + b.storeAddress(self.expectedSender); + }, + toCell(self: LockReleaseTokenPool_PendingRelease): c.Cell { + return makeCellFrom(self, LockReleaseTokenPool_PendingRelease.store); + } +} + +/** + > struct Storage { + > poolData: Cell + > jettonClient: Cell + > pendingReleases: map> + > } + */ +export interface Storage { + readonly $: 'Storage' + poolData: CellRef + jettonClient: CellRef + pendingReleases: c.Dictionary> +} + +export const Storage = { + create(args: { + poolData: CellRef + jettonClient: CellRef + pendingReleases: c.Dictionary> + }): Storage { + return { + $: 'Storage', + ...args + } + }, + fromSlice(s: c.Slice): Storage { + return { + $: 'Storage', + poolData: loadCellRef(s, TokenPool_Data.fromSlice), + jettonClient: loadCellRef(s, JettonClient.fromSlice), + pendingReleases: c.Dictionary.load>(c.Dictionary.Keys.BigUint(64), createDictionaryValue>( + (s) => loadCellRef(s, LockReleaseTokenPool_PendingRelease.fromSlice), + (v,b) => storeCellRef(v, b, LockReleaseTokenPool_PendingRelease.store) + ), s), + } + }, + store(self: Storage, b: c.Builder): void { + storeCellRef(self.poolData, b, TokenPool_Data.store); + storeCellRef(self.jettonClient, b, JettonClient.store); + b.storeDict>(self.pendingReleases, c.Dictionary.Keys.BigUint(64), createDictionaryValue>( + (s) => loadCellRef(s, LockReleaseTokenPool_PendingRelease.fromSlice), + (v,b) => storeCellRef(v, b, LockReleaseTokenPool_PendingRelease.store) + )); + }, + toCell(self: Storage): c.Cell { + return makeCellFrom(self, Storage.store); + } +} + +/** + > type CrossChainAddress = slice + */ +export type CrossChainAddress = c.Slice + +export const CrossChainAddress = { + fromSlice(s: c.Slice): CrossChainAddress { + return invokeCustomUnpackFromSlice('CrossChainAddress', s); + }, + store(self: CrossChainAddress, b: c.Builder): void { + invokeCustomPackToBuilder('CrossChainAddress', self, b); + }, + toCell(self: CrossChainAddress): c.Cell { + return makeCellFrom(self, CrossChainAddress.store); + } +} + +/** + > struct RateLimiter_TokenBucket { + > tokens: uint256 + > lastUpdated: uint64 + > isEnabled: bool + > capacity: uint256 + > rate: uint256 + > } + */ +export interface RateLimiter_TokenBucket { + readonly $: 'RateLimiter_TokenBucket' + tokens: uint256 + lastUpdated: uint64 + isEnabled: boolean + capacity: uint256 + rate: uint256 +} + +export const RateLimiter_TokenBucket = { + create(args: { + tokens: uint256 + lastUpdated: uint64 + isEnabled: boolean + capacity: uint256 + rate: uint256 + }): RateLimiter_TokenBucket { + return { + $: 'RateLimiter_TokenBucket', + ...args + } + }, + fromSlice(s: c.Slice): RateLimiter_TokenBucket { + return { + $: 'RateLimiter_TokenBucket', + tokens: s.loadUintBig(256), + lastUpdated: s.loadUintBig(64), + isEnabled: s.loadBoolean(), + capacity: s.loadUintBig(256), + rate: s.loadUintBig(256), + } + }, + store(self: RateLimiter_TokenBucket, b: c.Builder): void { + b.storeUint(self.tokens, 256); + b.storeUint(self.lastUpdated, 64); + b.storeBit(self.isEnabled); + b.storeUint(self.capacity, 256); + b.storeUint(self.rate, 256); + }, + toCell(self: RateLimiter_TokenBucket): c.Cell { + return makeCellFrom(self, RateLimiter_TokenBucket.store); + } +} + +// ———————————————————————————————————————————— +// class LockReleaseTokenPool +// + +interface ExtraSendOptions { + bounce?: boolean // default: false + sendMode?: SendMode // default: SendMode.PAY_GAS_SEPARATELY + extraCurrencies?: c.ExtraCurrency // default: empty dict +} + +interface DeployedAddrOptions { + workchain?: number // default: 0 (basechain) + toShard?: { fixedPrefixLength: number; closeTo: c.Address } + overrideContractCode?: c.Cell +} + +function calculateDeployedAddress(code: c.Cell, data: c.Cell, options: DeployedAddrOptions): c.Address { + const stateInitCell = beginCell().store(c.storeStateInit({ + code, + data, + splitDepth: options.toShard?.fixedPrefixLength, + special: null, + libraries: null, + })).endCell(); + + let addrHash = stateInitCell.hash(); + if (options.toShard) { + const shardDepth = options.toShard.fixedPrefixLength; + addrHash = beginCell() + .storeBits(new c.BitString(options.toShard.closeTo.hash, 0, shardDepth)) + .storeBits(new c.BitString(stateInitCell.hash(), shardDepth, 256 - shardDepth)) + .endCell() + .beginParse().loadBuffer(32); + } + + return new c.Address(options.workchain ?? 0, addrHash); +} + +export class LockReleaseTokenPool implements c.Contract { + static CodeCell = c.Cell.fromBase64('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'); + + static Errors = { + 'Common_Error.CrossChainAddressOutOfRange': 5, + 'Utils_Error.InvalidData': 13500, + 'TokenPool_Error.InvalidTransferFeeBps': 14900, + 'TokenPool_Error.InvalidTokenTransferFeeConfig': 14901, + 'TokenPool_Error.ZeroAddressInvalid': 14903, + 'TokenPool_Error.NonExistentChain': 14904, + 'TokenPool_Error.ChainNotAllowed': 14905, + 'TokenPool_Error.CursedByRMN': 14906, + 'TokenPool_Error.ChainAlreadyExists': 14907, + 'TokenPool_Error.InvalidToken': 14909, + 'TokenPool_Error.Unauthorized': 14910, + 'TokenPool_Error.PoolAlreadyAdded': 14911, + 'TokenPool_Error.InvalidRemotePoolForChain': 14912, + 'TokenPool_Error.InvalidRemoteChainDecimals': 14913, + 'TokenPool_Error.OverflowDetected': 14914, + 'TokenPool_Error.UnsupportedOperation': 14917, + 'TokenPool_Error.InvalidRequestedFinality': 14918, + 'Error.IncorrectJettonSender': 26300, + 'Error.MissingTransferInitiator': 26301, + 'Error.MissingForwardPayload': 26302, + 'Error.AmountMismatch': 26303, + 'Error.PendingReleaseAlreadyExists': 26304, + 'Error.PendingReleaseNotFound': 26305, + 'Error.UnexpectedReleaseConfirmationSender': 26306, + 'Error.UnexpectedReleaseBounce': 26307, + 'Ownable2Step_Error.OnlyCallableByOwner': 49800, + 'Ownable2Step_Error.CannotTransferToSelf': 49801, + 'Ownable2Step_Error.MustBeProposedOwner': 49802, + } + + readonly address: c.Address + readonly init: { code: c.Cell, data: c.Cell } | undefined + + protected constructor(address: c.Address, init?: { code: c.Cell, data: c.Cell }) { + this.address = address; + this.init = init; + } + + static registerCustomPackUnpack( + typeName: string, + packToBuilderFn: CustomPackToBuilderFn | null, + unpackFromSliceFn: CustomUnpackFromSliceFn | null, + ) { + if (customSerializersRegistry.has(typeName)) { + throw new Error(`Custom pack/unpack for 'LockReleaseTokenPool.${typeName}' already registered`); + } + customSerializersRegistry.set(typeName, [packToBuilderFn, unpackFromSliceFn]); + } + + static fromAddress(address: c.Address) { + return new LockReleaseTokenPool(address); + } + + static fromStorage(emptyStorage: { + poolData: CellRef + jettonClient: CellRef + pendingReleases: c.Dictionary> + }, deployedOptions?: DeployedAddrOptions) { + const initialState = { + code: deployedOptions?.overrideContractCode ?? LockReleaseTokenPool.CodeCell, + data: Storage.toCell(Storage.create(emptyStorage)), + }; + const address = calculateDeployedAddress(initialState.code, initialState.data, deployedOptions ?? {}); + return new LockReleaseTokenPool(address, initialState); + } + + static createCellOfTransferNotificationForRecipient(body: { + queryId: uint64 + jettonAmount: coins + transferInitiator: c.Address | null + forwardPayload: ForwardPayloadRemainder + }) { + return TransferNotificationForRecipient.toCell(TransferNotificationForRecipient.create(body)); + } + + static createCellOfReturnExcessesBack(body: { + queryId: uint64 + }) { + return ReturnExcessesBack.toCell(ReturnExcessesBack.create(body)); + } + + async sendDeploy(provider: ContractProvider, via: Sender, msgValue: coins, extraOptions?: ExtraSendOptions) { + return provider.internal(via, { + value: msgValue, + body: c.Cell.EMPTY, + ...extraOptions + }); + } + + async sendTransferNotificationForRecipient(provider: ContractProvider, via: Sender, msgValue: coins, body: { + queryId: uint64 + jettonAmount: coins + transferInitiator: c.Address | null + forwardPayload: ForwardPayloadRemainder + }, extraOptions?: ExtraSendOptions) { + return provider.internal(via, { + value: msgValue, + body: TransferNotificationForRecipient.toCell(TransferNotificationForRecipient.create(body)), + ...extraOptions + }); + } + + async sendReturnExcessesBack(provider: ContractProvider, via: Sender, msgValue: coins, body: { + queryId: uint64 + }, extraOptions?: ExtraSendOptions) { + return provider.internal(via, { + value: msgValue, + body: ReturnExcessesBack.toCell(ReturnExcessesBack.create(body)), + ...extraOptions + }); + } + + async getTypeAndVersion(provider: ContractProvider): Promise<[ + c.Slice, + c.Slice, + ]> { + const r = StackReader.fromGetMethod(2, await provider.get('typeAndVersion', [])); + return [ + r.readSlice(), + r.readSlice(), + ]; + } + + async getToken(provider: ContractProvider): Promise { + const r = StackReader.fromGetMethod(1, await provider.get('token', [])); + return r.readSlice().loadAddress(); + } + + async getTokenDecimals(provider: ContractProvider): Promise { + const r = StackReader.fromGetMethod(1, await provider.get('tokenDecimals', [])); + return r.readBigInt(); + } + + async getIsSupportedChain(provider: ContractProvider, remoteChainSelector: uint64): Promise { + const r = StackReader.fromGetMethod(1, await provider.get('isSupportedChain', [ + { type: 'int', value: remoteChainSelector }, + ])); + return r.readBoolean(); + } + + async getOnRamp(provider: ContractProvider, remoteChainSelector: uint64): Promise { + const r = StackReader.fromGetMethod(1, await provider.get('onRamp', [ + { type: 'int', value: remoteChainSelector }, + ])); + return r.readNullable( + (r) => r.readSlice().loadAddress() + ); + } + + async getOffRamp(provider: ContractProvider, remoteChainSelector: uint64): Promise { + const r = StackReader.fromGetMethod(1, await provider.get('offRamp', [ + { type: 'int', value: remoteChainSelector }, + ])); + return r.readNullable( + (r) => r.readSlice().loadAddress() + ); + } + + async getHasPendingRelease(provider: ContractProvider, queryId: uint64): Promise { + const r = StackReader.fromGetMethod(1, await provider.get('hasPendingRelease', [ + { type: 'int', value: queryId }, + ])); + return r.readBoolean(); + } + + async getVerifyNotCursed(provider: ContractProvider, subject: uint128): Promise { + const r = StackReader.fromGetMethod(1, await provider.get('verifyNotCursed', [ + { type: 'int', value: subject }, + ])); + return r.readBoolean(); + } + + async getOwner(provider: ContractProvider): Promise { + const r = StackReader.fromGetMethod(1, await provider.get('owner', [])); + return r.readSlice().loadAddress(); + } + + async getPendingOwner(provider: ContractProvider): Promise { + const r = StackReader.fromGetMethod(1, await provider.get('pendingOwner', [])); + return r.readNullable( + (r) => r.readSlice().loadAddress() + ); + } +} diff --git a/contracts/wrappers/gen/ccip/pools/TokenPool.ts b/contracts/wrappers/gen/ccip/pools/TokenPool.ts new file mode 100644 index 000000000..bf028b910 --- /dev/null +++ b/contracts/wrappers/gen/ccip/pools/TokenPool.ts @@ -0,0 +1,1885 @@ +// AUTO-GENERATED, do not edit +// It's a TypeScript wrapper for a TokenPool contract in Tolk. +/* eslint-disable */ + +import * as c from '@ton/core'; +import { beginCell, ContractProvider, Sender, SendMode } from '@ton/core'; + +// ———————————————————————————————————————————— +// predefined types and functions +// + +type StoreCallback = (obj: T, b: c.Builder) => void +type LoadCallback = (s: c.Slice) => T + +export type CellRef = { + ref: T +} + +function makeCellFrom(self: T, storeFn_T: StoreCallback): c.Cell { + let b = beginCell(); + storeFn_T(self, b); + return b.endCell(); +} + +function loadAndCheckPrefix32(s: c.Slice, expected: number, structName: string): void { + let prefix = s.loadUint(32); + if (prefix !== expected) { + throw new Error(`Incorrect prefix for '${structName}': expected 0x${expected.toString(16).padStart(8, '0')}, got 0x${prefix.toString(16).padStart(8, '0')}`); + } +} + +function lookupPrefix(s: c.Slice, expected: number, prefixLen: number): boolean { + return s.remainingBits >= prefixLen && s.preloadUint(prefixLen) === expected; +} + +function throwNonePrefixMatch(fieldPath: string): never { + throw new Error(`Incorrect prefix for '${fieldPath}': none of variants matched`); +} + +function storeCellRef(cell: CellRef, b: c.Builder, storeFn_T: StoreCallback): void { + let b_ref = c.beginCell(); + storeFn_T(cell.ref, b_ref); + b.storeRef(b_ref.endCell()); +} + +function loadCellRef(s: c.Slice, loadFn_T: LoadCallback): CellRef { + let s_ref = s.loadRef().beginParse(); + return { ref: loadFn_T(s_ref) }; +} + +function storeTolkNullable(v: T | null, b: c.Builder, storeFn_T: StoreCallback): void { + if (v === null) { + b.storeUint(0, 1); + } else { + b.storeUint(1, 1); + storeFn_T(v, b); + } +} + +function createDictionaryValue(loadFn_V: LoadCallback, storeFn_V: StoreCallback): c.DictionaryValue { + return { + serialize(self: V, b: c.Builder) { + storeFn_V(self, b); + }, + parse(s: c.Slice): V { + const value = loadFn_V(s); + s.endParse(); + return value; + } + } +} + +// ———————————————————————————————————————————— +// parse get methods result from a TVM stack +// + +class StackReader { + constructor(private tuple: c.TupleItem[]) { + } + + static fromGetMethod(expectedN: number, getMethodResult: { stack: c.TupleReader }): StackReader { + let tuple = [] as c.TupleItem[]; + while (getMethodResult.stack.remaining) { + tuple.push(getMethodResult.stack.pop()); + } + if (tuple.length !== expectedN) { + throw new Error(`expected ${expectedN} stack width, got ${tuple.length}`); + } + return new StackReader(tuple); + } + + private popExpecting(itemType: string): ItemT { + const item = this.tuple.shift(); + if (item?.type === itemType) { + return item as ItemT; + } + throw new Error(`not '${itemType}' on a stack`); + } + + private popCellLike(): c.Cell { + const item = this.tuple.shift(); + if (item && (item.type === 'cell' || item.type === 'slice' || item.type === 'builder')) { + return item.cell; + } + throw new Error(`not cell/slice on a stack`); + } + + readBigInt(): bigint { + return this.popExpecting('int').value; + } + + readBoolean(): boolean { + return this.popExpecting('int').value !== 0n; + } + + readCell(): c.Cell { + return this.popCellLike(); + } + + readSlice(): c.Slice { + return this.popCellLike().beginParse(); + } +} + +// ———————————————————————————————————————————— +// custom packToBuilder and unpackFromSlice +// + +type CustomPackToBuilderFn = (self: T, b: c.Builder) => void +type CustomUnpackFromSliceFn = (s: c.Slice) => T + +let customSerializersRegistry: Map | null, CustomUnpackFromSliceFn | null]> = new Map; + +function ensureCustomSerializerRegistered(typeName: string) { + if (!customSerializersRegistry.has(typeName)) { + throw new Error(`Custom packToBuilder/unpackFromSlice was not registered for type 'TokenPool.${typeName}'.\n(in Tolk code, they have custom logic \`fun ${typeName}__packToBuilder\`)\nSteps to fix:\n1) in your code, create and implement\n > function ${typeName}__packToBuilder(self: ${typeName}, b: Builder): void { ... }\n > function ${typeName}__unpackFromSlice(s: Slice): ${typeName} { ... }\n2) register them in advance by calling\n > TokenPool.registerCustomPackUnpack('${typeName}', ${typeName}__packToBuilder, ${typeName}__unpackFromSlice);`); + } +} + +function invokeCustomPackToBuilder(typeName: string, self: T, b: c.Builder) { + ensureCustomSerializerRegistered(typeName); + customSerializersRegistry.get(typeName)![0]!(self, b); +} + +function invokeCustomUnpackFromSlice(typeName: string, s: c.Slice): T { + ensureCustomSerializerRegistered(typeName); + return customSerializersRegistry.get(typeName)![1]!(s); +} + +// ———————————————————————————————————————————— +// auto-generated serializers to/from cells +// + +type coins = bigint + +type uint8 = bigint +type uint16 = bigint +type uint32 = bigint +type uint64 = bigint +type uint128 = bigint +type uint256 = bigint + +/** + > struct TokenPool_DynamicConfig { + > router: address + > rateLimitAdmin: address? + > feeAdmin: address? + > } + */ +export interface TokenPool_DynamicConfig { + readonly $: 'TokenPool_DynamicConfig' + router: c.Address + rateLimitAdmin: c.Address | null + feeAdmin: c.Address | null +} + +export const TokenPool_DynamicConfig = { + create(args: { + router: c.Address + rateLimitAdmin: c.Address | null + feeAdmin: c.Address | null + }): TokenPool_DynamicConfig { + return { + $: 'TokenPool_DynamicConfig', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_DynamicConfig { + return { + $: 'TokenPool_DynamicConfig', + router: s.loadAddress(), + rateLimitAdmin: s.loadMaybeAddress(), + feeAdmin: s.loadMaybeAddress(), + } + }, + store(self: TokenPool_DynamicConfig, b: c.Builder): void { + b.storeAddress(self.router); + b.storeAddress(self.rateLimitAdmin); + b.storeAddress(self.feeAdmin); + }, + toCell(self: TokenPool_DynamicConfig): c.Cell { + return makeCellFrom(self, TokenPool_DynamicConfig.store); + } +} + +/** + > struct TokenPool_MirroredPolicy { + > onRamps: map + > offRamps: map + > cursedSubjects: CursedSubjects + > } + */ +export interface TokenPool_MirroredPolicy { + readonly $: 'TokenPool_MirroredPolicy' + onRamps: c.Dictionary + offRamps: c.Dictionary + cursedSubjects: CursedSubjects +} + +export const TokenPool_MirroredPolicy = { + create(args: { + onRamps: c.Dictionary + offRamps: c.Dictionary + cursedSubjects: CursedSubjects + }): TokenPool_MirroredPolicy { + return { + $: 'TokenPool_MirroredPolicy', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_MirroredPolicy { + return { + $: 'TokenPool_MirroredPolicy', + onRamps: c.Dictionary.load(c.Dictionary.Keys.BigUint(64), createDictionaryValue( + (s) => s.loadAddress(), + (v,b) => b.storeAddress(v) + ), s), + offRamps: c.Dictionary.load(c.Dictionary.Keys.BigUint(64), createDictionaryValue( + (s) => s.loadAddress(), + (v,b) => b.storeAddress(v) + ), s), + cursedSubjects: CursedSubjects.fromSlice(s), + } + }, + store(self: TokenPool_MirroredPolicy, b: c.Builder): void { + b.storeDict(self.onRamps, c.Dictionary.Keys.BigUint(64), createDictionaryValue( + (s) => s.loadAddress(), + (v,b) => b.storeAddress(v) + )); + b.storeDict(self.offRamps, c.Dictionary.Keys.BigUint(64), createDictionaryValue( + (s) => s.loadAddress(), + (v,b) => b.storeAddress(v) + )); + CursedSubjects.store(self.cursedSubjects, b); + }, + toCell(self: TokenPool_MirroredPolicy): c.Cell { + return makeCellFrom(self, TokenPool_MirroredPolicy.store); + } +} + +/** + > struct TokenPool_RampUpdate { + > remoteChainSelector: uint64 + > onRamp: address? + > offRamp: address? + > } + */ +export interface TokenPool_RampUpdate { + readonly $: 'TokenPool_RampUpdate' + remoteChainSelector: uint64 + onRamp: c.Address | null /* = null */ + offRamp: c.Address | null /* = null */ +} + +export const TokenPool_RampUpdate = { + create(args: { + remoteChainSelector: uint64 + onRamp?: c.Address | null /* = null */ + offRamp?: c.Address | null /* = null */ + }): TokenPool_RampUpdate { + return { + $: 'TokenPool_RampUpdate', + onRamp: null, + offRamp: null, + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_RampUpdate { + return { + $: 'TokenPool_RampUpdate', + remoteChainSelector: s.loadUintBig(64), + onRamp: s.loadMaybeAddress(), + offRamp: s.loadMaybeAddress(), + } + }, + store(self: TokenPool_RampUpdate, b: c.Builder): void { + b.storeUint(self.remoteChainSelector, 64); + b.storeAddress(self.onRamp); + b.storeAddress(self.offRamp); + }, + toCell(self: TokenPool_RampUpdate): c.Cell { + return makeCellFrom(self, TokenPool_RampUpdate.store); + } +} + +/** + > struct TokenPool_RateLimiterPair { + > outbound: Cell + > inbound: Cell + > } + */ +export interface TokenPool_RateLimiterPair { + readonly $: 'TokenPool_RateLimiterPair' + outbound: CellRef + inbound: CellRef +} + +export const TokenPool_RateLimiterPair = { + create(args: { + outbound: CellRef + inbound: CellRef + }): TokenPool_RateLimiterPair { + return { + $: 'TokenPool_RateLimiterPair', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_RateLimiterPair { + return { + $: 'TokenPool_RateLimiterPair', + outbound: loadCellRef(s, RateLimiter_TokenBucket.fromSlice), + inbound: loadCellRef(s, RateLimiter_TokenBucket.fromSlice), + } + }, + store(self: TokenPool_RateLimiterPair, b: c.Builder): void { + storeCellRef(self.outbound, b, RateLimiter_TokenBucket.store); + storeCellRef(self.inbound, b, RateLimiter_TokenBucket.store); + }, + toCell(self: TokenPool_RateLimiterPair): c.Cell { + return makeCellFrom(self, TokenPool_RateLimiterPair.store); + } +} + +/** + > struct TokenPool_RateLimitConfigPair { + > outbound: Cell + > inbound: Cell + > } + */ +export interface TokenPool_RateLimitConfigPair { + readonly $: 'TokenPool_RateLimitConfigPair' + outbound: CellRef + inbound: CellRef +} + +export const TokenPool_RateLimitConfigPair = { + create(args: { + outbound: CellRef + inbound: CellRef + }): TokenPool_RateLimitConfigPair { + return { + $: 'TokenPool_RateLimitConfigPair', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_RateLimitConfigPair { + return { + $: 'TokenPool_RateLimitConfigPair', + outbound: loadCellRef(s, RateLimiter_Config.fromSlice), + inbound: loadCellRef(s, RateLimiter_Config.fromSlice), + } + }, + store(self: TokenPool_RateLimitConfigPair, b: c.Builder): void { + storeCellRef(self.outbound, b, RateLimiter_Config.store); + storeCellRef(self.inbound, b, RateLimiter_Config.store); + }, + toCell(self: TokenPool_RateLimitConfigPair): c.Cell { + return makeCellFrom(self, TokenPool_RateLimitConfigPair.store); + } +} + +/** + > struct TokenPool_ChainUpdate { + > remoteChainSelector: uint64 + > remotePoolAddresses: SnakedCell + > remoteTokenAddress: Cell + > rateLimitConfigs: Cell + > } + */ +export interface TokenPool_ChainUpdate { + readonly $: 'TokenPool_ChainUpdate' + remoteChainSelector: uint64 + remotePoolAddresses: SnakedCell + remoteTokenAddress: CellRef + rateLimitConfigs: CellRef +} + +export const TokenPool_ChainUpdate = { + create(args: { + remoteChainSelector: uint64 + remotePoolAddresses: SnakedCell + remoteTokenAddress: CellRef + rateLimitConfigs: CellRef + }): TokenPool_ChainUpdate { + return { + $: 'TokenPool_ChainUpdate', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_ChainUpdate { + return { + $: 'TokenPool_ChainUpdate', + remoteChainSelector: s.loadUintBig(64), + remotePoolAddresses: s.loadRef(), + remoteTokenAddress: loadCellRef(s, CrossChainAddress.fromSlice), + rateLimitConfigs: loadCellRef(s, TokenPool_RateLimitConfigPair.fromSlice), + } + }, + store(self: TokenPool_ChainUpdate, b: c.Builder): void { + b.storeUint(self.remoteChainSelector, 64); + b.storeRef(self.remotePoolAddresses); + storeCellRef(self.remoteTokenAddress, b, CrossChainAddress.store); + storeCellRef(self.rateLimitConfigs, b, TokenPool_RateLimitConfigPair.store); + }, + toCell(self: TokenPool_ChainUpdate): c.Cell { + return makeCellFrom(self, TokenPool_ChainUpdate.store); + } +} + +/** + > struct TokenPool_RemoteChainConfig { + > remoteTokenAddress: Cell + > remotePools: map> + > rateLimiters: Cell + > fastFinalityRateLimiters: Cell + > } + */ +export interface TokenPool_RemoteChainConfig { + readonly $: 'TokenPool_RemoteChainConfig' + remoteTokenAddress: CellRef + remotePools: c.Dictionary> + rateLimiters: CellRef + fastFinalityRateLimiters: CellRef +} + +export const TokenPool_RemoteChainConfig = { + create(args: { + remoteTokenAddress: CellRef + remotePools: c.Dictionary> + rateLimiters: CellRef + fastFinalityRateLimiters: CellRef + }): TokenPool_RemoteChainConfig { + return { + $: 'TokenPool_RemoteChainConfig', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_RemoteChainConfig { + return { + $: 'TokenPool_RemoteChainConfig', + remoteTokenAddress: loadCellRef(s, CrossChainAddress.fromSlice), + remotePools: c.Dictionary.load>(c.Dictionary.Keys.BigUint(256), createDictionaryValue>( + (s) => loadCellRef(s, CrossChainAddress.fromSlice), + (v,b) => storeCellRef(v, b, CrossChainAddress.store) + ), s), + rateLimiters: loadCellRef(s, TokenPool_RateLimiterPair.fromSlice), + fastFinalityRateLimiters: loadCellRef(s, TokenPool_RateLimiterPair.fromSlice), + } + }, + store(self: TokenPool_RemoteChainConfig, b: c.Builder): void { + storeCellRef(self.remoteTokenAddress, b, CrossChainAddress.store); + b.storeDict>(self.remotePools, c.Dictionary.Keys.BigUint(256), createDictionaryValue>( + (s) => loadCellRef(s, CrossChainAddress.fromSlice), + (v,b) => storeCellRef(v, b, CrossChainAddress.store) + )); + storeCellRef(self.rateLimiters, b, TokenPool_RateLimiterPair.store); + storeCellRef(self.fastFinalityRateLimiters, b, TokenPool_RateLimiterPair.store); + }, + toCell(self: TokenPool_RemoteChainConfig): c.Cell { + return makeCellFrom(self, TokenPool_RemoteChainConfig.store); + } +} + +/** + > struct TokenPool_RateLimitConfigArgs { + > remoteChainSelector: uint64 + > fastFinality: bool + > outboundRateLimiterConfig: Cell + > inboundRateLimiterConfig: Cell + > } + */ +export interface TokenPool_RateLimitConfigArgs { + readonly $: 'TokenPool_RateLimitConfigArgs' + remoteChainSelector: uint64 + fastFinality: boolean + outboundRateLimiterConfig: CellRef + inboundRateLimiterConfig: CellRef +} + +export const TokenPool_RateLimitConfigArgs = { + create(args: { + remoteChainSelector: uint64 + fastFinality: boolean + outboundRateLimiterConfig: CellRef + inboundRateLimiterConfig: CellRef + }): TokenPool_RateLimitConfigArgs { + return { + $: 'TokenPool_RateLimitConfigArgs', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_RateLimitConfigArgs { + return { + $: 'TokenPool_RateLimitConfigArgs', + remoteChainSelector: s.loadUintBig(64), + fastFinality: s.loadBoolean(), + outboundRateLimiterConfig: loadCellRef(s, RateLimiter_Config.fromSlice), + inboundRateLimiterConfig: loadCellRef(s, RateLimiter_Config.fromSlice), + } + }, + store(self: TokenPool_RateLimitConfigArgs, b: c.Builder): void { + b.storeUint(self.remoteChainSelector, 64); + b.storeBit(self.fastFinality); + storeCellRef(self.outboundRateLimiterConfig, b, RateLimiter_Config.store); + storeCellRef(self.inboundRateLimiterConfig, b, RateLimiter_Config.store); + }, + toCell(self: TokenPool_RateLimitConfigArgs): c.Cell { + return makeCellFrom(self, TokenPool_RateLimitConfigArgs.store); + } +} + +/** + > struct TokenPool_TokenTransferFeeConfigArgs { + > destChainSelector: uint64 + > tokenTransferFeeConfig: TokenPool_TokenTransferFeeConfig + > } + */ +export interface TokenPool_TokenTransferFeeConfigArgs { + readonly $: 'TokenPool_TokenTransferFeeConfigArgs' + destChainSelector: uint64 + tokenTransferFeeConfig: TokenPool_TokenTransferFeeConfig +} + +export const TokenPool_TokenTransferFeeConfigArgs = { + create(args: { + destChainSelector: uint64 + tokenTransferFeeConfig: TokenPool_TokenTransferFeeConfig + }): TokenPool_TokenTransferFeeConfigArgs { + return { + $: 'TokenPool_TokenTransferFeeConfigArgs', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_TokenTransferFeeConfigArgs { + return { + $: 'TokenPool_TokenTransferFeeConfigArgs', + destChainSelector: s.loadUintBig(64), + tokenTransferFeeConfig: TokenPool_TokenTransferFeeConfig.fromSlice(s), + } + }, + store(self: TokenPool_TokenTransferFeeConfigArgs, b: c.Builder): void { + b.storeUint(self.destChainSelector, 64); + TokenPool_TokenTransferFeeConfig.store(self.tokenTransferFeeConfig, b); + }, + toCell(self: TokenPool_TokenTransferFeeConfigArgs): c.Cell { + return makeCellFrom(self, TokenPool_TokenTransferFeeConfigArgs.store); + } +} + +/** + > struct TokenPool_TokenTransferFeeConfig { + > isEnabled: bool + > finalityFeeUSDCents: uint256 + > fastFinalityFeeUSDCents: uint256 + > destGasOverhead: uint32 + > destBytesOverhead: uint32 + > finalityTransferFeeBps: uint16 + > fastFinalityTransferFeeBps: uint16 + > } + */ +export interface TokenPool_TokenTransferFeeConfig { + readonly $: 'TokenPool_TokenTransferFeeConfig' + isEnabled: boolean + finalityFeeUSDCents: uint256 + fastFinalityFeeUSDCents: uint256 + destGasOverhead: uint32 + destBytesOverhead: uint32 + finalityTransferFeeBps: uint16 + fastFinalityTransferFeeBps: uint16 +} + +export const TokenPool_TokenTransferFeeConfig = { + create(args: { + isEnabled: boolean + finalityFeeUSDCents: uint256 + fastFinalityFeeUSDCents: uint256 + destGasOverhead: uint32 + destBytesOverhead: uint32 + finalityTransferFeeBps: uint16 + fastFinalityTransferFeeBps: uint16 + }): TokenPool_TokenTransferFeeConfig { + return { + $: 'TokenPool_TokenTransferFeeConfig', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_TokenTransferFeeConfig { + return { + $: 'TokenPool_TokenTransferFeeConfig', + isEnabled: s.loadBoolean(), + finalityFeeUSDCents: s.loadUintBig(256), + fastFinalityFeeUSDCents: s.loadUintBig(256), + destGasOverhead: s.loadUintBig(32), + destBytesOverhead: s.loadUintBig(32), + finalityTransferFeeBps: s.loadUintBig(16), + fastFinalityTransferFeeBps: s.loadUintBig(16), + } + }, + store(self: TokenPool_TokenTransferFeeConfig, b: c.Builder): void { + b.storeBit(self.isEnabled); + b.storeUint(self.finalityFeeUSDCents, 256); + b.storeUint(self.fastFinalityFeeUSDCents, 256); + b.storeUint(self.destGasOverhead, 32); + b.storeUint(self.destBytesOverhead, 32); + b.storeUint(self.finalityTransferFeeBps, 16); + b.storeUint(self.fastFinalityTransferFeeBps, 16); + }, + toCell(self: TokenPool_TokenTransferFeeConfig): c.Cell { + return makeCellFrom(self, TokenPool_TokenTransferFeeConfig.store); + } +} + +/** + > struct TokenPool_LockOrBurnInV1 { + > receiver: Cell + > remoteChainSelector: uint64 + > originalSender: address + > amount: uint256 + > localToken: address + > } + */ +export interface TokenPool_LockOrBurnInV1 { + readonly $: 'TokenPool_LockOrBurnInV1' + receiver: CellRef + remoteChainSelector: uint64 + originalSender: c.Address + amount: uint256 + localToken: c.Address +} + +export const TokenPool_LockOrBurnInV1 = { + create(args: { + receiver: CellRef + remoteChainSelector: uint64 + originalSender: c.Address + amount: uint256 + localToken: c.Address + }): TokenPool_LockOrBurnInV1 { + return { + $: 'TokenPool_LockOrBurnInV1', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_LockOrBurnInV1 { + return { + $: 'TokenPool_LockOrBurnInV1', + receiver: loadCellRef(s, CrossChainAddress.fromSlice), + remoteChainSelector: s.loadUintBig(64), + originalSender: s.loadAddress(), + amount: s.loadUintBig(256), + localToken: s.loadAddress(), + } + }, + store(self: TokenPool_LockOrBurnInV1, b: c.Builder): void { + storeCellRef(self.receiver, b, CrossChainAddress.store); + b.storeUint(self.remoteChainSelector, 64); + b.storeAddress(self.originalSender); + b.storeUint(self.amount, 256); + b.storeAddress(self.localToken); + }, + toCell(self: TokenPool_LockOrBurnInV1): c.Cell { + return makeCellFrom(self, TokenPool_LockOrBurnInV1.store); + } +} + +/** + > struct TokenPool_ReleaseOrMintInV1 { + > originalSender: Cell + > remoteChainSelector: uint64 + > receiver: address + > sourceDenominatedAmount: uint256 + > localToken: address + > sourcePoolAddress: Cell + > sourcePoolData: cell? + > offchainTokenData: cell? + > } + */ +export interface TokenPool_ReleaseOrMintInV1 { + readonly $: 'TokenPool_ReleaseOrMintInV1' + originalSender: CellRef + remoteChainSelector: uint64 + receiver: c.Address + sourceDenominatedAmount: uint256 + localToken: c.Address + sourcePoolAddress: CellRef + sourcePoolData: c.Cell | null + offchainTokenData: c.Cell | null +} + +export const TokenPool_ReleaseOrMintInV1 = { + create(args: { + originalSender: CellRef + remoteChainSelector: uint64 + receiver: c.Address + sourceDenominatedAmount: uint256 + localToken: c.Address + sourcePoolAddress: CellRef + sourcePoolData: c.Cell | null + offchainTokenData: c.Cell | null + }): TokenPool_ReleaseOrMintInV1 { + return { + $: 'TokenPool_ReleaseOrMintInV1', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_ReleaseOrMintInV1 { + return { + $: 'TokenPool_ReleaseOrMintInV1', + originalSender: loadCellRef(s, CrossChainAddress.fromSlice), + remoteChainSelector: s.loadUintBig(64), + receiver: s.loadAddress(), + sourceDenominatedAmount: s.loadUintBig(256), + localToken: s.loadAddress(), + sourcePoolAddress: loadCellRef(s, CrossChainAddress.fromSlice), + sourcePoolData: s.loadBoolean() ? s.loadRef() : null, + offchainTokenData: s.loadBoolean() ? s.loadRef() : null, + } + }, + store(self: TokenPool_ReleaseOrMintInV1, b: c.Builder): void { + storeCellRef(self.originalSender, b, CrossChainAddress.store); + b.storeUint(self.remoteChainSelector, 64); + b.storeAddress(self.receiver); + b.storeUint(self.sourceDenominatedAmount, 256); + b.storeAddress(self.localToken); + storeCellRef(self.sourcePoolAddress, b, CrossChainAddress.store); + storeTolkNullable(self.sourcePoolData, b, + (v,b) => b.storeRef(v) + ); + storeTolkNullable(self.offchainTokenData, b, + (v,b) => b.storeRef(v) + ); + }, + toCell(self: TokenPool_ReleaseOrMintInV1): c.Cell { + return makeCellFrom(self, TokenPool_ReleaseOrMintInV1.store); + } +} + +/** + > struct (0xdc0b6ff5) TokenPool_ApplyChainUpdates { + > queryId: uint64 + > remoteChainSelectorsToRemove: SnakedCell + > chainsToAdd: SnakedCell + > } + */ +export interface TokenPool_ApplyChainUpdates { + readonly $: 'TokenPool_ApplyChainUpdates' + queryId: uint64 + remoteChainSelectorsToRemove: SnakedCell + chainsToAdd: SnakedCell +} + +export const TokenPool_ApplyChainUpdates = { + PREFIX: 0xdc0b6ff5, + + create(args: { + queryId: uint64 + remoteChainSelectorsToRemove: SnakedCell + chainsToAdd: SnakedCell + }): TokenPool_ApplyChainUpdates { + return { + $: 'TokenPool_ApplyChainUpdates', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_ApplyChainUpdates { + loadAndCheckPrefix32(s, 0xdc0b6ff5, 'TokenPool_ApplyChainUpdates'); + return { + $: 'TokenPool_ApplyChainUpdates', + queryId: s.loadUintBig(64), + remoteChainSelectorsToRemove: s.loadRef(), + chainsToAdd: s.loadRef(), + } + }, + store(self: TokenPool_ApplyChainUpdates, b: c.Builder): void { + b.storeUint(0xdc0b6ff5, 32); + b.storeUint(self.queryId, 64); + b.storeRef(self.remoteChainSelectorsToRemove); + b.storeRef(self.chainsToAdd); + }, + toCell(self: TokenPool_ApplyChainUpdates): c.Cell { + return makeCellFrom(self, TokenPool_ApplyChainUpdates.store); + } +} + +/** + > struct (0x5fd2c8b6) TokenPool_AddRemotePool { + > queryId: uint64 + > remoteChainSelector: uint64 + > remotePoolAddress: Cell + > } + */ +export interface TokenPool_AddRemotePool { + readonly $: 'TokenPool_AddRemotePool' + queryId: uint64 + remoteChainSelector: uint64 + remotePoolAddress: CellRef +} + +export const TokenPool_AddRemotePool = { + PREFIX: 0x5fd2c8b6, + + create(args: { + queryId: uint64 + remoteChainSelector: uint64 + remotePoolAddress: CellRef + }): TokenPool_AddRemotePool { + return { + $: 'TokenPool_AddRemotePool', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_AddRemotePool { + loadAndCheckPrefix32(s, 0x5fd2c8b6, 'TokenPool_AddRemotePool'); + return { + $: 'TokenPool_AddRemotePool', + queryId: s.loadUintBig(64), + remoteChainSelector: s.loadUintBig(64), + remotePoolAddress: loadCellRef(s, CrossChainAddress.fromSlice), + } + }, + store(self: TokenPool_AddRemotePool, b: c.Builder): void { + b.storeUint(0x5fd2c8b6, 32); + b.storeUint(self.queryId, 64); + b.storeUint(self.remoteChainSelector, 64); + storeCellRef(self.remotePoolAddress, b, CrossChainAddress.store); + }, + toCell(self: TokenPool_AddRemotePool): c.Cell { + return makeCellFrom(self, TokenPool_AddRemotePool.store); + } +} + +/** + > struct (0xdbf0a2df) TokenPool_RemoveRemotePool { + > queryId: uint64 + > remoteChainSelector: uint64 + > remotePoolAddress: Cell + > } + */ +export interface TokenPool_RemoveRemotePool { + readonly $: 'TokenPool_RemoveRemotePool' + queryId: uint64 + remoteChainSelector: uint64 + remotePoolAddress: CellRef +} + +export const TokenPool_RemoveRemotePool = { + PREFIX: 0xdbf0a2df, + + create(args: { + queryId: uint64 + remoteChainSelector: uint64 + remotePoolAddress: CellRef + }): TokenPool_RemoveRemotePool { + return { + $: 'TokenPool_RemoveRemotePool', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_RemoveRemotePool { + loadAndCheckPrefix32(s, 0xdbf0a2df, 'TokenPool_RemoveRemotePool'); + return { + $: 'TokenPool_RemoveRemotePool', + queryId: s.loadUintBig(64), + remoteChainSelector: s.loadUintBig(64), + remotePoolAddress: loadCellRef(s, CrossChainAddress.fromSlice), + } + }, + store(self: TokenPool_RemoveRemotePool, b: c.Builder): void { + b.storeUint(0xdbf0a2df, 32); + b.storeUint(self.queryId, 64); + b.storeUint(self.remoteChainSelector, 64); + storeCellRef(self.remotePoolAddress, b, CrossChainAddress.store); + }, + toCell(self: TokenPool_RemoveRemotePool): c.Cell { + return makeCellFrom(self, TokenPool_RemoveRemotePool.store); + } +} + +/** + > struct (0x4eea060b) TokenPool_SetDynamicConfig { + > queryId: uint64 + > router: address + > rateLimitAdmin: address? + > feeAdmin: address? + > } + */ +export interface TokenPool_SetDynamicConfig { + readonly $: 'TokenPool_SetDynamicConfig' + queryId: uint64 + router: c.Address + rateLimitAdmin: c.Address | null /* = null */ + feeAdmin: c.Address | null /* = null */ +} + +export const TokenPool_SetDynamicConfig = { + PREFIX: 0x4eea060b, + + create(args: { + queryId: uint64 + router: c.Address + rateLimitAdmin?: c.Address | null /* = null */ + feeAdmin?: c.Address | null /* = null */ + }): TokenPool_SetDynamicConfig { + return { + $: 'TokenPool_SetDynamicConfig', + rateLimitAdmin: null, + feeAdmin: null, + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_SetDynamicConfig { + loadAndCheckPrefix32(s, 0x4eea060b, 'TokenPool_SetDynamicConfig'); + return { + $: 'TokenPool_SetDynamicConfig', + queryId: s.loadUintBig(64), + router: s.loadAddress(), + rateLimitAdmin: s.loadMaybeAddress(), + feeAdmin: s.loadMaybeAddress(), + } + }, + store(self: TokenPool_SetDynamicConfig, b: c.Builder): void { + b.storeUint(0x4eea060b, 32); + b.storeUint(self.queryId, 64); + b.storeAddress(self.router); + b.storeAddress(self.rateLimitAdmin); + b.storeAddress(self.feeAdmin); + }, + toCell(self: TokenPool_SetDynamicConfig): c.Cell { + return makeCellFrom(self, TokenPool_SetDynamicConfig.store); + } +} + +/** + > struct (0x29b46fc6) TokenPool_SetAllowedFinalityConfig { + > queryId: uint64 + > allowedFinalityConfig: uint32 + > } + */ +export interface TokenPool_SetAllowedFinalityConfig { + readonly $: 'TokenPool_SetAllowedFinalityConfig' + queryId: uint64 + allowedFinalityConfig: uint32 +} + +export const TokenPool_SetAllowedFinalityConfig = { + PREFIX: 0x29b46fc6, + + create(args: { + queryId: uint64 + allowedFinalityConfig: uint32 + }): TokenPool_SetAllowedFinalityConfig { + return { + $: 'TokenPool_SetAllowedFinalityConfig', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_SetAllowedFinalityConfig { + loadAndCheckPrefix32(s, 0x29b46fc6, 'TokenPool_SetAllowedFinalityConfig'); + return { + $: 'TokenPool_SetAllowedFinalityConfig', + queryId: s.loadUintBig(64), + allowedFinalityConfig: s.loadUintBig(32), + } + }, + store(self: TokenPool_SetAllowedFinalityConfig, b: c.Builder): void { + b.storeUint(0x29b46fc6, 32); + b.storeUint(self.queryId, 64); + b.storeUint(self.allowedFinalityConfig, 32); + }, + toCell(self: TokenPool_SetAllowedFinalityConfig): c.Cell { + return makeCellFrom(self, TokenPool_SetAllowedFinalityConfig.store); + } +} + +/** + > struct (0x3a028da2) TokenPool_SetRateLimitConfig { + > queryId: uint64 + > updates: SnakedCell + > } + */ +export interface TokenPool_SetRateLimitConfig { + readonly $: 'TokenPool_SetRateLimitConfig' + queryId: uint64 + updates: SnakedCell +} + +export const TokenPool_SetRateLimitConfig = { + PREFIX: 0x3a028da2, + + create(args: { + queryId: uint64 + updates: SnakedCell + }): TokenPool_SetRateLimitConfig { + return { + $: 'TokenPool_SetRateLimitConfig', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_SetRateLimitConfig { + loadAndCheckPrefix32(s, 0x3a028da2, 'TokenPool_SetRateLimitConfig'); + return { + $: 'TokenPool_SetRateLimitConfig', + queryId: s.loadUintBig(64), + updates: s.loadRef(), + } + }, + store(self: TokenPool_SetRateLimitConfig, b: c.Builder): void { + b.storeUint(0x3a028da2, 32); + b.storeUint(self.queryId, 64); + b.storeRef(self.updates); + }, + toCell(self: TokenPool_SetRateLimitConfig): c.Cell { + return makeCellFrom(self, TokenPool_SetRateLimitConfig.store); + } +} + +/** + > struct (0x10c4b4a1) TokenPool_ApplyTokenTransferFeeConfigUpdates { + > queryId: uint64 + > updates: SnakedCell + > disableChainSelectors: SnakedCell + > } + */ +export interface TokenPool_ApplyTokenTransferFeeConfigUpdates { + readonly $: 'TokenPool_ApplyTokenTransferFeeConfigUpdates' + queryId: uint64 + updates: SnakedCell + disableChainSelectors: SnakedCell +} + +export const TokenPool_ApplyTokenTransferFeeConfigUpdates = { + PREFIX: 0x10c4b4a1, + + create(args: { + queryId: uint64 + updates: SnakedCell + disableChainSelectors: SnakedCell + }): TokenPool_ApplyTokenTransferFeeConfigUpdates { + return { + $: 'TokenPool_ApplyTokenTransferFeeConfigUpdates', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_ApplyTokenTransferFeeConfigUpdates { + loadAndCheckPrefix32(s, 0x10c4b4a1, 'TokenPool_ApplyTokenTransferFeeConfigUpdates'); + return { + $: 'TokenPool_ApplyTokenTransferFeeConfigUpdates', + queryId: s.loadUintBig(64), + updates: s.loadRef(), + disableChainSelectors: s.loadRef(), + } + }, + store(self: TokenPool_ApplyTokenTransferFeeConfigUpdates, b: c.Builder): void { + b.storeUint(0x10c4b4a1, 32); + b.storeUint(self.queryId, 64); + b.storeRef(self.updates); + b.storeRef(self.disableChainSelectors); + }, + toCell(self: TokenPool_ApplyTokenTransferFeeConfigUpdates): c.Cell { + return makeCellFrom(self, TokenPool_ApplyTokenTransferFeeConfigUpdates.store); + } +} + +/** + > struct (0x7a9c4aa5) TokenPool_UpdateRampAccess { + > queryId: uint64 + > updates: SnakedCell + > } + */ +export interface TokenPool_UpdateRampAccess { + readonly $: 'TokenPool_UpdateRampAccess' + queryId: uint64 + updates: SnakedCell +} + +export const TokenPool_UpdateRampAccess = { + PREFIX: 0x7a9c4aa5, + + create(args: { + queryId: uint64 + updates: SnakedCell + }): TokenPool_UpdateRampAccess { + return { + $: 'TokenPool_UpdateRampAccess', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_UpdateRampAccess { + loadAndCheckPrefix32(s, 0x7a9c4aa5, 'TokenPool_UpdateRampAccess'); + return { + $: 'TokenPool_UpdateRampAccess', + queryId: s.loadUintBig(64), + updates: s.loadRef(), + } + }, + store(self: TokenPool_UpdateRampAccess, b: c.Builder): void { + b.storeUint(0x7a9c4aa5, 32); + b.storeUint(self.queryId, 64); + b.storeRef(self.updates); + }, + toCell(self: TokenPool_UpdateRampAccess): c.Cell { + return makeCellFrom(self, TokenPool_UpdateRampAccess.store); + } +} + +/** + > struct (0x823dadf2) TokenPool_UpdateCursedSubjects { + > cursedSubjects: CursedSubjects + > } + */ +export interface TokenPool_UpdateCursedSubjects { + readonly $: 'TokenPool_UpdateCursedSubjects' + cursedSubjects: CursedSubjects +} + +export const TokenPool_UpdateCursedSubjects = { + PREFIX: 0x823dadf2, + + create(args: { + cursedSubjects: CursedSubjects + }): TokenPool_UpdateCursedSubjects { + return { + $: 'TokenPool_UpdateCursedSubjects', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_UpdateCursedSubjects { + loadAndCheckPrefix32(s, 0x823dadf2, 'TokenPool_UpdateCursedSubjects'); + return { + $: 'TokenPool_UpdateCursedSubjects', + cursedSubjects: CursedSubjects.fromSlice(s), + } + }, + store(self: TokenPool_UpdateCursedSubjects, b: c.Builder): void { + b.storeUint(0x823dadf2, 32); + CursedSubjects.store(self.cursedSubjects, b); + }, + toCell(self: TokenPool_UpdateCursedSubjects): c.Cell { + return makeCellFrom(self, TokenPool_UpdateCursedSubjects.store); + } +} + +/** + > struct (0x1161516e) TokenPool_LockOrBurn { + > queryId: uint64 + > request: Cell + > requestedFinalityConfig: uint32 + > tokenArgs: cell? + > replyTo: address? + > } + */ +export interface TokenPool_LockOrBurn { + readonly $: 'TokenPool_LockOrBurn' + queryId: uint64 + request: CellRef + requestedFinalityConfig: uint32 + tokenArgs: c.Cell | null + replyTo: c.Address | null +} + +export const TokenPool_LockOrBurn = { + PREFIX: 0x1161516e, + + create(args: { + queryId: uint64 + request: CellRef + requestedFinalityConfig: uint32 + tokenArgs: c.Cell | null + replyTo: c.Address | null + }): TokenPool_LockOrBurn { + return { + $: 'TokenPool_LockOrBurn', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_LockOrBurn { + loadAndCheckPrefix32(s, 0x1161516e, 'TokenPool_LockOrBurn'); + return { + $: 'TokenPool_LockOrBurn', + queryId: s.loadUintBig(64), + request: loadCellRef(s, TokenPool_LockOrBurnInV1.fromSlice), + requestedFinalityConfig: s.loadUintBig(32), + tokenArgs: s.loadBoolean() ? s.loadRef() : null, + replyTo: s.loadMaybeAddress(), + } + }, + store(self: TokenPool_LockOrBurn, b: c.Builder): void { + b.storeUint(0x1161516e, 32); + b.storeUint(self.queryId, 64); + storeCellRef(self.request, b, TokenPool_LockOrBurnInV1.store); + b.storeUint(self.requestedFinalityConfig, 32); + storeTolkNullable(self.tokenArgs, b, + (v,b) => b.storeRef(v) + ); + b.storeAddress(self.replyTo); + }, + toCell(self: TokenPool_LockOrBurn): c.Cell { + return makeCellFrom(self, TokenPool_LockOrBurn.store); + } +} + +/** + > struct (0x7d0ffd89) TokenPool_ReleaseOrMint { + > queryId: uint64 + > request: Cell + > requestedFinalityConfig: uint32 + > replyTo: address? + > } + */ +export interface TokenPool_ReleaseOrMint { + readonly $: 'TokenPool_ReleaseOrMint' + queryId: uint64 + request: CellRef + requestedFinalityConfig: uint32 + replyTo: c.Address | null /* = null */ +} + +export const TokenPool_ReleaseOrMint = { + PREFIX: 0x7d0ffd89, + + create(args: { + queryId: uint64 + request: CellRef + requestedFinalityConfig: uint32 + replyTo?: c.Address | null /* = null */ + }): TokenPool_ReleaseOrMint { + return { + $: 'TokenPool_ReleaseOrMint', + replyTo: null, + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_ReleaseOrMint { + loadAndCheckPrefix32(s, 0x7d0ffd89, 'TokenPool_ReleaseOrMint'); + return { + $: 'TokenPool_ReleaseOrMint', + queryId: s.loadUintBig(64), + request: loadCellRef(s, TokenPool_ReleaseOrMintInV1.fromSlice), + requestedFinalityConfig: s.loadUintBig(32), + replyTo: s.loadMaybeAddress(), + } + }, + store(self: TokenPool_ReleaseOrMint, b: c.Builder): void { + b.storeUint(0x7d0ffd89, 32); + b.storeUint(self.queryId, 64); + storeCellRef(self.request, b, TokenPool_ReleaseOrMintInV1.store); + b.storeUint(self.requestedFinalityConfig, 32); + b.storeAddress(self.replyTo); + }, + toCell(self: TokenPool_ReleaseOrMint): c.Cell { + return makeCellFrom(self, TokenPool_ReleaseOrMint.store); + } +} + +/** + > struct TokenPool_AdminConfig { + > ownable: Cell + > rmnProxy: address + > dynamicConfig: Cell + > allowedFinalityConfig: uint32 + > } + */ +export interface TokenPool_AdminConfig { + readonly $: 'TokenPool_AdminConfig' + ownable: CellRef + rmnProxy: c.Address + dynamicConfig: CellRef + allowedFinalityConfig: uint32 /* = 0 as uint32 */ +} + +export const TokenPool_AdminConfig = { + create(args: { + ownable: CellRef + rmnProxy: c.Address + dynamicConfig: CellRef + allowedFinalityConfig?: uint32 /* = 0 as uint32 */ + }): TokenPool_AdminConfig { + return { + $: 'TokenPool_AdminConfig', + allowedFinalityConfig: 0n, + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_AdminConfig { + return { + $: 'TokenPool_AdminConfig', + ownable: loadCellRef(s, Ownable2Step.fromSlice), + rmnProxy: s.loadAddress(), + dynamicConfig: loadCellRef(s, TokenPool_DynamicConfig.fromSlice), + allowedFinalityConfig: s.loadUintBig(32), + } + }, + store(self: TokenPool_AdminConfig, b: c.Builder): void { + storeCellRef(self.ownable, b, Ownable2Step.store); + b.storeAddress(self.rmnProxy); + storeCellRef(self.dynamicConfig, b, TokenPool_DynamicConfig.store); + b.storeUint(self.allowedFinalityConfig, 32); + }, + toCell(self: TokenPool_AdminConfig): c.Cell { + return makeCellFrom(self, TokenPool_AdminConfig.store); + } +} + +/** + > struct TokenPool_Data { + > adminConfig: Cell + > mirroredPolicy: Cell + > token: address + > tokenDecimals: uint8 + > remoteChainConfigs: map + > tokenTransferFeeConfigs: map + > } + */ +export interface TokenPool_Data { + readonly $: 'TokenPool_Data' + adminConfig: CellRef + mirroredPolicy: CellRef + token: c.Address + tokenDecimals: uint8 + remoteChainConfigs: c.Dictionary + tokenTransferFeeConfigs: c.Dictionary +} + +export const TokenPool_Data = { + create(args: { + adminConfig: CellRef + mirroredPolicy: CellRef + token: c.Address + tokenDecimals: uint8 + remoteChainConfigs: c.Dictionary + tokenTransferFeeConfigs: c.Dictionary + }): TokenPool_Data { + return { + $: 'TokenPool_Data', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_Data { + return { + $: 'TokenPool_Data', + adminConfig: loadCellRef(s, TokenPool_AdminConfig.fromSlice), + mirroredPolicy: loadCellRef(s, TokenPool_MirroredPolicy.fromSlice), + token: s.loadAddress(), + tokenDecimals: s.loadUintBig(8), + remoteChainConfigs: c.Dictionary.load(c.Dictionary.Keys.BigUint(64), createDictionaryValue(TokenPool_RemoteChainConfig.fromSlice, TokenPool_RemoteChainConfig.store), s), + tokenTransferFeeConfigs: c.Dictionary.load(c.Dictionary.Keys.BigUint(64), createDictionaryValue(TokenPool_TokenTransferFeeConfig.fromSlice, TokenPool_TokenTransferFeeConfig.store), s), + } + }, + store(self: TokenPool_Data, b: c.Builder): void { + storeCellRef(self.adminConfig, b, TokenPool_AdminConfig.store); + storeCellRef(self.mirroredPolicy, b, TokenPool_MirroredPolicy.store); + b.storeAddress(self.token); + b.storeUint(self.tokenDecimals, 8); + b.storeDict(self.remoteChainConfigs, c.Dictionary.Keys.BigUint(64), createDictionaryValue(TokenPool_RemoteChainConfig.fromSlice, TokenPool_RemoteChainConfig.store)); + b.storeDict(self.tokenTransferFeeConfigs, c.Dictionary.Keys.BigUint(64), createDictionaryValue(TokenPool_TokenTransferFeeConfig.fromSlice, TokenPool_TokenTransferFeeConfig.store)); + }, + toCell(self: TokenPool_Data): c.Cell { + return makeCellFrom(self, TokenPool_Data.store); + } +} + +/** + > struct RateLimiter_Config { + > isEnabled: bool + > capacity: uint256 + > rate: uint256 + > } + */ +export interface RateLimiter_Config { + readonly $: 'RateLimiter_Config' + isEnabled: boolean + capacity: uint256 + rate: uint256 +} + +export const RateLimiter_Config = { + create(args: { + isEnabled: boolean + capacity: uint256 + rate: uint256 + }): RateLimiter_Config { + return { + $: 'RateLimiter_Config', + ...args + } + }, + fromSlice(s: c.Slice): RateLimiter_Config { + return { + $: 'RateLimiter_Config', + isEnabled: s.loadBoolean(), + capacity: s.loadUintBig(256), + rate: s.loadUintBig(256), + } + }, + store(self: RateLimiter_Config, b: c.Builder): void { + b.storeBit(self.isEnabled); + b.storeUint(self.capacity, 256); + b.storeUint(self.rate, 256); + }, + toCell(self: RateLimiter_Config): c.Cell { + return makeCellFrom(self, RateLimiter_Config.store); + } +} + +/** + > struct RateLimiter_TokenBucket { + > tokens: uint256 + > lastUpdated: uint64 + > isEnabled: bool + > capacity: uint256 + > rate: uint256 + > } + */ +export interface RateLimiter_TokenBucket { + readonly $: 'RateLimiter_TokenBucket' + tokens: uint256 + lastUpdated: uint64 + isEnabled: boolean + capacity: uint256 + rate: uint256 +} + +export const RateLimiter_TokenBucket = { + create(args: { + tokens: uint256 + lastUpdated: uint64 + isEnabled: boolean + capacity: uint256 + rate: uint256 + }): RateLimiter_TokenBucket { + return { + $: 'RateLimiter_TokenBucket', + ...args + } + }, + fromSlice(s: c.Slice): RateLimiter_TokenBucket { + return { + $: 'RateLimiter_TokenBucket', + tokens: s.loadUintBig(256), + lastUpdated: s.loadUintBig(64), + isEnabled: s.loadBoolean(), + capacity: s.loadUintBig(256), + rate: s.loadUintBig(256), + } + }, + store(self: RateLimiter_TokenBucket, b: c.Builder): void { + b.storeUint(self.tokens, 256); + b.storeUint(self.lastUpdated, 64); + b.storeBit(self.isEnabled); + b.storeUint(self.capacity, 256); + b.storeUint(self.rate, 256); + }, + toCell(self: RateLimiter_TokenBucket): c.Cell { + return makeCellFrom(self, RateLimiter_TokenBucket.store); + } +} + +/** + > type CrossChainAddress = slice + */ +export type CrossChainAddress = c.Slice + +export const CrossChainAddress = { + fromSlice(s: c.Slice): CrossChainAddress { + return invokeCustomUnpackFromSlice('CrossChainAddress', s); + }, + store(self: CrossChainAddress, b: c.Builder): void { + invokeCustomPackToBuilder('CrossChainAddress', self, b); + }, + toCell(self: CrossChainAddress): c.Cell { + return makeCellFrom(self, CrossChainAddress.store); + } +} + +/** + > struct CursedSubjects { + > data: map + > } + */ +export interface CursedSubjects { + readonly $: 'CursedSubjects' + data: c.Dictionary +} + +export const CursedSubjects = { + create(args: { + data: c.Dictionary + }): CursedSubjects { + return { + $: 'CursedSubjects', + ...args + } + }, + fromSlice(s: c.Slice): CursedSubjects { + return { + $: 'CursedSubjects', + data: c.Dictionary.load(c.Dictionary.Keys.BigUint(128), createDictionaryValue<[]>( + (s) => [], + (v,b) => { {} } + ), s), + } + }, + store(self: CursedSubjects, b: c.Builder): void { + b.storeDict(self.data, c.Dictionary.Keys.BigUint(128), createDictionaryValue<[]>( + (s) => [], + (v,b) => { {} } + )); + }, + toCell(self: CursedSubjects): c.Cell { + return makeCellFrom(self, CursedSubjects.store); + } +} + +/** + > type SnakedCell = cell + */ +export type SnakedCell = c.Cell + +/** + > struct Ownable2Step { + > owner: address + > pendingOwner: address? + > } + */ +export interface Ownable2Step { + readonly $: 'Ownable2Step' + owner: c.Address + pendingOwner: c.Address | null +} + +export const Ownable2Step = { + create(args: { + owner: c.Address + pendingOwner: c.Address | null + }): Ownable2Step { + return { + $: 'Ownable2Step', + ...args + } + }, + fromSlice(s: c.Slice): Ownable2Step { + return { + $: 'Ownable2Step', + owner: s.loadAddress(), + pendingOwner: s.loadMaybeAddress(), + } + }, + store(self: Ownable2Step, b: c.Builder): void { + b.storeAddress(self.owner); + b.storeAddress(self.pendingOwner); + }, + toCell(self: Ownable2Step): c.Cell { + return makeCellFrom(self, Ownable2Step.store); + } +} + +// ———————————————————————————————————————————— +// class TokenPool +// + +interface ExtraSendOptions { + bounce?: boolean // default: false + sendMode?: SendMode // default: SendMode.PAY_GAS_SEPARATELY + extraCurrencies?: c.ExtraCurrency // default: empty dict +} + +interface DeployedAddrOptions { + workchain?: number // default: 0 (basechain) + toShard?: { fixedPrefixLength: number; closeTo: c.Address } + overrideContractCode?: c.Cell +} + +function calculateDeployedAddress(code: c.Cell, data: c.Cell, options: DeployedAddrOptions): c.Address { + const stateInitCell = beginCell().store(c.storeStateInit({ + code, + data, + splitDepth: options.toShard?.fixedPrefixLength, + special: null, + libraries: null, + })).endCell(); + + let addrHash = stateInitCell.hash(); + if (options.toShard) { + const shardDepth = options.toShard.fixedPrefixLength; + addrHash = beginCell() + .storeBits(new c.BitString(options.toShard.closeTo.hash, 0, shardDepth)) + .storeBits(new c.BitString(stateInitCell.hash(), shardDepth, 256 - shardDepth)) + .endCell() + .beginParse().loadBuffer(32); + } + + return new c.Address(options.workchain ?? 0, addrHash); +} + +export class TokenPool implements c.Contract { + static CodeCell = c.Cell.fromBase64('te6ccgEBAgEAGQABFP8A9KQT9LzyyAsBABTTMPiR8kCED/Lw'); + + static Errors = { + } + + readonly address: c.Address + readonly init: { code: c.Cell, data: c.Cell } | undefined + + protected constructor(address: c.Address, init?: { code: c.Cell, data: c.Cell }) { + this.address = address; + this.init = init; + } + + static registerCustomPackUnpack( + typeName: string, + packToBuilderFn: CustomPackToBuilderFn | null, + unpackFromSliceFn: CustomUnpackFromSliceFn | null, + ) { + if (customSerializersRegistry.has(typeName)) { + throw new Error(`Custom pack/unpack for 'TokenPool.${typeName}' already registered`); + } + customSerializersRegistry.set(typeName, [packToBuilderFn, unpackFromSliceFn]); + } + + static fromAddress(address: c.Address) { + return new TokenPool(address); + } + + static fromStorage(emptyStorage: { + adminConfig: CellRef + mirroredPolicy: CellRef + token: c.Address + tokenDecimals: uint8 + remoteChainConfigs: c.Dictionary + tokenTransferFeeConfigs: c.Dictionary + }, deployedOptions?: DeployedAddrOptions) { + const initialState = { + code: deployedOptions?.overrideContractCode ?? TokenPool.CodeCell, + data: TokenPool_Data.toCell(TokenPool_Data.create(emptyStorage)), + }; + const address = calculateDeployedAddress(initialState.code, initialState.data, deployedOptions ?? {}); + return new TokenPool(address, initialState); + } + + static createCellOfTokenPoolApplyChainUpdates(body: { + queryId: uint64 + remoteChainSelectorsToRemove: SnakedCell + chainsToAdd: SnakedCell + }) { + return TokenPool_ApplyChainUpdates.toCell(TokenPool_ApplyChainUpdates.create(body)); + } + + static createCellOfTokenPoolAddRemotePool(body: { + queryId: uint64 + remoteChainSelector: uint64 + remotePoolAddress: CellRef + }) { + return TokenPool_AddRemotePool.toCell(TokenPool_AddRemotePool.create(body)); + } + + static createCellOfTokenPoolRemoveRemotePool(body: { + queryId: uint64 + remoteChainSelector: uint64 + remotePoolAddress: CellRef + }) { + return TokenPool_RemoveRemotePool.toCell(TokenPool_RemoveRemotePool.create(body)); + } + + static createCellOfTokenPoolSetDynamicConfig(body: { + queryId: uint64 + router: c.Address + rateLimitAdmin?: c.Address | null /* = null */ + feeAdmin?: c.Address | null /* = null */ + }) { + return TokenPool_SetDynamicConfig.toCell(TokenPool_SetDynamicConfig.create(body)); + } + + static createCellOfTokenPoolSetAllowedFinalityConfig(body: { + queryId: uint64 + allowedFinalityConfig: uint32 + }) { + return TokenPool_SetAllowedFinalityConfig.toCell(TokenPool_SetAllowedFinalityConfig.create(body)); + } + + static createCellOfTokenPoolSetRateLimitConfig(body: { + queryId: uint64 + updates: SnakedCell + }) { + return TokenPool_SetRateLimitConfig.toCell(TokenPool_SetRateLimitConfig.create(body)); + } + + static createCellOfTokenPoolApplyTokenTransferFeeConfigUpdates(body: { + queryId: uint64 + updates: SnakedCell + disableChainSelectors: SnakedCell + }) { + return TokenPool_ApplyTokenTransferFeeConfigUpdates.toCell(TokenPool_ApplyTokenTransferFeeConfigUpdates.create(body)); + } + + static createCellOfTokenPoolUpdateRampAccess(body: { + queryId: uint64 + updates: SnakedCell + }) { + return TokenPool_UpdateRampAccess.toCell(TokenPool_UpdateRampAccess.create(body)); + } + + static createCellOfTokenPoolUpdateCursedSubjects(body: { + cursedSubjects: CursedSubjects + }) { + return TokenPool_UpdateCursedSubjects.toCell(TokenPool_UpdateCursedSubjects.create(body)); + } + + static createCellOfTokenPoolLockOrBurn(body: { + queryId: uint64 + request: CellRef + requestedFinalityConfig: uint32 + tokenArgs: c.Cell | null + replyTo: c.Address | null + }) { + return TokenPool_LockOrBurn.toCell(TokenPool_LockOrBurn.create(body)); + } + + static createCellOfTokenPoolReleaseOrMint(body: { + queryId: uint64 + request: CellRef + requestedFinalityConfig: uint32 + replyTo?: c.Address | null /* = null */ + }) { + return TokenPool_ReleaseOrMint.toCell(TokenPool_ReleaseOrMint.create(body)); + } + + async sendDeploy(provider: ContractProvider, via: Sender, msgValue: coins, extraOptions?: ExtraSendOptions) { + return provider.internal(via, { + value: msgValue, + body: c.Cell.EMPTY, + ...extraOptions + }); + } + + async sendTokenPoolApplyChainUpdates(provider: ContractProvider, via: Sender, msgValue: coins, body: { + queryId: uint64 + remoteChainSelectorsToRemove: SnakedCell + chainsToAdd: SnakedCell + }, extraOptions?: ExtraSendOptions) { + return provider.internal(via, { + value: msgValue, + body: TokenPool_ApplyChainUpdates.toCell(TokenPool_ApplyChainUpdates.create(body)), + ...extraOptions + }); + } + + async sendTokenPoolAddRemotePool(provider: ContractProvider, via: Sender, msgValue: coins, body: { + queryId: uint64 + remoteChainSelector: uint64 + remotePoolAddress: CellRef + }, extraOptions?: ExtraSendOptions) { + return provider.internal(via, { + value: msgValue, + body: TokenPool_AddRemotePool.toCell(TokenPool_AddRemotePool.create(body)), + ...extraOptions + }); + } + + async sendTokenPoolRemoveRemotePool(provider: ContractProvider, via: Sender, msgValue: coins, body: { + queryId: uint64 + remoteChainSelector: uint64 + remotePoolAddress: CellRef + }, extraOptions?: ExtraSendOptions) { + return provider.internal(via, { + value: msgValue, + body: TokenPool_RemoveRemotePool.toCell(TokenPool_RemoveRemotePool.create(body)), + ...extraOptions + }); + } + + async sendTokenPoolSetDynamicConfig(provider: ContractProvider, via: Sender, msgValue: coins, body: { + queryId: uint64 + router: c.Address + rateLimitAdmin?: c.Address | null /* = null */ + feeAdmin?: c.Address | null /* = null */ + }, extraOptions?: ExtraSendOptions) { + return provider.internal(via, { + value: msgValue, + body: TokenPool_SetDynamicConfig.toCell(TokenPool_SetDynamicConfig.create(body)), + ...extraOptions + }); + } + + async sendTokenPoolSetAllowedFinalityConfig(provider: ContractProvider, via: Sender, msgValue: coins, body: { + queryId: uint64 + allowedFinalityConfig: uint32 + }, extraOptions?: ExtraSendOptions) { + return provider.internal(via, { + value: msgValue, + body: TokenPool_SetAllowedFinalityConfig.toCell(TokenPool_SetAllowedFinalityConfig.create(body)), + ...extraOptions + }); + } + + async sendTokenPoolSetRateLimitConfig(provider: ContractProvider, via: Sender, msgValue: coins, body: { + queryId: uint64 + updates: SnakedCell + }, extraOptions?: ExtraSendOptions) { + return provider.internal(via, { + value: msgValue, + body: TokenPool_SetRateLimitConfig.toCell(TokenPool_SetRateLimitConfig.create(body)), + ...extraOptions + }); + } + + async sendTokenPoolApplyTokenTransferFeeConfigUpdates(provider: ContractProvider, via: Sender, msgValue: coins, body: { + queryId: uint64 + updates: SnakedCell + disableChainSelectors: SnakedCell + }, extraOptions?: ExtraSendOptions) { + return provider.internal(via, { + value: msgValue, + body: TokenPool_ApplyTokenTransferFeeConfigUpdates.toCell(TokenPool_ApplyTokenTransferFeeConfigUpdates.create(body)), + ...extraOptions + }); + } + + async sendTokenPoolUpdateRampAccess(provider: ContractProvider, via: Sender, msgValue: coins, body: { + queryId: uint64 + updates: SnakedCell + }, extraOptions?: ExtraSendOptions) { + return provider.internal(via, { + value: msgValue, + body: TokenPool_UpdateRampAccess.toCell(TokenPool_UpdateRampAccess.create(body)), + ...extraOptions + }); + } + + async sendTokenPoolUpdateCursedSubjects(provider: ContractProvider, via: Sender, msgValue: coins, body: { + cursedSubjects: CursedSubjects + }, extraOptions?: ExtraSendOptions) { + return provider.internal(via, { + value: msgValue, + body: TokenPool_UpdateCursedSubjects.toCell(TokenPool_UpdateCursedSubjects.create(body)), + ...extraOptions + }); + } + + async sendTokenPoolLockOrBurn(provider: ContractProvider, via: Sender, msgValue: coins, body: { + queryId: uint64 + request: CellRef + requestedFinalityConfig: uint32 + tokenArgs: c.Cell | null + replyTo: c.Address | null + }, extraOptions?: ExtraSendOptions) { + return provider.internal(via, { + value: msgValue, + body: TokenPool_LockOrBurn.toCell(TokenPool_LockOrBurn.create(body)), + ...extraOptions + }); + } + + async sendTokenPoolReleaseOrMint(provider: ContractProvider, via: Sender, msgValue: coins, body: { + queryId: uint64 + request: CellRef + requestedFinalityConfig: uint32 + replyTo?: c.Address | null /* = null */ + }, extraOptions?: ExtraSendOptions) { + return provider.internal(via, { + value: msgValue, + body: TokenPool_ReleaseOrMint.toCell(TokenPool_ReleaseOrMint.create(body)), + ...extraOptions + }); + } +} From 16365de1feff06dcfacd607468d4bde5a64b4311 Mon Sep 17 00:00:00 2001 From: Kristijan Date: Tue, 9 Jun 2026 12:55:54 +0200 Subject: [PATCH 03/16] yarn fmt --- .../ccip/pools/BurnMintTokenPool.spec.ts | 29 ++++-- .../ccip/pools/LockReleaseTokenPool.spec.ts | 74 +++++++++------ .../tests/ccip/pools/TokenPool.behavior.ts | 93 ++++++++++++------- .../wrappers/ccip.cct.JettonMinter.compile.ts | 2 +- .../wrappers/ccip.cct.JettonWallet.compile.ts | 2 +- contracts/wrappers/ccip/BurnMintTokenPool.ts | 38 ++++++-- contracts/wrappers/ccip/CCTJettonCode.ts | 2 +- contracts/wrappers/ccip/CCTJettonMinter.ts | 11 +-- .../wrappers/ccip/LockReleaseTokenPool.ts | 18 +++- contracts/wrappers/ccip/TokenPool.ts | 27 +++--- 10 files changed, 193 insertions(+), 103 deletions(-) diff --git a/contracts/tests/ccip/pools/BurnMintTokenPool.spec.ts b/contracts/tests/ccip/pools/BurnMintTokenPool.spec.ts index b7327d9b4..024e800c5 100644 --- a/contracts/tests/ccip/pools/BurnMintTokenPool.spec.ts +++ b/contracts/tests/ccip/pools/BurnMintTokenPool.spec.ts @@ -2,7 +2,11 @@ import '@ton/test-utils' import { Blockchain, SandboxContract, TreasuryContract } from '@ton/sandbox' import { Address, Cell, beginCell, toNano } from '@ton/core' import { JettonMinter, JettonWallet } from '../../../wrappers/examples/jetton' -import { BurnMintTokenPool, codec as poolCodec, opcodes as poolOpcodes } from '../../../wrappers/ccip/BurnMintTokenPool' +import { + BurnMintTokenPool, + codec as poolCodec, + opcodes as poolOpcodes, +} from '../../../wrappers/ccip/BurnMintTokenPool' import { CCTJettonMinter } from '../../../wrappers/ccip/CCTJettonMinter' import { CCTJettonMinterCode, CCTJettonWalletCode } from '../../../wrappers/ccip/CCTJettonCode' import { runTokenPoolBehaviorTests } from './TokenPool.behavior' @@ -143,7 +147,11 @@ describe('BurnMintTokenPool', () => { success: true, }) - const claimAdminResult = await burnMintPool.sendClaimMinterAdmin(deployer.getSender(), toNano('0.2'), 202n) + const claimAdminResult = await burnMintPool.sendClaimMinterAdmin( + deployer.getSender(), + toNano('0.2'), + 202n, + ) expect(claimAdminResult.transactions).toHaveTransaction({ from: burnMintPool.address, to: cctMinter.address, @@ -155,7 +163,9 @@ describe('BurnMintTokenPool', () => { expect(await cctMinterRuntime.getNextAdminAddress()).toBeNull() userWallet = async (address: Address) => { - return blockchain.openContract(JettonWallet.createFromAddress(await cctMinterRuntime.getWalletAddress(address))) + return blockchain.openContract( + JettonWallet.createFromAddress(await cctMinterRuntime.getWalletAddress(address)), + ) } }) @@ -168,7 +178,9 @@ describe('BurnMintTokenPool', () => { recipient, remoteChainSelector, unsupportedChainSelector: remoteChainSelector + 1n, - unknownSourcePoolAddress: poolCodec.crossChainAddressFromBuffer(Buffer.from('unknown-source-pool')), + unknownSourcePoolAddress: poolCodec.crossChainAddressFromBuffer( + Buffer.from('unknown-source-pool'), + ), remoteTokenAddress: destTokenAddress, onRampAddress: deployer.address, destTokenAddress, @@ -182,7 +194,11 @@ describe('BurnMintTokenPool', () => { }) it('rejects claim-minter-admin from non-owner sender', async () => { - const result = await burnMintPool.sendClaimMinterAdmin(unauthorized.getSender(), toNano('0.2'), 302n) + const result = await burnMintPool.sendClaimMinterAdmin( + unauthorized.getSender(), + toNano('0.2'), + 302n, + ) expect(result.transactions).toHaveTransaction({ from: unauthorized.address, @@ -388,7 +404,8 @@ describe('BurnMintTokenPool', () => { const releaseResponses = result.transactions.filter((tx: any) => { return ( tx.inMessage?.info?.src?.equals?.(burnMintPool.address) && - tx.inMessage?.body?.beginParse?.().preloadUint?.(32) === poolOpcodes.out.releaseOrMintResponse + tx.inMessage?.body?.beginParse?.().preloadUint?.(32) === + poolOpcodes.out.releaseOrMintResponse ) }) expect(releaseResponses.length).toBe(0) diff --git a/contracts/tests/ccip/pools/LockReleaseTokenPool.spec.ts b/contracts/tests/ccip/pools/LockReleaseTokenPool.spec.ts index 1cfabe092..2e6e04ef5 100644 --- a/contracts/tests/ccip/pools/LockReleaseTokenPool.spec.ts +++ b/contracts/tests/ccip/pools/LockReleaseTokenPool.spec.ts @@ -2,7 +2,11 @@ import '@ton/test-utils' import { Blockchain, SandboxContract, TreasuryContract } from '@ton/sandbox' import { Address, Cell, Message, beginCell, toNano } from '@ton/core' import { JettonMinter, JettonSender, JettonWallet } from '../../../wrappers/examples/jetton' -import { LockReleaseTokenPool, codec as poolCodec, opcodes as poolOpcodes } from '../../../wrappers/ccip/LockReleaseTokenPool' +import { + LockReleaseTokenPool, + codec as poolCodec, + opcodes as poolOpcodes, +} from '../../../wrappers/ccip/LockReleaseTokenPool' import * as jetton from '../../../wrappers/jetton/JettonCode' import { runTokenPoolBehaviorTests } from './TokenPool.behavior' @@ -80,19 +84,23 @@ describe('LockReleaseTokenPool', () => { ) await lockReleasePool.sendDeploy(deployer.getSender(), toNano('2')) - const applyChains = await lockReleasePool.sendApplyChainUpdates(deployer.getSender(), toNano('0.2'), { - queryId: 1n, - remove: [], - add: [ - { - remoteChainSelector, - remotePoolAddresses: [sourcePoolAddress], - remoteTokenAddress: destTokenAddress, - outboundRateLimiterConfig: { isEnabled: true, capacity: toNano('100'), rate: 1n }, - inboundRateLimiterConfig: { isEnabled: true, capacity: toNano('100'), rate: 1n }, - }, - ], - }) + const applyChains = await lockReleasePool.sendApplyChainUpdates( + deployer.getSender(), + toNano('0.2'), + { + queryId: 1n, + remove: [], + add: [ + { + remoteChainSelector, + remotePoolAddresses: [sourcePoolAddress], + remoteTokenAddress: destTokenAddress, + outboundRateLimiterConfig: { isEnabled: true, capacity: toNano('100'), rate: 1n }, + inboundRateLimiterConfig: { isEnabled: true, capacity: toNano('100'), rate: 1n }, + }, + ], + }, + ) expect(applyChains.transactions).toHaveTransaction({ from: deployer.address, @@ -100,16 +108,20 @@ describe('LockReleaseTokenPool', () => { success: true, }) - const updateRampAccess = await lockReleasePool.sendUpdateRampAccess(deployer.getSender(), toNano('0.2'), { - queryId: 2n, - updates: [ - { - remoteChainSelector, - onRamp: jettonSender.address, - offRamp: offRamp.address, - }, - ], - }) + const updateRampAccess = await lockReleasePool.sendUpdateRampAccess( + deployer.getSender(), + toNano('0.2'), + { + queryId: 2n, + updates: [ + { + remoteChainSelector, + onRamp: jettonSender.address, + offRamp: offRamp.address, + }, + ], + }, + ) expect(updateRampAccess.transactions).toHaveTransaction({ from: deployer.address, @@ -151,7 +163,9 @@ describe('LockReleaseTokenPool', () => { recipient, remoteChainSelector, unsupportedChainSelector: remoteChainSelector + 1n, - unknownSourcePoolAddress: poolCodec.crossChainAddressFromBuffer(Buffer.from('unknown-source-pool')), + unknownSourcePoolAddress: poolCodec.crossChainAddressFromBuffer( + Buffer.from('unknown-source-pool'), + ), remoteTokenAddress: destTokenAddress, onRampAddress: jettonSender.address, destTokenAddress, @@ -344,9 +358,11 @@ describe('LockReleaseTokenPool', () => { }) it('mirrors cursed state locally and blocks release while cursed', async () => { - const curseUpdate = await lockReleasePool.sendUpdateCursedSubjects(deployer.getSender(), toNano('0.2'), [ - remoteChainSelector, - ]) + const curseUpdate = await lockReleasePool.sendUpdateCursedSubjects( + deployer.getSender(), + toNano('0.2'), + [remoteChainSelector], + ) expect(curseUpdate.transactions).toHaveTransaction({ from: deployer.address, @@ -378,4 +394,4 @@ describe('LockReleaseTokenPool', () => { success: false, }) }) -}) \ No newline at end of file +}) diff --git a/contracts/tests/ccip/pools/TokenPool.behavior.ts b/contracts/tests/ccip/pools/TokenPool.behavior.ts index 4e206e311..dc0c717ff 100644 --- a/contracts/tests/ccip/pools/TokenPool.behavior.ts +++ b/contracts/tests/ccip/pools/TokenPool.behavior.ts @@ -112,7 +112,9 @@ export function runTokenPoolBehaviorTests( it('reverts releaseOrMint while chain is cursed', async () => { const ctx = await setup() - await ctx.pool.sendUpdateCursedSubjects(ctx.deployer.getSender(), toNano('0.2'), [ctx.remoteChainSelector]) + await ctx.pool.sendUpdateCursedSubjects(ctx.deployer.getSender(), toNano('0.2'), [ + ctx.remoteChainSelector, + ]) expect(await ctx.pool.getVerifyNotCursed(ctx.remoteChainSelector)).toBe(false) const result = await ctx.pool.sendReleaseOrMint(ctx.offRamp.getSender(), toNano('0.3'), { @@ -149,11 +151,15 @@ export function runTokenPoolBehaviorTests( it('rejects applyChainUpdates from non-owner', async () => { const ctx = await setup() - const result = await ctx.pool.sendApplyChainUpdates(ctx.unauthorized.getSender(), toNano('0.2'), { - queryId: 903n, - remove: [], - add: [], - }) + const result = await ctx.pool.sendApplyChainUpdates( + ctx.unauthorized.getSender(), + toNano('0.2'), + { + queryId: 903n, + remove: [], + add: [], + }, + ) expect(result.transactions).toHaveTransaction({ from: ctx.unauthorized.address, @@ -164,16 +170,20 @@ export function runTokenPoolBehaviorTests( it('rejects updateRampAccess from non-owner', async () => { const ctx = await setup() - const result = await ctx.pool.sendUpdateRampAccess(ctx.unauthorized.getSender(), toNano('0.2'), { - queryId: 904n, - updates: [ - { - remoteChainSelector: ctx.remoteChainSelector, - onRamp: ctx.onRampAddress, - offRamp: ctx.unauthorized.address, - }, - ], - }) + const result = await ctx.pool.sendUpdateRampAccess( + ctx.unauthorized.getSender(), + toNano('0.2'), + { + queryId: 904n, + updates: [ + { + remoteChainSelector: ctx.remoteChainSelector, + onRamp: ctx.onRampAddress, + offRamp: ctx.unauthorized.address, + }, + ], + }, + ) expect(result.transactions).toHaveTransaction({ from: ctx.unauthorized.address, @@ -184,9 +194,11 @@ export function runTokenPoolBehaviorTests( it('rejects cursed-subject updates from non-rmn sender', async () => { const ctx = await setup() - const result = await ctx.pool.sendUpdateCursedSubjects(ctx.unauthorized.getSender(), toNano('0.2'), [ - ctx.remoteChainSelector, - ]) + const result = await ctx.pool.sendUpdateCursedSubjects( + ctx.unauthorized.getSender(), + toNano('0.2'), + [ctx.remoteChainSelector], + ) expect(result.transactions).toHaveTransaction({ from: ctx.unauthorized.address, @@ -197,7 +209,9 @@ export function runTokenPoolBehaviorTests( it('can clear cursed subject back to not cursed', async () => { const ctx = await setup() - await ctx.pool.sendUpdateCursedSubjects(ctx.deployer.getSender(), toNano('0.2'), [ctx.remoteChainSelector]) + await ctx.pool.sendUpdateCursedSubjects(ctx.deployer.getSender(), toNano('0.2'), [ + ctx.remoteChainSelector, + ]) expect(await ctx.pool.getVerifyNotCursed(ctx.remoteChainSelector)).toBe(false) await ctx.pool.sendUpdateCursedSubjects(ctx.deployer.getSender(), toNano('0.2'), []) @@ -275,7 +289,9 @@ export function runTokenPoolBehaviorTests( to: ctx.pool.address, success: true, }) - expect(await ctx.pool.getOffRamp(ctx.remoteChainSelector)).toEqualAddress(ctx.unauthorized.address) + expect(await ctx.pool.getOffRamp(ctx.remoteChainSelector)).toEqualAddress( + ctx.unauthorized.address, + ) }) it('rejects old off-ramp sender after remapping off-ramp', async () => { @@ -307,7 +323,10 @@ export function runTokenPoolBehaviorTests( it('rejects releaseOrMint when source pool is not configured', async () => { const ctx = await setup() - const wrongSourcePoolAddress = beginCell().storeUint(4, 8).storeBuffer(Buffer.from('evil')).endCell() + const wrongSourcePoolAddress = beginCell() + .storeUint(4, 8) + .storeBuffer(Buffer.from('evil')) + .endCell() const result = await ctx.pool.sendReleaseOrMint(ctx.offRamp.getSender(), toNano('0.3'), { queryId: 912n, request: releaseRequest(ctx, { sourcePoolAddress: wrongSourcePoolAddress }), @@ -391,19 +410,23 @@ export function runTokenPoolBehaviorTests( add: [], }) - const addResult = await ctx.pool.sendApplyChainUpdates(ctx.deployer.getSender(), toNano('0.2'), { - queryId: 918n, - remove: [], - add: [ - { - remoteChainSelector: ctx.remoteChainSelector, - remotePoolAddresses: [ctx.sourcePoolAddress], - remoteTokenAddress: ctx.destTokenAddress, - outboundRateLimiterConfig: { isEnabled: true, capacity: toNano('100'), rate: 1n }, - inboundRateLimiterConfig: { isEnabled: true, capacity: toNano('100'), rate: 1n }, - }, - ], - }) + const addResult = await ctx.pool.sendApplyChainUpdates( + ctx.deployer.getSender(), + toNano('0.2'), + { + queryId: 918n, + remove: [], + add: [ + { + remoteChainSelector: ctx.remoteChainSelector, + remotePoolAddresses: [ctx.sourcePoolAddress], + remoteTokenAddress: ctx.destTokenAddress, + outboundRateLimiterConfig: { isEnabled: true, capacity: toNano('100'), rate: 1n }, + inboundRateLimiterConfig: { isEnabled: true, capacity: toNano('100'), rate: 1n }, + }, + ], + }, + ) expect(addResult.transactions).toHaveTransaction({ from: ctx.deployer.address, diff --git a/contracts/wrappers/ccip.cct.JettonMinter.compile.ts b/contracts/wrappers/ccip.cct.JettonMinter.compile.ts index 0377bcaca..229320137 100644 --- a/contracts/wrappers/ccip.cct.JettonMinter.compile.ts +++ b/contracts/wrappers/ccip.cct.JettonMinter.compile.ts @@ -4,4 +4,4 @@ export const compile: CompilerConfig = { lang: 'tolk', entrypoint: 'contracts/ccip/cct/JettonMinter.tolk', withStackComments: true, -} \ No newline at end of file +} diff --git a/contracts/wrappers/ccip.cct.JettonWallet.compile.ts b/contracts/wrappers/ccip.cct.JettonWallet.compile.ts index 00584c349..4694eb8ad 100644 --- a/contracts/wrappers/ccip.cct.JettonWallet.compile.ts +++ b/contracts/wrappers/ccip.cct.JettonWallet.compile.ts @@ -4,4 +4,4 @@ export const compile: CompilerConfig = { lang: 'tolk', entrypoint: 'contracts/ccip/cct/JettonWallet.tolk', withStackComments: true, -} \ No newline at end of file +} diff --git a/contracts/wrappers/ccip/BurnMintTokenPool.ts b/contracts/wrappers/ccip/BurnMintTokenPool.ts index 2212e6c2b..8dfa58f73 100644 --- a/contracts/wrappers/ccip/BurnMintTokenPool.ts +++ b/contracts/wrappers/ccip/BurnMintTokenPool.ts @@ -123,34 +123,56 @@ export class BurnMintTokenPool implements Contract { await provider.internal(via, { value, sendMode: SendMode.PAY_GAS_SEPARATELY, - body: beginCell().storeUint(BURN_MINT_CLAIM_MINTER_ADMIN_OPCODE, 32).storeUint(queryId, 64).endCell(), + body: beginCell() + .storeUint(BURN_MINT_CLAIM_MINTER_ADMIN_OPCODE, 32) + .storeUint(queryId, 64) + .endCell(), }) } async getHasPendingBurn(provider: ContractProvider, queryId: bigint) { - return provider.get('hasPendingBurn', [{ type: 'int', value: queryId }]).then((res) => res.stack.readBoolean()) + return provider + .get('hasPendingBurn', [{ type: 'int', value: queryId }]) + .then((res) => res.stack.readBoolean()) } async getHasPendingMint(provider: ContractProvider, queryId: bigint) { - return provider.get('hasPendingMint', [{ type: 'int', value: queryId }]).then((res) => res.stack.readBoolean()) + return provider + .get('hasPendingMint', [{ type: 'int', value: queryId }]) + .then((res) => res.stack.readBoolean()) } async getVerifyNotCursed(provider: ContractProvider, subject: bigint) { - return provider.get('verifyNotCursed', [{ type: 'int', value: subject }]).then((res) => res.stack.readBoolean()) + return provider + .get('verifyNotCursed', [{ type: 'int', value: subject }]) + .then((res) => res.stack.readBoolean()) } async getOnRamp(provider: ContractProvider, remoteChainSelector: bigint) { - return provider.get('onRamp', [{ type: 'int', value: remoteChainSelector }]).then((res) => res.stack.readAddressOpt()) + return provider + .get('onRamp', [{ type: 'int', value: remoteChainSelector }]) + .then((res) => res.stack.readAddressOpt()) } async getOffRamp(provider: ContractProvider, remoteChainSelector: bigint) { - return provider.get('offRamp', [{ type: 'int', value: remoteChainSelector }]).then((res) => res.stack.readAddressOpt()) + return provider + .get('offRamp', [{ type: 'int', value: remoteChainSelector }]) + .then((res) => res.stack.readAddressOpt()) } async getIsSupportedChain(provider: ContractProvider, remoteChainSelector: bigint) { - return provider.get('isSupportedChain', [{ type: 'int', value: remoteChainSelector }]).then((res) => res.stack.readBoolean()) + return provider + .get('isSupportedChain', [{ type: 'int', value: remoteChainSelector }]) + .then((res) => res.stack.readBoolean()) } } export { codec, opcodes } -export type { ChainUpdate, JettonClientConfig, LockOrBurnInV1, LockOrBurnPayload, RampAccess, ReleaseOrMintInV1 } \ No newline at end of file +export type { + ChainUpdate, + JettonClientConfig, + LockOrBurnInV1, + LockOrBurnPayload, + RampAccess, + ReleaseOrMintInV1, +} diff --git a/contracts/wrappers/ccip/CCTJettonCode.ts b/contracts/wrappers/ccip/CCTJettonCode.ts index 1fffa93b7..807206fc2 100644 --- a/contracts/wrappers/ccip/CCTJettonCode.ts +++ b/contracts/wrappers/ccip/CCTJettonCode.ts @@ -7,4 +7,4 @@ export async function CCTJettonMinterCode(): Promise { export async function CCTJettonWalletCode(): Promise { return contractCode.ccip.local('ccip.cct.JettonWallet') -} \ No newline at end of file +} diff --git a/contracts/wrappers/ccip/CCTJettonMinter.ts b/contracts/wrappers/ccip/CCTJettonMinter.ts index b23559b99..b8103138a 100644 --- a/contracts/wrappers/ccip/CCTJettonMinter.ts +++ b/contracts/wrappers/ccip/CCTJettonMinter.ts @@ -9,9 +9,7 @@ import { SendMode, } from '@ton/core' import { contractCode } from '../codeLoader' -import { - builder as jettonMinterBuilder, -} from '../jetton/JettonMinter' +import { builder as jettonMinterBuilder } from '../jetton/JettonMinter' export type CCTJettonMinterConfig = { totalSupply: bigint @@ -109,15 +107,16 @@ export class CCTJettonMinter implements Contract { await provider.internal(via, { value: opts.value, sendMode: SendMode.PAY_GAS_SEPARATELY, - body: jettonMinterBuilder.messages.in - .changeMinterAdmin + body: jettonMinterBuilder.messages.in.changeMinterAdmin .encode({ queryId: opts.queryId ?? 0n, newAdmin: opts.newAdminAddress }) .asCell(), }) } async getWalletAddress(provider: ContractProvider, ownerAddress: Address): Promise
{ - const { stack } = await provider.get('get_wallet_address', [{ type: 'slice', cell: beginCell().storeAddress(ownerAddress).endCell() }]) + const { stack } = await provider.get('get_wallet_address', [ + { type: 'slice', cell: beginCell().storeAddress(ownerAddress).endCell() }, + ]) return stack.readAddress() } } diff --git a/contracts/wrappers/ccip/LockReleaseTokenPool.ts b/contracts/wrappers/ccip/LockReleaseTokenPool.ts index 61930489d..c71ab4c14 100644 --- a/contracts/wrappers/ccip/LockReleaseTokenPool.ts +++ b/contracts/wrappers/ccip/LockReleaseTokenPool.ts @@ -122,20 +122,28 @@ export class LockReleaseTokenPool implements Contract { } async getVerifyNotCursed(provider: ContractProvider, subject: bigint) { - return provider.get('verifyNotCursed', [{ type: 'int', value: subject }]).then((res) => res.stack.readBoolean()) + return provider + .get('verifyNotCursed', [{ type: 'int', value: subject }]) + .then((res) => res.stack.readBoolean()) } async getOnRamp(provider: ContractProvider, remoteChainSelector: bigint) { - return provider.get('onRamp', [{ type: 'int', value: remoteChainSelector }]).then((res) => res.stack.readAddressOpt()) + return provider + .get('onRamp', [{ type: 'int', value: remoteChainSelector }]) + .then((res) => res.stack.readAddressOpt()) } async getOffRamp(provider: ContractProvider, remoteChainSelector: bigint) { - return provider.get('offRamp', [{ type: 'int', value: remoteChainSelector }]).then((res) => res.stack.readAddressOpt()) + return provider + .get('offRamp', [{ type: 'int', value: remoteChainSelector }]) + .then((res) => res.stack.readAddressOpt()) } async getIsSupportedChain(provider: ContractProvider, remoteChainSelector: bigint) { - return provider.get('isSupportedChain', [{ type: 'int', value: remoteChainSelector }]).then((res) => res.stack.readBoolean()) + return provider + .get('isSupportedChain', [{ type: 'int', value: remoteChainSelector }]) + .then((res) => res.stack.readBoolean()) } } -export { codec, opcodes } \ No newline at end of file +export { codec, opcodes } diff --git a/contracts/wrappers/ccip/TokenPool.ts b/contracts/wrappers/ccip/TokenPool.ts index 59724674f..4ec21372d 100644 --- a/contracts/wrappers/ccip/TokenPool.ts +++ b/contracts/wrappers/ccip/TokenPool.ts @@ -115,7 +115,10 @@ export const codec = { rateLimitConfig: { encode(data: RateLimitConfig): Builder { - return beginCell().storeBit(data.isEnabled).storeUint(data.capacity, 256).storeUint(data.rate, 256) + return beginCell() + .storeBit(data.isEnabled) + .storeUint(data.capacity, 256) + .storeUint(data.rate, 256) }, }, @@ -209,10 +212,12 @@ export function createTokenPoolData(config: TokenPoolConfig): Cell { const adminConfig = beginCell() .storeRef( - ownable2step.builder.data.traitData.encode({ - owner: config.owner, - pendingOwner: null, - }).asCell(), + ownable2step.builder.data.traitData + .encode({ + owner: config.owner, + pendingOwner: null, + }) + .asCell(), ) .storeAddress(config.rmnProxy) .storeRef(dynamicConfig) @@ -236,10 +241,7 @@ export function createTokenPoolData(config: TokenPoolConfig): Cell { } export function createJettonClientData(config: JettonClientConfig): Cell { - return beginCell() - .storeAddress(config.masterAddress) - .storeRef(config.jettonWalletCode) - .endCell() + return beginCell().storeAddress(config.masterAddress).storeRef(config.jettonWalletCode).endCell() } export async function sendApplyChainUpdates( @@ -341,6 +343,9 @@ function asSnakeChainUpdates(items: ChainUpdate[]): Cell { function asSnakeRampAccess(items: RampAccess[]): Cell { return asSnakedCell(items, (item) => - beginCell().storeUint(item.remoteChainSelector, 64).storeAddress(item.onRamp).storeAddress(item.offRamp), + beginCell() + .storeUint(item.remoteChainSelector, 64) + .storeAddress(item.onRamp) + .storeAddress(item.offRamp), ) -} \ No newline at end of file +} From 1437e0640e75f07f74ce96d7dda27564a55919f8 Mon Sep 17 00:00:00 2001 From: Kristijan Date: Tue, 9 Jun 2026 20:47:25 +0200 Subject: [PATCH 04/16] Add docs, polish, add SetRMNProxy msg --- contracts/contracts/ccip/pools/events.tolk | 1 + .../lock_release_token_pool/storage.tolk | 7 +- .../pools/lock_release_token_pool/types.tolk | 2 +- contracts/contracts/ccip/pools/messages.tolk | 9 ++ .../contracts/ccip/pools/token_pool.tolk | 119 +++++++++++++----- contracts/contracts/ccip/pools/types.tolk | 2 + 6 files changed, 103 insertions(+), 37 deletions(-) diff --git a/contracts/contracts/ccip/pools/events.tolk b/contracts/contracts/ccip/pools/events.tolk index dff934d73..6ae2141ad 100644 --- a/contracts/contracts/ccip/pools/events.tolk +++ b/contracts/contracts/ccip/pools/events.tolk @@ -1,5 +1,6 @@ // SPDX-License-Identifier: BUSL-1.1 import "../common/types" + import "types" const TOKEN_POOL_LOCKED_OR_BURNED_TOPIC = stringCrc32("TokenPool_LockedOrBurned"); diff --git a/contracts/contracts/ccip/pools/lock_release_token_pool/storage.tolk b/contracts/contracts/ccip/pools/lock_release_token_pool/storage.tolk index 9b482d808..04b087890 100644 --- a/contracts/contracts/ccip/pools/lock_release_token_pool/storage.tolk +++ b/contracts/contracts/ccip/pools/lock_release_token_pool/storage.tolk @@ -1,9 +1,10 @@ // SPDX-License-Identifier: BUSL-1.1 -import "../token_pool.tolk" -import "../types" -import "../../rmn_remote/lib" import "../../../lib/jetton/jetton_client.tolk" import "../../../lib/access/ownable_2step.tolk" +import "../../rmn_remote/lib" +import "../types" +import "../token_pool.tolk" + import "types" struct Storage { diff --git a/contracts/contracts/ccip/pools/lock_release_token_pool/types.tolk b/contracts/contracts/ccip/pools/lock_release_token_pool/types.tolk index 603eed16e..6c8da4d9d 100644 --- a/contracts/contracts/ccip/pools/lock_release_token_pool/types.tolk +++ b/contracts/contracts/ccip/pools/lock_release_token_pool/types.tolk @@ -2,7 +2,7 @@ import "../../../lib/jetton/jetton_client.tolk" import "../types" -const LockReleaseTokenPool_CONTRACT_NAME = "LockReleaseTokenPool".literalSlice(); +const LockReleaseTokenPool_CONTRACT_NAME = "link.chain.ton.ccip.LockReleaseTokenPool".literalSlice(); const LockReleaseTokenPool_CONTRACT_VERSION = "0.1.0".literalSlice(); const LockReleaseTokenPool_RELEASE_TRANSFER_VALUE = ton("0.05"); const LockReleaseTokenPool_REPLY_VALUE = ton("0.01"); diff --git a/contracts/contracts/ccip/pools/messages.tolk b/contracts/contracts/ccip/pools/messages.tolk index c6250edc5..e56febca4 100644 --- a/contracts/contracts/ccip/pools/messages.tolk +++ b/contracts/contracts/ccip/pools/messages.tolk @@ -2,6 +2,7 @@ import "../../lib/utils" import "../common/types" import "../rmn_remote/lib" + import "types" struct (0xdc0b6ff5) TokenPool_ApplyChainUpdates { @@ -50,7 +51,15 @@ struct (0x7a9c4aa5) TokenPool_UpdateRampAccess { updates: SnakedCell; } +// TODO: update opcode +/// Sets the RMN proxy address, a role which is responsible for updating the cursed subjects list. +struct (0x12345678) TokenPool_SetRMNProxy { + queryId: uint64; + rmnProxy: address; +} + struct (0x823dadf2) TokenPool_UpdateCursedSubjects { + queryId: uint64; cursedSubjects: CursedSubjects; } diff --git a/contracts/contracts/ccip/pools/token_pool.tolk b/contracts/contracts/ccip/pools/token_pool.tolk index 4bec6c970..048b9625c 100644 --- a/contracts/contracts/ccip/pools/token_pool.tolk +++ b/contracts/contracts/ccip/pools/token_pool.tolk @@ -415,6 +415,14 @@ fun TokenPool.applyRampAccessUpdates( self.data.mirroredPolicy = mirroredPolicy.toCell(); } +fun TokenPool.setRMNProxy(mutate self, sender: address, rmnProxy: address) { + var adminConfig = self.data.adminConfig.load(); + adminConfig.ownable.load().requireOwner(sender); + + adminConfig.rmnProxy = rmnProxy; + self.data.adminConfig = adminConfig.toCell(); +} + fun TokenPool.setCursedSubjects( mutate self, sender: address, @@ -465,6 +473,10 @@ fun TokenPool.onInternalMessage(mutate self, msgSender: address, msgValue: co self.applyRampAccessUpdates(msgSender, msg.updates); return true; } + TokenPool_SetRMNProxy => { + self.setRMNProxy(msgSender, msg.rmnProxy); + return true; + } TokenPool_UpdateCursedSubjects => { self.setCursedSubjects(msgSender, msg.cursedSubjects); return true; @@ -523,10 +535,17 @@ fun TokenPool.getTokenTransferFeeConfig(self, destChainSelector: uint64): Tok return entry.isFound ? entry.loadValue() : null; } +/// Returns the pool fee parameters that will apply to a transfer. +/// @param destChainSelector The destination lane selector. +/// @param requestedFinalityConfig Requested finality encoding (see `FinalityCodec`). fun TokenPool.getFee( self, + _localToken: address, destChainSelector: uint64, + _amount: uint256, + _feeToken: address, requestedFinalityConfig: uint32, + _tokenArgs: cell?, ): (uint256, uint32, uint32, uint16, bool) { TokenPool_ensureRequestedFinalityAllowed(requestedFinalityConfig, self.data.adminConfig.load().allowedFinalityConfig); @@ -536,6 +555,7 @@ fun TokenPool.getFee( } val feeConfig = entry.loadValue(); + // If config is disabled, return zeros with isEnabled=false to signal OnRamp to use FeeQuoter defaults. if (!feeConfig.isEnabled) { return (0, 0, 0, 0, false); } @@ -559,6 +579,33 @@ fun TokenPool.getFee( ); } +/// @dev Calculates the fee based on the transferred amount, and the configured basis points. +/// @param lockOrBurnIn The original lock or burn request. +/// @param requestedFinalityConfig The requested finality encoding (see `FinalityCodec`). +/// A value of zero (FinalityCodec.WAIT_FOR_FINALITY_FLAG) applies default finality fees. +/// Returns the fee amount. +fun TokenPool.getFeeAmount( + self, + request: TokenPool_LockOrBurnInV1, + requestedFinalityConfig: uint32, +): uint256 { + val entry = self.data.tokenTransferFeeConfigs.get(request.remoteChainSelector); + if (!entry.isFound) { + return 0; + } + + val feeConfig = entry.loadValue(); + if (!feeConfig.isEnabled) { + return 0; + } + + if (requestedFinalityConfig != TOKEN_POOL_WAIT_FOR_FINALITY_FLAG) { + return (request.amount * (feeConfig.fastFinalityTransferFeeBps as uint256)) / TOKEN_POOL_BPS_DIVIDER; + } + + return (request.amount * (feeConfig.finalityTransferFeeBps as uint256)) / TOKEN_POOL_BPS_DIVIDER; +} + fun TokenPool.prepareLockOrBurn( mutate self, sender: address, @@ -664,18 +711,28 @@ fun TokenPool.encodeLocalDecimals(self): cell { } fun TokenPool.parseRemoteDecimals(self, sourcePoolData: cell?): uint8 { + // Fallback to the local token decimals if the source pool data is empty. This allows for backwards compatibility. if (sourcePoolData == null) { return self.data.tokenDecimals; } - var cs = sourcePoolData!.beginParse(); - assert(cs.remainingBitsCount() == 256 && cs.remainingRefsCount() == 0, TokenPool_Error.InvalidRemoteChainDecimals); - val remoteDecimals = cs.loadUint(256); - cs.assertEnd(); - assert(remoteDecimals <= 255, TokenPool_Error.InvalidRemoteChainDecimals); + var s = sourcePoolData!.beginParse(); + assert(s.remainingBitsCount() == 256 && s.remainingRefsCount() == 0, TokenPool_Error.InvalidRemoteChainDecimals); + val remoteDecimals = s.loadUint(256); + s.assertEnd(); + assert(remoteDecimals <= TOKEN_POOL_MAX_UINT8, TokenPool_Error.InvalidRemoteChainDecimals); + return remoteDecimals as uint8; } + /// Calculates the local amount based on the remote amount and decimals. + /// @param remoteAmount The amount on the remote chain. + /// @param remoteDecimals The decimals of the token on the remote chain. + /// @return The local amount. + /// @dev This function protects against overflows. If there is a transaction that hits the overflow check, it is + /// probably incorrect as that means the amount cannot be represented on this chain. If the local decimals have been + /// wrongly configured, the token issuer could redeploy the pool with the correct decimals and manually re-execute the + /// CCIP tx to fix the issue. fun TokenPool.calculateLocalAmount(self, remoteAmount: uint256, remoteDecimals: uint8): uint256 { if (remoteDecimals == self.data.tokenDecimals) { return remoteAmount; @@ -683,38 +740,23 @@ fun TokenPool.calculateLocalAmount(self, remoteAmount: uint256, remoteDecimal if (remoteDecimals > self.data.tokenDecimals) { val decimalsDiff = remoteDecimals - self.data.tokenDecimals; + // This is a safety check to prevent overflow in the next calculation. assert(decimalsDiff <= TOKEN_POOL_MAX_EXP10, TokenPool_Error.OverflowDetected); - return remoteAmount / TokenPool_pow10(decimalsDiff); + + return remoteAmount / pow10(decimalsDiff); } + // This is a safety check to prevent overflow in the next calculation. + // More than 77 would never fit in a uint256 and would cause an overflow. + // We also check if the resulting amount would overflow. val decimalsDiff = self.data.tokenDecimals - remoteDecimals; assert(decimalsDiff <= TOKEN_POOL_MAX_EXP10, TokenPool_Error.OverflowDetected); - val scale = TokenPool_pow10(decimalsDiff); + val scale = pow10(decimalsDiff); assert(scale == 0 || remoteAmount <= TOKEN_POOL_MAX_UINT256 / scale, TokenPool_Error.OverflowDetected); + return remoteAmount * scale; } -fun TokenPool.getFeeAmount( - self, - request: TokenPool_LockOrBurnInV1, - requestedFinalityConfig: uint32, -): uint256 { - val entry = self.data.tokenTransferFeeConfigs.get(request.remoteChainSelector); - if (!entry.isFound) { - return 0; - } - - val feeConfig = entry.loadValue(); - if (!feeConfig.isEnabled) { - return 0; - } - - if (requestedFinalityConfig != TOKEN_POOL_WAIT_FOR_FINALITY_FLAG) { - return (request.amount * (feeConfig.fastFinalityTransferFeeBps as uint256)) / TOKEN_POOL_BPS_DIVIDER; - } - return (request.amount * (feeConfig.finalityTransferFeeBps as uint256)) / TOKEN_POOL_BPS_DIVIDER; -} - fun TokenPool.requireSupportedChain(self, remoteChainSelector: uint64) { assert(self.isSupportedChain(remoteChainSelector), TokenPool_Error.ChainNotAllowed); } @@ -960,6 +1002,8 @@ fun TokenPool._setRemotePool(mutate self, mutate config: TokenPool_RemoteChai config.remotePools.set(poolHash, remotePoolAddress); } +// TODO: withdrawFeeTokens + fun TokenPool_ensureRequestedFinalityAllowed(requestedFinalityConfig: uint32, allowedFinalityConfig: uint32) { if (requestedFinalityConfig == TOKEN_POOL_WAIT_FOR_FINALITY_FLAG) { return; @@ -992,12 +1036,21 @@ fun TokenPool_boxCrossChainAddress(addressBytes: CrossChainAddress): Cell; } -fun TokenPool_pow10(exponent: uint8): uint256 { - var i: uint8 = 0; +// TODO: move to common utils library +// @dev Calculates 10^n for n <= 77 in O(log n). For n > 77, it would overflow uint256. +fun pow10(n: uint8): uint256 { var result: uint256 = 1; - while (i < exponent) { - result *= 10; - i += 1; + var base: uint256 = 10; + + while (n > 0) { + if (n & 1 == 1) { + // Check for potential overflow before multiplication + assert(result == 0 || base <= TOKEN_POOL_MAX_UINT256 / result, TokenPool_Error.OverflowDetected); + result *= base; + } + base *= base; + n >>= 1; } + return result; } diff --git a/contracts/contracts/ccip/pools/types.tolk b/contracts/contracts/ccip/pools/types.tolk index 120b4bf06..e587e868e 100644 --- a/contracts/contracts/ccip/pools/types.tolk +++ b/contracts/contracts/ccip/pools/types.tolk @@ -6,7 +6,9 @@ import "../../lib/utils" const TOKEN_POOL_WAIT_FOR_FINALITY_FLAG: uint32 = 0; const TOKEN_POOL_DEFAULT_FINALITY: uint32 = TOKEN_POOL_WAIT_FOR_FINALITY_FLAG; +/// The division factor for bps. This also represents the maximum bps fee. const TOKEN_POOL_BPS_DIVIDER: uint256 = 10000; +const TOKEN_POOL_MAX_UINT8: uint8 = 0xFF; // 255 const TOKEN_POOL_MAX_UINT256: uint256 = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; const TOKEN_POOL_MAX_EXP10: uint8 = 77; From a6a62f543c0b194bcd776563da6c3450929b4402 Mon Sep 17 00:00:00 2001 From: Kristijan Date: Tue, 9 Jun 2026 21:21:22 +0200 Subject: [PATCH 05/16] Add getRMNProxy getters, regenerate bindings --- .../pools/burn_mint_token_pool/contract.tolk | 8 +- .../pools/burn_mint_token_pool/messages.tolk | 4 +- .../lock_release_token_pool/contract.tolk | 8 +- .../pools/lock_release_token_pool/events.tolk | 2 - .../lock_release_token_pool/messages.tolk | 4 +- contracts/contracts/ccip/pools/messages.tolk | 6 +- .../contracts/ccip/pools/token_pool.tolk | 14 +- contracts/contracts/ccip/pools/types.tolk | 9 +- .../gen/ccip/pools/BurnMintTokenPool.ts | 1185 +++++++++++++++-- .../gen/ccip/pools/LockReleaseTokenPool.ts | 1027 +++++++++++++- .../wrappers/gen/ccip/pools/TokenPool.ts | 361 ++--- 11 files changed, 2325 insertions(+), 303 deletions(-) diff --git a/contracts/contracts/ccip/pools/burn_mint_token_pool/contract.tolk b/contracts/contracts/ccip/pools/burn_mint_token_pool/contract.tolk index 6680c2706..24a498341 100644 --- a/contracts/contracts/ccip/pools/burn_mint_token_pool/contract.tolk +++ b/contracts/contracts/ccip/pools/burn_mint_token_pool/contract.tolk @@ -24,7 +24,7 @@ contract BurnMintTokenPool { description: "link.chain.ton.ccip.BurnMintTokenPool" storage: Storage - incomingMessages: BurnMintTokenPool_CustomInMessage // TODO: all incoming messages should be registered + incomingMessages: TokenPool_InMessage | BurnMintTokenPool_InMessage // TODO: all incoming messages should be registered } fun onInternalMessage(in: InMessage) { @@ -38,7 +38,7 @@ fun onInternalMessage(in: InMessage) { return; } - val msg = lazy BurnMintTokenPool_CustomInMessage.fromSlice(in.body); + val msg = lazy BurnMintTokenPool_InMessage.fromSlice(in.body); match (msg) { BurnMintTokenPool_ClaimMinterAdmin => { onClaimMinterAdmin(mutate st, in.senderAddress, msg); @@ -289,6 +289,10 @@ get fun hasPendingMint(queryId: uint64): bool { return Storage.load().pendingMints.get(queryId).isFound; } +get fun getRMNProxy(): address { + return Storage.load().poolData.load().adminConfig.load().rmnProxy; +} + get fun verifyNotCursed(subject: uint128): bool { return !Storage.load().poolData.load().mirroredPolicy.load().cursedSubjects.isCursed(subject); } diff --git a/contracts/contracts/ccip/pools/burn_mint_token_pool/messages.tolk b/contracts/contracts/ccip/pools/burn_mint_token_pool/messages.tolk index 82c179be9..ddbb10d11 100644 --- a/contracts/contracts/ccip/pools/burn_mint_token_pool/messages.tolk +++ b/contracts/contracts/ccip/pools/burn_mint_token_pool/messages.tolk @@ -6,7 +6,7 @@ struct (0x93c174a1) BurnMintTokenPool_ClaimMinterAdmin { queryId: uint64; } -type BurnMintTokenPool_CustomInMessage = - | BurnMintTokenPool_ClaimMinterAdmin +type BurnMintTokenPool_InMessage = | TransferNotificationForRecipient + | BurnMintTokenPool_ClaimMinterAdmin | ReturnExcessesBack; diff --git a/contracts/contracts/ccip/pools/lock_release_token_pool/contract.tolk b/contracts/contracts/ccip/pools/lock_release_token_pool/contract.tolk index f17da4a2c..9e8170ace 100644 --- a/contracts/contracts/ccip/pools/lock_release_token_pool/contract.tolk +++ b/contracts/contracts/ccip/pools/lock_release_token_pool/contract.tolk @@ -24,7 +24,7 @@ contract LockReleaseTokenPool { description: "link.chain.ton.ccip.LockReleaseTokenPool" storage: Storage - incomingMessages: LockReleaseTokenPool_CustomInMessage // TODO: all incoming messages should be registered + incomingMessages: TokenPool_InMessage | LockReleaseTokenPool_InMessage // TODO: all incoming messages should be registered } fun onInternalMessage(in: InMessage) { @@ -38,7 +38,7 @@ fun onInternalMessage(in: InMessage) { return; } - val msg = lazy LockReleaseTokenPool_CustomInMessage.fromSlice(in.body); + val msg = lazy LockReleaseTokenPool_InMessage.fromSlice(in.body); match (msg) { TransferNotificationForRecipient => { onJettonTransferNotification(mutate st, msg, in.senderAddress); @@ -264,6 +264,10 @@ get fun hasPendingRelease(queryId: uint64): bool { return Storage.load().pendingReleases.get(queryId).isFound; } +get fun getRMNProxy(): address { + return Storage.load().poolData.load().adminConfig.load().rmnProxy; +} + get fun verifyNotCursed(subject: uint128): bool { return !Storage.load().poolData.load().mirroredPolicy.load().cursedSubjects.isCursed(subject); } diff --git a/contracts/contracts/ccip/pools/lock_release_token_pool/events.tolk b/contracts/contracts/ccip/pools/lock_release_token_pool/events.tolk index 198d01e41..52817d6e9 100644 --- a/contracts/contracts/ccip/pools/lock_release_token_pool/events.tolk +++ b/contracts/contracts/ccip/pools/lock_release_token_pool/events.tolk @@ -37,5 +37,3 @@ struct RampAccessUpdated { onRamp: address? = null; offRamp: address? = null; } - -struct CursedSubjectsUpdated {} diff --git a/contracts/contracts/ccip/pools/lock_release_token_pool/messages.tolk b/contracts/contracts/ccip/pools/lock_release_token_pool/messages.tolk index 9248344b4..ae18afc9d 100644 --- a/contracts/contracts/ccip/pools/lock_release_token_pool/messages.tolk +++ b/contracts/contracts/ccip/pools/lock_release_token_pool/messages.tolk @@ -1,8 +1,8 @@ // SPDX-License-Identifier: BUSL-1.1 -import "../messages" import "../../../lib/jetton/messages.tolk" +import "../messages" -type LockReleaseTokenPool_CustomInMessage = +type LockReleaseTokenPool_InMessage = | TransferNotificationForRecipient | ReturnExcessesBack; diff --git a/contracts/contracts/ccip/pools/messages.tolk b/contracts/contracts/ccip/pools/messages.tolk index e56febca4..ea57343cd 100644 --- a/contracts/contracts/ccip/pools/messages.tolk +++ b/contracts/contracts/ccip/pools/messages.tolk @@ -1,4 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 +import "../../lib/jetton/messages.tolk" import "../../lib/utils" import "../common/types" import "../rmn_remote/lib" @@ -111,6 +112,7 @@ type TokenPool_InMessage = | TokenPool_SetRateLimitConfig | TokenPool_ApplyTokenTransferFeeConfigUpdates | TokenPool_UpdateRampAccess + | TokenPool_SetRMNProxy | TokenPool_UpdateCursedSubjects - | TokenPool_LockOrBurn - | TokenPool_ReleaseOrMint; + | TokenPool_ReleaseOrMint + | TransferNotificationForRecipient; // fwdPayload = TokenPool_LockOrBurn diff --git a/contracts/contracts/ccip/pools/token_pool.tolk b/contracts/contracts/ccip/pools/token_pool.tolk index 048b9625c..213d252ce 100644 --- a/contracts/contracts/ccip/pools/token_pool.tolk +++ b/contracts/contracts/ccip/pools/token_pool.tolk @@ -2,6 +2,7 @@ import "@stdlib/lisp-lists" import "../../lib/utils" +import "../../lib/jetton/messages.tolk" import "../../lib/access/ownable_2step.tolk" import "../common/types" import "../rmn_remote/lib" @@ -60,11 +61,8 @@ struct TokenPool { @inline fun TokenPool.load(context: T? = null, hooks: TokenPool_Hooks? = null): TokenPool { - return TokenPool { - data: TokenPool_Data.fromContractData(), - context, - hooks, - }; + val data = TokenPool_Data.fromContractData(); + return TokenPool { data, context, hooks }; } fun TokenPool.store(self) { @@ -487,8 +485,8 @@ fun TokenPool.onInternalMessage(mutate self, msgSender: address, msgValue: co self.context = self.hooks.handleReleaseOrMintMessage(self.context, msgSender, msg, prepared); return true; } - TokenPool_LockOrBurn => { - return false; // TODO: handle me, should be JettonNitification payload + TransferNotificationForRecipient => { + return false; // TODO: handle me, should host fwdPayload = TokenPool_LockOrBurn } else => { var adminConfig = self.data.adminConfig.load(); @@ -1043,7 +1041,7 @@ fun pow10(n: uint8): uint256 { var base: uint256 = 10; while (n > 0) { - if (n & 1 == 1) { + if ((n & 1) == 1) { // Check for potential overflow before multiplication assert(result == 0 || base <= TOKEN_POOL_MAX_UINT256 / result, TokenPool_Error.OverflowDetected); result *= base; diff --git a/contracts/contracts/ccip/pools/types.tolk b/contracts/contracts/ccip/pools/types.tolk index e587e868e..ae249d139 100644 --- a/contracts/contracts/ccip/pools/types.tolk +++ b/contracts/contracts/ccip/pools/types.tolk @@ -1,8 +1,9 @@ // SPDX-License-Identifier: BUSL-1.1 -import "rate_limiter" +import "../../lib/utils" import "../common/types" import "../rmn_remote/lib" -import "../../lib/utils" + +import "rate_limiter" const TOKEN_POOL_WAIT_FOR_FINALITY_FLAG: uint32 = 0; const TOKEN_POOL_DEFAULT_FINALITY: uint32 = TOKEN_POOL_WAIT_FOR_FINALITY_FLAG; @@ -130,8 +131,8 @@ enum TokenPool_MessageDirection: uint8 { struct TokenPool_LockOrBurnInV1 { receiver: Cell; // The recipient of the tokens on the destination chain. For EVM source chains, this is abi-encoded (32 bytes). - remoteChainSelector: uint64; // ─╮The chain ID of the destination chain. - originalSender: address; // ─╯The original sender of the tx on the source chain. + remoteChainSelector: uint64; // ─╮ The chain ID of the destination chain. + originalSender: address; // ─╯ The original sender of the tx on the source chain. amount: uint256; // The amount of tokens to lock or burn, denominated in the source token's decimals. localToken: address; // The address on this chain of the token to lock or burn. } diff --git a/contracts/wrappers/gen/ccip/pools/BurnMintTokenPool.ts b/contracts/wrappers/gen/ccip/pools/BurnMintTokenPool.ts index d6377e4dc..52264d2e2 100644 --- a/contracts/wrappers/gen/ccip/pools/BurnMintTokenPool.ts +++ b/contracts/wrappers/gen/ccip/pools/BurnMintTokenPool.ts @@ -183,6 +183,11 @@ type uint64 = bigint type uint128 = bigint type uint256 = bigint +/** + > type SnakedCell = cell + */ +export type SnakedCell = c.Cell + /** > struct Ownable2Step { > owner: address @@ -895,6 +900,51 @@ export const TokenPool_MirroredPolicy = { } } +/** + > struct TokenPool_RampUpdate { + > remoteChainSelector: uint64 + > onRamp: address? + > offRamp: address? + > } + */ +export interface TokenPool_RampUpdate { + readonly $: 'TokenPool_RampUpdate' + remoteChainSelector: uint64 + onRamp: c.Address | null /* = null */ + offRamp: c.Address | null /* = null */ +} + +export const TokenPool_RampUpdate = { + create(args: { + remoteChainSelector: uint64 + onRamp?: c.Address | null /* = null */ + offRamp?: c.Address | null /* = null */ + }): TokenPool_RampUpdate { + return { + $: 'TokenPool_RampUpdate', + onRamp: null, + offRamp: null, + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_RampUpdate { + return { + $: 'TokenPool_RampUpdate', + remoteChainSelector: s.loadUintBig(64), + onRamp: s.loadMaybeAddress(), + offRamp: s.loadMaybeAddress(), + } + }, + store(self: TokenPool_RampUpdate, b: c.Builder): void { + b.storeUint(self.remoteChainSelector, 64); + b.storeAddress(self.onRamp); + b.storeAddress(self.offRamp); + }, + toCell(self: TokenPool_RampUpdate): c.Cell { + return makeCellFrom(self, TokenPool_RampUpdate.store); + } +} + /** > struct TokenPool_RateLimiterPair { > outbound: Cell @@ -933,6 +983,92 @@ export const TokenPool_RateLimiterPair = { } } +/** + > struct TokenPool_RateLimitConfigPair { + > outbound: Cell + > inbound: Cell + > } + */ +export interface TokenPool_RateLimitConfigPair { + readonly $: 'TokenPool_RateLimitConfigPair' + outbound: CellRef + inbound: CellRef +} + +export const TokenPool_RateLimitConfigPair = { + create(args: { + outbound: CellRef + inbound: CellRef + }): TokenPool_RateLimitConfigPair { + return { + $: 'TokenPool_RateLimitConfigPair', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_RateLimitConfigPair { + return { + $: 'TokenPool_RateLimitConfigPair', + outbound: loadCellRef(s, RateLimiter_Config.fromSlice), + inbound: loadCellRef(s, RateLimiter_Config.fromSlice), + } + }, + store(self: TokenPool_RateLimitConfigPair, b: c.Builder): void { + storeCellRef(self.outbound, b, RateLimiter_Config.store); + storeCellRef(self.inbound, b, RateLimiter_Config.store); + }, + toCell(self: TokenPool_RateLimitConfigPair): c.Cell { + return makeCellFrom(self, TokenPool_RateLimitConfigPair.store); + } +} + +/** + > struct TokenPool_ChainUpdate { + > remoteChainSelector: uint64 + > remotePoolAddresses: SnakedCell + > remoteTokenAddress: Cell + > rateLimitConfigs: Cell + > } + */ +export interface TokenPool_ChainUpdate { + readonly $: 'TokenPool_ChainUpdate' + remoteChainSelector: uint64 + remotePoolAddresses: SnakedCell + remoteTokenAddress: CellRef + rateLimitConfigs: CellRef +} + +export const TokenPool_ChainUpdate = { + create(args: { + remoteChainSelector: uint64 + remotePoolAddresses: SnakedCell + remoteTokenAddress: CellRef + rateLimitConfigs: CellRef + }): TokenPool_ChainUpdate { + return { + $: 'TokenPool_ChainUpdate', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_ChainUpdate { + return { + $: 'TokenPool_ChainUpdate', + remoteChainSelector: s.loadUintBig(64), + remotePoolAddresses: s.loadRef(), + remoteTokenAddress: loadCellRef(s, CrossChainAddress.fromSlice), + rateLimitConfigs: loadCellRef(s, TokenPool_RateLimitConfigPair.fromSlice), + } + }, + store(self: TokenPool_ChainUpdate, b: c.Builder): void { + b.storeUint(self.remoteChainSelector, 64); + b.storeRef(self.remotePoolAddresses); + storeCellRef(self.remoteTokenAddress, b, CrossChainAddress.store); + storeCellRef(self.rateLimitConfigs, b, TokenPool_RateLimitConfigPair.store); + }, + toCell(self: TokenPool_ChainUpdate): c.Cell { + return makeCellFrom(self, TokenPool_ChainUpdate.store); + } +} + /** > struct TokenPool_RemoteChainConfig { > remoteTokenAddress: Cell @@ -987,6 +1123,92 @@ export const TokenPool_RemoteChainConfig = { } } +/** + > struct TokenPool_RateLimitConfigArgs { + > remoteChainSelector: uint64 + > fastFinality: bool + > outboundRateLimiterConfig: Cell + > inboundRateLimiterConfig: Cell + > } + */ +export interface TokenPool_RateLimitConfigArgs { + readonly $: 'TokenPool_RateLimitConfigArgs' + remoteChainSelector: uint64 + fastFinality: boolean + outboundRateLimiterConfig: CellRef + inboundRateLimiterConfig: CellRef +} + +export const TokenPool_RateLimitConfigArgs = { + create(args: { + remoteChainSelector: uint64 + fastFinality: boolean + outboundRateLimiterConfig: CellRef + inboundRateLimiterConfig: CellRef + }): TokenPool_RateLimitConfigArgs { + return { + $: 'TokenPool_RateLimitConfigArgs', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_RateLimitConfigArgs { + return { + $: 'TokenPool_RateLimitConfigArgs', + remoteChainSelector: s.loadUintBig(64), + fastFinality: s.loadBoolean(), + outboundRateLimiterConfig: loadCellRef(s, RateLimiter_Config.fromSlice), + inboundRateLimiterConfig: loadCellRef(s, RateLimiter_Config.fromSlice), + } + }, + store(self: TokenPool_RateLimitConfigArgs, b: c.Builder): void { + b.storeUint(self.remoteChainSelector, 64); + b.storeBit(self.fastFinality); + storeCellRef(self.outboundRateLimiterConfig, b, RateLimiter_Config.store); + storeCellRef(self.inboundRateLimiterConfig, b, RateLimiter_Config.store); + }, + toCell(self: TokenPool_RateLimitConfigArgs): c.Cell { + return makeCellFrom(self, TokenPool_RateLimitConfigArgs.store); + } +} + +/** + > struct TokenPool_TokenTransferFeeConfigArgs { + > destChainSelector: uint64 + > tokenTransferFeeConfig: TokenPool_TokenTransferFeeConfig + > } + */ +export interface TokenPool_TokenTransferFeeConfigArgs { + readonly $: 'TokenPool_TokenTransferFeeConfigArgs' + destChainSelector: uint64 + tokenTransferFeeConfig: TokenPool_TokenTransferFeeConfig +} + +export const TokenPool_TokenTransferFeeConfigArgs = { + create(args: { + destChainSelector: uint64 + tokenTransferFeeConfig: TokenPool_TokenTransferFeeConfig + }): TokenPool_TokenTransferFeeConfigArgs { + return { + $: 'TokenPool_TokenTransferFeeConfigArgs', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_TokenTransferFeeConfigArgs { + return { + $: 'TokenPool_TokenTransferFeeConfigArgs', + destChainSelector: s.loadUintBig(64), + tokenTransferFeeConfig: TokenPool_TokenTransferFeeConfig.fromSlice(s), + } + }, + store(self: TokenPool_TokenTransferFeeConfigArgs, b: c.Builder): void { + b.storeUint(self.destChainSelector, 64); + TokenPool_TokenTransferFeeConfig.store(self.tokenTransferFeeConfig, b); + }, + toCell(self: TokenPool_TokenTransferFeeConfigArgs): c.Cell { + return makeCellFrom(self, TokenPool_TokenTransferFeeConfigArgs.store); + } +} + /** > struct TokenPool_TokenTransferFeeConfig { > isEnabled: bool @@ -1247,179 +1469,684 @@ export const TokenPool_ReleaseOrMintOutV1 = { } /** - > struct (0x19e65bea) TokenPool_LockOrBurnResponse { + > struct (0xdc0b6ff5) TokenPool_ApplyChainUpdates { > queryId: uint64 - > out: Cell - > destTokenAmount: uint256 + > remoteChainSelectorsToRemove: SnakedCell + > chainsToAdd: SnakedCell > } */ -export interface TokenPool_LockOrBurnResponse { - readonly $: 'TokenPool_LockOrBurnResponse' +export interface TokenPool_ApplyChainUpdates { + readonly $: 'TokenPool_ApplyChainUpdates' queryId: uint64 - out: CellRef - destTokenAmount: uint256 + remoteChainSelectorsToRemove: SnakedCell + chainsToAdd: SnakedCell } -export const TokenPool_LockOrBurnResponse = { - PREFIX: 0x19e65bea, +export const TokenPool_ApplyChainUpdates = { + PREFIX: 0xdc0b6ff5, create(args: { queryId: uint64 - out: CellRef - destTokenAmount: uint256 - }): TokenPool_LockOrBurnResponse { + remoteChainSelectorsToRemove: SnakedCell + chainsToAdd: SnakedCell + }): TokenPool_ApplyChainUpdates { return { - $: 'TokenPool_LockOrBurnResponse', + $: 'TokenPool_ApplyChainUpdates', ...args } }, - fromSlice(s: c.Slice): TokenPool_LockOrBurnResponse { - loadAndCheckPrefix32(s, 0x19e65bea, 'TokenPool_LockOrBurnResponse'); + fromSlice(s: c.Slice): TokenPool_ApplyChainUpdates { + loadAndCheckPrefix32(s, 0xdc0b6ff5, 'TokenPool_ApplyChainUpdates'); return { - $: 'TokenPool_LockOrBurnResponse', + $: 'TokenPool_ApplyChainUpdates', queryId: s.loadUintBig(64), - out: loadCellRef(s, TokenPool_LockOrBurnOutV1.fromSlice), - destTokenAmount: s.loadUintBig(256), + remoteChainSelectorsToRemove: s.loadRef(), + chainsToAdd: s.loadRef(), } }, - store(self: TokenPool_LockOrBurnResponse, b: c.Builder): void { - b.storeUint(0x19e65bea, 32); + store(self: TokenPool_ApplyChainUpdates, b: c.Builder): void { + b.storeUint(0xdc0b6ff5, 32); b.storeUint(self.queryId, 64); - storeCellRef(self.out, b, TokenPool_LockOrBurnOutV1.store); - b.storeUint(self.destTokenAmount, 256); + b.storeRef(self.remoteChainSelectorsToRemove); + b.storeRef(self.chainsToAdd); }, - toCell(self: TokenPool_LockOrBurnResponse): c.Cell { - return makeCellFrom(self, TokenPool_LockOrBurnResponse.store); + toCell(self: TokenPool_ApplyChainUpdates): c.Cell { + return makeCellFrom(self, TokenPool_ApplyChainUpdates.store); } } /** - > struct (0x7ec43aee) TokenPool_ReleaseOrMintResponse { + > struct (0x5fd2c8b6) TokenPool_AddRemotePool { > queryId: uint64 - > out: Cell + > remoteChainSelector: uint64 + > remotePoolAddress: Cell > } */ -export interface TokenPool_ReleaseOrMintResponse { - readonly $: 'TokenPool_ReleaseOrMintResponse' +export interface TokenPool_AddRemotePool { + readonly $: 'TokenPool_AddRemotePool' queryId: uint64 - out: CellRef + remoteChainSelector: uint64 + remotePoolAddress: CellRef } -export const TokenPool_ReleaseOrMintResponse = { - PREFIX: 0x7ec43aee, +export const TokenPool_AddRemotePool = { + PREFIX: 0x5fd2c8b6, create(args: { queryId: uint64 - out: CellRef - }): TokenPool_ReleaseOrMintResponse { + remoteChainSelector: uint64 + remotePoolAddress: CellRef + }): TokenPool_AddRemotePool { return { - $: 'TokenPool_ReleaseOrMintResponse', + $: 'TokenPool_AddRemotePool', ...args } }, - fromSlice(s: c.Slice): TokenPool_ReleaseOrMintResponse { - loadAndCheckPrefix32(s, 0x7ec43aee, 'TokenPool_ReleaseOrMintResponse'); + fromSlice(s: c.Slice): TokenPool_AddRemotePool { + loadAndCheckPrefix32(s, 0x5fd2c8b6, 'TokenPool_AddRemotePool'); return { - $: 'TokenPool_ReleaseOrMintResponse', + $: 'TokenPool_AddRemotePool', queryId: s.loadUintBig(64), - out: loadCellRef(s, TokenPool_ReleaseOrMintOutV1.fromSlice), + remoteChainSelector: s.loadUintBig(64), + remotePoolAddress: loadCellRef(s, CrossChainAddress.fromSlice), } }, - store(self: TokenPool_ReleaseOrMintResponse, b: c.Builder): void { - b.storeUint(0x7ec43aee, 32); + store(self: TokenPool_AddRemotePool, b: c.Builder): void { + b.storeUint(0x5fd2c8b6, 32); b.storeUint(self.queryId, 64); - storeCellRef(self.out, b, TokenPool_ReleaseOrMintOutV1.store); + b.storeUint(self.remoteChainSelector, 64); + storeCellRef(self.remotePoolAddress, b, CrossChainAddress.store); }, - toCell(self: TokenPool_ReleaseOrMintResponse): c.Cell { - return makeCellFrom(self, TokenPool_ReleaseOrMintResponse.store); + toCell(self: TokenPool_AddRemotePool): c.Cell { + return makeCellFrom(self, TokenPool_AddRemotePool.store); } } /** - > struct TokenPool_LockedOrBurnedDetails { - > token: address - > sender: address - > amount: uint256 + > struct (0xdbf0a2df) TokenPool_RemoveRemotePool { + > queryId: uint64 + > remoteChainSelector: uint64 + > remotePoolAddress: Cell > } */ -export interface TokenPool_LockedOrBurnedDetails { - readonly $: 'TokenPool_LockedOrBurnedDetails' - token: c.Address - sender: c.Address - amount: uint256 +export interface TokenPool_RemoveRemotePool { + readonly $: 'TokenPool_RemoveRemotePool' + queryId: uint64 + remoteChainSelector: uint64 + remotePoolAddress: CellRef } -export const TokenPool_LockedOrBurnedDetails = { +export const TokenPool_RemoveRemotePool = { + PREFIX: 0xdbf0a2df, + create(args: { - token: c.Address - sender: c.Address - amount: uint256 - }): TokenPool_LockedOrBurnedDetails { + queryId: uint64 + remoteChainSelector: uint64 + remotePoolAddress: CellRef + }): TokenPool_RemoveRemotePool { return { - $: 'TokenPool_LockedOrBurnedDetails', + $: 'TokenPool_RemoveRemotePool', ...args } }, - fromSlice(s: c.Slice): TokenPool_LockedOrBurnedDetails { + fromSlice(s: c.Slice): TokenPool_RemoveRemotePool { + loadAndCheckPrefix32(s, 0xdbf0a2df, 'TokenPool_RemoveRemotePool'); return { - $: 'TokenPool_LockedOrBurnedDetails', - token: s.loadAddress(), - sender: s.loadAddress(), - amount: s.loadUintBig(256), + $: 'TokenPool_RemoveRemotePool', + queryId: s.loadUintBig(64), + remoteChainSelector: s.loadUintBig(64), + remotePoolAddress: loadCellRef(s, CrossChainAddress.fromSlice), } }, - store(self: TokenPool_LockedOrBurnedDetails, b: c.Builder): void { - b.storeAddress(self.token); - b.storeAddress(self.sender); - b.storeUint(self.amount, 256); + store(self: TokenPool_RemoveRemotePool, b: c.Builder): void { + b.storeUint(0xdbf0a2df, 32); + b.storeUint(self.queryId, 64); + b.storeUint(self.remoteChainSelector, 64); + storeCellRef(self.remotePoolAddress, b, CrossChainAddress.store); }, - toCell(self: TokenPool_LockedOrBurnedDetails): c.Cell { - return makeCellFrom(self, TokenPool_LockedOrBurnedDetails.store); + toCell(self: TokenPool_RemoveRemotePool): c.Cell { + return makeCellFrom(self, TokenPool_RemoveRemotePool.store); } } /** - > struct TokenPool_LockedOrBurned { - > remoteChainSelector: uint64 - > details: Cell + > struct (0x4eea060b) TokenPool_SetDynamicConfig { + > queryId: uint64 + > router: address + > rateLimitAdmin: address? + > feeAdmin: address? > } */ -export interface TokenPool_LockedOrBurned { - readonly $: 'TokenPool_LockedOrBurned' - remoteChainSelector: uint64 - details: CellRef +export interface TokenPool_SetDynamicConfig { + readonly $: 'TokenPool_SetDynamicConfig' + queryId: uint64 + router: c.Address + rateLimitAdmin: c.Address | null /* = null */ + feeAdmin: c.Address | null /* = null */ } -export const TokenPool_LockedOrBurned = { +export const TokenPool_SetDynamicConfig = { + PREFIX: 0x4eea060b, + create(args: { - remoteChainSelector: uint64 - details: CellRef - }): TokenPool_LockedOrBurned { + queryId: uint64 + router: c.Address + rateLimitAdmin?: c.Address | null /* = null */ + feeAdmin?: c.Address | null /* = null */ + }): TokenPool_SetDynamicConfig { return { - $: 'TokenPool_LockedOrBurned', + $: 'TokenPool_SetDynamicConfig', + rateLimitAdmin: null, + feeAdmin: null, ...args } }, - fromSlice(s: c.Slice): TokenPool_LockedOrBurned { + fromSlice(s: c.Slice): TokenPool_SetDynamicConfig { + loadAndCheckPrefix32(s, 0x4eea060b, 'TokenPool_SetDynamicConfig'); return { - $: 'TokenPool_LockedOrBurned', - remoteChainSelector: s.loadUintBig(64), - details: loadCellRef(s, TokenPool_LockedOrBurnedDetails.fromSlice), + $: 'TokenPool_SetDynamicConfig', + queryId: s.loadUintBig(64), + router: s.loadAddress(), + rateLimitAdmin: s.loadMaybeAddress(), + feeAdmin: s.loadMaybeAddress(), } }, - store(self: TokenPool_LockedOrBurned, b: c.Builder): void { - b.storeUint(self.remoteChainSelector, 64); - storeCellRef(self.details, b, TokenPool_LockedOrBurnedDetails.store); + store(self: TokenPool_SetDynamicConfig, b: c.Builder): void { + b.storeUint(0x4eea060b, 32); + b.storeUint(self.queryId, 64); + b.storeAddress(self.router); + b.storeAddress(self.rateLimitAdmin); + b.storeAddress(self.feeAdmin); }, - toCell(self: TokenPool_LockedOrBurned): c.Cell { - return makeCellFrom(self, TokenPool_LockedOrBurned.store); + toCell(self: TokenPool_SetDynamicConfig): c.Cell { + return makeCellFrom(self, TokenPool_SetDynamicConfig.store); } } /** - > struct TokenPool_ReleasedOrMintedParticipants { - > sender: address - > recipient: address + > struct (0x29b46fc6) TokenPool_SetAllowedFinalityConfig { + > queryId: uint64 + > allowedFinalityConfig: uint32 + > } + */ +export interface TokenPool_SetAllowedFinalityConfig { + readonly $: 'TokenPool_SetAllowedFinalityConfig' + queryId: uint64 + allowedFinalityConfig: uint32 +} + +export const TokenPool_SetAllowedFinalityConfig = { + PREFIX: 0x29b46fc6, + + create(args: { + queryId: uint64 + allowedFinalityConfig: uint32 + }): TokenPool_SetAllowedFinalityConfig { + return { + $: 'TokenPool_SetAllowedFinalityConfig', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_SetAllowedFinalityConfig { + loadAndCheckPrefix32(s, 0x29b46fc6, 'TokenPool_SetAllowedFinalityConfig'); + return { + $: 'TokenPool_SetAllowedFinalityConfig', + queryId: s.loadUintBig(64), + allowedFinalityConfig: s.loadUintBig(32), + } + }, + store(self: TokenPool_SetAllowedFinalityConfig, b: c.Builder): void { + b.storeUint(0x29b46fc6, 32); + b.storeUint(self.queryId, 64); + b.storeUint(self.allowedFinalityConfig, 32); + }, + toCell(self: TokenPool_SetAllowedFinalityConfig): c.Cell { + return makeCellFrom(self, TokenPool_SetAllowedFinalityConfig.store); + } +} + +/** + > struct (0x3a028da2) TokenPool_SetRateLimitConfig { + > queryId: uint64 + > updates: SnakedCell + > } + */ +export interface TokenPool_SetRateLimitConfig { + readonly $: 'TokenPool_SetRateLimitConfig' + queryId: uint64 + updates: SnakedCell +} + +export const TokenPool_SetRateLimitConfig = { + PREFIX: 0x3a028da2, + + create(args: { + queryId: uint64 + updates: SnakedCell + }): TokenPool_SetRateLimitConfig { + return { + $: 'TokenPool_SetRateLimitConfig', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_SetRateLimitConfig { + loadAndCheckPrefix32(s, 0x3a028da2, 'TokenPool_SetRateLimitConfig'); + return { + $: 'TokenPool_SetRateLimitConfig', + queryId: s.loadUintBig(64), + updates: s.loadRef(), + } + }, + store(self: TokenPool_SetRateLimitConfig, b: c.Builder): void { + b.storeUint(0x3a028da2, 32); + b.storeUint(self.queryId, 64); + b.storeRef(self.updates); + }, + toCell(self: TokenPool_SetRateLimitConfig): c.Cell { + return makeCellFrom(self, TokenPool_SetRateLimitConfig.store); + } +} + +/** + > struct (0x10c4b4a1) TokenPool_ApplyTokenTransferFeeConfigUpdates { + > queryId: uint64 + > updates: SnakedCell + > disableChainSelectors: SnakedCell + > } + */ +export interface TokenPool_ApplyTokenTransferFeeConfigUpdates { + readonly $: 'TokenPool_ApplyTokenTransferFeeConfigUpdates' + queryId: uint64 + updates: SnakedCell + disableChainSelectors: SnakedCell +} + +export const TokenPool_ApplyTokenTransferFeeConfigUpdates = { + PREFIX: 0x10c4b4a1, + + create(args: { + queryId: uint64 + updates: SnakedCell + disableChainSelectors: SnakedCell + }): TokenPool_ApplyTokenTransferFeeConfigUpdates { + return { + $: 'TokenPool_ApplyTokenTransferFeeConfigUpdates', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_ApplyTokenTransferFeeConfigUpdates { + loadAndCheckPrefix32(s, 0x10c4b4a1, 'TokenPool_ApplyTokenTransferFeeConfigUpdates'); + return { + $: 'TokenPool_ApplyTokenTransferFeeConfigUpdates', + queryId: s.loadUintBig(64), + updates: s.loadRef(), + disableChainSelectors: s.loadRef(), + } + }, + store(self: TokenPool_ApplyTokenTransferFeeConfigUpdates, b: c.Builder): void { + b.storeUint(0x10c4b4a1, 32); + b.storeUint(self.queryId, 64); + b.storeRef(self.updates); + b.storeRef(self.disableChainSelectors); + }, + toCell(self: TokenPool_ApplyTokenTransferFeeConfigUpdates): c.Cell { + return makeCellFrom(self, TokenPool_ApplyTokenTransferFeeConfigUpdates.store); + } +} + +/** + > struct (0x7a9c4aa5) TokenPool_UpdateRampAccess { + > queryId: uint64 + > updates: SnakedCell + > } + */ +export interface TokenPool_UpdateRampAccess { + readonly $: 'TokenPool_UpdateRampAccess' + queryId: uint64 + updates: SnakedCell +} + +export const TokenPool_UpdateRampAccess = { + PREFIX: 0x7a9c4aa5, + + create(args: { + queryId: uint64 + updates: SnakedCell + }): TokenPool_UpdateRampAccess { + return { + $: 'TokenPool_UpdateRampAccess', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_UpdateRampAccess { + loadAndCheckPrefix32(s, 0x7a9c4aa5, 'TokenPool_UpdateRampAccess'); + return { + $: 'TokenPool_UpdateRampAccess', + queryId: s.loadUintBig(64), + updates: s.loadRef(), + } + }, + store(self: TokenPool_UpdateRampAccess, b: c.Builder): void { + b.storeUint(0x7a9c4aa5, 32); + b.storeUint(self.queryId, 64); + b.storeRef(self.updates); + }, + toCell(self: TokenPool_UpdateRampAccess): c.Cell { + return makeCellFrom(self, TokenPool_UpdateRampAccess.store); + } +} + +/** + > struct (0x12345678) TokenPool_SetRMNProxy { + > queryId: uint64 + > rmnProxy: address + > } + */ +export interface TokenPool_SetRMNProxy { + readonly $: 'TokenPool_SetRMNProxy' + queryId: uint64 + rmnProxy: c.Address +} + +export const TokenPool_SetRMNProxy = { + PREFIX: 0x12345678, + + create(args: { + queryId: uint64 + rmnProxy: c.Address + }): TokenPool_SetRMNProxy { + return { + $: 'TokenPool_SetRMNProxy', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_SetRMNProxy { + loadAndCheckPrefix32(s, 0x12345678, 'TokenPool_SetRMNProxy'); + return { + $: 'TokenPool_SetRMNProxy', + queryId: s.loadUintBig(64), + rmnProxy: s.loadAddress(), + } + }, + store(self: TokenPool_SetRMNProxy, b: c.Builder): void { + b.storeUint(0x12345678, 32); + b.storeUint(self.queryId, 64); + b.storeAddress(self.rmnProxy); + }, + toCell(self: TokenPool_SetRMNProxy): c.Cell { + return makeCellFrom(self, TokenPool_SetRMNProxy.store); + } +} + +/** + > struct (0x823dadf2) TokenPool_UpdateCursedSubjects { + > queryId: uint64 + > cursedSubjects: CursedSubjects + > } + */ +export interface TokenPool_UpdateCursedSubjects { + readonly $: 'TokenPool_UpdateCursedSubjects' + queryId: uint64 + cursedSubjects: CursedSubjects +} + +export const TokenPool_UpdateCursedSubjects = { + PREFIX: 0x823dadf2, + + create(args: { + queryId: uint64 + cursedSubjects: CursedSubjects + }): TokenPool_UpdateCursedSubjects { + return { + $: 'TokenPool_UpdateCursedSubjects', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_UpdateCursedSubjects { + loadAndCheckPrefix32(s, 0x823dadf2, 'TokenPool_UpdateCursedSubjects'); + return { + $: 'TokenPool_UpdateCursedSubjects', + queryId: s.loadUintBig(64), + cursedSubjects: CursedSubjects.fromSlice(s), + } + }, + store(self: TokenPool_UpdateCursedSubjects, b: c.Builder): void { + b.storeUint(0x823dadf2, 32); + b.storeUint(self.queryId, 64); + CursedSubjects.store(self.cursedSubjects, b); + }, + toCell(self: TokenPool_UpdateCursedSubjects): c.Cell { + return makeCellFrom(self, TokenPool_UpdateCursedSubjects.store); + } +} + +/** + > struct (0x19e65bea) TokenPool_LockOrBurnResponse { + > queryId: uint64 + > out: Cell + > destTokenAmount: uint256 + > } + */ +export interface TokenPool_LockOrBurnResponse { + readonly $: 'TokenPool_LockOrBurnResponse' + queryId: uint64 + out: CellRef + destTokenAmount: uint256 +} + +export const TokenPool_LockOrBurnResponse = { + PREFIX: 0x19e65bea, + + create(args: { + queryId: uint64 + out: CellRef + destTokenAmount: uint256 + }): TokenPool_LockOrBurnResponse { + return { + $: 'TokenPool_LockOrBurnResponse', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_LockOrBurnResponse { + loadAndCheckPrefix32(s, 0x19e65bea, 'TokenPool_LockOrBurnResponse'); + return { + $: 'TokenPool_LockOrBurnResponse', + queryId: s.loadUintBig(64), + out: loadCellRef(s, TokenPool_LockOrBurnOutV1.fromSlice), + destTokenAmount: s.loadUintBig(256), + } + }, + store(self: TokenPool_LockOrBurnResponse, b: c.Builder): void { + b.storeUint(0x19e65bea, 32); + b.storeUint(self.queryId, 64); + storeCellRef(self.out, b, TokenPool_LockOrBurnOutV1.store); + b.storeUint(self.destTokenAmount, 256); + }, + toCell(self: TokenPool_LockOrBurnResponse): c.Cell { + return makeCellFrom(self, TokenPool_LockOrBurnResponse.store); + } +} + +/** + > struct (0x7d0ffd89) TokenPool_ReleaseOrMint { + > queryId: uint64 + > request: Cell + > requestedFinalityConfig: uint32 + > replyTo: address? + > } + */ +export interface TokenPool_ReleaseOrMint { + readonly $: 'TokenPool_ReleaseOrMint' + queryId: uint64 + request: CellRef + requestedFinalityConfig: uint32 + replyTo: c.Address | null /* = null */ +} + +export const TokenPool_ReleaseOrMint = { + PREFIX: 0x7d0ffd89, + + create(args: { + queryId: uint64 + request: CellRef + requestedFinalityConfig: uint32 + replyTo?: c.Address | null /* = null */ + }): TokenPool_ReleaseOrMint { + return { + $: 'TokenPool_ReleaseOrMint', + replyTo: null, + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_ReleaseOrMint { + loadAndCheckPrefix32(s, 0x7d0ffd89, 'TokenPool_ReleaseOrMint'); + return { + $: 'TokenPool_ReleaseOrMint', + queryId: s.loadUintBig(64), + request: loadCellRef(s, TokenPool_ReleaseOrMintInV1.fromSlice), + requestedFinalityConfig: s.loadUintBig(32), + replyTo: s.loadMaybeAddress(), + } + }, + store(self: TokenPool_ReleaseOrMint, b: c.Builder): void { + b.storeUint(0x7d0ffd89, 32); + b.storeUint(self.queryId, 64); + storeCellRef(self.request, b, TokenPool_ReleaseOrMintInV1.store); + b.storeUint(self.requestedFinalityConfig, 32); + b.storeAddress(self.replyTo); + }, + toCell(self: TokenPool_ReleaseOrMint): c.Cell { + return makeCellFrom(self, TokenPool_ReleaseOrMint.store); + } +} + +/** + > struct (0x7ec43aee) TokenPool_ReleaseOrMintResponse { + > queryId: uint64 + > out: Cell + > } + */ +export interface TokenPool_ReleaseOrMintResponse { + readonly $: 'TokenPool_ReleaseOrMintResponse' + queryId: uint64 + out: CellRef +} + +export const TokenPool_ReleaseOrMintResponse = { + PREFIX: 0x7ec43aee, + + create(args: { + queryId: uint64 + out: CellRef + }): TokenPool_ReleaseOrMintResponse { + return { + $: 'TokenPool_ReleaseOrMintResponse', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_ReleaseOrMintResponse { + loadAndCheckPrefix32(s, 0x7ec43aee, 'TokenPool_ReleaseOrMintResponse'); + return { + $: 'TokenPool_ReleaseOrMintResponse', + queryId: s.loadUintBig(64), + out: loadCellRef(s, TokenPool_ReleaseOrMintOutV1.fromSlice), + } + }, + store(self: TokenPool_ReleaseOrMintResponse, b: c.Builder): void { + b.storeUint(0x7ec43aee, 32); + b.storeUint(self.queryId, 64); + storeCellRef(self.out, b, TokenPool_ReleaseOrMintOutV1.store); + }, + toCell(self: TokenPool_ReleaseOrMintResponse): c.Cell { + return makeCellFrom(self, TokenPool_ReleaseOrMintResponse.store); + } +} + +/** + > struct TokenPool_LockedOrBurnedDetails { + > token: address + > sender: address + > amount: uint256 + > } + */ +export interface TokenPool_LockedOrBurnedDetails { + readonly $: 'TokenPool_LockedOrBurnedDetails' + token: c.Address + sender: c.Address + amount: uint256 +} + +export const TokenPool_LockedOrBurnedDetails = { + create(args: { + token: c.Address + sender: c.Address + amount: uint256 + }): TokenPool_LockedOrBurnedDetails { + return { + $: 'TokenPool_LockedOrBurnedDetails', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_LockedOrBurnedDetails { + return { + $: 'TokenPool_LockedOrBurnedDetails', + token: s.loadAddress(), + sender: s.loadAddress(), + amount: s.loadUintBig(256), + } + }, + store(self: TokenPool_LockedOrBurnedDetails, b: c.Builder): void { + b.storeAddress(self.token); + b.storeAddress(self.sender); + b.storeUint(self.amount, 256); + }, + toCell(self: TokenPool_LockedOrBurnedDetails): c.Cell { + return makeCellFrom(self, TokenPool_LockedOrBurnedDetails.store); + } +} + +/** + > struct TokenPool_LockedOrBurned { + > remoteChainSelector: uint64 + > details: Cell + > } + */ +export interface TokenPool_LockedOrBurned { + readonly $: 'TokenPool_LockedOrBurned' + remoteChainSelector: uint64 + details: CellRef +} + +export const TokenPool_LockedOrBurned = { + create(args: { + remoteChainSelector: uint64 + details: CellRef + }): TokenPool_LockedOrBurned { + return { + $: 'TokenPool_LockedOrBurned', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_LockedOrBurned { + return { + $: 'TokenPool_LockedOrBurned', + remoteChainSelector: s.loadUintBig(64), + details: loadCellRef(s, TokenPool_LockedOrBurnedDetails.fromSlice), + } + }, + store(self: TokenPool_LockedOrBurned, b: c.Builder): void { + b.storeUint(self.remoteChainSelector, 64); + storeCellRef(self.details, b, TokenPool_LockedOrBurnedDetails.store); + }, + toCell(self: TokenPool_LockedOrBurned): c.Cell { + return makeCellFrom(self, TokenPool_LockedOrBurned.store); + } +} + +/** + > struct TokenPool_ReleasedOrMintedParticipants { + > sender: address + > recipient: address > } */ export interface TokenPool_ReleasedOrMintedParticipants { @@ -2046,6 +2773,49 @@ export const CrossChainAddress = { } } +/** + > struct RateLimiter_Config { + > isEnabled: bool + > capacity: uint256 + > rate: uint256 + > } + */ +export interface RateLimiter_Config { + readonly $: 'RateLimiter_Config' + isEnabled: boolean + capacity: uint256 + rate: uint256 +} + +export const RateLimiter_Config = { + create(args: { + isEnabled: boolean + capacity: uint256 + rate: uint256 + }): RateLimiter_Config { + return { + $: 'RateLimiter_Config', + ...args + } + }, + fromSlice(s: c.Slice): RateLimiter_Config { + return { + $: 'RateLimiter_Config', + isEnabled: s.loadBoolean(), + capacity: s.loadUintBig(256), + rate: s.loadUintBig(256), + } + }, + store(self: RateLimiter_Config, b: c.Builder): void { + b.storeBit(self.isEnabled); + b.storeUint(self.capacity, 256); + b.storeUint(self.rate, 256); + }, + toCell(self: RateLimiter_Config): c.Cell { + return makeCellFrom(self, RateLimiter_Config.store); + } +} + /** > struct RateLimiter_TokenBucket { > tokens: uint256 @@ -2138,7 +2908,7 @@ function calculateDeployedAddress(code: c.Cell, data: c.Cell, options: DeployedA } export class BurnMintTokenPool implements c.Contract { - static CodeCell = c.Cell.fromBase64('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'); + static CodeCell = c.Cell.fromBase64('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'); static Errors = { 'Common_Error.CrossChainAddressOutOfRange': 5, @@ -2209,10 +2979,89 @@ export class BurnMintTokenPool implements c.Contract { return new BurnMintTokenPool(address, initialState); } - static createCellOfBurnMintTokenPoolClaimMinterAdmin(body: { + static createCellOfTokenPoolApplyChainUpdates(body: { queryId: uint64 + remoteChainSelectorsToRemove: SnakedCell + chainsToAdd: SnakedCell }) { - return BurnMintTokenPool_ClaimMinterAdmin.toCell(BurnMintTokenPool_ClaimMinterAdmin.create(body)); + return TokenPool_ApplyChainUpdates.toCell(TokenPool_ApplyChainUpdates.create(body)); + } + + static createCellOfTokenPoolAddRemotePool(body: { + queryId: uint64 + remoteChainSelector: uint64 + remotePoolAddress: CellRef + }) { + return TokenPool_AddRemotePool.toCell(TokenPool_AddRemotePool.create(body)); + } + + static createCellOfTokenPoolRemoveRemotePool(body: { + queryId: uint64 + remoteChainSelector: uint64 + remotePoolAddress: CellRef + }) { + return TokenPool_RemoveRemotePool.toCell(TokenPool_RemoveRemotePool.create(body)); + } + + static createCellOfTokenPoolSetDynamicConfig(body: { + queryId: uint64 + router: c.Address + rateLimitAdmin?: c.Address | null /* = null */ + feeAdmin?: c.Address | null /* = null */ + }) { + return TokenPool_SetDynamicConfig.toCell(TokenPool_SetDynamicConfig.create(body)); + } + + static createCellOfTokenPoolSetAllowedFinalityConfig(body: { + queryId: uint64 + allowedFinalityConfig: uint32 + }) { + return TokenPool_SetAllowedFinalityConfig.toCell(TokenPool_SetAllowedFinalityConfig.create(body)); + } + + static createCellOfTokenPoolSetRateLimitConfig(body: { + queryId: uint64 + updates: SnakedCell + }) { + return TokenPool_SetRateLimitConfig.toCell(TokenPool_SetRateLimitConfig.create(body)); + } + + static createCellOfTokenPoolApplyTokenTransferFeeConfigUpdates(body: { + queryId: uint64 + updates: SnakedCell + disableChainSelectors: SnakedCell + }) { + return TokenPool_ApplyTokenTransferFeeConfigUpdates.toCell(TokenPool_ApplyTokenTransferFeeConfigUpdates.create(body)); + } + + static createCellOfTokenPoolUpdateRampAccess(body: { + queryId: uint64 + updates: SnakedCell + }) { + return TokenPool_UpdateRampAccess.toCell(TokenPool_UpdateRampAccess.create(body)); + } + + static createCellOfTokenPoolSetRMNProxy(body: { + queryId: uint64 + rmnProxy: c.Address + }) { + return TokenPool_SetRMNProxy.toCell(TokenPool_SetRMNProxy.create(body)); + } + + static createCellOfTokenPoolUpdateCursedSubjects(body: { + queryId: uint64 + cursedSubjects: CursedSubjects + }) { + return TokenPool_UpdateCursedSubjects.toCell(TokenPool_UpdateCursedSubjects.create(body)); + } + + static createCellOfTokenPoolReleaseOrMint(body: { + queryId: uint64 + request: CellRef + requestedFinalityConfig: uint32 + replyTo?: c.Address | null /* = null */ + }) { + return TokenPool_ReleaseOrMint.toCell(TokenPool_ReleaseOrMint.create(body)); } static createCellOfTransferNotificationForRecipient(body: { @@ -2224,6 +3073,12 @@ export class BurnMintTokenPool implements c.Contract { return TransferNotificationForRecipient.toCell(TransferNotificationForRecipient.create(body)); } + static createCellOfBurnMintTokenPoolClaimMinterAdmin(body: { + queryId: uint64 + }) { + return BurnMintTokenPool_ClaimMinterAdmin.toCell(BurnMintTokenPool_ClaimMinterAdmin.create(body)); + } + static createCellOfReturnExcessesBack(body: { queryId: uint64 }) { @@ -2238,12 +3093,131 @@ export class BurnMintTokenPool implements c.Contract { }); } - async sendBurnMintTokenPoolClaimMinterAdmin(provider: ContractProvider, via: Sender, msgValue: coins, body: { + async sendTokenPoolApplyChainUpdates(provider: ContractProvider, via: Sender, msgValue: coins, body: { queryId: uint64 + remoteChainSelectorsToRemove: SnakedCell + chainsToAdd: SnakedCell }, extraOptions?: ExtraSendOptions) { return provider.internal(via, { value: msgValue, - body: BurnMintTokenPool_ClaimMinterAdmin.toCell(BurnMintTokenPool_ClaimMinterAdmin.create(body)), + body: TokenPool_ApplyChainUpdates.toCell(TokenPool_ApplyChainUpdates.create(body)), + ...extraOptions + }); + } + + async sendTokenPoolAddRemotePool(provider: ContractProvider, via: Sender, msgValue: coins, body: { + queryId: uint64 + remoteChainSelector: uint64 + remotePoolAddress: CellRef + }, extraOptions?: ExtraSendOptions) { + return provider.internal(via, { + value: msgValue, + body: TokenPool_AddRemotePool.toCell(TokenPool_AddRemotePool.create(body)), + ...extraOptions + }); + } + + async sendTokenPoolRemoveRemotePool(provider: ContractProvider, via: Sender, msgValue: coins, body: { + queryId: uint64 + remoteChainSelector: uint64 + remotePoolAddress: CellRef + }, extraOptions?: ExtraSendOptions) { + return provider.internal(via, { + value: msgValue, + body: TokenPool_RemoveRemotePool.toCell(TokenPool_RemoveRemotePool.create(body)), + ...extraOptions + }); + } + + async sendTokenPoolSetDynamicConfig(provider: ContractProvider, via: Sender, msgValue: coins, body: { + queryId: uint64 + router: c.Address + rateLimitAdmin?: c.Address | null /* = null */ + feeAdmin?: c.Address | null /* = null */ + }, extraOptions?: ExtraSendOptions) { + return provider.internal(via, { + value: msgValue, + body: TokenPool_SetDynamicConfig.toCell(TokenPool_SetDynamicConfig.create(body)), + ...extraOptions + }); + } + + async sendTokenPoolSetAllowedFinalityConfig(provider: ContractProvider, via: Sender, msgValue: coins, body: { + queryId: uint64 + allowedFinalityConfig: uint32 + }, extraOptions?: ExtraSendOptions) { + return provider.internal(via, { + value: msgValue, + body: TokenPool_SetAllowedFinalityConfig.toCell(TokenPool_SetAllowedFinalityConfig.create(body)), + ...extraOptions + }); + } + + async sendTokenPoolSetRateLimitConfig(provider: ContractProvider, via: Sender, msgValue: coins, body: { + queryId: uint64 + updates: SnakedCell + }, extraOptions?: ExtraSendOptions) { + return provider.internal(via, { + value: msgValue, + body: TokenPool_SetRateLimitConfig.toCell(TokenPool_SetRateLimitConfig.create(body)), + ...extraOptions + }); + } + + async sendTokenPoolApplyTokenTransferFeeConfigUpdates(provider: ContractProvider, via: Sender, msgValue: coins, body: { + queryId: uint64 + updates: SnakedCell + disableChainSelectors: SnakedCell + }, extraOptions?: ExtraSendOptions) { + return provider.internal(via, { + value: msgValue, + body: TokenPool_ApplyTokenTransferFeeConfigUpdates.toCell(TokenPool_ApplyTokenTransferFeeConfigUpdates.create(body)), + ...extraOptions + }); + } + + async sendTokenPoolUpdateRampAccess(provider: ContractProvider, via: Sender, msgValue: coins, body: { + queryId: uint64 + updates: SnakedCell + }, extraOptions?: ExtraSendOptions) { + return provider.internal(via, { + value: msgValue, + body: TokenPool_UpdateRampAccess.toCell(TokenPool_UpdateRampAccess.create(body)), + ...extraOptions + }); + } + + async sendTokenPoolSetRMNProxy(provider: ContractProvider, via: Sender, msgValue: coins, body: { + queryId: uint64 + rmnProxy: c.Address + }, extraOptions?: ExtraSendOptions) { + return provider.internal(via, { + value: msgValue, + body: TokenPool_SetRMNProxy.toCell(TokenPool_SetRMNProxy.create(body)), + ...extraOptions + }); + } + + async sendTokenPoolUpdateCursedSubjects(provider: ContractProvider, via: Sender, msgValue: coins, body: { + queryId: uint64 + cursedSubjects: CursedSubjects + }, extraOptions?: ExtraSendOptions) { + return provider.internal(via, { + value: msgValue, + body: TokenPool_UpdateCursedSubjects.toCell(TokenPool_UpdateCursedSubjects.create(body)), + ...extraOptions + }); + } + + async sendTokenPoolReleaseOrMint(provider: ContractProvider, via: Sender, msgValue: coins, body: { + queryId: uint64 + request: CellRef + requestedFinalityConfig: uint32 + replyTo?: c.Address | null /* = null */ + }, extraOptions?: ExtraSendOptions) { + return provider.internal(via, { + value: msgValue, + body: TokenPool_ReleaseOrMint.toCell(TokenPool_ReleaseOrMint.create(body)), ...extraOptions }); } @@ -2261,6 +3235,16 @@ export class BurnMintTokenPool implements c.Contract { }); } + async sendBurnMintTokenPoolClaimMinterAdmin(provider: ContractProvider, via: Sender, msgValue: coins, body: { + queryId: uint64 + }, extraOptions?: ExtraSendOptions) { + return provider.internal(via, { + value: msgValue, + body: BurnMintTokenPool_ClaimMinterAdmin.toCell(BurnMintTokenPool_ClaimMinterAdmin.create(body)), + ...extraOptions + }); + } + async sendReturnExcessesBack(provider: ContractProvider, via: Sender, msgValue: coins, body: { queryId: uint64 }, extraOptions?: ExtraSendOptions) { @@ -2331,6 +3315,11 @@ export class BurnMintTokenPool implements c.Contract { return r.readBoolean(); } + async getRMNProxy(provider: ContractProvider): Promise { + const r = StackReader.fromGetMethod(1, await provider.get('getRMNProxy', [])); + return r.readSlice().loadAddress(); + } + async getVerifyNotCursed(provider: ContractProvider, subject: uint128): Promise { const r = StackReader.fromGetMethod(1, await provider.get('verifyNotCursed', [ { type: 'int', value: subject }, diff --git a/contracts/wrappers/gen/ccip/pools/LockReleaseTokenPool.ts b/contracts/wrappers/gen/ccip/pools/LockReleaseTokenPool.ts index 4fba812bc..3d478dceb 100644 --- a/contracts/wrappers/gen/ccip/pools/LockReleaseTokenPool.ts +++ b/contracts/wrappers/gen/ccip/pools/LockReleaseTokenPool.ts @@ -183,6 +183,11 @@ type uint64 = bigint type uint128 = bigint type uint256 = bigint +/** + > type SnakedCell = cell + */ +export type SnakedCell = c.Cell + /** > struct Ownable2Step { > owner: address @@ -759,6 +764,51 @@ export const TokenPool_MirroredPolicy = { } } +/** + > struct TokenPool_RampUpdate { + > remoteChainSelector: uint64 + > onRamp: address? + > offRamp: address? + > } + */ +export interface TokenPool_RampUpdate { + readonly $: 'TokenPool_RampUpdate' + remoteChainSelector: uint64 + onRamp: c.Address | null /* = null */ + offRamp: c.Address | null /* = null */ +} + +export const TokenPool_RampUpdate = { + create(args: { + remoteChainSelector: uint64 + onRamp?: c.Address | null /* = null */ + offRamp?: c.Address | null /* = null */ + }): TokenPool_RampUpdate { + return { + $: 'TokenPool_RampUpdate', + onRamp: null, + offRamp: null, + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_RampUpdate { + return { + $: 'TokenPool_RampUpdate', + remoteChainSelector: s.loadUintBig(64), + onRamp: s.loadMaybeAddress(), + offRamp: s.loadMaybeAddress(), + } + }, + store(self: TokenPool_RampUpdate, b: c.Builder): void { + b.storeUint(self.remoteChainSelector, 64); + b.storeAddress(self.onRamp); + b.storeAddress(self.offRamp); + }, + toCell(self: TokenPool_RampUpdate): c.Cell { + return makeCellFrom(self, TokenPool_RampUpdate.store); + } +} + /** > struct TokenPool_RateLimiterPair { > outbound: Cell @@ -797,6 +847,92 @@ export const TokenPool_RateLimiterPair = { } } +/** + > struct TokenPool_RateLimitConfigPair { + > outbound: Cell + > inbound: Cell + > } + */ +export interface TokenPool_RateLimitConfigPair { + readonly $: 'TokenPool_RateLimitConfigPair' + outbound: CellRef + inbound: CellRef +} + +export const TokenPool_RateLimitConfigPair = { + create(args: { + outbound: CellRef + inbound: CellRef + }): TokenPool_RateLimitConfigPair { + return { + $: 'TokenPool_RateLimitConfigPair', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_RateLimitConfigPair { + return { + $: 'TokenPool_RateLimitConfigPair', + outbound: loadCellRef(s, RateLimiter_Config.fromSlice), + inbound: loadCellRef(s, RateLimiter_Config.fromSlice), + } + }, + store(self: TokenPool_RateLimitConfigPair, b: c.Builder): void { + storeCellRef(self.outbound, b, RateLimiter_Config.store); + storeCellRef(self.inbound, b, RateLimiter_Config.store); + }, + toCell(self: TokenPool_RateLimitConfigPair): c.Cell { + return makeCellFrom(self, TokenPool_RateLimitConfigPair.store); + } +} + +/** + > struct TokenPool_ChainUpdate { + > remoteChainSelector: uint64 + > remotePoolAddresses: SnakedCell + > remoteTokenAddress: Cell + > rateLimitConfigs: Cell + > } + */ +export interface TokenPool_ChainUpdate { + readonly $: 'TokenPool_ChainUpdate' + remoteChainSelector: uint64 + remotePoolAddresses: SnakedCell + remoteTokenAddress: CellRef + rateLimitConfigs: CellRef +} + +export const TokenPool_ChainUpdate = { + create(args: { + remoteChainSelector: uint64 + remotePoolAddresses: SnakedCell + remoteTokenAddress: CellRef + rateLimitConfigs: CellRef + }): TokenPool_ChainUpdate { + return { + $: 'TokenPool_ChainUpdate', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_ChainUpdate { + return { + $: 'TokenPool_ChainUpdate', + remoteChainSelector: s.loadUintBig(64), + remotePoolAddresses: s.loadRef(), + remoteTokenAddress: loadCellRef(s, CrossChainAddress.fromSlice), + rateLimitConfigs: loadCellRef(s, TokenPool_RateLimitConfigPair.fromSlice), + } + }, + store(self: TokenPool_ChainUpdate, b: c.Builder): void { + b.storeUint(self.remoteChainSelector, 64); + b.storeRef(self.remotePoolAddresses); + storeCellRef(self.remoteTokenAddress, b, CrossChainAddress.store); + storeCellRef(self.rateLimitConfigs, b, TokenPool_RateLimitConfigPair.store); + }, + toCell(self: TokenPool_ChainUpdate): c.Cell { + return makeCellFrom(self, TokenPool_ChainUpdate.store); + } +} + /** > struct TokenPool_RemoteChainConfig { > remoteTokenAddress: Cell @@ -851,6 +987,92 @@ export const TokenPool_RemoteChainConfig = { } } +/** + > struct TokenPool_RateLimitConfigArgs { + > remoteChainSelector: uint64 + > fastFinality: bool + > outboundRateLimiterConfig: Cell + > inboundRateLimiterConfig: Cell + > } + */ +export interface TokenPool_RateLimitConfigArgs { + readonly $: 'TokenPool_RateLimitConfigArgs' + remoteChainSelector: uint64 + fastFinality: boolean + outboundRateLimiterConfig: CellRef + inboundRateLimiterConfig: CellRef +} + +export const TokenPool_RateLimitConfigArgs = { + create(args: { + remoteChainSelector: uint64 + fastFinality: boolean + outboundRateLimiterConfig: CellRef + inboundRateLimiterConfig: CellRef + }): TokenPool_RateLimitConfigArgs { + return { + $: 'TokenPool_RateLimitConfigArgs', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_RateLimitConfigArgs { + return { + $: 'TokenPool_RateLimitConfigArgs', + remoteChainSelector: s.loadUintBig(64), + fastFinality: s.loadBoolean(), + outboundRateLimiterConfig: loadCellRef(s, RateLimiter_Config.fromSlice), + inboundRateLimiterConfig: loadCellRef(s, RateLimiter_Config.fromSlice), + } + }, + store(self: TokenPool_RateLimitConfigArgs, b: c.Builder): void { + b.storeUint(self.remoteChainSelector, 64); + b.storeBit(self.fastFinality); + storeCellRef(self.outboundRateLimiterConfig, b, RateLimiter_Config.store); + storeCellRef(self.inboundRateLimiterConfig, b, RateLimiter_Config.store); + }, + toCell(self: TokenPool_RateLimitConfigArgs): c.Cell { + return makeCellFrom(self, TokenPool_RateLimitConfigArgs.store); + } +} + +/** + > struct TokenPool_TokenTransferFeeConfigArgs { + > destChainSelector: uint64 + > tokenTransferFeeConfig: TokenPool_TokenTransferFeeConfig + > } + */ +export interface TokenPool_TokenTransferFeeConfigArgs { + readonly $: 'TokenPool_TokenTransferFeeConfigArgs' + destChainSelector: uint64 + tokenTransferFeeConfig: TokenPool_TokenTransferFeeConfig +} + +export const TokenPool_TokenTransferFeeConfigArgs = { + create(args: { + destChainSelector: uint64 + tokenTransferFeeConfig: TokenPool_TokenTransferFeeConfig + }): TokenPool_TokenTransferFeeConfigArgs { + return { + $: 'TokenPool_TokenTransferFeeConfigArgs', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_TokenTransferFeeConfigArgs { + return { + $: 'TokenPool_TokenTransferFeeConfigArgs', + destChainSelector: s.loadUintBig(64), + tokenTransferFeeConfig: TokenPool_TokenTransferFeeConfig.fromSlice(s), + } + }, + store(self: TokenPool_TokenTransferFeeConfigArgs, b: c.Builder): void { + b.storeUint(self.destChainSelector, 64); + TokenPool_TokenTransferFeeConfig.store(self.tokenTransferFeeConfig, b); + }, + toCell(self: TokenPool_TokenTransferFeeConfigArgs): c.Cell { + return makeCellFrom(self, TokenPool_TokenTransferFeeConfigArgs.store); + } +} + /** > struct TokenPool_TokenTransferFeeConfig { > isEnabled: bool @@ -1019,41 +1241,493 @@ export const TokenPool_ReleaseOrMintInV1 = { (v,b) => b.storeRef(v) ); }, - toCell(self: TokenPool_ReleaseOrMintInV1): c.Cell { - return makeCellFrom(self, TokenPool_ReleaseOrMintInV1.store); + toCell(self: TokenPool_ReleaseOrMintInV1): c.Cell { + return makeCellFrom(self, TokenPool_ReleaseOrMintInV1.store); + } +} + +/** + > struct TokenPool_ReleaseOrMintOutV1 { + > destinationAmount: uint256 + > } + */ +export interface TokenPool_ReleaseOrMintOutV1 { + readonly $: 'TokenPool_ReleaseOrMintOutV1' + destinationAmount: uint256 +} + +export const TokenPool_ReleaseOrMintOutV1 = { + create(args: { + destinationAmount: uint256 + }): TokenPool_ReleaseOrMintOutV1 { + return { + $: 'TokenPool_ReleaseOrMintOutV1', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_ReleaseOrMintOutV1 { + return { + $: 'TokenPool_ReleaseOrMintOutV1', + destinationAmount: s.loadUintBig(256), + } + }, + store(self: TokenPool_ReleaseOrMintOutV1, b: c.Builder): void { + b.storeUint(self.destinationAmount, 256); + }, + toCell(self: TokenPool_ReleaseOrMintOutV1): c.Cell { + return makeCellFrom(self, TokenPool_ReleaseOrMintOutV1.store); + } +} + +/** + > struct (0xdc0b6ff5) TokenPool_ApplyChainUpdates { + > queryId: uint64 + > remoteChainSelectorsToRemove: SnakedCell + > chainsToAdd: SnakedCell + > } + */ +export interface TokenPool_ApplyChainUpdates { + readonly $: 'TokenPool_ApplyChainUpdates' + queryId: uint64 + remoteChainSelectorsToRemove: SnakedCell + chainsToAdd: SnakedCell +} + +export const TokenPool_ApplyChainUpdates = { + PREFIX: 0xdc0b6ff5, + + create(args: { + queryId: uint64 + remoteChainSelectorsToRemove: SnakedCell + chainsToAdd: SnakedCell + }): TokenPool_ApplyChainUpdates { + return { + $: 'TokenPool_ApplyChainUpdates', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_ApplyChainUpdates { + loadAndCheckPrefix32(s, 0xdc0b6ff5, 'TokenPool_ApplyChainUpdates'); + return { + $: 'TokenPool_ApplyChainUpdates', + queryId: s.loadUintBig(64), + remoteChainSelectorsToRemove: s.loadRef(), + chainsToAdd: s.loadRef(), + } + }, + store(self: TokenPool_ApplyChainUpdates, b: c.Builder): void { + b.storeUint(0xdc0b6ff5, 32); + b.storeUint(self.queryId, 64); + b.storeRef(self.remoteChainSelectorsToRemove); + b.storeRef(self.chainsToAdd); + }, + toCell(self: TokenPool_ApplyChainUpdates): c.Cell { + return makeCellFrom(self, TokenPool_ApplyChainUpdates.store); + } +} + +/** + > struct (0x5fd2c8b6) TokenPool_AddRemotePool { + > queryId: uint64 + > remoteChainSelector: uint64 + > remotePoolAddress: Cell + > } + */ +export interface TokenPool_AddRemotePool { + readonly $: 'TokenPool_AddRemotePool' + queryId: uint64 + remoteChainSelector: uint64 + remotePoolAddress: CellRef +} + +export const TokenPool_AddRemotePool = { + PREFIX: 0x5fd2c8b6, + + create(args: { + queryId: uint64 + remoteChainSelector: uint64 + remotePoolAddress: CellRef + }): TokenPool_AddRemotePool { + return { + $: 'TokenPool_AddRemotePool', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_AddRemotePool { + loadAndCheckPrefix32(s, 0x5fd2c8b6, 'TokenPool_AddRemotePool'); + return { + $: 'TokenPool_AddRemotePool', + queryId: s.loadUintBig(64), + remoteChainSelector: s.loadUintBig(64), + remotePoolAddress: loadCellRef(s, CrossChainAddress.fromSlice), + } + }, + store(self: TokenPool_AddRemotePool, b: c.Builder): void { + b.storeUint(0x5fd2c8b6, 32); + b.storeUint(self.queryId, 64); + b.storeUint(self.remoteChainSelector, 64); + storeCellRef(self.remotePoolAddress, b, CrossChainAddress.store); + }, + toCell(self: TokenPool_AddRemotePool): c.Cell { + return makeCellFrom(self, TokenPool_AddRemotePool.store); + } +} + +/** + > struct (0xdbf0a2df) TokenPool_RemoveRemotePool { + > queryId: uint64 + > remoteChainSelector: uint64 + > remotePoolAddress: Cell + > } + */ +export interface TokenPool_RemoveRemotePool { + readonly $: 'TokenPool_RemoveRemotePool' + queryId: uint64 + remoteChainSelector: uint64 + remotePoolAddress: CellRef +} + +export const TokenPool_RemoveRemotePool = { + PREFIX: 0xdbf0a2df, + + create(args: { + queryId: uint64 + remoteChainSelector: uint64 + remotePoolAddress: CellRef + }): TokenPool_RemoveRemotePool { + return { + $: 'TokenPool_RemoveRemotePool', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_RemoveRemotePool { + loadAndCheckPrefix32(s, 0xdbf0a2df, 'TokenPool_RemoveRemotePool'); + return { + $: 'TokenPool_RemoveRemotePool', + queryId: s.loadUintBig(64), + remoteChainSelector: s.loadUintBig(64), + remotePoolAddress: loadCellRef(s, CrossChainAddress.fromSlice), + } + }, + store(self: TokenPool_RemoveRemotePool, b: c.Builder): void { + b.storeUint(0xdbf0a2df, 32); + b.storeUint(self.queryId, 64); + b.storeUint(self.remoteChainSelector, 64); + storeCellRef(self.remotePoolAddress, b, CrossChainAddress.store); + }, + toCell(self: TokenPool_RemoveRemotePool): c.Cell { + return makeCellFrom(self, TokenPool_RemoveRemotePool.store); + } +} + +/** + > struct (0x4eea060b) TokenPool_SetDynamicConfig { + > queryId: uint64 + > router: address + > rateLimitAdmin: address? + > feeAdmin: address? + > } + */ +export interface TokenPool_SetDynamicConfig { + readonly $: 'TokenPool_SetDynamicConfig' + queryId: uint64 + router: c.Address + rateLimitAdmin: c.Address | null /* = null */ + feeAdmin: c.Address | null /* = null */ +} + +export const TokenPool_SetDynamicConfig = { + PREFIX: 0x4eea060b, + + create(args: { + queryId: uint64 + router: c.Address + rateLimitAdmin?: c.Address | null /* = null */ + feeAdmin?: c.Address | null /* = null */ + }): TokenPool_SetDynamicConfig { + return { + $: 'TokenPool_SetDynamicConfig', + rateLimitAdmin: null, + feeAdmin: null, + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_SetDynamicConfig { + loadAndCheckPrefix32(s, 0x4eea060b, 'TokenPool_SetDynamicConfig'); + return { + $: 'TokenPool_SetDynamicConfig', + queryId: s.loadUintBig(64), + router: s.loadAddress(), + rateLimitAdmin: s.loadMaybeAddress(), + feeAdmin: s.loadMaybeAddress(), + } + }, + store(self: TokenPool_SetDynamicConfig, b: c.Builder): void { + b.storeUint(0x4eea060b, 32); + b.storeUint(self.queryId, 64); + b.storeAddress(self.router); + b.storeAddress(self.rateLimitAdmin); + b.storeAddress(self.feeAdmin); + }, + toCell(self: TokenPool_SetDynamicConfig): c.Cell { + return makeCellFrom(self, TokenPool_SetDynamicConfig.store); + } +} + +/** + > struct (0x29b46fc6) TokenPool_SetAllowedFinalityConfig { + > queryId: uint64 + > allowedFinalityConfig: uint32 + > } + */ +export interface TokenPool_SetAllowedFinalityConfig { + readonly $: 'TokenPool_SetAllowedFinalityConfig' + queryId: uint64 + allowedFinalityConfig: uint32 +} + +export const TokenPool_SetAllowedFinalityConfig = { + PREFIX: 0x29b46fc6, + + create(args: { + queryId: uint64 + allowedFinalityConfig: uint32 + }): TokenPool_SetAllowedFinalityConfig { + return { + $: 'TokenPool_SetAllowedFinalityConfig', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_SetAllowedFinalityConfig { + loadAndCheckPrefix32(s, 0x29b46fc6, 'TokenPool_SetAllowedFinalityConfig'); + return { + $: 'TokenPool_SetAllowedFinalityConfig', + queryId: s.loadUintBig(64), + allowedFinalityConfig: s.loadUintBig(32), + } + }, + store(self: TokenPool_SetAllowedFinalityConfig, b: c.Builder): void { + b.storeUint(0x29b46fc6, 32); + b.storeUint(self.queryId, 64); + b.storeUint(self.allowedFinalityConfig, 32); + }, + toCell(self: TokenPool_SetAllowedFinalityConfig): c.Cell { + return makeCellFrom(self, TokenPool_SetAllowedFinalityConfig.store); + } +} + +/** + > struct (0x3a028da2) TokenPool_SetRateLimitConfig { + > queryId: uint64 + > updates: SnakedCell + > } + */ +export interface TokenPool_SetRateLimitConfig { + readonly $: 'TokenPool_SetRateLimitConfig' + queryId: uint64 + updates: SnakedCell +} + +export const TokenPool_SetRateLimitConfig = { + PREFIX: 0x3a028da2, + + create(args: { + queryId: uint64 + updates: SnakedCell + }): TokenPool_SetRateLimitConfig { + return { + $: 'TokenPool_SetRateLimitConfig', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_SetRateLimitConfig { + loadAndCheckPrefix32(s, 0x3a028da2, 'TokenPool_SetRateLimitConfig'); + return { + $: 'TokenPool_SetRateLimitConfig', + queryId: s.loadUintBig(64), + updates: s.loadRef(), + } + }, + store(self: TokenPool_SetRateLimitConfig, b: c.Builder): void { + b.storeUint(0x3a028da2, 32); + b.storeUint(self.queryId, 64); + b.storeRef(self.updates); + }, + toCell(self: TokenPool_SetRateLimitConfig): c.Cell { + return makeCellFrom(self, TokenPool_SetRateLimitConfig.store); + } +} + +/** + > struct (0x10c4b4a1) TokenPool_ApplyTokenTransferFeeConfigUpdates { + > queryId: uint64 + > updates: SnakedCell + > disableChainSelectors: SnakedCell + > } + */ +export interface TokenPool_ApplyTokenTransferFeeConfigUpdates { + readonly $: 'TokenPool_ApplyTokenTransferFeeConfigUpdates' + queryId: uint64 + updates: SnakedCell + disableChainSelectors: SnakedCell +} + +export const TokenPool_ApplyTokenTransferFeeConfigUpdates = { + PREFIX: 0x10c4b4a1, + + create(args: { + queryId: uint64 + updates: SnakedCell + disableChainSelectors: SnakedCell + }): TokenPool_ApplyTokenTransferFeeConfigUpdates { + return { + $: 'TokenPool_ApplyTokenTransferFeeConfigUpdates', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_ApplyTokenTransferFeeConfigUpdates { + loadAndCheckPrefix32(s, 0x10c4b4a1, 'TokenPool_ApplyTokenTransferFeeConfigUpdates'); + return { + $: 'TokenPool_ApplyTokenTransferFeeConfigUpdates', + queryId: s.loadUintBig(64), + updates: s.loadRef(), + disableChainSelectors: s.loadRef(), + } + }, + store(self: TokenPool_ApplyTokenTransferFeeConfigUpdates, b: c.Builder): void { + b.storeUint(0x10c4b4a1, 32); + b.storeUint(self.queryId, 64); + b.storeRef(self.updates); + b.storeRef(self.disableChainSelectors); + }, + toCell(self: TokenPool_ApplyTokenTransferFeeConfigUpdates): c.Cell { + return makeCellFrom(self, TokenPool_ApplyTokenTransferFeeConfigUpdates.store); + } +} + +/** + > struct (0x7a9c4aa5) TokenPool_UpdateRampAccess { + > queryId: uint64 + > updates: SnakedCell + > } + */ +export interface TokenPool_UpdateRampAccess { + readonly $: 'TokenPool_UpdateRampAccess' + queryId: uint64 + updates: SnakedCell +} + +export const TokenPool_UpdateRampAccess = { + PREFIX: 0x7a9c4aa5, + + create(args: { + queryId: uint64 + updates: SnakedCell + }): TokenPool_UpdateRampAccess { + return { + $: 'TokenPool_UpdateRampAccess', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_UpdateRampAccess { + loadAndCheckPrefix32(s, 0x7a9c4aa5, 'TokenPool_UpdateRampAccess'); + return { + $: 'TokenPool_UpdateRampAccess', + queryId: s.loadUintBig(64), + updates: s.loadRef(), + } + }, + store(self: TokenPool_UpdateRampAccess, b: c.Builder): void { + b.storeUint(0x7a9c4aa5, 32); + b.storeUint(self.queryId, 64); + b.storeRef(self.updates); + }, + toCell(self: TokenPool_UpdateRampAccess): c.Cell { + return makeCellFrom(self, TokenPool_UpdateRampAccess.store); + } +} + +/** + > struct (0x12345678) TokenPool_SetRMNProxy { + > queryId: uint64 + > rmnProxy: address + > } + */ +export interface TokenPool_SetRMNProxy { + readonly $: 'TokenPool_SetRMNProxy' + queryId: uint64 + rmnProxy: c.Address +} + +export const TokenPool_SetRMNProxy = { + PREFIX: 0x12345678, + + create(args: { + queryId: uint64 + rmnProxy: c.Address + }): TokenPool_SetRMNProxy { + return { + $: 'TokenPool_SetRMNProxy', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_SetRMNProxy { + loadAndCheckPrefix32(s, 0x12345678, 'TokenPool_SetRMNProxy'); + return { + $: 'TokenPool_SetRMNProxy', + queryId: s.loadUintBig(64), + rmnProxy: s.loadAddress(), + } + }, + store(self: TokenPool_SetRMNProxy, b: c.Builder): void { + b.storeUint(0x12345678, 32); + b.storeUint(self.queryId, 64); + b.storeAddress(self.rmnProxy); + }, + toCell(self: TokenPool_SetRMNProxy): c.Cell { + return makeCellFrom(self, TokenPool_SetRMNProxy.store); } } /** - > struct TokenPool_ReleaseOrMintOutV1 { - > destinationAmount: uint256 + > struct (0x823dadf2) TokenPool_UpdateCursedSubjects { + > queryId: uint64 + > cursedSubjects: CursedSubjects > } */ -export interface TokenPool_ReleaseOrMintOutV1 { - readonly $: 'TokenPool_ReleaseOrMintOutV1' - destinationAmount: uint256 +export interface TokenPool_UpdateCursedSubjects { + readonly $: 'TokenPool_UpdateCursedSubjects' + queryId: uint64 + cursedSubjects: CursedSubjects } -export const TokenPool_ReleaseOrMintOutV1 = { +export const TokenPool_UpdateCursedSubjects = { + PREFIX: 0x823dadf2, + create(args: { - destinationAmount: uint256 - }): TokenPool_ReleaseOrMintOutV1 { + queryId: uint64 + cursedSubjects: CursedSubjects + }): TokenPool_UpdateCursedSubjects { return { - $: 'TokenPool_ReleaseOrMintOutV1', + $: 'TokenPool_UpdateCursedSubjects', ...args } }, - fromSlice(s: c.Slice): TokenPool_ReleaseOrMintOutV1 { + fromSlice(s: c.Slice): TokenPool_UpdateCursedSubjects { + loadAndCheckPrefix32(s, 0x823dadf2, 'TokenPool_UpdateCursedSubjects'); return { - $: 'TokenPool_ReleaseOrMintOutV1', - destinationAmount: s.loadUintBig(256), + $: 'TokenPool_UpdateCursedSubjects', + queryId: s.loadUintBig(64), + cursedSubjects: CursedSubjects.fromSlice(s), } }, - store(self: TokenPool_ReleaseOrMintOutV1, b: c.Builder): void { - b.storeUint(self.destinationAmount, 256); + store(self: TokenPool_UpdateCursedSubjects, b: c.Builder): void { + b.storeUint(0x823dadf2, 32); + b.storeUint(self.queryId, 64); + CursedSubjects.store(self.cursedSubjects, b); }, - toCell(self: TokenPool_ReleaseOrMintOutV1): c.Cell { - return makeCellFrom(self, TokenPool_ReleaseOrMintOutV1.store); + toCell(self: TokenPool_UpdateCursedSubjects): c.Cell { + return makeCellFrom(self, TokenPool_UpdateCursedSubjects.store); } } @@ -1104,6 +1778,59 @@ export const TokenPool_LockOrBurnResponse = { } } +/** + > struct (0x7d0ffd89) TokenPool_ReleaseOrMint { + > queryId: uint64 + > request: Cell + > requestedFinalityConfig: uint32 + > replyTo: address? + > } + */ +export interface TokenPool_ReleaseOrMint { + readonly $: 'TokenPool_ReleaseOrMint' + queryId: uint64 + request: CellRef + requestedFinalityConfig: uint32 + replyTo: c.Address | null /* = null */ +} + +export const TokenPool_ReleaseOrMint = { + PREFIX: 0x7d0ffd89, + + create(args: { + queryId: uint64 + request: CellRef + requestedFinalityConfig: uint32 + replyTo?: c.Address | null /* = null */ + }): TokenPool_ReleaseOrMint { + return { + $: 'TokenPool_ReleaseOrMint', + replyTo: null, + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_ReleaseOrMint { + loadAndCheckPrefix32(s, 0x7d0ffd89, 'TokenPool_ReleaseOrMint'); + return { + $: 'TokenPool_ReleaseOrMint', + queryId: s.loadUintBig(64), + request: loadCellRef(s, TokenPool_ReleaseOrMintInV1.fromSlice), + requestedFinalityConfig: s.loadUintBig(32), + replyTo: s.loadMaybeAddress(), + } + }, + store(self: TokenPool_ReleaseOrMint, b: c.Builder): void { + b.storeUint(0x7d0ffd89, 32); + b.storeUint(self.queryId, 64); + storeCellRef(self.request, b, TokenPool_ReleaseOrMintInV1.store); + b.storeUint(self.requestedFinalityConfig, 32); + b.storeAddress(self.replyTo); + }, + toCell(self: TokenPool_ReleaseOrMint): c.Cell { + return makeCellFrom(self, TokenPool_ReleaseOrMint.store); + } +} + /** > struct (0x7ec43aee) TokenPool_ReleaseOrMintResponse { > queryId: uint64 @@ -1797,6 +2524,49 @@ export const CrossChainAddress = { } } +/** + > struct RateLimiter_Config { + > isEnabled: bool + > capacity: uint256 + > rate: uint256 + > } + */ +export interface RateLimiter_Config { + readonly $: 'RateLimiter_Config' + isEnabled: boolean + capacity: uint256 + rate: uint256 +} + +export const RateLimiter_Config = { + create(args: { + isEnabled: boolean + capacity: uint256 + rate: uint256 + }): RateLimiter_Config { + return { + $: 'RateLimiter_Config', + ...args + } + }, + fromSlice(s: c.Slice): RateLimiter_Config { + return { + $: 'RateLimiter_Config', + isEnabled: s.loadBoolean(), + capacity: s.loadUintBig(256), + rate: s.loadUintBig(256), + } + }, + store(self: RateLimiter_Config, b: c.Builder): void { + b.storeBit(self.isEnabled); + b.storeUint(self.capacity, 256); + b.storeUint(self.rate, 256); + }, + toCell(self: RateLimiter_Config): c.Cell { + return makeCellFrom(self, RateLimiter_Config.store); + } +} + /** > struct RateLimiter_TokenBucket { > tokens: uint256 @@ -1889,7 +2659,7 @@ function calculateDeployedAddress(code: c.Cell, data: c.Cell, options: DeployedA } export class LockReleaseTokenPool implements c.Contract { - static CodeCell = c.Cell.fromBase64('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'); + static CodeCell = c.Cell.fromBase64('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'); static Errors = { 'Common_Error.CrossChainAddressOutOfRange': 5, @@ -1958,6 +2728,91 @@ export class LockReleaseTokenPool implements c.Contract { return new LockReleaseTokenPool(address, initialState); } + static createCellOfTokenPoolApplyChainUpdates(body: { + queryId: uint64 + remoteChainSelectorsToRemove: SnakedCell + chainsToAdd: SnakedCell + }) { + return TokenPool_ApplyChainUpdates.toCell(TokenPool_ApplyChainUpdates.create(body)); + } + + static createCellOfTokenPoolAddRemotePool(body: { + queryId: uint64 + remoteChainSelector: uint64 + remotePoolAddress: CellRef + }) { + return TokenPool_AddRemotePool.toCell(TokenPool_AddRemotePool.create(body)); + } + + static createCellOfTokenPoolRemoveRemotePool(body: { + queryId: uint64 + remoteChainSelector: uint64 + remotePoolAddress: CellRef + }) { + return TokenPool_RemoveRemotePool.toCell(TokenPool_RemoveRemotePool.create(body)); + } + + static createCellOfTokenPoolSetDynamicConfig(body: { + queryId: uint64 + router: c.Address + rateLimitAdmin?: c.Address | null /* = null */ + feeAdmin?: c.Address | null /* = null */ + }) { + return TokenPool_SetDynamicConfig.toCell(TokenPool_SetDynamicConfig.create(body)); + } + + static createCellOfTokenPoolSetAllowedFinalityConfig(body: { + queryId: uint64 + allowedFinalityConfig: uint32 + }) { + return TokenPool_SetAllowedFinalityConfig.toCell(TokenPool_SetAllowedFinalityConfig.create(body)); + } + + static createCellOfTokenPoolSetRateLimitConfig(body: { + queryId: uint64 + updates: SnakedCell + }) { + return TokenPool_SetRateLimitConfig.toCell(TokenPool_SetRateLimitConfig.create(body)); + } + + static createCellOfTokenPoolApplyTokenTransferFeeConfigUpdates(body: { + queryId: uint64 + updates: SnakedCell + disableChainSelectors: SnakedCell + }) { + return TokenPool_ApplyTokenTransferFeeConfigUpdates.toCell(TokenPool_ApplyTokenTransferFeeConfigUpdates.create(body)); + } + + static createCellOfTokenPoolUpdateRampAccess(body: { + queryId: uint64 + updates: SnakedCell + }) { + return TokenPool_UpdateRampAccess.toCell(TokenPool_UpdateRampAccess.create(body)); + } + + static createCellOfTokenPoolSetRMNProxy(body: { + queryId: uint64 + rmnProxy: c.Address + }) { + return TokenPool_SetRMNProxy.toCell(TokenPool_SetRMNProxy.create(body)); + } + + static createCellOfTokenPoolUpdateCursedSubjects(body: { + queryId: uint64 + cursedSubjects: CursedSubjects + }) { + return TokenPool_UpdateCursedSubjects.toCell(TokenPool_UpdateCursedSubjects.create(body)); + } + + static createCellOfTokenPoolReleaseOrMint(body: { + queryId: uint64 + request: CellRef + requestedFinalityConfig: uint32 + replyTo?: c.Address | null /* = null */ + }) { + return TokenPool_ReleaseOrMint.toCell(TokenPool_ReleaseOrMint.create(body)); + } + static createCellOfTransferNotificationForRecipient(body: { queryId: uint64 jettonAmount: coins @@ -1981,6 +2836,135 @@ export class LockReleaseTokenPool implements c.Contract { }); } + async sendTokenPoolApplyChainUpdates(provider: ContractProvider, via: Sender, msgValue: coins, body: { + queryId: uint64 + remoteChainSelectorsToRemove: SnakedCell + chainsToAdd: SnakedCell + }, extraOptions?: ExtraSendOptions) { + return provider.internal(via, { + value: msgValue, + body: TokenPool_ApplyChainUpdates.toCell(TokenPool_ApplyChainUpdates.create(body)), + ...extraOptions + }); + } + + async sendTokenPoolAddRemotePool(provider: ContractProvider, via: Sender, msgValue: coins, body: { + queryId: uint64 + remoteChainSelector: uint64 + remotePoolAddress: CellRef + }, extraOptions?: ExtraSendOptions) { + return provider.internal(via, { + value: msgValue, + body: TokenPool_AddRemotePool.toCell(TokenPool_AddRemotePool.create(body)), + ...extraOptions + }); + } + + async sendTokenPoolRemoveRemotePool(provider: ContractProvider, via: Sender, msgValue: coins, body: { + queryId: uint64 + remoteChainSelector: uint64 + remotePoolAddress: CellRef + }, extraOptions?: ExtraSendOptions) { + return provider.internal(via, { + value: msgValue, + body: TokenPool_RemoveRemotePool.toCell(TokenPool_RemoveRemotePool.create(body)), + ...extraOptions + }); + } + + async sendTokenPoolSetDynamicConfig(provider: ContractProvider, via: Sender, msgValue: coins, body: { + queryId: uint64 + router: c.Address + rateLimitAdmin?: c.Address | null /* = null */ + feeAdmin?: c.Address | null /* = null */ + }, extraOptions?: ExtraSendOptions) { + return provider.internal(via, { + value: msgValue, + body: TokenPool_SetDynamicConfig.toCell(TokenPool_SetDynamicConfig.create(body)), + ...extraOptions + }); + } + + async sendTokenPoolSetAllowedFinalityConfig(provider: ContractProvider, via: Sender, msgValue: coins, body: { + queryId: uint64 + allowedFinalityConfig: uint32 + }, extraOptions?: ExtraSendOptions) { + return provider.internal(via, { + value: msgValue, + body: TokenPool_SetAllowedFinalityConfig.toCell(TokenPool_SetAllowedFinalityConfig.create(body)), + ...extraOptions + }); + } + + async sendTokenPoolSetRateLimitConfig(provider: ContractProvider, via: Sender, msgValue: coins, body: { + queryId: uint64 + updates: SnakedCell + }, extraOptions?: ExtraSendOptions) { + return provider.internal(via, { + value: msgValue, + body: TokenPool_SetRateLimitConfig.toCell(TokenPool_SetRateLimitConfig.create(body)), + ...extraOptions + }); + } + + async sendTokenPoolApplyTokenTransferFeeConfigUpdates(provider: ContractProvider, via: Sender, msgValue: coins, body: { + queryId: uint64 + updates: SnakedCell + disableChainSelectors: SnakedCell + }, extraOptions?: ExtraSendOptions) { + return provider.internal(via, { + value: msgValue, + body: TokenPool_ApplyTokenTransferFeeConfigUpdates.toCell(TokenPool_ApplyTokenTransferFeeConfigUpdates.create(body)), + ...extraOptions + }); + } + + async sendTokenPoolUpdateRampAccess(provider: ContractProvider, via: Sender, msgValue: coins, body: { + queryId: uint64 + updates: SnakedCell + }, extraOptions?: ExtraSendOptions) { + return provider.internal(via, { + value: msgValue, + body: TokenPool_UpdateRampAccess.toCell(TokenPool_UpdateRampAccess.create(body)), + ...extraOptions + }); + } + + async sendTokenPoolSetRMNProxy(provider: ContractProvider, via: Sender, msgValue: coins, body: { + queryId: uint64 + rmnProxy: c.Address + }, extraOptions?: ExtraSendOptions) { + return provider.internal(via, { + value: msgValue, + body: TokenPool_SetRMNProxy.toCell(TokenPool_SetRMNProxy.create(body)), + ...extraOptions + }); + } + + async sendTokenPoolUpdateCursedSubjects(provider: ContractProvider, via: Sender, msgValue: coins, body: { + queryId: uint64 + cursedSubjects: CursedSubjects + }, extraOptions?: ExtraSendOptions) { + return provider.internal(via, { + value: msgValue, + body: TokenPool_UpdateCursedSubjects.toCell(TokenPool_UpdateCursedSubjects.create(body)), + ...extraOptions + }); + } + + async sendTokenPoolReleaseOrMint(provider: ContractProvider, via: Sender, msgValue: coins, body: { + queryId: uint64 + request: CellRef + requestedFinalityConfig: uint32 + replyTo?: c.Address | null /* = null */ + }, extraOptions?: ExtraSendOptions) { + return provider.internal(via, { + value: msgValue, + body: TokenPool_ReleaseOrMint.toCell(TokenPool_ReleaseOrMint.create(body)), + ...extraOptions + }); + } + async sendTransferNotificationForRecipient(provider: ContractProvider, via: Sender, msgValue: coins, body: { queryId: uint64 jettonAmount: coins @@ -2057,6 +3041,11 @@ export class LockReleaseTokenPool implements c.Contract { return r.readBoolean(); } + async getRMNProxy(provider: ContractProvider): Promise { + const r = StackReader.fromGetMethod(1, await provider.get('getRMNProxy', [])); + return r.readSlice().loadAddress(); + } + async getVerifyNotCursed(provider: ContractProvider, subject: uint128): Promise { const r = StackReader.fromGetMethod(1, await provider.get('verifyNotCursed', [ { type: 'int', value: subject }, diff --git a/contracts/wrappers/gen/ccip/pools/TokenPool.ts b/contracts/wrappers/gen/ccip/pools/TokenPool.ts index bf028b910..77d014325 100644 --- a/contracts/wrappers/gen/ccip/pools/TokenPool.ts +++ b/contracts/wrappers/gen/ccip/pools/TokenPool.ts @@ -9,6 +9,8 @@ import { beginCell, ContractProvider, Sender, SendMode } from '@ton/core'; // predefined types and functions // +type RemainingBitsAndRefs = c.Slice + type StoreCallback = (obj: T, b: c.Builder) => void type LoadCallback = (s: c.Slice) => T @@ -48,6 +50,19 @@ function loadCellRef(s: c.Slice, loadFn_T: LoadCallback): CellRef { return { ref: loadFn_T(s_ref) }; } +function storeTolkRemaining(v: RemainingBitsAndRefs, b: c.Builder): void { + b.storeSlice(v); +} + +function loadTolkRemaining(s: c.Slice): RemainingBitsAndRefs { + let rest = s.clone(); + s.loadBits(s.remainingBits); + while (s.remainingRefs) { + s.loadRef(); + } + return rest; +} + function storeTolkNullable(v: T | null, b: c.Builder, storeFn_T: StoreCallback): void { if (v === null) { b.storeUint(0, 1); @@ -630,59 +645,6 @@ export const TokenPool_TokenTransferFeeConfig = { } } -/** - > struct TokenPool_LockOrBurnInV1 { - > receiver: Cell - > remoteChainSelector: uint64 - > originalSender: address - > amount: uint256 - > localToken: address - > } - */ -export interface TokenPool_LockOrBurnInV1 { - readonly $: 'TokenPool_LockOrBurnInV1' - receiver: CellRef - remoteChainSelector: uint64 - originalSender: c.Address - amount: uint256 - localToken: c.Address -} - -export const TokenPool_LockOrBurnInV1 = { - create(args: { - receiver: CellRef - remoteChainSelector: uint64 - originalSender: c.Address - amount: uint256 - localToken: c.Address - }): TokenPool_LockOrBurnInV1 { - return { - $: 'TokenPool_LockOrBurnInV1', - ...args - } - }, - fromSlice(s: c.Slice): TokenPool_LockOrBurnInV1 { - return { - $: 'TokenPool_LockOrBurnInV1', - receiver: loadCellRef(s, CrossChainAddress.fromSlice), - remoteChainSelector: s.loadUintBig(64), - originalSender: s.loadAddress(), - amount: s.loadUintBig(256), - localToken: s.loadAddress(), - } - }, - store(self: TokenPool_LockOrBurnInV1, b: c.Builder): void { - storeCellRef(self.receiver, b, CrossChainAddress.store); - b.storeUint(self.remoteChainSelector, 64); - b.storeAddress(self.originalSender); - b.storeUint(self.amount, 256); - b.storeAddress(self.localToken); - }, - toCell(self: TokenPool_LockOrBurnInV1): c.Cell { - return makeCellFrom(self, TokenPool_LockOrBurnInV1.store); - } -} - /** > struct TokenPool_ReleaseOrMintInV1 { > originalSender: Cell @@ -1124,98 +1086,86 @@ export const TokenPool_UpdateRampAccess = { } /** - > struct (0x823dadf2) TokenPool_UpdateCursedSubjects { - > cursedSubjects: CursedSubjects + > struct (0x12345678) TokenPool_SetRMNProxy { + > queryId: uint64 + > rmnProxy: address > } */ -export interface TokenPool_UpdateCursedSubjects { - readonly $: 'TokenPool_UpdateCursedSubjects' - cursedSubjects: CursedSubjects +export interface TokenPool_SetRMNProxy { + readonly $: 'TokenPool_SetRMNProxy' + queryId: uint64 + rmnProxy: c.Address } -export const TokenPool_UpdateCursedSubjects = { - PREFIX: 0x823dadf2, +export const TokenPool_SetRMNProxy = { + PREFIX: 0x12345678, create(args: { - cursedSubjects: CursedSubjects - }): TokenPool_UpdateCursedSubjects { + queryId: uint64 + rmnProxy: c.Address + }): TokenPool_SetRMNProxy { return { - $: 'TokenPool_UpdateCursedSubjects', + $: 'TokenPool_SetRMNProxy', ...args } }, - fromSlice(s: c.Slice): TokenPool_UpdateCursedSubjects { - loadAndCheckPrefix32(s, 0x823dadf2, 'TokenPool_UpdateCursedSubjects'); + fromSlice(s: c.Slice): TokenPool_SetRMNProxy { + loadAndCheckPrefix32(s, 0x12345678, 'TokenPool_SetRMNProxy'); return { - $: 'TokenPool_UpdateCursedSubjects', - cursedSubjects: CursedSubjects.fromSlice(s), + $: 'TokenPool_SetRMNProxy', + queryId: s.loadUintBig(64), + rmnProxy: s.loadAddress(), } }, - store(self: TokenPool_UpdateCursedSubjects, b: c.Builder): void { - b.storeUint(0x823dadf2, 32); - CursedSubjects.store(self.cursedSubjects, b); + store(self: TokenPool_SetRMNProxy, b: c.Builder): void { + b.storeUint(0x12345678, 32); + b.storeUint(self.queryId, 64); + b.storeAddress(self.rmnProxy); }, - toCell(self: TokenPool_UpdateCursedSubjects): c.Cell { - return makeCellFrom(self, TokenPool_UpdateCursedSubjects.store); + toCell(self: TokenPool_SetRMNProxy): c.Cell { + return makeCellFrom(self, TokenPool_SetRMNProxy.store); } } /** - > struct (0x1161516e) TokenPool_LockOrBurn { + > struct (0x823dadf2) TokenPool_UpdateCursedSubjects { > queryId: uint64 - > request: Cell - > requestedFinalityConfig: uint32 - > tokenArgs: cell? - > replyTo: address? + > cursedSubjects: CursedSubjects > } */ -export interface TokenPool_LockOrBurn { - readonly $: 'TokenPool_LockOrBurn' +export interface TokenPool_UpdateCursedSubjects { + readonly $: 'TokenPool_UpdateCursedSubjects' queryId: uint64 - request: CellRef - requestedFinalityConfig: uint32 - tokenArgs: c.Cell | null - replyTo: c.Address | null + cursedSubjects: CursedSubjects } -export const TokenPool_LockOrBurn = { - PREFIX: 0x1161516e, +export const TokenPool_UpdateCursedSubjects = { + PREFIX: 0x823dadf2, create(args: { queryId: uint64 - request: CellRef - requestedFinalityConfig: uint32 - tokenArgs: c.Cell | null - replyTo: c.Address | null - }): TokenPool_LockOrBurn { + cursedSubjects: CursedSubjects + }): TokenPool_UpdateCursedSubjects { return { - $: 'TokenPool_LockOrBurn', + $: 'TokenPool_UpdateCursedSubjects', ...args } }, - fromSlice(s: c.Slice): TokenPool_LockOrBurn { - loadAndCheckPrefix32(s, 0x1161516e, 'TokenPool_LockOrBurn'); + fromSlice(s: c.Slice): TokenPool_UpdateCursedSubjects { + loadAndCheckPrefix32(s, 0x823dadf2, 'TokenPool_UpdateCursedSubjects'); return { - $: 'TokenPool_LockOrBurn', + $: 'TokenPool_UpdateCursedSubjects', queryId: s.loadUintBig(64), - request: loadCellRef(s, TokenPool_LockOrBurnInV1.fromSlice), - requestedFinalityConfig: s.loadUintBig(32), - tokenArgs: s.loadBoolean() ? s.loadRef() : null, - replyTo: s.loadMaybeAddress(), + cursedSubjects: CursedSubjects.fromSlice(s), } }, - store(self: TokenPool_LockOrBurn, b: c.Builder): void { - b.storeUint(0x1161516e, 32); + store(self: TokenPool_UpdateCursedSubjects, b: c.Builder): void { + b.storeUint(0x823dadf2, 32); b.storeUint(self.queryId, 64); - storeCellRef(self.request, b, TokenPool_LockOrBurnInV1.store); - b.storeUint(self.requestedFinalityConfig, 32); - storeTolkNullable(self.tokenArgs, b, - (v,b) => b.storeRef(v) - ); - b.storeAddress(self.replyTo); + CursedSubjects.store(self.cursedSubjects, b); }, - toCell(self: TokenPool_LockOrBurn): c.Cell { - return makeCellFrom(self, TokenPool_LockOrBurn.store); + toCell(self: TokenPool_UpdateCursedSubjects): c.Cell { + return makeCellFrom(self, TokenPool_UpdateCursedSubjects.store); } } @@ -1379,6 +1329,67 @@ export const TokenPool_Data = { } } +/** + > type SnakedCell = cell + */ +export type SnakedCell = c.Cell + +/** + > type CrossChainAddress = slice + */ +export type CrossChainAddress = c.Slice + +export const CrossChainAddress = { + fromSlice(s: c.Slice): CrossChainAddress { + return invokeCustomUnpackFromSlice('CrossChainAddress', s); + }, + store(self: CrossChainAddress, b: c.Builder): void { + invokeCustomPackToBuilder('CrossChainAddress', self, b); + }, + toCell(self: CrossChainAddress): c.Cell { + return makeCellFrom(self, CrossChainAddress.store); + } +} + +/** + > struct CursedSubjects { + > data: map + > } + */ +export interface CursedSubjects { + readonly $: 'CursedSubjects' + data: c.Dictionary +} + +export const CursedSubjects = { + create(args: { + data: c.Dictionary + }): CursedSubjects { + return { + $: 'CursedSubjects', + ...args + } + }, + fromSlice(s: c.Slice): CursedSubjects { + return { + $: 'CursedSubjects', + data: c.Dictionary.load(c.Dictionary.Keys.BigUint(128), createDictionaryValue<[]>( + (s) => [], + (v,b) => { {} } + ), s), + } + }, + store(self: CursedSubjects, b: c.Builder): void { + b.storeDict(self.data, c.Dictionary.Keys.BigUint(128), createDictionaryValue<[]>( + (s) => [], + (v,b) => { {} } + )); + }, + toCell(self: CursedSubjects): c.Cell { + return makeCellFrom(self, CursedSubjects.store); + } +} + /** > struct RateLimiter_Config { > isEnabled: bool @@ -1476,66 +1487,74 @@ export const RateLimiter_TokenBucket = { } /** - > type CrossChainAddress = slice + > type ForwardPayloadRemainder = RemainingBitsAndRefs */ -export type CrossChainAddress = c.Slice +export type ForwardPayloadRemainder = RemainingBitsAndRefs -export const CrossChainAddress = { - fromSlice(s: c.Slice): CrossChainAddress { - return invokeCustomUnpackFromSlice('CrossChainAddress', s); +export const ForwardPayloadRemainder = { + fromSlice(s: c.Slice): ForwardPayloadRemainder { + return loadTolkRemaining(s); }, - store(self: CrossChainAddress, b: c.Builder): void { - invokeCustomPackToBuilder('CrossChainAddress', self, b); + store(self: ForwardPayloadRemainder, b: c.Builder): void { + storeTolkRemaining(self, b); }, - toCell(self: CrossChainAddress): c.Cell { - return makeCellFrom(self, CrossChainAddress.store); + toCell(self: ForwardPayloadRemainder): c.Cell { + return makeCellFrom(self, ForwardPayloadRemainder.store); } } /** - > struct CursedSubjects { - > data: map + > struct (0x7362d09c) TransferNotificationForRecipient { + > queryId: uint64 + > jettonAmount: coins + > transferInitiator: address? + > forwardPayload: ForwardPayloadRemainder > } */ -export interface CursedSubjects { - readonly $: 'CursedSubjects' - data: c.Dictionary +export interface TransferNotificationForRecipient { + readonly $: 'TransferNotificationForRecipient' + queryId: uint64 + jettonAmount: coins + transferInitiator: c.Address | null + forwardPayload: ForwardPayloadRemainder } -export const CursedSubjects = { +export const TransferNotificationForRecipient = { + PREFIX: 0x7362d09c, + create(args: { - data: c.Dictionary - }): CursedSubjects { + queryId: uint64 + jettonAmount: coins + transferInitiator: c.Address | null + forwardPayload: ForwardPayloadRemainder + }): TransferNotificationForRecipient { return { - $: 'CursedSubjects', + $: 'TransferNotificationForRecipient', ...args } }, - fromSlice(s: c.Slice): CursedSubjects { + fromSlice(s: c.Slice): TransferNotificationForRecipient { + loadAndCheckPrefix32(s, 0x7362d09c, 'TransferNotificationForRecipient'); return { - $: 'CursedSubjects', - data: c.Dictionary.load(c.Dictionary.Keys.BigUint(128), createDictionaryValue<[]>( - (s) => [], - (v,b) => { {} } - ), s), + $: 'TransferNotificationForRecipient', + queryId: s.loadUintBig(64), + jettonAmount: s.loadCoins(), + transferInitiator: s.loadMaybeAddress(), + forwardPayload: ForwardPayloadRemainder.fromSlice(s), } }, - store(self: CursedSubjects, b: c.Builder): void { - b.storeDict(self.data, c.Dictionary.Keys.BigUint(128), createDictionaryValue<[]>( - (s) => [], - (v,b) => { {} } - )); + store(self: TransferNotificationForRecipient, b: c.Builder): void { + b.storeUint(0x7362d09c, 32); + b.storeUint(self.queryId, 64); + b.storeCoins(self.jettonAmount); + b.storeAddress(self.transferInitiator); + ForwardPayloadRemainder.store(self.forwardPayload, b); }, - toCell(self: CursedSubjects): c.Cell { - return makeCellFrom(self, CursedSubjects.store); + toCell(self: TransferNotificationForRecipient): c.Cell { + return makeCellFrom(self, TransferNotificationForRecipient.store); } } -/** - > type SnakedCell = cell - */ -export type SnakedCell = c.Cell - /** > struct Ownable2Step { > owner: address @@ -1719,20 +1738,18 @@ export class TokenPool implements c.Contract { return TokenPool_UpdateRampAccess.toCell(TokenPool_UpdateRampAccess.create(body)); } - static createCellOfTokenPoolUpdateCursedSubjects(body: { - cursedSubjects: CursedSubjects + static createCellOfTokenPoolSetRMNProxy(body: { + queryId: uint64 + rmnProxy: c.Address }) { - return TokenPool_UpdateCursedSubjects.toCell(TokenPool_UpdateCursedSubjects.create(body)); + return TokenPool_SetRMNProxy.toCell(TokenPool_SetRMNProxy.create(body)); } - static createCellOfTokenPoolLockOrBurn(body: { + static createCellOfTokenPoolUpdateCursedSubjects(body: { queryId: uint64 - request: CellRef - requestedFinalityConfig: uint32 - tokenArgs: c.Cell | null - replyTo: c.Address | null + cursedSubjects: CursedSubjects }) { - return TokenPool_LockOrBurn.toCell(TokenPool_LockOrBurn.create(body)); + return TokenPool_UpdateCursedSubjects.toCell(TokenPool_UpdateCursedSubjects.create(body)); } static createCellOfTokenPoolReleaseOrMint(body: { @@ -1744,6 +1761,15 @@ export class TokenPool implements c.Contract { return TokenPool_ReleaseOrMint.toCell(TokenPool_ReleaseOrMint.create(body)); } + static createCellOfTransferNotificationForRecipient(body: { + queryId: uint64 + jettonAmount: coins + transferInitiator: c.Address | null + forwardPayload: ForwardPayloadRemainder + }) { + return TransferNotificationForRecipient.toCell(TransferNotificationForRecipient.create(body)); + } + async sendDeploy(provider: ContractProvider, via: Sender, msgValue: coins, extraOptions?: ExtraSendOptions) { return provider.internal(via, { value: msgValue, @@ -1846,26 +1872,24 @@ export class TokenPool implements c.Contract { }); } - async sendTokenPoolUpdateCursedSubjects(provider: ContractProvider, via: Sender, msgValue: coins, body: { - cursedSubjects: CursedSubjects + async sendTokenPoolSetRMNProxy(provider: ContractProvider, via: Sender, msgValue: coins, body: { + queryId: uint64 + rmnProxy: c.Address }, extraOptions?: ExtraSendOptions) { return provider.internal(via, { value: msgValue, - body: TokenPool_UpdateCursedSubjects.toCell(TokenPool_UpdateCursedSubjects.create(body)), + body: TokenPool_SetRMNProxy.toCell(TokenPool_SetRMNProxy.create(body)), ...extraOptions }); } - async sendTokenPoolLockOrBurn(provider: ContractProvider, via: Sender, msgValue: coins, body: { + async sendTokenPoolUpdateCursedSubjects(provider: ContractProvider, via: Sender, msgValue: coins, body: { queryId: uint64 - request: CellRef - requestedFinalityConfig: uint32 - tokenArgs: c.Cell | null - replyTo: c.Address | null + cursedSubjects: CursedSubjects }, extraOptions?: ExtraSendOptions) { return provider.internal(via, { value: msgValue, - body: TokenPool_LockOrBurn.toCell(TokenPool_LockOrBurn.create(body)), + body: TokenPool_UpdateCursedSubjects.toCell(TokenPool_UpdateCursedSubjects.create(body)), ...extraOptions }); } @@ -1882,4 +1906,17 @@ export class TokenPool implements c.Contract { ...extraOptions }); } + + async sendTransferNotificationForRecipient(provider: ContractProvider, via: Sender, msgValue: coins, body: { + queryId: uint64 + jettonAmount: coins + transferInitiator: c.Address | null + forwardPayload: ForwardPayloadRemainder + }, extraOptions?: ExtraSendOptions) { + return provider.internal(via, { + value: msgValue, + body: TransferNotificationForRecipient.toCell(TransferNotificationForRecipient.create(body)), + ...extraOptions + }); + } } From a1d947b9d2e530fd0981e3685c1092fb236e723d Mon Sep 17 00:00:00 2001 From: Kristijan Date: Wed, 10 Jun 2026 13:03:15 +0200 Subject: [PATCH 06/16] Update RateLimiter lib --- .../contracts/ccip/pools/rate_limiter.tolk | 157 ++++++++++++++---- .../contracts/ccip/pools/token_pool.tolk | 12 +- .../ccip/pools/LockReleaseTokenPool.spec.ts | 2 +- .../tests/ccip/pools/TokenPool.behavior.ts | 26 ++- contracts/wrappers/ccip/BurnMintTokenPool.ts | 4 +- .../wrappers/ccip/LockReleaseTokenPool.ts | 4 +- contracts/wrappers/ccip/TokenPool.ts | 14 +- 7 files changed, 160 insertions(+), 59 deletions(-) diff --git a/contracts/contracts/ccip/pools/rate_limiter.tolk b/contracts/contracts/ccip/pools/rate_limiter.tolk index 2ddf8b6f1..8c88322e8 100644 --- a/contracts/contracts/ccip/pools/rate_limiter.tolk +++ b/contracts/contracts/ccip/pools/rate_limiter.tolk @@ -1,17 +1,28 @@ // SPDX-License-Identifier: BUSL-1.1 +const RateLimiter_FACILITY_NAME = "link.chain.ton.ccip.rateLimiter"; +const RateLimiter_FACILITY_ID = 263; // (crc32() % 640) + 10 // TODO: update with computed val + +enum RateLimiter_Error { + BucketOverfilled = RateLimiter_FACILITY_ID * 100 + TokenMaxCapacityExceeded // (uint256 capacity, uint256 requested, address tokenAddress); + TokenRateLimitReached // (uint256 minWaitInSeconds, uint256 available, address tokenAddress); + InvalidRateLimitConfig // (Config rateLimiterConfig); + DisabledNonZeroRateLimit // (Config config); +} + struct RateLimiter_Config { - isEnabled: bool; - capacity: uint256; - rate: uint256; + isEnabled: bool // Indication whether the rate limiting should be enabled. + capacity: uint128 // ──╮ Specifies the capacity of the rate limiter. + rate: uint128 // ──────╯ Specifies the rate of the rate limiter. } struct RateLimiter_TokenBucket { - tokens: uint256; - lastUpdated: uint64; - isEnabled: bool; - capacity: uint256; - rate: uint256; + tokens: uint128 // ────╮ Current number of tokens that are in the bucket. + lastUpdated: uint64 // │ Timestamp in seconds of the last token refill, good for 100+ years. + isEnabled: bool // ────╯ Indication whether the rate limiting is enabled or not. + capacity: uint128 // ──╮ Maximum number of tokens that can be in the bucket. + rate: uint128 // ──────╯ Number of tokens per second that the bucket is refilled. } fun RateLimiter_tokenBucketFromConfig(config: RateLimiter_Config): RateLimiter_TokenBucket { @@ -24,22 +35,11 @@ fun RateLimiter_tokenBucketFromConfig(config: RateLimiter_Config): RateLimiter_T }; } -fun RateLimiter_consumeBucket(mutate bucket: RateLimiter_TokenBucket, amount: uint256) { - if (!bucket.isEnabled) { - return; - } - - RateLimiter_refillBucket(mutate bucket); - // TODO: should be RateLimiter error - // assert(bucket.tokens >= amount, TokenPool_Error.RateLimitExceeded); - bucket.tokens -= amount; -} - fun RateLimiter_rateLimitConfigFromCell(data: cell): RateLimiter_Config { var cs = data.beginParse(); val isEnabled = cs.loadUint(1) != 0; - val capacity = cs.loadUint(256); - val rate = cs.loadUint(256); + val capacity = cs.loadUint(128); + val rate = cs.loadUint(128); cs.assertEnd(); return RateLimiter_Config { isEnabled, @@ -48,24 +48,113 @@ fun RateLimiter_rateLimitConfigFromCell(data: cell): RateLimiter_Config { }; } -fun RateLimiter_refillBucket(mutate bucket: RateLimiter_TokenBucket) { - if (!bucket.isEnabled) { +/// @notice _consume removes the given tokens from the pool, lowering the rate tokens allowed to be +/// consumed for subsequent calls. +/// @param requestTokens The total tokens to be consumed from the bucket. +/// @param tokenAddress The token to consume capacity for, use 0x0 to indicate aggregate value capacity. +/// @dev Reverts when requestTokens exceeds bucket capacity or available tokens in the bucket. +/// @dev emits removal of requestTokens if requestTokens is > 0. +fun RateLimiter_TokenBucket._consume(mutate self, requestTokens: uint256, _tokenAddress: address) { + // If there is no value to remove or rate limiting is turned off, skip this step to reduce gas usage. + if (!self.isEnabled || requestTokens == 0) { return; } - val nowTs = blockchain.now(); - if (nowTs <= bucket.lastUpdated) { - return; + var tokens = self.tokens; + val capacity = self.capacity; + val timeDiff = blockchain.now() - self.lastUpdated; + + if (timeDiff != 0) { + if (tokens > capacity) { + throw RateLimiter_Error.BucketOverfilled; + } + + // Refill tokens when arriving at a new block time. + tokens = _calculateRefill(capacity, tokens, timeDiff, self.rate); + + self.lastUpdated = blockchain.now(); } - val elapsed = nowTs - bucket.lastUpdated; - val refill = (elapsed as uint256) * bucket.rate; - if (refill == 0) { - bucket.lastUpdated = nowTs; - return; + if (capacity < requestTokens) { + throw RateLimiter_Error.TokenMaxCapacityExceeded; + } + if (tokens < requestTokens) { + var rate = self.rate; + if (rate == 0) { + // No tokens will ever be refilled. Check is required to avoid division by zero later. + throw RateLimiter_Error.TokenRateLimitReached; + } + // Wait required until the bucket is refilled enough to accept this value, round up to next higher second. + // Consume is not guaranteed to succeed after wait time passes if there is competing traffic. + // This acts as a lower bound of wait time. + val _minWaitInSeconds = ((requestTokens - tokens) + (rate - 1)) / rate; + + throw RateLimiter_Error.TokenRateLimitReached; // TODO this should be a return? revert TokenRateLimitReached(minWaitInSeconds, tokens, tokenAddress); + } + tokens -= requestTokens; + + // Downcast is safe here, as tokens is not larger than capacity. + self.tokens = tokens as uint128; +} + +/// @notice Gets the token bucket with its values for the block it was requested at. +/// @return The token bucket. +fun RateLimiter_TokenBucket._currentTokenBucketState(mutate self): RateLimiter_TokenBucket { + // We update the bucket to reflect the status at the exact time of the call. This means we might need to refill a + // part of the bucket based on the time that has passed since the last update. + self.tokens = _calculateRefill( + self.capacity, + self.tokens, + blockchain.now() - self.lastUpdated, + self.rate + ); + self.lastUpdated = blockchain.now(); + return self; +} + +/// @notice Sets the rate limited config. +/// @param s_bucket The token bucket. +/// @param config The new config. +fun RateLimiter_TokenBucket._setTokenBucketConfig(mutate self, config: RateLimiter_Config) { + config.validate(); + + self.isEnabled = config.isEnabled; + self.tokens = config.capacity; + self.capacity = config.capacity; + self.rate = config.rate; + self.lastUpdated = blockchain.now(); +} + +/// @notice Validates the token bucket config. +fun RateLimiter_Config.validate(self) { + if (self.isEnabled) { + if (self.rate > self.capacity) { + throw RateLimiter_Error.InvalidRateLimitConfig; + } + } else { + if (self.rate != 0 || self.capacity != 0) { + throw RateLimiter_Error.DisabledNonZeroRateLimit; + } } +} - val nextTokens = bucket.tokens + refill; - bucket.tokens = nextTokens > bucket.capacity ? bucket.capacity : nextTokens; - bucket.lastUpdated = nowTs; +/// @notice Calculate refilled tokens. +/// @param capacity bucket capacity. +/// @param tokens current bucket tokens. +/// @param timeDiff block time difference since last refill. +/// @param rate bucket refill rate. +/// @return the value of tokens after refill. +fun _calculateRefill(capacity: uint128, tokens: uint128, timeDiff: uint256, rate: uint128): uint128 { + return _min(capacity, (tokens as uint256 + timeDiff * rate as uint256) as uint128); +} + +/// @notice Return the smallest of two integers. +/// @param a first int. +/// @param b second int. +/// @return smallest. +fun _min(a: uint128, b: uint128): uint128 { + if (a < b) { + return a; + } + return b; } diff --git a/contracts/contracts/ccip/pools/token_pool.tolk b/contracts/contracts/ccip/pools/token_pool.tolk index 213d252ce..0ceee4b92 100644 --- a/contracts/contracts/ccip/pools/token_pool.tolk +++ b/contracts/contracts/ccip/pools/token_pool.tolk @@ -846,7 +846,7 @@ fun TokenPool.consumeOutboundRateLimit(mutate self, remoteChainSelector: uint var config = self.data.remoteChainConfigs.mustGet(remoteChainSelector, TokenPool_Error.NonExistentChain as int); var rateLimiters = config.rateLimiters.load(); var bucket = rateLimiters.outbound.load(); - RateLimiter_consumeBucket(mutate bucket, amount); + bucket._consume(amount, self.data.token); rateLimiters.outbound = bucket.toCell(); config.rateLimiters = rateLimiters.toCell(); self.data.remoteChainConfigs.set(remoteChainSelector, config); @@ -862,7 +862,7 @@ fun TokenPool.consumeInboundRateLimit(mutate self, remoteChainSelector: uint6 var config = self.data.remoteChainConfigs.mustGet(remoteChainSelector, TokenPool_Error.NonExistentChain as int); var rateLimiters = config.rateLimiters.load(); var bucket = rateLimiters.inbound.load(); - RateLimiter_consumeBucket(mutate bucket, amount); + bucket._consume(amount, self.data.token); rateLimiters.inbound = bucket.toCell(); config.rateLimiters = rateLimiters.toCell(); self.data.remoteChainConfigs.set(remoteChainSelector, config); @@ -883,11 +883,11 @@ fun TokenPool.consumeFastFinalityOutboundRateLimit(mutate self, remoteChainSe if (!fastBucket.isEnabled) { var rateLimiters = config.rateLimiters.load(); var bucket = rateLimiters.outbound.load(); - RateLimiter_consumeBucket(mutate bucket, amount); + bucket._consume(amount, self.data.token); rateLimiters.outbound = bucket.toCell(); config.rateLimiters = rateLimiters.toCell(); } else { - RateLimiter_consumeBucket(mutate fastBucket, amount); + fastBucket._consume(amount, self.data.token); fastRateLimiters.outbound = fastBucket.toCell(); config.fastFinalityRateLimiters = fastRateLimiters.toCell(); } @@ -909,11 +909,11 @@ fun TokenPool.consumeFastFinalityInboundRateLimit(mutate self, remoteChainSel if (!fastBucket.isEnabled) { var rateLimiters = config.rateLimiters.load(); var bucket = rateLimiters.inbound.load(); - RateLimiter_consumeBucket(mutate bucket, amount); + bucket._consume(amount, self.data.token); rateLimiters.inbound = bucket.toCell(); config.rateLimiters = rateLimiters.toCell(); } else { - RateLimiter_consumeBucket(mutate fastBucket, amount); + fastBucket._consume(amount, self.data.token); fastRateLimiters.inbound = fastBucket.toCell(); config.fastFinalityRateLimiters = fastRateLimiters.toCell(); } diff --git a/contracts/tests/ccip/pools/LockReleaseTokenPool.spec.ts b/contracts/tests/ccip/pools/LockReleaseTokenPool.spec.ts index 2e6e04ef5..0f979ec38 100644 --- a/contracts/tests/ccip/pools/LockReleaseTokenPool.spec.ts +++ b/contracts/tests/ccip/pools/LockReleaseTokenPool.spec.ts @@ -361,7 +361,7 @@ describe('LockReleaseTokenPool', () => { const curseUpdate = await lockReleasePool.sendUpdateCursedSubjects( deployer.getSender(), toNano('0.2'), - [remoteChainSelector], + { queryId: 901n, cursedSubjects: [remoteChainSelector] }, ) expect(curseUpdate.transactions).toHaveTransaction({ diff --git a/contracts/tests/ccip/pools/TokenPool.behavior.ts b/contracts/tests/ccip/pools/TokenPool.behavior.ts index dc0c717ff..61b6cc79b 100644 --- a/contracts/tests/ccip/pools/TokenPool.behavior.ts +++ b/contracts/tests/ccip/pools/TokenPool.behavior.ts @@ -25,7 +25,7 @@ export type TokenPoolBehaviorContext = { sendUpdateCursedSubjects: ( via: Sender, value: bigint, - cursedSubjects: bigint[], + body: { queryId: bigint; cursedSubjects: bigint[] }, ) => Promise<{ transactions: unknown[] }> sendReleaseOrMint: ( via: Sender, @@ -112,9 +112,10 @@ export function runTokenPoolBehaviorTests( it('reverts releaseOrMint while chain is cursed', async () => { const ctx = await setup() - await ctx.pool.sendUpdateCursedSubjects(ctx.deployer.getSender(), toNano('0.2'), [ - ctx.remoteChainSelector, - ]) + await ctx.pool.sendUpdateCursedSubjects(ctx.deployer.getSender(), toNano('0.2'), { + queryId: 901n, + cursedSubjects: [ctx.remoteChainSelector], + }) expect(await ctx.pool.getVerifyNotCursed(ctx.remoteChainSelector)).toBe(false) const result = await ctx.pool.sendReleaseOrMint(ctx.offRamp.getSender(), toNano('0.3'), { @@ -197,7 +198,10 @@ export function runTokenPoolBehaviorTests( const result = await ctx.pool.sendUpdateCursedSubjects( ctx.unauthorized.getSender(), toNano('0.2'), - [ctx.remoteChainSelector], + { + queryId: 904n, + cursedSubjects: [ctx.remoteChainSelector], + }, ) expect(result.transactions).toHaveTransaction({ @@ -209,12 +213,16 @@ export function runTokenPoolBehaviorTests( it('can clear cursed subject back to not cursed', async () => { const ctx = await setup() - await ctx.pool.sendUpdateCursedSubjects(ctx.deployer.getSender(), toNano('0.2'), [ - ctx.remoteChainSelector, - ]) + await ctx.pool.sendUpdateCursedSubjects(ctx.deployer.getSender(), toNano('0.2'), { + queryId: 901n, + cursedSubjects: [ctx.remoteChainSelector], + }) expect(await ctx.pool.getVerifyNotCursed(ctx.remoteChainSelector)).toBe(false) - await ctx.pool.sendUpdateCursedSubjects(ctx.deployer.getSender(), toNano('0.2'), []) + await ctx.pool.sendUpdateCursedSubjects(ctx.deployer.getSender(), toNano('0.2'), { + queryId: 902n, + cursedSubjects: [], + }) expect(await ctx.pool.getVerifyNotCursed(ctx.remoteChainSelector)).toBe(true) }) diff --git a/contracts/wrappers/ccip/BurnMintTokenPool.ts b/contracts/wrappers/ccip/BurnMintTokenPool.ts index 8dfa58f73..14393ebab 100644 --- a/contracts/wrappers/ccip/BurnMintTokenPool.ts +++ b/contracts/wrappers/ccip/BurnMintTokenPool.ts @@ -95,9 +95,9 @@ export class BurnMintTokenPool implements Contract { provider: ContractProvider, via: Sender, value: bigint, - cursedSubjects: bigint[], + body: { queryId: bigint; cursedSubjects: bigint[] }, ) { - await sendUpdateCursedSubjects(provider, via, value, cursedSubjects) + await sendUpdateCursedSubjects(provider, via, value, body) } async sendReleaseOrMint( diff --git a/contracts/wrappers/ccip/LockReleaseTokenPool.ts b/contracts/wrappers/ccip/LockReleaseTokenPool.ts index c71ab4c14..7dae22609 100644 --- a/contracts/wrappers/ccip/LockReleaseTokenPool.ts +++ b/contracts/wrappers/ccip/LockReleaseTokenPool.ts @@ -96,9 +96,9 @@ export class LockReleaseTokenPool implements Contract { provider: ContractProvider, via: Sender, value: bigint, - cursedSubjects: bigint[], + body: { queryId: bigint; cursedSubjects: bigint[] }, ) { - await sendUpdateCursedSubjects(provider, via, value, cursedSubjects) + await sendUpdateCursedSubjects(provider, via, value, body) } async sendReleaseOrMint( diff --git a/contracts/wrappers/ccip/TokenPool.ts b/contracts/wrappers/ccip/TokenPool.ts index 4ec21372d..a9935055f 100644 --- a/contracts/wrappers/ccip/TokenPool.ts +++ b/contracts/wrappers/ccip/TokenPool.ts @@ -117,8 +117,8 @@ export const codec = { encode(data: RateLimitConfig): Builder { return beginCell() .storeBit(data.isEnabled) - .storeUint(data.capacity, 256) - .storeUint(data.rate, 256) + .storeUint(data.capacity, 128) + .storeUint(data.rate, 128) }, }, @@ -283,14 +283,18 @@ export async function sendUpdateCursedSubjects( provider: ContractProvider, via: Sender, value: bigint, - cursedSubjects: bigint[], + body: { queryId: bigint; cursedSubjects: bigint[] }, ) { const dict = Dictionary.empty(Dictionary.Keys.BigInt(128), Dictionary.Values.Bool()) - cursedSubjects.forEach((subject) => dict.set(subject, true)) + body.cursedSubjects.forEach((subject) => dict.set(subject, true)) await provider.internal(via, { value, sendMode: SendMode.PAY_GAS_SEPARATELY, - body: beginCell().storeUint(opcodes.in.updateCursedSubjects, 32).storeDict(dict).endCell(), + body: beginCell() + .storeUint(opcodes.in.updateCursedSubjects, 32) + .storeUint(body.queryId, 64) + .storeDict(dict) + .endCell(), }) } From 1f7ddf74fab6ef812400063b0abc145401910324 Mon Sep 17 00:00:00 2001 From: Kristijan Date: Wed, 10 Jun 2026 13:15:22 +0200 Subject: [PATCH 07/16] abigen --- .../gen/ccip/pools/BurnMintTokenPool.ts | 55 ++++++++++--------- .../gen/ccip/pools/LockReleaseTokenPool.ts | 55 ++++++++++--------- .../wrappers/gen/ccip/pools/TokenPool.ts | 50 ++++++++--------- 3 files changed, 83 insertions(+), 77 deletions(-) diff --git a/contracts/wrappers/gen/ccip/pools/BurnMintTokenPool.ts b/contracts/wrappers/gen/ccip/pools/BurnMintTokenPool.ts index 52264d2e2..62a672015 100644 --- a/contracts/wrappers/gen/ccip/pools/BurnMintTokenPool.ts +++ b/contracts/wrappers/gen/ccip/pools/BurnMintTokenPool.ts @@ -2776,22 +2776,22 @@ export const CrossChainAddress = { /** > struct RateLimiter_Config { > isEnabled: bool - > capacity: uint256 - > rate: uint256 + > capacity: uint128 + > rate: uint128 > } */ export interface RateLimiter_Config { readonly $: 'RateLimiter_Config' isEnabled: boolean - capacity: uint256 - rate: uint256 + capacity: uint128 + rate: uint128 } export const RateLimiter_Config = { create(args: { isEnabled: boolean - capacity: uint256 - rate: uint256 + capacity: uint128 + rate: uint128 }): RateLimiter_Config { return { $: 'RateLimiter_Config', @@ -2802,14 +2802,14 @@ export const RateLimiter_Config = { return { $: 'RateLimiter_Config', isEnabled: s.loadBoolean(), - capacity: s.loadUintBig(256), - rate: s.loadUintBig(256), + capacity: s.loadUintBig(128), + rate: s.loadUintBig(128), } }, store(self: RateLimiter_Config, b: c.Builder): void { b.storeBit(self.isEnabled); - b.storeUint(self.capacity, 256); - b.storeUint(self.rate, 256); + b.storeUint(self.capacity, 128); + b.storeUint(self.rate, 128); }, toCell(self: RateLimiter_Config): c.Cell { return makeCellFrom(self, RateLimiter_Config.store); @@ -2818,29 +2818,29 @@ export const RateLimiter_Config = { /** > struct RateLimiter_TokenBucket { - > tokens: uint256 + > tokens: uint128 > lastUpdated: uint64 > isEnabled: bool - > capacity: uint256 - > rate: uint256 + > capacity: uint128 + > rate: uint128 > } */ export interface RateLimiter_TokenBucket { readonly $: 'RateLimiter_TokenBucket' - tokens: uint256 + tokens: uint128 lastUpdated: uint64 isEnabled: boolean - capacity: uint256 - rate: uint256 + capacity: uint128 + rate: uint128 } export const RateLimiter_TokenBucket = { create(args: { - tokens: uint256 + tokens: uint128 lastUpdated: uint64 isEnabled: boolean - capacity: uint256 - rate: uint256 + capacity: uint128 + rate: uint128 }): RateLimiter_TokenBucket { return { $: 'RateLimiter_TokenBucket', @@ -2850,19 +2850,19 @@ export const RateLimiter_TokenBucket = { fromSlice(s: c.Slice): RateLimiter_TokenBucket { return { $: 'RateLimiter_TokenBucket', - tokens: s.loadUintBig(256), + tokens: s.loadUintBig(128), lastUpdated: s.loadUintBig(64), isEnabled: s.loadBoolean(), - capacity: s.loadUintBig(256), - rate: s.loadUintBig(256), + capacity: s.loadUintBig(128), + rate: s.loadUintBig(128), } }, store(self: RateLimiter_TokenBucket, b: c.Builder): void { - b.storeUint(self.tokens, 256); + b.storeUint(self.tokens, 128); b.storeUint(self.lastUpdated, 64); b.storeBit(self.isEnabled); - b.storeUint(self.capacity, 256); - b.storeUint(self.rate, 256); + b.storeUint(self.capacity, 128); + b.storeUint(self.rate, 128); }, toCell(self: RateLimiter_TokenBucket): c.Cell { return makeCellFrom(self, RateLimiter_TokenBucket.store); @@ -2908,7 +2908,7 @@ function calculateDeployedAddress(code: c.Cell, data: c.Cell, options: DeployedA } export class BurnMintTokenPool implements c.Contract { - static CodeCell = c.Cell.fromBase64('te6ccgECZwEAFiAAART/APSkE/S88sgLAQIBYgIDAgLMBAUCASAeHwIBIAYHAgEgMjMCASAICQIBIBgZAgEgCgsAV1IW6SW3DggmkAAAAAAAAAAAAAAAAAAAEigwb0Dm+hMZJbf+ABgwb0Dm+hMYBO0+JHyQO1E0NTU9AT0BNEj0NTU+kjTB/QE9ATRgQCFbW1tbW1tbZLwCACBAIZWE1YTVhNWE/iS+JcQXxBOED0QLBBbEEoQORAoEFcQRhA1ECRWGvAKPl8JBOMCXwok1ywkngulDOMC1ywjmxaE5OMC1ywmqZO23IAwNDg8BqTtou371ywnkNvtDI5E1ywnzxTyVJRbcNsx4YIAwoojbrPy9CGCAMKKBMcFE/L0IG0D1ws/iwIByMs/FfpSEvpSycjPhyAUznHPC2ETzMlw+wDjDX+AXAFw9PQHDAJM3NzeZMDk5EFheJBBF4gPIzBLM+lLLBxP0APQAycjMzBL0APQAye1UAMg1BNcLP/iSJNDU1DH6SDHTBzH0BDH0BDHR0NT6SDHUMdMfMdHQ+kj6UDHRAYIAwogCxwXy9IIK+vCAI9D6SNQx0cjPhYj6UgH6AoIQ+4jhGc8Liss/yXH7AALIzMz0APQAye1UAfo1BNM/MfoA+lD4kiXQ+kjU0YIAoPD4KCPIz4QCEvpS+lLJWMjPhNDMzPkWyM+KAEDL/89QI8cF8vQC9AQhbpgxIMcAkjBt4JLR0OKCAKDyIW6z8vTXLCCLCot08r/TP9TTH/QE+lDRA9DU0z/6SNP/+kjRIYIAoPMOuh3y9BAATo4bNQTXCz/4khBFEDQQI/AJA8jMEsz0APQAye1U4F8FhA8BxwDy9AH+ggCg8Stus/L0ggCg9FONgED0Dm+hMbPy9C7Q1NT6SNMH9AT0BNGBAIVtbW1tbW1tkvAIAIEAhlYdVh1WIYE6PVYRViDHBfL0gTo5VhZWEIBA9A5voTHy9IE6OlYS0PQEMfQEMfQE0VYX8AOz8vQpbrOcViFUcyFWEFYaL9pg3hEB/lYR0PQE9AQx9AQx0VYWAYBA9A5voZP6SNGSMG3igTo+IW6z8vSBOj4BVh/HBfL0K26zn1YhVGMzU/ARIlYaVhHacJJXHeJWEVYRVhFWEVYRVhFWJlOHViVWFVYVVhVWFVYVVhVWFVYVVhVWFVYpVilWKVYpVjVWMPAPbDMzMzQSAv40NFOyoTNWEI5LgTo4U+eAQPQOb6ES8vTU9ATU1NEB0NTU0QHQ0//TP9IA0//T/9Er8AQEyMv/E8s/ygDL/8v/ycjMzMkDyMwS9AASzMxUIOiAQPRD4w0mbrOOGlYZUyRWGChWE1YTVhNWE1YfVhpWGi5WE9rQ3jE1PVs7P1cSExQB/irQ1DH6SDHUMdMf0VYRAfAGgTo4U+eAQPQOb6ES8vTU9ATU1NEg0NTU0QHQ0//TP9IA0//T/9EijhdsFivwBATIy/8Tyz/KAMv/y//JyMzMyY4qXwYB0NTU0QHQ0//TP9IA0//T/9Er8AQEyMv/E8s/ygDL/8v/ycjMzMkB4gMVAf6BOjhTboBA9A5voRLy9NT0BDHUMdQx0VYSyMv/yQTIzBPM+lIBEREBywcc9AAW9ADJA8jMEss/+lITy/8Y+lLJCsjMFszJAcj6VBnMGMwkzwv/EvpSyVQgZYBA9BeCCvrwgPgobcjPhYgX+lJY+gKCEFlfB7zPC4oXyz9QA/oCFgAcyMwS9ADMzFQg6IBA9EMAKhX6VBL0AMlx+wACyMzM9AD0AMntVABmbBLTP/pIMIIAwohRNMcFE/L0ggDCiVMjxwWz8vQhiwLIz4cgznDPC2ESyz8S+lLJcPsAAgEgGhsCASAcHQAbCORMOFVQPAFUEWhQTSAAOwi3fgjUwS7kTDgUgWhIaggkTDhFaBTAbxSIuMEBIAApCGRW+GBOkYhlAK6wwCTbCFw4vL0gAE8cXqTIsIAjhwicbDAAZ+BOkKE/yOpBCK+8vRmqAHeIKgCqwAC6DAxgAgEgICECASAuLwIBICIjAgEgLC0CASAkJQBBtbUdqJoamoY+gIY+gIY6OhqGOoY/SQY6YP6Ahj6AhjowAgEgJicCAUgqKwAtrSp2omhqGOoY+gIY+gJowCB6BzfQmMACAUgoKQBvpXXaiaGpqGPoCGPoCGOjoahjqfSQY6YOY+gIY+gIY6Oh6Ahj6AnoCGOjAIHoHN9DJ/SRoyRg28UAP6cj2omhqahj6Ahj6Ahjo6GoY6hj9JGmDmPoCGPoCGOjAGKpX40JWxpbmsuY2hhaW4udG9uLmNjaXAuQnVybk1pbnRUb2tlblBvb2yCLUwLjEuMIACyp3e1E0NQx1DH0BPQEMdGAQPQOb6ExAGW0o72omhqahj6Ahj6Ahjo6GpqGP0kGOmDmPoCGPoCGOjoan0kGOoY6Y+Y6Oh9JH0oGOjAAcbdw3aiaGpqGPoCGPoCGOjoahjqfSQY6YOY+gIY+gIY6Oh6AnoCGPoCGOjAIHoHN9DJ/SRoyRg28UABXuD7e1E0NTUMfQEMfQEMdHQ1NQx+kgx0wcx9AQx9AQx0dDUMfpI1DHTHzHRgCAVgwMQBdsuB7UTQ1NQx9AQx9AQx0dDUMdT6SDHTBzH0BDH0BDHR0PQEMfQEMfQE0QHwA7OAAT7Ice1E0NTUMfQEMfQEMdHQ1DHUMfpIMdMHMfQE9AQx0YBA9A5voTGACASA0NQIBIGFiAgEgNjcCASA8PQL3DEyOzs8gTpFDcMAHfL0ggCg9lOtgED0Dm+hMbPy9C7Q+kjU0VNRyM+EAhL6UvpSyQHIz4TQzMz5FsjPigBAy//PUAfIzBbLP1JA+lITy//6UswZ9AAX9ADJBMjL/8kCyPpUFMzMEvpSyVQgJoBA9BeCEAX14QAgbfgoiYDg5AvcUxOAQPQOb6HjAjBTEoBA9A5voYIAoPcB8vTU0dD6UNTU+kjRBIIAoPkFxwUU8vRSNYBA9FswBNDUMdM/+kjT/zH6SNQx9AQx9AQx0STQ0//R+CjI+lIT+lLJAcj6UhLL/8zJyM+PGAAEghDpwAyXzwv3cM8LYRLLP8zJgOjsAAUAAeMjPkF41FGYnzws/UAr6AhL6VPpUz4QgF87JyM+FiBX6UgH6AoAVzwuKEss/E/pSUAP6AhLMyXH7AIEAhQD+1NHQ+lDU1NP/+kjRBYIAoPgGxwUV8vRSR4BA9FswAdDUMdM/+kjT/zH6SNHI+lL6UiTPC//JyM+PGAAEghA33W9uzwv3cM8LYRLLP8zJcPsAIW6TNV8DjiWCCJiWgMjPhYgT+lJY+gKCEBnmW+rPC4oTyz8UzBPL/8mAQfsA4gBYcPsAIG6SXwOOIYIImJaAyM+FiBL6UgH6AoIQfsQ67s8LihLLP8zJgEH7AOIESQxINcsJuBbf6zjAtcsIv6WRbTjAtcsJt+FFvzjAtcsIndQMFyA+P0BBAHkVxBfD2wxAdDU+kgx1NMfMdEB0PpI+lAx0SLHBZFb4ND6SDH6UPpQMdGBOj4hbrOVAscFwwCTbCFw4vL0gAfQx1NdMVhbQ1PpIMdQx0x8x0dD6SPpQMdEDggDCiATHBRPy9NBwkiCzjkWVIddJwgCOLgHTP1IQERSAQPRbgTo4AfL0yM+PGAAEghAnkIKLzwv3cM8LYRLLP8lw+wAREgHoIddKlAHXTNCTMH8B4gHoW9BwkiCziuhbf0IB/jHTPzHTP9dMVhbQ1PpIMdQx0x8x0dD6SPpQMdEDggDCiATHBRPy9IE6OCFWE4BA9A5voTHy9IE6OCFWE4BA9A5voRLy9NT0BNTU0YE6NybQ0wchwUHyhQGqAtcY0ddJwwDy9CXQ0wchwUHyhQGqAtcY0cjOcfkEA4E6P1MUgwdHAv4x0z8x0z/XTFYW0NT6SDHUMdMfMdHQ+kj6UDHRA4IAwogExwUT8vSBOjghVhOAQPQOb6Ex8vSBOjghVhOAQPQOb6ES8vTU9ATU1NEl0NMHIcFB8oUBqgLXGNHIznH5BANQA4MH9FuBOkAB8vQDyMwT9AASzMxREBETgED0Q8iJSEkE/I5oMdM/MfpI+lD6UDARF9DU+kjUMdMf0SLQ+kj6UDHRBoIAwogHxwUW8vQjyPpSUjD6VFYZAfpUyQLIzPpSzBPLH8kByPpSEvpUAREVAfpUycjPjxgABIIQtzXjDM8L93HPC2HMyXD7AH/g1ywhTaN+NOMC1ywh0BRtFOMCiUpLTE0BLJUh10nCAIroIddKlAHXTNCTMH8B4gFDAf4B0z/U1NQB0NQB0NMAAcMAAdP/0//RA9QB0NMAAcMAAdP/0//RA9GBOjco0NMHIcFB8oUBqgLXGNHXScMA8vSBOjsqVhyAQPQOb6Exs/L0bfgjJcjL/8s/FsoAFMv/Fcv/yfgjI8jL/8s/FcoAEsv/y//JAsjMEszJ+CNwyMv/RAHqyz/PgXDPC/9wzwv/yfgjcMjL/8s/z4Fwzwv/cM8L/8kByMzMySQG0HCSILOOlpUh10nCAIroIddKlAHXTNCTMH8B4gHoW8jPjxgABIIQ7TfEvM8L93DPC2Enzws/FczJcPsABMjM9AATzMxZEROAQPRDEREBRQH6AdMHIcFB8oUBqgLXGCHXSYE6QiGpOALy8lEi1xkCqwLIywcSzsmBOjch0NMHIcFB8oUBqgLXGNHXScMA8vQg0NMHIcFB8oUBqgLXGNHIznH5BAOBOj9TF4MH9A5voTGz8vRUQReDB/QXyM+PGAAEghC/DRq2zwv3cM8LYSpGABTPCz8WzMlw+wABAH70Dm+hMbPy9FRGFIMH9BcDyMwT9AASzMxREBETgED0Q8jPjxgABIIQvw0ats8L93DPC2EBERIByz/MyXD7AH8ABcYAAQA2zxaCELwUx+jPC/dwzwthARESAcs/zMlw+wB/AJ4x0z8x1wsfERXQ1PpI1NMfMdEi0PpI+lAx0QSCAMKIBccFFPL0VhYCyMz6UhLMyx/JyM+PGAAEghBCanE7zwv3cM8LYQERFQHLH8lw+wB/AZox10xWFQFWFQFWFQFWFQFWFQFWFQFWFQFWFQFWFQFWFQFWFQFWFQFWFQFWFQFWFQFWFQFWFQFWFQFWFQFWFQERFfAL0JQgxwCziugwf04ACBDEtKEE5NcnjtQx1NdMVhbQ1PpIMdQx0x8x0dD6SPpQMdEDggDCiATHBRPy9NCUIMcAs4roMNCUIMcAs44dINdLAZEwm4E0vAHAAfL010zQ4tM/ERCAQPRbMA/oMH/g1ywj1OJVLOMC1ywgkaKzxOMC1ywkEe1vlFFSU1QC/iDXSwGRMJuBNLwBwAHy9NdM0OLTP9IA1NSBOjglVhaAQPQOb6ES8vTU9ATU1NEHjj/Q1DHUMdEE0NIA0//T/9H4IyLIy//LPxPKAMv/y//JA9DSANP/0//R+CMiyMv/yz8TygDL/8v/yQPIzBPMyQTjDQLIzBP0ABPMEsxZERJPUAB+BtDUMdQx0QTQ0gDT/9P/0fgjIsjL/8s/E8oAy//L/8kD0NIA0//T/9H4IyLIy//LPxPKAMv/y//JA8jME8zJAAyAQPRDERAA4CDXSwGRMJuBNLwBwAHy9NdM0OLTP9IA0//T/9Mf0x/TD9MPgTo4KVYbgED0Dm+hMfL0gTo1KPL0gTo0I4EnELny9IE6NCKBJxC58vSBOjUlwgDy9AfIygAWy/8Uy/8Syx/LH8sPyw9ZERKAQPRDERABrDHXTBEV0NT6SNTTH9ED0PpI+lDRggDCiFFixwUW8vTI+lIU+lTJyMz6UhLMyx/JERPQ9AT0BPQE0REW0JQgxwCziugwAcj0APQAAREUAfQAyRESERN/VQB6MdM/MfpIMBEV0NT6SDHU0x/RItD6SPpQMdEEggDCiAXHBRTy9AHIzAERFgH6UgERFQHMAREUAcsfyRETfwP8jk4x0z8x9AWBOj5WFtDUMfpI1DHTHzHRE8cFEvL0ERPQ9AT0BPQEMdEByPQA9AABERMB9ADJyM+PGAAEghAnXgI0zwv3cM8LYclw+wAREn/g1ywj6H/sTOMC1ywjmxaE5DGSW3DgVhXQ1PpI1NMf0QPQ+kj6UNFBBiXwAeMCVldYANQg10sBkTCbgTS8AcAB8vTXTNDi0z/6UPpQIm6XUjaAQPRbMJsiyPpSVCBHgED0Q+IhbpdSNYBA9FswmyHI+lJUIEaAQPRD4gPIyz8S+lT6VMnIz48YAASCEJxau5XPC/dxzwthzMlw+wBYA/4x0z/U0x/6UDAi0NTTP/pI0//6SNT0BPQE0YE6PVYfJccF8vSBOjknVh6AQPQOb6Ex8vSBOjpWIND0BDH0BDH0BNEo8AOz8vQtwwCWVhNus8MAkXDin1YaVhpWGlYaVhorVhnaYN5WH9D0BDH0BPQEMdFScIBA9A5voeMPgTo+WVpbAD40VxgRF8j6UhL6VMnIzAERFgH6UswBERQByx/JERN/AAwQRV8FxwAABvpI0QAEMG0B/CFus/L0gTo+UR7HBfL0LcMAllYUbrPDAJFw4o4RVhpWGlYaVhpWGlYRLFYb2nDegTpAViFWIVYhViFWIVYhViFWIVYhViFWIVYhViFWIVYhViFWIVYhViFWIVYbVhjwDPL0ViBWIFYgViBWIFYgViBWIFYgViBWIFYgViBWIFwD/lYgViBWIFYgViBWIFYV8A1WIQFWIQFWIQFWIQFWIQFWIQFWIQFWIQFWIQFWIQFWIQFWIQFWIQFWIQFWIQFWIQFWIQFWIQFWIQFWIQFWGQHwDirDACvjDy/DAJZWE26zwwCRcOKOGVYcVhxWHFYcVhxUftxUftxUftxWGVYi2vBdXl8B/lYi0NQx+kgx1DHTH9FSwPAGgTo4KVYggED0Dm+hEvL01PQE1NTRINDU1NHQ0//TP9IA0//T/9EijhhsFirwBATIy/8Tyz/KAMv/y//JAcjMzMmOKl8GAdDU1NHQ0//TP9IA0//T/9Eq8AQEyMv/E8s/ygDL/8v/yQHIzMzJAeJgAJqBOjgpViCAQPQOb6ES8vTU9ATU1NEB0NTU0dDT/9M/0gDT/9P/0SrwBATIy/8Tyz/KAMv/y//JAcjMzMkDyMwS9AASzMxSkhEggED0QwCO3lOxgTpFVhLDAJZWE26zwwCRcOLy9BEVER4RFREUER0RFBETERwRExESERsREhERERoREQIRIFADVhuAFnXbOBBNEDxLqX8AIAPIzBL0AMzMUpIRIIBA9EMCASBjZAIBIGVmAHEVxNXEV8PbCOAQPQOb6GSW3Dh1DH0BNQx1DHRAdDTByHBQfKFAaoC1xjRyM5x+QQDAYMH9A5voTGAAYRXEF8PbCIyIW6RMeAw0IE6QSHXSYMHupch10rAAMMAkXDi8vTT/9GBOkEhhAe78vSAAhRXE1cQXw8zM1MCupIwMeBTAryeWKGBOkIhwU7y9PAHqQTgEqGBOkIhwU7y9PAHgTpCIZmE/yKpBCO+wwCRf+Ly9KiAAewxMmzzbEQ0AoBA9A5voZNfA3Dh0gDT/zHT/zHTHzHTHzHTD9MP0QKTXwRw4QKXMaiBJxCpBOAwqIEnEKkEg'); + static CodeCell = c.Cell.fromBase64('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'); static Errors = { 'Common_Error.CrossChainAddressOutOfRange': 5, @@ -2928,6 +2928,9 @@ export class BurnMintTokenPool implements c.Contract { 'TokenPool_Error.OverflowDetected': 14914, 'TokenPool_Error.UnsupportedOperation': 14917, 'TokenPool_Error.InvalidRequestedFinality': 14918, + 'RateLimiter_Error.BucketOverfilled': 26300, + 'RateLimiter_Error.TokenMaxCapacityExceeded': 26301, + 'RateLimiter_Error.TokenRateLimitReached': 26302, 'Error.IncorrectJettonSender': 41200, 'Error.MissingTransferInitiator': 41201, 'Error.MissingForwardPayload': 41202, diff --git a/contracts/wrappers/gen/ccip/pools/LockReleaseTokenPool.ts b/contracts/wrappers/gen/ccip/pools/LockReleaseTokenPool.ts index 3d478dceb..f2b9935e6 100644 --- a/contracts/wrappers/gen/ccip/pools/LockReleaseTokenPool.ts +++ b/contracts/wrappers/gen/ccip/pools/LockReleaseTokenPool.ts @@ -2527,22 +2527,22 @@ export const CrossChainAddress = { /** > struct RateLimiter_Config { > isEnabled: bool - > capacity: uint256 - > rate: uint256 + > capacity: uint128 + > rate: uint128 > } */ export interface RateLimiter_Config { readonly $: 'RateLimiter_Config' isEnabled: boolean - capacity: uint256 - rate: uint256 + capacity: uint128 + rate: uint128 } export const RateLimiter_Config = { create(args: { isEnabled: boolean - capacity: uint256 - rate: uint256 + capacity: uint128 + rate: uint128 }): RateLimiter_Config { return { $: 'RateLimiter_Config', @@ -2553,14 +2553,14 @@ export const RateLimiter_Config = { return { $: 'RateLimiter_Config', isEnabled: s.loadBoolean(), - capacity: s.loadUintBig(256), - rate: s.loadUintBig(256), + capacity: s.loadUintBig(128), + rate: s.loadUintBig(128), } }, store(self: RateLimiter_Config, b: c.Builder): void { b.storeBit(self.isEnabled); - b.storeUint(self.capacity, 256); - b.storeUint(self.rate, 256); + b.storeUint(self.capacity, 128); + b.storeUint(self.rate, 128); }, toCell(self: RateLimiter_Config): c.Cell { return makeCellFrom(self, RateLimiter_Config.store); @@ -2569,29 +2569,29 @@ export const RateLimiter_Config = { /** > struct RateLimiter_TokenBucket { - > tokens: uint256 + > tokens: uint128 > lastUpdated: uint64 > isEnabled: bool - > capacity: uint256 - > rate: uint256 + > capacity: uint128 + > rate: uint128 > } */ export interface RateLimiter_TokenBucket { readonly $: 'RateLimiter_TokenBucket' - tokens: uint256 + tokens: uint128 lastUpdated: uint64 isEnabled: boolean - capacity: uint256 - rate: uint256 + capacity: uint128 + rate: uint128 } export const RateLimiter_TokenBucket = { create(args: { - tokens: uint256 + tokens: uint128 lastUpdated: uint64 isEnabled: boolean - capacity: uint256 - rate: uint256 + capacity: uint128 + rate: uint128 }): RateLimiter_TokenBucket { return { $: 'RateLimiter_TokenBucket', @@ -2601,19 +2601,19 @@ export const RateLimiter_TokenBucket = { fromSlice(s: c.Slice): RateLimiter_TokenBucket { return { $: 'RateLimiter_TokenBucket', - tokens: s.loadUintBig(256), + tokens: s.loadUintBig(128), lastUpdated: s.loadUintBig(64), isEnabled: s.loadBoolean(), - capacity: s.loadUintBig(256), - rate: s.loadUintBig(256), + capacity: s.loadUintBig(128), + rate: s.loadUintBig(128), } }, store(self: RateLimiter_TokenBucket, b: c.Builder): void { - b.storeUint(self.tokens, 256); + b.storeUint(self.tokens, 128); b.storeUint(self.lastUpdated, 64); b.storeBit(self.isEnabled); - b.storeUint(self.capacity, 256); - b.storeUint(self.rate, 256); + b.storeUint(self.capacity, 128); + b.storeUint(self.rate, 128); }, toCell(self: RateLimiter_TokenBucket): c.Cell { return makeCellFrom(self, RateLimiter_TokenBucket.store); @@ -2659,7 +2659,7 @@ function calculateDeployedAddress(code: c.Cell, data: c.Cell, options: DeployedA } export class LockReleaseTokenPool implements c.Contract { - static CodeCell = c.Cell.fromBase64('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'); + static CodeCell = c.Cell.fromBase64('te6ccgECaAEAFbgAART/APSkE/S88sgLAQIBYgIDAgLMBAUCASAGBwIBIBobAgEgODkCASAICQIBIBQVAgEgCgsCASAQEQIBIAwNADu1tR2omhqahj6Ahjo6GoY6hj9JBjpg/oCGPoCGOjACAWoODwBpsFfjQobGluay5jaGFpbi50b24uY2NpcC5Mb2NrUmVsZWFzZVRva2VuUG9vbIItTAuMS4wiAAaaV12omhqahj6Ahjo6GoY6n0kGOmDmPoCGPoCGOjoegIY+gJ6AhjowCB6BzfQyf0kaMkYNvFADmnI9qJoamoY+gIY6OhqGOoY/SRpg5j6Ahj6AhjowBftKO9qJoamoY+gIY6Ohqahj9JBjpg5j6Ahj6Ahjo6Gp9JBjqGOmPmOjofSR9KBjowAgN7YBITAF2jr7UTQ1NQx9AQx0dDU1DH6SDHTBzH0BDH0BDHR0NT6SDHUMdMfMdHQ+kgx+lDRgBpohu1E0NTUMfQEMdHQ1DHU+kgx0wcx9AQx9AQx0dD0BPQEMfQEMdGAQPQOb6GT+kjRkjBt4oAUbg+3tRNDU1DH0BDHR0NTUMfpIMdMHMfQEMfQEMdHQ1DH6SNQx0x8x0YAgFYFhcAV7Lge1E0NTUMfQEMdHQ1DHU+kgx0wcx9AQx9AQx0dD0BDH0BDH0BNEB8AOzgAgFYGBkASKhx7UTQ1NQx9AQx0dDUMdQx+kgx0wcx9AT0BDHRgED0Dm+hMQAmqqjtRNDUMdQx9ATRgED0Dm+hMQIBIBwdAgEgMjMCASAeHwBXUhbpJbcOCCaQAAAAAAAAAAAAAAAAAAASKDBvQOb6Exklt/4AGDBvQOb6ExgE0z4keMC7UTQ1NT0BNEi0NTU+kjTB/QE9ATRgQCFbW1tbW1tbZLwCACBAIZWElYSVhL4kviXEE4QPRAsEEsQOhApEEgQNxAmEEUQNBAjVhjwCT1fCQPjAl8JI9csI5sWhOTjAtcsJqmTttyAgISIjAak7aLt+9csJ5Db7QyORNcsJ88U8lSUW3DbMeGCAMKKI26z8vQhggDCigTHBRPy9CBtA9cLP4sCAcjLPxX6UhL6UsnIz4cgFM5xzwthE8zJcPsA4w1/gMQH20x8x1ywgfFP1LI7s7UTQ1NT0BNED1ws/+JIi0PpI1NGBZsP4KMjPhAL6UhP6UskByM+E0MzM+RbIz4oAQMv/z1ASxwXy9FMDgED0Dm+hgWbBAfL01NHQ+lDUMdQx+kgx0VIVgED0WzAkbpI0MOMOAcjMzPQAye1U4PI/JABOOzvDAJI2NpY4OBBXEEbiA8jMEsz6UssHEvQA9ADJyMwSzPQAye1UAfw0A9M/MfoA+lD4kiTQ+kjU0YFmvPgoyM+EAvpSE/pSyQHIz4TQzMz5FsjPigBAy//PUBLHBfL09AQhbpgxIMcAkjBt4JLR0OKBZr4hbrPy9NcsIIsKi3Tyv9M/1NMf9AT6UNED0NTTP/pI0//6SNEhgWa/DLob8vSBZr0pbrMlARbjAl8EhA8BxwDy9C0ASIIImJaAyM+FiBb6UlAF+gKCEEGhcCvPC4rLP8+Jmw7JgEH7AAL68vQr0NTU+kjTB/QE9ATRgQCFbW1tbW1tbZLwCACBAIZWGlYdgTo9VhBWHccF8vSBOjlWFS+AQPQOb6Ex8vSBOjpWEdD0BDH0BDH0BNFWFvADs/L0KG6zmlYdVHIcVhgt2lDeVhDQ9AT0BDH0BDHRVhUBgED0Dm+hkjBt4w1bJgT+gTo+IW6z8vSBOj4BVhzHBfL0Km6znVYdVHIcVh5WGVYQ2mDeVhFWEVYRVhFWEVYRViNTh1YUVhRWFFYUVhRWFFYUVhRWFFYUVihWKFYoVihWMlYv8A5sMzMzNDQ0U7KhM1YQ4w8mbrPjADE1OVs3ODg4PYE6OFNFgED0Dm+hEicoKSoB7irQ1DH6SDHUMdMf0VYRAfAGgTo4U+eAQPQOb6ES8vTU9ATU1NEg0NTU0QHQ03/TP9IA03/Tf9EijixfBgHQ1NTRAdDTf9M/0gDTf9N/0StWEvAEBMjLfxPLP8oAy3/Lf8nIzMzJAeMNA8jMEvQAzMxUIOiAQPRDKwCagTo4U+eAQPQOb6ES8vTU9ATU1NEB0NTU0QHQ03/TP9IA03/Tf9ErVhLwBATIy38Tyz/KAMt/y3/JyMzMyQPIzBL0ABLMzFQg6IBA9EMAMFYWVHJFVhJWElYSVhJWHFYZVhktVhLawAH+8vTU9AQx1DHUMdEmyMv/yQLIzB7MF/pSFcsHE/QAEvQAyQfI+lIW+lIhzwv/ycjPjxgABIIQN91vbs8L93DPC2EWyz8VzMlw+wAhbpNfBDKOKoIImJaAB8jMzMnIz4WIEvpSUAb6AoIQGeZb6s8Liss/FMwTy//JgEH7AOIByCwAMmwWK1YS8AQEyMt/E8s/ygDLf8t/ycjMzMkADszM9ADJ7VQD/jQD1ws/+JJTFIBA9A5voYFmwQHy9NTR0PpQ1NT6SNEEgWbCBccFFPL0UjeAQPRbMAbQ1DHTP/pI0/8x+kjUMfQEMfQEMdEk0NP/0fgoyPpSE/pSyQHI+lISy//MycjPjxgABIIQ6cAMl88L93DPC2ESyz/MyXD7ACBu4w8ByMwuLzAABF8DAEKCCJiWgMjPhYgS+lIB+gKCEH7EOu7PC4oSyz/MyYBB+wAADMz0AMntVABmbBLTP/pIMIIAwohRNMcFE/L0ggDCiVMjxwWz8vQhiwLIz4cgznDPC2ESyz8S+lLJcPsAAgEgNDUCASA2NwCrDAjs5F/lSDAAMMA4pEw4CL4IyahII4YNlNgvJWBZrzy8OBRUqgWoFJA8AUF+CMFkTDiIbmVgWa98vDgU1C5jhEVXwUglYFmvvLw4TCBZr7y8OAVoQSAADRcuZEw4DGAAKQhkVvhgTpGIZQCusMAk2whcOLy9IABPHF6kyLCAI4cInGwwAGfgTpChP8jqQQivvL0ZqgB3iCoAqsAAugwMYAIBIDo7AgEgZGUCASA8PQIBIGJjAfcMTI7OzyBOkUNwwAd8vSBZsBTrYBA9A5voTGz8vQt0PpI1NFTUcjPhAIS+lL6UskhyM+E0MzM+RbIz4oAQMv/z1AIyMwXyz9SUPpSFMv/EvpSzBr0ABj0AMkFyMv/yQPI+lQVzBLM+lLJVCA3gED0F4IK+vCAcfgo+CjIgPgRJDEg1ywm4Ft/rOMC1ywi/pZFtOMC1ywm34UW/OMC1ywid1AwXIEBBQkMBponPFvpSGPpSyVAEyM+E0MzM+RbIz4oAQMv/z1BtiwTIz5A+KfqWF8s/UAn6Ahb6Uhb6VBb0AM+EIBLOycjPhYgT+lJQA/oCcc8LaszJAfsAgQCFPwACAAH0MdTXTFYV0NT6SDHUMdMfMdHQ+kj6UDHRA4IAwogExwUT8vTQcJIgs45FlSHXScIAji4B0z9SEBETgED0W4E6OAHy9MjPjxgABIIQJ5CCi88L93DPC2ESyz/JcPsAEREB6CHXSpQB10zQkzB/AeIB6FvQcJIgs4roW39EAf4x0z8x0z/XTFYV0NT6SDHUMdMfMdHQ+kj6UDHRA4IAwogExwUT8vSBOjghVhKAQPQOb6Ex8vSBOjghVhKAQPQOb6ES8vTU9ATU1NGBOjcm0NMHIcFB8oUBqgLXGNHXScMA8vQl0NMHIcFB8oUBqgLXGNHIznH5BAOBOj9TFIMHSQL+MdM/MdM/10xWFdDU+kgx1DHTHzHR0PpI+lAx0QOCAMKIBMcFE/L0gTo4IVYSgED0Dm+hMfL0gTo4IVYSgED0Dm+hEvL01PQE1NTRJdDTByHBQfKFAaoC1xjRyM5x+QQDUAODB/RbgTpAAfL0A8jME/QAEszMURAREoBA9EPIiUpLBPyOaDHTPzH6SPpQ+lAwERbQ1PpI1DHTH9Ei0PpI+lAx0QaCAMKIB8cFFvL0I8j6UlIw+lRWGAH6VMkCyMz6UswTyx/JAcj6UhL6VAERFAH6VMnIz48YAASCELc14wzPC/dxzwthzMlw+wB/4NcsIU2jfjTjAtcsIdAUbRTjAolMTU5PASyVIddJwgCK6CHXSpQB10zQkzB/AeIBRQH+AdM/1NTUAdDUAdDTAAHDAAHTf9N/0QPUAdDTAAHDAAHTf9N/0QPRgTo3KNDTByHBQfKFAaoC1xjR10nDAPL0gTo7KlYbgED0Dm+hMbPy9G34IyXIy3/LPxbKABTLfxXLf8n4IyPIy3/LPxXKABLLf8t/yQLIzBLMyfgjcMjLf0YB4ss/cM8LgHDPC3/J+CNwyMt/yz9wzwuAcM8Lf8kByMzMySQG0HCSILOOlpUh10nCAIroIddKlAHXTNCTMH8B4gHoW8jPjxgABIIQ7TfEvM8L93DPC2Enzws/FczJcPsABMjM9AATzMxZERKAQPRDERABRwH6AdMHIcFB8oUBqgLXGCHXSYE6QiGpOALy8lEi1xkCqwLIywcSzsmBOjch0NMHIcFB8oUBqgLXGNHXScMA8vQg0NMHIcFB8oUBqgLXGNHIznH5BAOBOj9TF4MH9A5voTGz8vRUQReDB/QXyM+PGAAEghC/DRq2zwv3cM8LYSpIABTPCz8WzMlw+wABAH70Dm+hMbPy9FRGFIMH9BcDyMwT9AASzMxREBESgED0Q8jPjxgABIIQvw0ats8L93DPC2EBEREByz/MyXD7AH8ABcYAAQA2zxaCELwUx+jPC/dwzwthARERAcs/zMlw+wB/AJ4x0z8x1wsfERTQ1PpI1NMfMdEi0PpI+lAx0QSCAMKIBccFFPL0VhUCyMz6UhLMyx/JyM+PGAAEghBCanE7zwv3cM8LYQERFAHLH8lw+wB/AZQx10xWFAFWFAFWFAFWFAFWFAFWFAFWFAFWFAFWFAFWFAFWFAFWFAFWFAFWFAFWFAFWFAFWFAFWFAFWFAERFPAK0JQgxwCziugwf1AACBDEtKEE4tcnjtMx1NdMVhXQ1PpIMdQx0x8x0dD6SPpQMdEDggDCiATHBRPy9NCUIMcAs4roMNCUIMcAs44cINdLAZEwm4E0vAHAAfL010zQ4tM/D4BA9FswDugwf+DXLCPU4lUs4wLXLCCRorPE4wLXLCQR7W+UU1RVVgL+INdLAZEwm4E0vAHAAfL010zQ4tM/0gDU1IE6OCVWFYBA9A5voRLy9NT0BNTU0QeOP9DUMdQx0QTQ0gDTf9N/0fgjIsjLf8s/E8oAy3/Lf8kD0NIA03/Tf9H4IyLIy3/LPxPKAMt/y3/JA8jME8zJBOMNAsjME/QAE8wSzFkREVFSAH4G0NQx1DHRBNDSANN/03/R+CMiyMt/yz8TygDLf8t/yQPQ0gDTf9N/0fgjIsjLf8s/E8oAy3/Lf8kDyMwTzMkACoBA9EMPAN4g10sBkTCbgTS8AcAB8vTXTNDi0z/SANP/0//TH9Mf0w/TD4E6OClWGoBA9A5voTHy9IE6NSjy9IE6NCOBJxC58vSBOjQigScQufL0gTo1JcIA8vQHyMoAFsv/FMv/Essfyx/LD8sPWRERgED0Qw8BrDHXTBEU0NT6SNTTH9ED0PpI+lDRggDCiFFixwUW8vTI+lIU+lTJyMz6UhLMyx/JERLQ9AT0BPQE0REV0JQgxwCziugwAcj0APQAARETAfQAyRERERJ/VwB6MdM/MfpIMBEU0NT6SDHU0x/RItD6SPpQMdEEggDCiAXHBRTy9AHIzAERFQH6UgERFAHMARETAcsfyRESfwP8jk4x0z8x9AWBOj5WFdDUMfpI1DHTHzHRE8cFEvL0ERLQ9AT0BPQEMdEByPQA9AABERIB9ADJyM+PGAAEghAnXgI0zwv3cM8LYclw+wAREX/g1ywj6H/sTOMC1ywjmxaE5DGSW3DgVhTQ1PpI1NMf0QPQ+kj6UNFBBiXwAeMCWFlaANQg10sBkTCbgTS8AcAB8vTXTNDi0z/6UPpQIm6XUjaAQPRbMJsiyPpSVCBHgED0Q+IhbpdSNYBA9FswmyHI+lJUIEaAQPRD4gPIyz8S+lT6VMnIz48YAASCEJxau5XPC/dxzwthzMlw+wBYAvox0z/U0x/6UDAi0NTTP/pI0//6SNT0BPQE0YE6PVYeJccF8vSBOjknVh2AQPQOb6Ex8vSBOjpWH9D0BDH0BDH0BNEo8AOz8vQtwwCWVhNus8MAkXDinVYZVhlWGVYZKlYY2lDeVh7Q9AQx9AT0BDHRUnCAQPQOb6GSMG3jDVtcAD40VxcRFsj6UhL6VMnIzAERFQH6UswBERMByx/JERJ/AAwQRV8FxwAABvpI0QH8gTo+IW6z8vSBOj5RHscF8vQtwwCWVhRus8MAkXDin1YZVhlWGVYZVhArVhraYN6BOkBWIFYgViBWIFYgViBWIFYgViBWIFYgViBWIFYgViBWIFYgViBWIFYaVhfwC/L0Vh9WH1YfVh9WH1YfVh9WH1YfVh9WH1YfVh9WH1YfXQP8Vh9WH1YfVh9WFPAMViABViABViABViABViABViABViABViABViABViABViABViABViABViABViABViABViABViABViABVhgB8A0qwwAr4w8vwwCWVhNus8MAkXDijhdWG1YbVhtWG1R9y1R9y1R9y1YYViHa4N5TsYE6RVYSXl9gAfBWIdDUMfpIMdQx0x/RUsDwBoE6OClWH4BA9A5voRLy9NT0BNTU0SDQ1NTR0NN/0z/SANN/03/RIo4sXwYB0NTU0dDTf9M/0gDTf9N/0SpWKfAEBMjLfxPLP8oAy3/Lf8kByMzMyQHjDQPIzBL0AMzMUpIRH4BA9ENhAJ6BOjgpVh+AQPQOb6ES8vTU9ATU1NEB0NTU0dDTf9M/0gDTf9N/0SpWKfAEBMjLfxPLP8oAy3/Lf8kByMzMyQPIzBL0ABLMzFKSER+AQPRDAG7DAJZWE26zwwCRcOLy9BEUER0RFBETERwRExESERsREhERERoREQIRH1ADVhuAFXTbOBA8S6l/ADRsFipWKfAEBMjLfxPLP8oAy3/Lf8kByMzMyQB5FcQXw9sIQHQ1PpIMdTTHzHRAdD6SPpQMdEixwWRW+DQ+kgx+lD6UDHRgTo+IW6zlQLHBcMAk2whcOLy9IABzFcRVxFfDjMzAYBA9A5voZJbcOHUMfQE1DHUMdEB0NMHIcFB8oUBqgLXGNHIznH5BAMBgwf0Dm+hMYAIBIGZnAH9DEybMMzM2xENFqAQPQOb6GTXwNw4dIA0/8x0/8x0x8x0x8x0w/TD9ECk18EcOEDlzKogScQqQTgMKiBJxCpBIAF8VxFfD2wiIW6RMeAw0IE6QSHXSYMHupch10rAAMMAkXDi8vTT/9GBOkEhhAe78vSAAgxXE1cRXw8zUxK6kmwh4FMSvJ4CoYE6QiHBTvL08AepBOACooE6QiHBTvL08AeBOkIhmYT/IqkEI77DAJF/4vL0qIA=='); static Errors = { 'Common_Error.CrossChainAddressOutOfRange': 5, @@ -2679,8 +2679,11 @@ export class LockReleaseTokenPool implements c.Contract { 'TokenPool_Error.OverflowDetected': 14914, 'TokenPool_Error.UnsupportedOperation': 14917, 'TokenPool_Error.InvalidRequestedFinality': 14918, + 'RateLimiter_Error.BucketOverfilled': 26300, 'Error.IncorrectJettonSender': 26300, 'Error.MissingTransferInitiator': 26301, + 'RateLimiter_Error.TokenMaxCapacityExceeded': 26301, + 'RateLimiter_Error.TokenRateLimitReached': 26302, 'Error.MissingForwardPayload': 26302, 'Error.AmountMismatch': 26303, 'Error.PendingReleaseAlreadyExists': 26304, diff --git a/contracts/wrappers/gen/ccip/pools/TokenPool.ts b/contracts/wrappers/gen/ccip/pools/TokenPool.ts index 77d014325..bfc5533de 100644 --- a/contracts/wrappers/gen/ccip/pools/TokenPool.ts +++ b/contracts/wrappers/gen/ccip/pools/TokenPool.ts @@ -1393,22 +1393,22 @@ export const CursedSubjects = { /** > struct RateLimiter_Config { > isEnabled: bool - > capacity: uint256 - > rate: uint256 + > capacity: uint128 + > rate: uint128 > } */ export interface RateLimiter_Config { readonly $: 'RateLimiter_Config' isEnabled: boolean - capacity: uint256 - rate: uint256 + capacity: uint128 + rate: uint128 } export const RateLimiter_Config = { create(args: { isEnabled: boolean - capacity: uint256 - rate: uint256 + capacity: uint128 + rate: uint128 }): RateLimiter_Config { return { $: 'RateLimiter_Config', @@ -1419,14 +1419,14 @@ export const RateLimiter_Config = { return { $: 'RateLimiter_Config', isEnabled: s.loadBoolean(), - capacity: s.loadUintBig(256), - rate: s.loadUintBig(256), + capacity: s.loadUintBig(128), + rate: s.loadUintBig(128), } }, store(self: RateLimiter_Config, b: c.Builder): void { b.storeBit(self.isEnabled); - b.storeUint(self.capacity, 256); - b.storeUint(self.rate, 256); + b.storeUint(self.capacity, 128); + b.storeUint(self.rate, 128); }, toCell(self: RateLimiter_Config): c.Cell { return makeCellFrom(self, RateLimiter_Config.store); @@ -1435,29 +1435,29 @@ export const RateLimiter_Config = { /** > struct RateLimiter_TokenBucket { - > tokens: uint256 + > tokens: uint128 > lastUpdated: uint64 > isEnabled: bool - > capacity: uint256 - > rate: uint256 + > capacity: uint128 + > rate: uint128 > } */ export interface RateLimiter_TokenBucket { readonly $: 'RateLimiter_TokenBucket' - tokens: uint256 + tokens: uint128 lastUpdated: uint64 isEnabled: boolean - capacity: uint256 - rate: uint256 + capacity: uint128 + rate: uint128 } export const RateLimiter_TokenBucket = { create(args: { - tokens: uint256 + tokens: uint128 lastUpdated: uint64 isEnabled: boolean - capacity: uint256 - rate: uint256 + capacity: uint128 + rate: uint128 }): RateLimiter_TokenBucket { return { $: 'RateLimiter_TokenBucket', @@ -1467,19 +1467,19 @@ export const RateLimiter_TokenBucket = { fromSlice(s: c.Slice): RateLimiter_TokenBucket { return { $: 'RateLimiter_TokenBucket', - tokens: s.loadUintBig(256), + tokens: s.loadUintBig(128), lastUpdated: s.loadUintBig(64), isEnabled: s.loadBoolean(), - capacity: s.loadUintBig(256), - rate: s.loadUintBig(256), + capacity: s.loadUintBig(128), + rate: s.loadUintBig(128), } }, store(self: RateLimiter_TokenBucket, b: c.Builder): void { - b.storeUint(self.tokens, 256); + b.storeUint(self.tokens, 128); b.storeUint(self.lastUpdated, 64); b.storeBit(self.isEnabled); - b.storeUint(self.capacity, 256); - b.storeUint(self.rate, 256); + b.storeUint(self.capacity, 128); + b.storeUint(self.rate, 128); }, toCell(self: RateLimiter_TokenBucket): c.Cell { return makeCellFrom(self, RateLimiter_TokenBucket.store); From 37fa92f8b660b5a50cfa94f32aadf476fdad0f3b Mon Sep 17 00:00:00 2001 From: Kristijan Date: Thu, 11 Jun 2026 10:45:34 +0200 Subject: [PATCH 08/16] Use abigen - init --- .../lock_release_token_pool/contract.tolk | 4 + .../ccip/pools/token_pool_contract.tolk | 44 ++ contracts/src/utils/dict.ts | 6 + contracts/src/utils/types.ts | 4 + .../ccip/pools/BurnMintTokenPool.spec.ts | 29 +- .../ccip/pools/LockReleaseTokenPool.spec.ts | 29 +- .../tests/ccip/pools/TokenPool.behavior.ts | 426 ++++++++++-------- .../wrappers/gen/ccip/pools/TokenPool.ts | 87 +++- 8 files changed, 447 insertions(+), 182 deletions(-) diff --git a/contracts/contracts/ccip/pools/lock_release_token_pool/contract.tolk b/contracts/contracts/ccip/pools/lock_release_token_pool/contract.tolk index 9e8170ace..8f814ff32 100644 --- a/contracts/contracts/ccip/pools/lock_release_token_pool/contract.tolk +++ b/contracts/contracts/ccip/pools/lock_release_token_pool/contract.tolk @@ -27,6 +27,10 @@ contract LockReleaseTokenPool { incomingMessages: TokenPool_InMessage | LockReleaseTokenPool_InMessage // TODO: all incoming messages should be registered } +// TODO: +// _lockOrBurn -> after async checks, (1) does nothing, or (2) deposits to the Lockbox +// _releaseOrMint -> after async checks, (1) transfers from own wallet, or (2) withdraws from the Lockbox + fun onInternalMessage(in: InMessage) { var st = Storage.load(); var pool = loadPool(st); diff --git a/contracts/contracts/ccip/pools/token_pool_contract.tolk b/contracts/contracts/ccip/pools/token_pool_contract.tolk index ae5d054d1..850bcc163 100644 --- a/contracts/contracts/ccip/pools/token_pool_contract.tolk +++ b/contracts/contracts/ccip/pools/token_pool_contract.tolk @@ -19,3 +19,47 @@ contract TokenPool { fun onInternalMessage(in: InMessage) { throw 0xFFFF; // template for bindings, should not be deployed } + +get fun typeAndVersion(): (slice, slice) { + throw 0xFFFF; +} + +get fun token(): address { + throw 0xFFFF; +} + +get fun tokenDecimals(): uint8 { + throw 0xFFFF; +} + +get fun isSupportedChain(remoteChainSelector: uint64): bool { + throw 0xFFFF; +} + +get fun onRamp(remoteChainSelector: uint64): address? { + throw 0xFFFF; +} + +get fun offRamp(remoteChainSelector: uint64): address? { + throw 0xFFFF; +} + +get fun hasPendingRelease(queryId: uint64): bool { + throw 0xFFFF; +} + +get fun getRMNProxy(): address { + throw 0xFFFF; +} + +get fun verifyNotCursed(subject: uint128): bool { + throw 0xFFFF; +} + +get fun owner(): address { + throw 0xFFFF; +} + +get fun pendingOwner(): address? { + throw 0xFFFF; +} diff --git a/contracts/src/utils/dict.ts b/contracts/src/utils/dict.ts index aef130f7c..01b0a70b4 100644 --- a/contracts/src/utils/dict.ts +++ b/contracts/src/utils/dict.ts @@ -21,3 +21,9 @@ export function loadDict(dict: Dictionary return map } + +// Returns an DictionaryValue<[]> key (serialized as bool), used for map +// where value is an empty tesnor (not important, only presence of key matters) +export function createEmptyTensorValue() { + return Dictionary.Values.Bool() as unknown as DictionaryValue<[]> +} diff --git a/contracts/src/utils/types.ts b/contracts/src/utils/types.ts index 5cc280742..d32893104 100644 --- a/contracts/src/utils/types.ts +++ b/contracts/src/utils/types.ts @@ -33,6 +33,10 @@ export function uint8ArrayToBigInt(bytes: Uint8Array): bigint { return result } +export function asSnakedCellEmpty(): Cell { + return asSnakedCell([], (item: T) => new Builder()) +} + export function asSnakedCell(array: T[], builderFn: (item: T) => Builder): Cell { const cells: Builder[] = [] let builder = beginCell() diff --git a/contracts/tests/ccip/pools/BurnMintTokenPool.spec.ts b/contracts/tests/ccip/pools/BurnMintTokenPool.spec.ts index 024e800c5..0d4fa43bb 100644 --- a/contracts/tests/ccip/pools/BurnMintTokenPool.spec.ts +++ b/contracts/tests/ccip/pools/BurnMintTokenPool.spec.ts @@ -1,6 +1,6 @@ import '@ton/test-utils' import { Blockchain, SandboxContract, TreasuryContract } from '@ton/sandbox' -import { Address, Cell, beginCell, toNano } from '@ton/core' +import { Address, Builder, Cell, Slice, beginCell, toNano } from '@ton/core' import { JettonMinter, JettonWallet } from '../../../wrappers/examples/jetton' import { BurnMintTokenPool, @@ -10,6 +10,8 @@ import { import { CCTJettonMinter } from '../../../wrappers/ccip/CCTJettonMinter' import { CCTJettonMinterCode, CCTJettonWalletCode } from '../../../wrappers/ccip/CCTJettonCode' import { runTokenPoolBehaviorTests } from './TokenPool.behavior' +import { CrossChainAddress, TokenPool } from '../../../wrappers/gen/ccip/pools/TokenPool' +import * as rtOld from '../../../wrappers/ccip/Router' describe('BurnMintTokenPool', () => { let blockchain: Blockchain @@ -21,6 +23,7 @@ describe('BurnMintTokenPool', () => { let cctMinter: SandboxContract let cctMinterRuntime: SandboxContract let burnMintPool: SandboxContract + let pool: SandboxContract let cctWalletCode: Cell let userWallet: (address: Address) => Promise> @@ -30,6 +33,25 @@ describe('BurnMintTokenPool', () => { const destTokenAddress = poolCodec.crossChainAddressFromBuffer(Buffer.from('dest-token')) const receiverAddress = poolCodec.crossChainAddressFromBuffer(Buffer.from('receiver')) + beforeAll(async () => { + // TODO: move this to a common setup utility + function CrossChainAddress__packToBuilder(self: CrossChainAddress, b: Builder): void { + const src = self.clone() + const buffer = src.loadBuffer(src.remainingBits / 8) + b.storeBuilder(rtOld.builder.data.crossChainAddress.encode(buffer)) + } + function CrossChainAddress__unpackFromSlice(s: Slice): CrossChainAddress { + const buff = rtOld.builder.data.crossChainAddress.load(s) + return beginCell().storeBuffer(buff).asSlice() as CrossChainAddress + } + + TokenPool.registerCustomPackUnpack( + 'CrossChainAddress', + CrossChainAddress__packToBuilder, + CrossChainAddress__unpackFromSlice, + ) + }) + beforeEach(async () => { blockchain = await Blockchain.create() deployer = await blockchain.treasury('deployer') @@ -74,6 +96,9 @@ describe('BurnMintTokenPool', () => { ) await burnMintPool.sendDeploy(deployer.getSender(), toNano('2')) + // Standard TokenPool interface + pool = blockchain.openContract(TokenPool.fromAddress(burnMintPool.address)) + await burnMintPool.sendApplyChainUpdates(deployer.getSender(), toNano('0.2'), { queryId: 1n, remove: [], @@ -170,7 +195,7 @@ describe('BurnMintTokenPool', () => { }) runTokenPoolBehaviorTests('BurnMintTokenPool', async () => ({ - pool: burnMintPool, + pool, deployer, offRamp, altOffRamp: deployer, diff --git a/contracts/tests/ccip/pools/LockReleaseTokenPool.spec.ts b/contracts/tests/ccip/pools/LockReleaseTokenPool.spec.ts index 0f979ec38..2d49fbe0b 100644 --- a/contracts/tests/ccip/pools/LockReleaseTokenPool.spec.ts +++ b/contracts/tests/ccip/pools/LockReleaseTokenPool.spec.ts @@ -1,6 +1,6 @@ import '@ton/test-utils' import { Blockchain, SandboxContract, TreasuryContract } from '@ton/sandbox' -import { Address, Cell, Message, beginCell, toNano } from '@ton/core' +import { Address, Builder, Cell, Message, Slice, beginCell, toNano } from '@ton/core' import { JettonMinter, JettonSender, JettonWallet } from '../../../wrappers/examples/jetton' import { LockReleaseTokenPool, @@ -9,6 +9,8 @@ import { } from '../../../wrappers/ccip/LockReleaseTokenPool' import * as jetton from '../../../wrappers/jetton/JettonCode' import { runTokenPoolBehaviorTests } from './TokenPool.behavior' +import { CrossChainAddress, TokenPool } from '../../../wrappers/gen/ccip/pools/TokenPool' +import * as rtOld from '../../../wrappers/ccip/Router' describe('LockReleaseTokenPool', () => { let blockchain: Blockchain @@ -19,6 +21,7 @@ describe('LockReleaseTokenPool', () => { let jettonMinter: SandboxContract let jettonSender: SandboxContract let lockReleasePool: SandboxContract + let pool: SandboxContract let jettonWalletCode: Cell let userWallet: (address: Address) => Promise> @@ -28,6 +31,25 @@ describe('LockReleaseTokenPool', () => { const destTokenAddress = poolCodec.crossChainAddressFromBuffer(Buffer.from('dest-token')) const receiverAddress = poolCodec.crossChainAddressFromBuffer(Buffer.from('receiver')) + beforeAll(async () => { + // TODO: move this to a common setup utility + function CrossChainAddress__packToBuilder(self: CrossChainAddress, b: Builder): void { + const src = self.clone() + const buffer = src.loadBuffer(src.remainingBits / 8) + b.storeBuilder(rtOld.builder.data.crossChainAddress.encode(buffer)) + } + function CrossChainAddress__unpackFromSlice(s: Slice): CrossChainAddress { + const buff = rtOld.builder.data.crossChainAddress.load(s) + return beginCell().storeBuffer(buff).asSlice() as CrossChainAddress + } + + TokenPool.registerCustomPackUnpack( + 'CrossChainAddress', + CrossChainAddress__packToBuilder, + CrossChainAddress__unpackFromSlice, + ) + }) + beforeEach(async () => { blockchain = await Blockchain.create() deployer = await blockchain.treasury('deployer') @@ -84,6 +106,9 @@ describe('LockReleaseTokenPool', () => { ) await lockReleasePool.sendDeploy(deployer.getSender(), toNano('2')) + // Standard TokenPool interface + pool = blockchain.openContract(TokenPool.fromAddress(lockReleasePool.address)) + const applyChains = await lockReleasePool.sendApplyChainUpdates( deployer.getSender(), toNano('0.2'), @@ -155,7 +180,7 @@ describe('LockReleaseTokenPool', () => { }) runTokenPoolBehaviorTests('LockReleaseTokenPool', async () => ({ - pool: lockReleasePool, + pool, deployer, offRamp, altOffRamp: deployer, diff --git a/contracts/tests/ccip/pools/TokenPool.behavior.ts b/contracts/tests/ccip/pools/TokenPool.behavior.ts index 61b6cc79b..789e7ccab 100644 --- a/contracts/tests/ccip/pools/TokenPool.behavior.ts +++ b/contracts/tests/ccip/pools/TokenPool.behavior.ts @@ -1,48 +1,20 @@ import '@ton/test-utils' import { SandboxContract, TreasuryContract } from '@ton/sandbox' -import { Address, beginCell, Cell, Sender, toNano } from '@ton/core' -import { ReleaseOrMintInV1 } from '../../../wrappers/ccip/TokenPool' +import { Address, beginCell, Cell, Dictionary, DictionaryValue, Sender, toNano } from '@ton/core' +import { + CursedSubjects, + TokenPool, + TokenPool_ChainUpdate, + TokenPool_RampUpdate, + TokenPool_RateLimitConfigPair, + TokenPool_ReleaseOrMintInV1, + RateLimiter_Config, +} from '../../../wrappers/gen/ccip/pools/TokenPool' +import { asSnakedCell, asSnakedCellEmpty } from '../../../src/utils' +import { createEmptyTensorValue, loadMap } from '../../../src/utils/dict' export type TokenPoolBehaviorContext = { - pool: { - sendApplyChainUpdates: ( - via: Sender, - value: bigint, - body: { queryId: bigint; remove: bigint[]; add: ChainUpdateInput[] }, - ) => Promise<{ transactions: unknown[] }> - sendUpdateRampAccess: ( - via: Sender, - value: bigint, - body: { - queryId: bigint - updates: { - remoteChainSelector: bigint - onRamp: Address | null - offRamp: Address | null - }[] - }, - ) => Promise<{ transactions: unknown[] }> - sendUpdateCursedSubjects: ( - via: Sender, - value: bigint, - body: { queryId: bigint; cursedSubjects: bigint[] }, - ) => Promise<{ transactions: unknown[] }> - sendReleaseOrMint: ( - via: Sender, - value: bigint, - body: { - queryId: bigint - request: ReleaseOrMintInV1 - requestedFinalityConfig?: number - replyTo?: Address | null - }, - ) => Promise<{ transactions: unknown[] }> - getVerifyNotCursed: (subject: bigint) => Promise - getOnRamp: (remoteChainSelector: bigint) => Promise
- getOffRamp: (remoteChainSelector: bigint) => Promise
- getIsSupportedChain: (remoteChainSelector: bigint) => Promise - address: Address - } + pool: SandboxContract deployer: SandboxContract offRamp: SandboxContract unauthorized: SandboxContract @@ -54,29 +26,21 @@ export type TokenPoolBehaviorContext = { localToken: Address } -type ChainUpdateInput = { - remoteChainSelector: bigint - remotePoolAddresses: Cell[] - remoteTokenAddress: Cell - outboundRateLimiterConfig: { isEnabled: boolean; capacity: bigint; rate: bigint } - inboundRateLimiterConfig: { isEnabled: boolean; capacity: bigint; rate: bigint } -} - function releaseRequest( ctx: TokenPoolBehaviorContext, - overrides: Partial = {}, -): ReleaseOrMintInV1 { - return { - originalSender: ctx.sourcePoolAddress, + overrides: Partial = {}, +): TokenPool_ReleaseOrMintInV1 { + return TokenPool_ReleaseOrMintInV1.create({ + originalSender: { ref: ctx.sourcePoolAddress.beginParse() }, remoteChainSelector: ctx.remoteChainSelector, receiver: ctx.recipient.address, sourceDenominatedAmount: 1n, localToken: ctx.localToken, - sourcePoolAddress: ctx.sourcePoolAddress, + sourcePoolAddress: { ref: ctx.sourcePoolAddress.beginParse() }, sourcePoolData: null, offchainTokenData: null, ...overrides, - } + }) } export function runTokenPoolBehaviorTests( @@ -95,12 +59,16 @@ export function runTokenPoolBehaviorTests( it('reverts releaseOrMint when caller is not configured off-ramp', async () => { const ctx = await setup() - const result = await ctx.pool.sendReleaseOrMint(ctx.unauthorized.getSender(), toNano('0.3'), { - queryId: 901n, - request: releaseRequest(ctx), - requestedFinalityConfig: 0, - replyTo: ctx.deployer.address, - }) + const result = await ctx.pool.sendTokenPoolReleaseOrMint( + ctx.unauthorized.getSender(), + toNano('0.3'), + { + queryId: 901n, + request: { ref: releaseRequest(ctx) }, + requestedFinalityConfig: 0n, + replyTo: ctx.deployer.address, + }, + ) expect(result.transactions).toHaveTransaction({ from: ctx.unauthorized.address, @@ -112,18 +80,28 @@ export function runTokenPoolBehaviorTests( it('reverts releaseOrMint while chain is cursed', async () => { const ctx = await setup() - await ctx.pool.sendUpdateCursedSubjects(ctx.deployer.getSender(), toNano('0.2'), { + await ctx.pool.sendTokenPoolUpdateCursedSubjects(ctx.deployer.getSender(), toNano('0.2'), { queryId: 901n, - cursedSubjects: [ctx.remoteChainSelector], + cursedSubjects: CursedSubjects.create({ + data: loadMap( + Dictionary.Keys.BigInt(128), + createEmptyTensorValue(), + new Map([[ctx.remoteChainSelector, []]]), + ), + }), }) expect(await ctx.pool.getVerifyNotCursed(ctx.remoteChainSelector)).toBe(false) - const result = await ctx.pool.sendReleaseOrMint(ctx.offRamp.getSender(), toNano('0.3'), { - queryId: 902n, - request: releaseRequest(ctx), - requestedFinalityConfig: 0, - replyTo: ctx.deployer.address, - }) + const result = await ctx.pool.sendTokenPoolReleaseOrMint( + ctx.offRamp.getSender(), + toNano('0.3'), + { + queryId: 902n, + request: { ref: releaseRequest(ctx) }, + requestedFinalityConfig: 0n, + replyTo: ctx.deployer.address, + }, + ) expect(result.transactions).toHaveTransaction({ from: ctx.offRamp.address, @@ -152,13 +130,13 @@ export function runTokenPoolBehaviorTests( it('rejects applyChainUpdates from non-owner', async () => { const ctx = await setup() - const result = await ctx.pool.sendApplyChainUpdates( + const result = await ctx.pool.sendTokenPoolApplyChainUpdates( ctx.unauthorized.getSender(), toNano('0.2'), { queryId: 903n, - remove: [], - add: [], + remoteChainSelectorsToRemove: asSnakedCellEmpty(), + chainsToAdd: asSnakedCellEmpty(), }, ) @@ -171,18 +149,21 @@ export function runTokenPoolBehaviorTests( it('rejects updateRampAccess from non-owner', async () => { const ctx = await setup() - const result = await ctx.pool.sendUpdateRampAccess( + const result = await ctx.pool.sendTokenPoolUpdateRampAccess( ctx.unauthorized.getSender(), toNano('0.2'), { queryId: 904n, - updates: [ - { - remoteChainSelector: ctx.remoteChainSelector, - onRamp: ctx.onRampAddress, - offRamp: ctx.unauthorized.address, - }, - ], + updates: asSnakedCell( + [ + TokenPool_RampUpdate.create({ + remoteChainSelector: ctx.remoteChainSelector, + onRamp: ctx.onRampAddress, + offRamp: ctx.unauthorized.address, + }), + ], + (item) => TokenPool_RampUpdate.toCell(item).asBuilder(), + ), }, ) @@ -195,12 +176,18 @@ export function runTokenPoolBehaviorTests( it('rejects cursed-subject updates from non-rmn sender', async () => { const ctx = await setup() - const result = await ctx.pool.sendUpdateCursedSubjects( + const result = await ctx.pool.sendTokenPoolUpdateCursedSubjects( ctx.unauthorized.getSender(), toNano('0.2'), { queryId: 904n, - cursedSubjects: [ctx.remoteChainSelector], + cursedSubjects: CursedSubjects.create({ + data: loadMap( + Dictionary.Keys.BigInt(128), + createEmptyTensorValue(), + new Map([[ctx.remoteChainSelector, []]]), + ), + }), }, ) @@ -213,26 +200,40 @@ export function runTokenPoolBehaviorTests( it('can clear cursed subject back to not cursed', async () => { const ctx = await setup() - await ctx.pool.sendUpdateCursedSubjects(ctx.deployer.getSender(), toNano('0.2'), { + await ctx.pool.sendTokenPoolUpdateCursedSubjects(ctx.deployer.getSender(), toNano('0.2'), { queryId: 901n, - cursedSubjects: [ctx.remoteChainSelector], + cursedSubjects: CursedSubjects.create({ + data: loadMap( + Dictionary.Keys.BigInt(128), + createEmptyTensorValue(), + new Map([[ctx.remoteChainSelector, []]]), + ), + }), }) expect(await ctx.pool.getVerifyNotCursed(ctx.remoteChainSelector)).toBe(false) - await ctx.pool.sendUpdateCursedSubjects(ctx.deployer.getSender(), toNano('0.2'), { + await ctx.pool.sendTokenPoolUpdateCursedSubjects(ctx.deployer.getSender(), toNano('0.2'), { queryId: 902n, - cursedSubjects: [], + cursedSubjects: CursedSubjects.create({ + data: Dictionary.empty(Dictionary.Keys.BigInt(128)), + }), }) expect(await ctx.pool.getVerifyNotCursed(ctx.remoteChainSelector)).toBe(true) }) it('removes configured chain via applyChainUpdates', async () => { const ctx = await setup() - const result = await ctx.pool.sendApplyChainUpdates(ctx.deployer.getSender(), toNano('0.2'), { - queryId: 905n, - remove: [ctx.remoteChainSelector], - add: [], - }) + const result = await ctx.pool.sendTokenPoolApplyChainUpdates( + ctx.deployer.getSender(), + toNano('0.2'), + { + queryId: 905n, + remoteChainSelectorsToRemove: asSnakedCell([ctx.remoteChainSelector], (item: bigint) => + beginCell().storeUint(item, 64), + ), + chainsToAdd: asSnakedCellEmpty(), + }, + ) expect(result.transactions).toHaveTransaction({ from: ctx.deployer.address, @@ -244,18 +245,24 @@ export function runTokenPoolBehaviorTests( it('reverts releaseOrMint after configured chain is removed', async () => { const ctx = await setup() - await ctx.pool.sendApplyChainUpdates(ctx.deployer.getSender(), toNano('0.2'), { + await ctx.pool.sendTokenPoolApplyChainUpdates(ctx.deployer.getSender(), toNano('0.2'), { queryId: 906n, - remove: [ctx.remoteChainSelector], - add: [], + remoteChainSelectorsToRemove: asSnakedCell([ctx.remoteChainSelector], (item: bigint) => + beginCell().storeUint(item, 64), + ), + chainsToAdd: asSnakedCellEmpty(), }) - const result = await ctx.pool.sendReleaseOrMint(ctx.offRamp.getSender(), toNano('0.3'), { - queryId: 907n, - request: releaseRequest(ctx), - requestedFinalityConfig: 0, - replyTo: ctx.deployer.address, - }) + const result = await ctx.pool.sendTokenPoolReleaseOrMint( + ctx.offRamp.getSender(), + toNano('0.3'), + { + queryId: 907n, + request: { ref: releaseRequest(ctx) }, + requestedFinalityConfig: 0n, + replyTo: ctx.deployer.address, + }, + ) expect(result.transactions).toHaveTransaction({ from: ctx.offRamp.address, @@ -266,11 +273,18 @@ export function runTokenPoolBehaviorTests( it('rejects removing a non-existent chain', async () => { const ctx = await setup() - const result = await ctx.pool.sendApplyChainUpdates(ctx.deployer.getSender(), toNano('0.2'), { - queryId: 908n, - remove: [ctx.remoteChainSelector + 1n], - add: [], - }) + const result = await ctx.pool.sendTokenPoolApplyChainUpdates( + ctx.deployer.getSender(), + toNano('0.2'), + { + queryId: 908n, + remoteChainSelectorsToRemove: asSnakedCell( + [ctx.remoteChainSelector + 1n], + (item: bigint) => beginCell().storeUint(item, 64), + ), + chainsToAdd: asSnakedCellEmpty(), + }, + ) expect(result.transactions).toHaveTransaction({ from: ctx.deployer.address, @@ -281,16 +295,23 @@ export function runTokenPoolBehaviorTests( it('can replace off-ramp mapping via updateRampAccess', async () => { const ctx = await setup() - const result = await ctx.pool.sendUpdateRampAccess(ctx.deployer.getSender(), toNano('0.2'), { - queryId: 909n, - updates: [ - { - remoteChainSelector: ctx.remoteChainSelector, - onRamp: ctx.onRampAddress, - offRamp: ctx.unauthorized.address, - }, - ], - }) + const result = await ctx.pool.sendTokenPoolUpdateRampAccess( + ctx.deployer.getSender(), + toNano('0.2'), + { + queryId: 909n, + updates: asSnakedCell( + [ + TokenPool_RampUpdate.create({ + remoteChainSelector: ctx.remoteChainSelector, + onRamp: ctx.onRampAddress, + offRamp: ctx.unauthorized.address, + }), + ], + (item) => TokenPool_RampUpdate.toCell(item).asBuilder(), + ), + }, + ) expect(result.transactions).toHaveTransaction({ from: ctx.deployer.address, @@ -304,23 +325,30 @@ export function runTokenPoolBehaviorTests( it('rejects old off-ramp sender after remapping off-ramp', async () => { const ctx = await setup() - await ctx.pool.sendUpdateRampAccess(ctx.deployer.getSender(), toNano('0.2'), { + await ctx.pool.sendTokenPoolUpdateRampAccess(ctx.deployer.getSender(), toNano('0.2'), { queryId: 910n, - updates: [ - { - remoteChainSelector: ctx.remoteChainSelector, - onRamp: ctx.onRampAddress, - offRamp: ctx.unauthorized.address, - }, - ], + updates: asSnakedCell( + [ + TokenPool_RampUpdate.create({ + remoteChainSelector: ctx.remoteChainSelector, + onRamp: ctx.onRampAddress, + offRamp: ctx.unauthorized.address, + }), + ], + (item) => TokenPool_RampUpdate.toCell(item).asBuilder(), + ), }) - const result = await ctx.pool.sendReleaseOrMint(ctx.offRamp.getSender(), toNano('0.3'), { - queryId: 911n, - request: releaseRequest(ctx), - requestedFinalityConfig: 0, - replyTo: ctx.deployer.address, - }) + const result = await ctx.pool.sendTokenPoolReleaseOrMint( + ctx.offRamp.getSender(), + toNano('0.3'), + { + queryId: 911n, + request: { ref: releaseRequest(ctx) }, + requestedFinalityConfig: 0n, + replyTo: ctx.deployer.address, + }, + ) expect(result.transactions).toHaveTransaction({ from: ctx.offRamp.address, @@ -335,12 +363,19 @@ export function runTokenPoolBehaviorTests( .storeUint(4, 8) .storeBuffer(Buffer.from('evil')) .endCell() - const result = await ctx.pool.sendReleaseOrMint(ctx.offRamp.getSender(), toNano('0.3'), { - queryId: 912n, - request: releaseRequest(ctx, { sourcePoolAddress: wrongSourcePoolAddress }), - requestedFinalityConfig: 0, - replyTo: ctx.deployer.address, - }) + .beginParse() + const result = await ctx.pool.sendTokenPoolReleaseOrMint( + ctx.offRamp.getSender(), + toNano('0.3'), + { + queryId: 912n, + request: { + ref: releaseRequest(ctx, { sourcePoolAddress: { ref: wrongSourcePoolAddress } }), + }, + requestedFinalityConfig: 0n, + replyTo: ctx.deployer.address, + }, + ) expect(result.transactions).toHaveTransaction({ from: ctx.offRamp.address, @@ -352,12 +387,16 @@ export function runTokenPoolBehaviorTests( it('rejects releaseOrMint when local token does not match pool token', async () => { const ctx = await setup() const wrongLocalToken = ctx.deployer.address - const result = await ctx.pool.sendReleaseOrMint(ctx.offRamp.getSender(), toNano('0.3'), { - queryId: 913n, - request: releaseRequest(ctx, { localToken: wrongLocalToken }), - requestedFinalityConfig: 0, - replyTo: ctx.deployer.address, - }) + const result = await ctx.pool.sendTokenPoolReleaseOrMint( + ctx.offRamp.getSender(), + toNano('0.3'), + { + queryId: 913n, + request: { ref: releaseRequest(ctx, { localToken: wrongLocalToken }) }, + requestedFinalityConfig: 0n, + replyTo: ctx.deployer.address, + }, + ) expect(result.transactions).toHaveTransaction({ from: ctx.offRamp.address, @@ -368,15 +407,18 @@ export function runTokenPoolBehaviorTests( it('clears existing off-ramp when update passes null off-ramp', async () => { const ctx = await setup() - await ctx.pool.sendUpdateRampAccess(ctx.deployer.getSender(), toNano('0.2'), { + await ctx.pool.sendTokenPoolUpdateRampAccess(ctx.deployer.getSender(), toNano('0.2'), { queryId: 914n, - updates: [ - { - remoteChainSelector: ctx.remoteChainSelector, - onRamp: ctx.onRampAddress, - offRamp: null, - }, - ], + updates: asSnakedCell( + [ + TokenPool_RampUpdate.create({ + remoteChainSelector: ctx.remoteChainSelector, + onRamp: ctx.onRampAddress, + offRamp: null, + }), + ], + (item) => TokenPool_RampUpdate.toCell(item).asBuilder(), + ), }) expect(await ctx.pool.getOffRamp(ctx.remoteChainSelector)).toBeNull() @@ -384,23 +426,30 @@ export function runTokenPoolBehaviorTests( it('rejects existing off-ramp sender after null off-ramp update', async () => { const ctx = await setup() - await ctx.pool.sendUpdateRampAccess(ctx.deployer.getSender(), toNano('0.2'), { + await ctx.pool.sendTokenPoolUpdateRampAccess(ctx.deployer.getSender(), toNano('0.2'), { queryId: 915n, - updates: [ - { - remoteChainSelector: ctx.remoteChainSelector, - onRamp: ctx.onRampAddress, - offRamp: null, - }, - ], + updates: asSnakedCell( + [ + TokenPool_RampUpdate.create({ + remoteChainSelector: ctx.remoteChainSelector, + onRamp: ctx.onRampAddress, + offRamp: null, + }), + ], + (item) => TokenPool_RampUpdate.toCell(item).asBuilder(), + ), }) - const result = await ctx.pool.sendReleaseOrMint(ctx.offRamp.getSender(), toNano('0.3'), { - queryId: 916n, - request: releaseRequest(ctx), - requestedFinalityConfig: 0, - replyTo: ctx.deployer.address, - }) + const result = await ctx.pool.sendTokenPoolReleaseOrMint( + ctx.offRamp.getSender(), + toNano('0.3'), + { + queryId: 916n, + request: { ref: releaseRequest(ctx) }, + requestedFinalityConfig: 0n, + replyTo: ctx.deployer.address, + }, + ) expect(result.transactions).toHaveTransaction({ from: ctx.offRamp.address, @@ -412,27 +461,50 @@ export function runTokenPoolBehaviorTests( it('can re-add chain after remove via applyChainUpdates', async () => { const ctx = await setup() - await ctx.pool.sendApplyChainUpdates(ctx.deployer.getSender(), toNano('0.2'), { + await ctx.pool.sendTokenPoolApplyChainUpdates(ctx.deployer.getSender(), toNano('0.2'), { queryId: 917n, - remove: [ctx.remoteChainSelector], - add: [], + remoteChainSelectorsToRemove: asSnakedCell([ctx.remoteChainSelector], (item) => + beginCell().storeUint(item, 64), + ), + chainsToAdd: asSnakedCellEmpty(), }) - const addResult = await ctx.pool.sendApplyChainUpdates( + const addResult = await ctx.pool.sendTokenPoolApplyChainUpdates( ctx.deployer.getSender(), toNano('0.2'), { queryId: 918n, - remove: [], - add: [ - { - remoteChainSelector: ctx.remoteChainSelector, - remotePoolAddresses: [ctx.sourcePoolAddress], - remoteTokenAddress: ctx.destTokenAddress, - outboundRateLimiterConfig: { isEnabled: true, capacity: toNano('100'), rate: 1n }, - inboundRateLimiterConfig: { isEnabled: true, capacity: toNano('100'), rate: 1n }, - }, - ], + remoteChainSelectorsToRemove: asSnakedCell([], (item) => beginCell().storeUint(item, 64)), + chainsToAdd: asSnakedCell( + [ + TokenPool_ChainUpdate.create({ + remoteChainSelector: ctx.remoteChainSelector, + remotePoolAddresses: asSnakedCell([ctx.sourcePoolAddress.beginParse()], (item) => + item.asBuilder(), + ), + remoteTokenAddress: { ref: ctx.destTokenAddress.beginParse() }, + rateLimitConfigs: { + ref: TokenPool_RateLimitConfigPair.create({ + outbound: { + ref: RateLimiter_Config.create({ + isEnabled: true, + capacity: toNano('100'), + rate: 1n, + }), + }, + inbound: { + ref: RateLimiter_Config.create({ + isEnabled: true, + capacity: toNano('100'), + rate: 1n, + }), + }, + }), + }, + }), + ], + (item) => TokenPool_ChainUpdate.toCell(item).asBuilder(), + ), }, ) diff --git a/contracts/wrappers/gen/ccip/pools/TokenPool.ts b/contracts/wrappers/gen/ccip/pools/TokenPool.ts index bfc5533de..c405df142 100644 --- a/contracts/wrappers/gen/ccip/pools/TokenPool.ts +++ b/contracts/wrappers/gen/ccip/pools/TokenPool.ts @@ -135,6 +135,14 @@ class StackReader { readSlice(): c.Slice { return this.popCellLike().beginParse(); } + + readNullable(readFn_T: (r: StackReader) => T): T | null { + if (this.tuple[0].type === 'null') { + this.tuple.shift(); + return null; + } + return readFn_T(this); + } } // ———————————————————————————————————————————— @@ -1632,7 +1640,7 @@ function calculateDeployedAddress(code: c.Cell, data: c.Cell, options: DeployedA } export class TokenPool implements c.Contract { - static CodeCell = c.Cell.fromBase64('te6ccgEBAgEAGQABFP8A9KQT9LzyyAsBABTTMPiR8kCED/Lw'); + static CodeCell = c.Cell.fromBase64('te6ccgEBGAEArgABFP8A9KQT9LzyyAsBAgFiAgMAFNAw+JHyQIQP8vACASAEBQIBIAYHAgEgEhMCASAICQIBIA4PAgEgCgsADbW1EIH+XhACAWoMDQANsFfhA/y8IAALpXUIH+XhAAunIwgf5eEADbSjsIH+XhACA3tgEBEAC6OuED/LwgALohoQP8vCAA24PthA/y8IAgFYFBUADbLgYQP8vCACAVgWFwAMqHGED/LwAAyqqIQP8vA='); static Errors = { } @@ -1919,4 +1927,81 @@ export class TokenPool implements c.Contract { ...extraOptions }); } + + async getTypeAndVersion(provider: ContractProvider): Promise<[ + c.Slice, + c.Slice, + ]> { + const r = StackReader.fromGetMethod(2, await provider.get('typeAndVersion', [])); + return [ + r.readSlice(), + r.readSlice(), + ]; + } + + async getToken(provider: ContractProvider): Promise { + const r = StackReader.fromGetMethod(1, await provider.get('token', [])); + return r.readSlice().loadAddress(); + } + + async getTokenDecimals(provider: ContractProvider): Promise { + const r = StackReader.fromGetMethod(1, await provider.get('tokenDecimals', [])); + return r.readBigInt(); + } + + async getIsSupportedChain(provider: ContractProvider, remoteChainSelector: uint64): Promise { + const r = StackReader.fromGetMethod(1, await provider.get('isSupportedChain', [ + { type: 'int', value: remoteChainSelector }, + ])); + return r.readBoolean(); + } + + async getOnRamp(provider: ContractProvider, remoteChainSelector: uint64): Promise { + const r = StackReader.fromGetMethod(1, await provider.get('onRamp', [ + { type: 'int', value: remoteChainSelector }, + ])); + return r.readNullable( + (r) => r.readSlice().loadAddress() + ); + } + + async getOffRamp(provider: ContractProvider, remoteChainSelector: uint64): Promise { + const r = StackReader.fromGetMethod(1, await provider.get('offRamp', [ + { type: 'int', value: remoteChainSelector }, + ])); + return r.readNullable( + (r) => r.readSlice().loadAddress() + ); + } + + async getHasPendingRelease(provider: ContractProvider, queryId: uint64): Promise { + const r = StackReader.fromGetMethod(1, await provider.get('hasPendingRelease', [ + { type: 'int', value: queryId }, + ])); + return r.readBoolean(); + } + + async getRMNProxy(provider: ContractProvider): Promise { + const r = StackReader.fromGetMethod(1, await provider.get('getRMNProxy', [])); + return r.readSlice().loadAddress(); + } + + async getVerifyNotCursed(provider: ContractProvider, subject: uint128): Promise { + const r = StackReader.fromGetMethod(1, await provider.get('verifyNotCursed', [ + { type: 'int', value: subject }, + ])); + return r.readBoolean(); + } + + async getOwner(provider: ContractProvider): Promise { + const r = StackReader.fromGetMethod(1, await provider.get('owner', [])); + return r.readSlice().loadAddress(); + } + + async getPendingOwner(provider: ContractProvider): Promise { + const r = StackReader.fromGetMethod(1, await provider.get('pendingOwner', [])); + return r.readNullable( + (r) => r.readSlice().loadAddress() + ); + } } From 193641a8407856a9b24e6d89688cc35be81b6388 Mon Sep 17 00:00:00 2001 From: Kristijan Date: Thu, 11 Jun 2026 11:09:25 +0200 Subject: [PATCH 09/16] Unify gen bindings setup --- .../ccip/pools/BurnMintTokenPool.spec.ts | 23 ++-------- .../ccip/pools/LockReleaseTokenPool.spec.ts | 23 ++-------- .../tests/ccip/router/Router.getFee.spec.ts | 19 ++------ contracts/wrappers/gen/index.ts | 44 +++++++++++++++++++ 4 files changed, 55 insertions(+), 54 deletions(-) create mode 100644 contracts/wrappers/gen/index.ts diff --git a/contracts/tests/ccip/pools/BurnMintTokenPool.spec.ts b/contracts/tests/ccip/pools/BurnMintTokenPool.spec.ts index 0d4fa43bb..5d90016be 100644 --- a/contracts/tests/ccip/pools/BurnMintTokenPool.spec.ts +++ b/contracts/tests/ccip/pools/BurnMintTokenPool.spec.ts @@ -1,6 +1,6 @@ import '@ton/test-utils' import { Blockchain, SandboxContract, TreasuryContract } from '@ton/sandbox' -import { Address, Builder, Cell, Slice, beginCell, toNano } from '@ton/core' +import { Address, Cell, toNano } from '@ton/core' import { JettonMinter, JettonWallet } from '../../../wrappers/examples/jetton' import { BurnMintTokenPool, @@ -10,8 +10,8 @@ import { import { CCTJettonMinter } from '../../../wrappers/ccip/CCTJettonMinter' import { CCTJettonMinterCode, CCTJettonWalletCode } from '../../../wrappers/ccip/CCTJettonCode' import { runTokenPoolBehaviorTests } from './TokenPool.behavior' -import { CrossChainAddress, TokenPool } from '../../../wrappers/gen/ccip/pools/TokenPool' -import * as rtOld from '../../../wrappers/ccip/Router' +import { TokenPool } from '../../../wrappers/gen/ccip/pools/TokenPool' +import { setupGenBindings } from '../../../wrappers/gen' describe('BurnMintTokenPool', () => { let blockchain: Blockchain @@ -34,22 +34,7 @@ describe('BurnMintTokenPool', () => { const receiverAddress = poolCodec.crossChainAddressFromBuffer(Buffer.from('receiver')) beforeAll(async () => { - // TODO: move this to a common setup utility - function CrossChainAddress__packToBuilder(self: CrossChainAddress, b: Builder): void { - const src = self.clone() - const buffer = src.loadBuffer(src.remainingBits / 8) - b.storeBuilder(rtOld.builder.data.crossChainAddress.encode(buffer)) - } - function CrossChainAddress__unpackFromSlice(s: Slice): CrossChainAddress { - const buff = rtOld.builder.data.crossChainAddress.load(s) - return beginCell().storeBuffer(buff).asSlice() as CrossChainAddress - } - - TokenPool.registerCustomPackUnpack( - 'CrossChainAddress', - CrossChainAddress__packToBuilder, - CrossChainAddress__unpackFromSlice, - ) + setupGenBindings() }) beforeEach(async () => { diff --git a/contracts/tests/ccip/pools/LockReleaseTokenPool.spec.ts b/contracts/tests/ccip/pools/LockReleaseTokenPool.spec.ts index 2d49fbe0b..d27753a58 100644 --- a/contracts/tests/ccip/pools/LockReleaseTokenPool.spec.ts +++ b/contracts/tests/ccip/pools/LockReleaseTokenPool.spec.ts @@ -1,6 +1,6 @@ import '@ton/test-utils' import { Blockchain, SandboxContract, TreasuryContract } from '@ton/sandbox' -import { Address, Builder, Cell, Message, Slice, beginCell, toNano } from '@ton/core' +import { Address, Cell, beginCell, toNano } from '@ton/core' import { JettonMinter, JettonSender, JettonWallet } from '../../../wrappers/examples/jetton' import { LockReleaseTokenPool, @@ -9,8 +9,8 @@ import { } from '../../../wrappers/ccip/LockReleaseTokenPool' import * as jetton from '../../../wrappers/jetton/JettonCode' import { runTokenPoolBehaviorTests } from './TokenPool.behavior' -import { CrossChainAddress, TokenPool } from '../../../wrappers/gen/ccip/pools/TokenPool' -import * as rtOld from '../../../wrappers/ccip/Router' +import { TokenPool } from '../../../wrappers/gen/ccip/pools/TokenPool' +import { setupGenBindings } from '../../../wrappers/gen' describe('LockReleaseTokenPool', () => { let blockchain: Blockchain @@ -32,22 +32,7 @@ describe('LockReleaseTokenPool', () => { const receiverAddress = poolCodec.crossChainAddressFromBuffer(Buffer.from('receiver')) beforeAll(async () => { - // TODO: move this to a common setup utility - function CrossChainAddress__packToBuilder(self: CrossChainAddress, b: Builder): void { - const src = self.clone() - const buffer = src.loadBuffer(src.remainingBits / 8) - b.storeBuilder(rtOld.builder.data.crossChainAddress.encode(buffer)) - } - function CrossChainAddress__unpackFromSlice(s: Slice): CrossChainAddress { - const buff = rtOld.builder.data.crossChainAddress.load(s) - return beginCell().storeBuffer(buff).asSlice() as CrossChainAddress - } - - TokenPool.registerCustomPackUnpack( - 'CrossChainAddress', - CrossChainAddress__packToBuilder, - CrossChainAddress__unpackFromSlice, - ) + setupGenBindings() }) beforeEach(async () => { diff --git a/contracts/tests/ccip/router/Router.getFee.spec.ts b/contracts/tests/ccip/router/Router.getFee.spec.ts index f1e1c4d5f..32d190453 100644 --- a/contracts/tests/ccip/router/Router.getFee.spec.ts +++ b/contracts/tests/ccip/router/Router.getFee.spec.ts @@ -13,6 +13,7 @@ import { EVM_ADDRESS, contractsCoverageConfig, } from './Router.Setup' +import { setupGenBindings } from '../../../wrappers/gen' const EVM_CC_ADDRESS: rt.CrossChainAddress = beginCell().storeBuffer(EVM_ADDRESS).asSlice() @@ -25,6 +26,8 @@ describe('Router', () => { let onRamp: SandboxContract beforeAll(async () => { + setupGenBindings() + blockchain = await Blockchain.create() blockchain.verbosity = { print: true, @@ -39,22 +42,6 @@ describe('Router', () => { } feeQuoter = await blockchain.treasury('feeQuoter') onRamp = await blockchain.treasury('onRamp') - - function CrossChainAddress__packToBuilder(self: rt.CrossChainAddress, b: Builder): void { - const src = self.clone() - const buffer = src.loadBuffer(src.remainingBits / 8) - b.storeBuilder(rtOld.builder.data.crossChainAddress.encode(buffer)) - } - function CrossChainAddress__unpackFromSlice(s: Slice): rt.CrossChainAddress { - const buff = rtOld.builder.data.crossChainAddress.load(s) - return beginCell().storeBuffer(buff).asSlice() as rt.CrossChainAddress - } - - rt.Router.registerCustomPackUnpack( - 'CrossChainAddress', - CrossChainAddress__packToBuilder, - CrossChainAddress__unpackFromSlice, - ) }) beforeEach(async () => { diff --git a/contracts/wrappers/gen/index.ts b/contracts/wrappers/gen/index.ts new file mode 100644 index 000000000..424f8f4f2 --- /dev/null +++ b/contracts/wrappers/gen/index.ts @@ -0,0 +1,44 @@ +import { Builder, Slice, beginCell, toNano } from '@ton/core' +import { Router } from './ccip/Router'; +import { TokenPool } from './ccip/pools/TokenPool' +import { BurnMintTokenPool } from './ccip/pools/BurnMintTokenPool' +import { LockReleaseTokenPool } from './ccip/pools/LockReleaseTokenPool' + +import * as rtOld from '../ccip/Router' + +function CrossChainAddress__packToBuilder(self: Slice, b: Builder): void { + const src = self.clone() + const buffer = src.loadBuffer(src.remainingBits / 8) + b.storeBuilder(rtOld.builder.data.crossChainAddress.encode(buffer)) +} +function CrossChainAddress__unpackFromSlice(s: Slice): Slice { + const buff = rtOld.builder.data.crossChainAddress.load(s) + return beginCell().storeBuffer(buff).asSlice() +} + +export function setupGenBindings() { + // Setup custom pack/unpack for CrossChainAddress + TokenPool.registerCustomPackUnpack( + 'CrossChainAddress', + CrossChainAddress__packToBuilder, + CrossChainAddress__unpackFromSlice, + ) + + BurnMintTokenPool.registerCustomPackUnpack( + 'CrossChainAddress', + CrossChainAddress__packToBuilder, + CrossChainAddress__unpackFromSlice, + ) + + LockReleaseTokenPool.registerCustomPackUnpack( + 'CrossChainAddress', + CrossChainAddress__packToBuilder, + CrossChainAddress__unpackFromSlice, + ) + + Router.registerCustomPackUnpack( + 'CrossChainAddress', + CrossChainAddress__packToBuilder, + CrossChainAddress__unpackFromSlice, + ) +} From 5b5f44c62e746ec29283b64020ae114ab7871bce Mon Sep 17 00:00:00 2001 From: Kristijan Date: Thu, 11 Jun 2026 11:13:13 +0200 Subject: [PATCH 10/16] Update metadata --- contracts/contracts/ccip/cct/JettonWallet.tolk | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/contracts/contracts/ccip/cct/JettonWallet.tolk b/contracts/contracts/ccip/cct/JettonWallet.tolk index f4b738cec..507f674e0 100644 --- a/contracts/contracts/ccip/cct/JettonWallet.tolk +++ b/contracts/contracts/ccip/cct/JettonWallet.tolk @@ -6,9 +6,12 @@ import "../../lib/jetton/messages" import "fees-management" contract JettonWallet { - author: "The Tolk Team" - incomingMessages: AllowedMessageToWallet + author: "SmartContract Chainlink Limited SEZC" + version: "0.0.1" + description: "link.chain.ton.ccip.cct.JettonWallet" + storage: WalletStorage + incomingMessages: AllowedMessageToWallet } type AllowedMessageToWallet = From 811c7b013d69fa23368cacda7b25fd5a83c71159 Mon Sep 17 00:00:00 2001 From: Kristijan Date: Thu, 11 Jun 2026 11:26:16 +0200 Subject: [PATCH 11/16] Update opcodes --- .../pools/burn_mint_token_pool/messages.tolk | 2 +- contracts/contracts/ccip/pools/messages.tolk | 31 +++-- contracts/wrappers/ccip/BurnMintTokenPool.ts | 1 - contracts/wrappers/ccip/TokenPool.ts | 44 ++++--- .../gen/ccip/pools/BurnMintTokenPool.ts | 114 +++++++++--------- .../gen/ccip/pools/LockReleaseTokenPool.ts | 114 +++++++++--------- .../wrappers/gen/ccip/pools/TokenPool.ts | 88 +++++++------- 7 files changed, 204 insertions(+), 190 deletions(-) diff --git a/contracts/contracts/ccip/pools/burn_mint_token_pool/messages.tolk b/contracts/contracts/ccip/pools/burn_mint_token_pool/messages.tolk index ddbb10d11..fa92f10b1 100644 --- a/contracts/contracts/ccip/pools/burn_mint_token_pool/messages.tolk +++ b/contracts/contracts/ccip/pools/burn_mint_token_pool/messages.tolk @@ -2,7 +2,7 @@ import "../../../lib/jetton/messages.tolk" import "../messages" -struct (0x93c174a1) BurnMintTokenPool_ClaimMinterAdmin { +struct (0x39898e4d) BurnMintTokenPool_ClaimMinterAdmin { queryId: uint64; } diff --git a/contracts/contracts/ccip/pools/messages.tolk b/contracts/contracts/ccip/pools/messages.tolk index ea57343cd..61e336a1f 100644 --- a/contracts/contracts/ccip/pools/messages.tolk +++ b/contracts/contracts/ccip/pools/messages.tolk @@ -6,60 +6,59 @@ import "../rmn_remote/lib" import "types" -struct (0xdc0b6ff5) TokenPool_ApplyChainUpdates { +struct (0x56f73d37) TokenPool_ApplyChainUpdates { queryId: uint64; remoteChainSelectorsToRemove: SnakedCell; chainsToAdd: SnakedCell; } -struct (0x5fd2c8b6) TokenPool_AddRemotePool { +struct (0x17c242dc) TokenPool_AddRemotePool { queryId: uint64; remoteChainSelector: uint64; remotePoolAddress: Cell; } -struct (0xdbf0a2df) TokenPool_RemoveRemotePool { +struct (0x426b8cc4) TokenPool_RemoveRemotePool { queryId: uint64; remoteChainSelector: uint64; remotePoolAddress: Cell; } -struct (0x4eea060b) TokenPool_SetDynamicConfig { +struct (0xd7712810) TokenPool_SetDynamicConfig { queryId: uint64; router: address; rateLimitAdmin: address? = null; feeAdmin: address? = null; } -struct (0x29b46fc6) TokenPool_SetAllowedFinalityConfig { +struct (0x3c50a39b) TokenPool_SetAllowedFinalityConfig { queryId: uint64; allowedFinalityConfig: uint32; } -struct (0x3a028da2) TokenPool_SetRateLimitConfig { +struct (0x4fe2d26c) TokenPool_SetRateLimitConfig { queryId: uint64; updates: SnakedCell; } -struct (0x10c4b4a1) TokenPool_ApplyTokenTransferFeeConfigUpdates { +struct (0x30a1d1f7) TokenPool_ApplyTokenTransferFeeConfigUpdates { queryId: uint64; updates: SnakedCell; disableChainSelectors: SnakedCell; } -struct (0x7a9c4aa5) TokenPool_UpdateRampAccess { +struct (0xe30764be) TokenPool_UpdateRampAccess { queryId: uint64; updates: SnakedCell; } -// TODO: update opcode /// Sets the RMN proxy address, a role which is responsible for updating the cursed subjects list. -struct (0x12345678) TokenPool_SetRMNProxy { +struct (0x9929b642) TokenPool_SetRMNProxy { queryId: uint64; rmnProxy: address; } -struct (0x823dadf2) TokenPool_UpdateCursedSubjects { +struct (0x2c906eb7) TokenPool_UpdateCursedSubjects { queryId: uint64; cursedSubjects: CursedSubjects; } @@ -68,7 +67,7 @@ struct (0x823dadf2) TokenPool_UpdateCursedSubjects { /// @param lockOrBurnIn Encoded data fields for the processing of tokens on the source chain. /// @param requestedFinalityConfig Requested finality encoding (see `FinalityCodec`). /// @param tokenArgs Additional token arguments. -struct (0x1161516e) TokenPool_LockOrBurn { +struct (0xfa7da444) TokenPool_LockOrBurn { queryId: uint64; request: Cell; // TODO: consider renaming requestedFinalityConfig: uint32; @@ -76,7 +75,7 @@ struct (0x1161516e) TokenPool_LockOrBurn { replyTo: address?; } -struct (0x19e65bea) TokenPool_LockOrBurnResponse { +struct (0x6c060424) TokenPool_LockOrBurnResponse { queryId: uint64; // TODO: unwrap and inline this type out: Cell; @@ -86,19 +85,19 @@ struct (0x19e65bea) TokenPool_LockOrBurnResponse { /// @Releases or mints tokens on the destination chain. /// @param releaseOrMintIn Encoded data fields for the processing of tokens on the destination chain. /// @param requestedFinalityConfig Requested finality encoding (see `FinalityCodec`). -struct (0x7d0ffd89) TokenPool_ReleaseOrMint { +struct (0x351f77e3) TokenPool_ReleaseOrMint { queryId: uint64; request: Cell; requestedFinalityConfig: uint32; replyTo: address? = null; } -struct (0x7ec43aee) TokenPool_ReleaseOrMintResponse { +struct (0x78dc2232) TokenPool_ReleaseOrMintResponse { queryId: uint64; out: Cell; } -struct (0x41a1702b) TokenPool_ReleaseOrMintFailure { +struct (0xef0cb36e) TokenPool_ReleaseOrMintFailure { queryId: uint64; errorCode: uint16; } diff --git a/contracts/wrappers/ccip/BurnMintTokenPool.ts b/contracts/wrappers/ccip/BurnMintTokenPool.ts index 14393ebab..0bcfcf6c7 100644 --- a/contracts/wrappers/ccip/BurnMintTokenPool.ts +++ b/contracts/wrappers/ccip/BurnMintTokenPool.ts @@ -33,7 +33,6 @@ export const FACILITY_NAME = 'link.chain.ton.ccip.BurnMintTokenPool' export const FACILITY_ID = facilityId(crc32(FACILITY_NAME)) export const ERROR_CODE = errorCode(crc32(FACILITY_NAME)) export const CONTRACT_VERSION = '0.1.0' -const BURN_MINT_CLAIM_MINTER_ADMIN_OPCODE = 0x93c174a1 export type Config = TokenPoolConfig & { jettonClient: JettonClientConfig diff --git a/contracts/wrappers/ccip/TokenPool.ts b/contracts/wrappers/ccip/TokenPool.ts index a9935055f..e6dfd930c 100644 --- a/contracts/wrappers/ccip/TokenPool.ts +++ b/contracts/wrappers/ccip/TokenPool.ts @@ -11,27 +11,43 @@ import { } from '@ton/core' import * as ownable2step from '../libraries/access/Ownable2Step' import { asSnakedCell } from '../../src/utils' +import { + TokenPool_ApplyChainUpdates, + TokenPool_AddRemotePool, + TokenPool_RemoveRemotePool, + TokenPool_SetDynamicConfig, + TokenPool_SetAllowedFinalityConfig, + TokenPool_SetRateLimitConfig, + TokenPool_UpdateRampAccess, + TokenPool_ApplyTokenTransferFeeConfigUpdates, + TokenPool_UpdateCursedSubjects, + TokenPool_ReleaseOrMint, +} from '../gen/ccip/pools/TokenPool' +import { + TokenPool_ReleaseOrMintFailure, + TokenPool_ReleaseOrMintResponse, +} from '../gen/ccip/pools/LockReleaseTokenPool' export const opcodes = { in: { - applyChainUpdates: 0xdc0b6ff5, - addRemotePool: 0x5fd2c8b6, - removeRemotePool: 0xdbf0a2df, - setDynamicConfig: 0x4eea060b, - setAllowedFinalityConfig: 0x29b46fc6, - setRateLimitConfig: 0x3a028da2, - applyTokenTransferFeeConfigUpdates: 0x10c4b4a1, - updateRampAccess: 0x7a9c4aa5, - updateCursedSubjects: 0x823dadf2, - releaseOrMint: 0x7d0ffd89, + applyChainUpdates: TokenPool_ApplyChainUpdates.PREFIX, + addRemotePool: TokenPool_AddRemotePool.PREFIX, + removeRemotePool: TokenPool_RemoveRemotePool.PREFIX, + setDynamicConfig: TokenPool_SetDynamicConfig.PREFIX, + setAllowedFinalityConfig: TokenPool_SetAllowedFinalityConfig.PREFIX, + setRateLimitConfig: TokenPool_SetRateLimitConfig.PREFIX, + applyTokenTransferFeeConfigUpdates: TokenPool_ApplyTokenTransferFeeConfigUpdates.PREFIX, + updateRampAccess: TokenPool_UpdateRampAccess.PREFIX, + updateCursedSubjects: TokenPool_UpdateCursedSubjects.PREFIX, + releaseOrMint: TokenPool_ReleaseOrMint.PREFIX, }, payload: { - lockOrBurn: 0x1161516e, + lockOrBurn: 0xfa7da444, }, out: { - lockOrBurnResponse: 0x19e65bea, - releaseOrMintResponse: 0x7ec43aee, - releaseOrMintFailure: 0x41a1702b, + lockOrBurnResponse: 0x6c060424, + releaseOrMintResponse: TokenPool_ReleaseOrMintResponse.PREFIX, + releaseOrMintFailure: TokenPool_ReleaseOrMintFailure.PREFIX, }, } diff --git a/contracts/wrappers/gen/ccip/pools/BurnMintTokenPool.ts b/contracts/wrappers/gen/ccip/pools/BurnMintTokenPool.ts index 62a672015..9a0746ed5 100644 --- a/contracts/wrappers/gen/ccip/pools/BurnMintTokenPool.ts +++ b/contracts/wrappers/gen/ccip/pools/BurnMintTokenPool.ts @@ -1469,7 +1469,7 @@ export const TokenPool_ReleaseOrMintOutV1 = { } /** - > struct (0xdc0b6ff5) TokenPool_ApplyChainUpdates { + > struct (0x56f73d37) TokenPool_ApplyChainUpdates { > queryId: uint64 > remoteChainSelectorsToRemove: SnakedCell > chainsToAdd: SnakedCell @@ -1483,7 +1483,7 @@ export interface TokenPool_ApplyChainUpdates { } export const TokenPool_ApplyChainUpdates = { - PREFIX: 0xdc0b6ff5, + PREFIX: 0x56f73d37, create(args: { queryId: uint64 @@ -1496,7 +1496,7 @@ export const TokenPool_ApplyChainUpdates = { } }, fromSlice(s: c.Slice): TokenPool_ApplyChainUpdates { - loadAndCheckPrefix32(s, 0xdc0b6ff5, 'TokenPool_ApplyChainUpdates'); + loadAndCheckPrefix32(s, 0x56f73d37, 'TokenPool_ApplyChainUpdates'); return { $: 'TokenPool_ApplyChainUpdates', queryId: s.loadUintBig(64), @@ -1505,7 +1505,7 @@ export const TokenPool_ApplyChainUpdates = { } }, store(self: TokenPool_ApplyChainUpdates, b: c.Builder): void { - b.storeUint(0xdc0b6ff5, 32); + b.storeUint(0x56f73d37, 32); b.storeUint(self.queryId, 64); b.storeRef(self.remoteChainSelectorsToRemove); b.storeRef(self.chainsToAdd); @@ -1516,7 +1516,7 @@ export const TokenPool_ApplyChainUpdates = { } /** - > struct (0x5fd2c8b6) TokenPool_AddRemotePool { + > struct (0x17c242dc) TokenPool_AddRemotePool { > queryId: uint64 > remoteChainSelector: uint64 > remotePoolAddress: Cell @@ -1530,7 +1530,7 @@ export interface TokenPool_AddRemotePool { } export const TokenPool_AddRemotePool = { - PREFIX: 0x5fd2c8b6, + PREFIX: 0x17c242dc, create(args: { queryId: uint64 @@ -1543,7 +1543,7 @@ export const TokenPool_AddRemotePool = { } }, fromSlice(s: c.Slice): TokenPool_AddRemotePool { - loadAndCheckPrefix32(s, 0x5fd2c8b6, 'TokenPool_AddRemotePool'); + loadAndCheckPrefix32(s, 0x17c242dc, 'TokenPool_AddRemotePool'); return { $: 'TokenPool_AddRemotePool', queryId: s.loadUintBig(64), @@ -1552,7 +1552,7 @@ export const TokenPool_AddRemotePool = { } }, store(self: TokenPool_AddRemotePool, b: c.Builder): void { - b.storeUint(0x5fd2c8b6, 32); + b.storeUint(0x17c242dc, 32); b.storeUint(self.queryId, 64); b.storeUint(self.remoteChainSelector, 64); storeCellRef(self.remotePoolAddress, b, CrossChainAddress.store); @@ -1563,7 +1563,7 @@ export const TokenPool_AddRemotePool = { } /** - > struct (0xdbf0a2df) TokenPool_RemoveRemotePool { + > struct (0x426b8cc4) TokenPool_RemoveRemotePool { > queryId: uint64 > remoteChainSelector: uint64 > remotePoolAddress: Cell @@ -1577,7 +1577,7 @@ export interface TokenPool_RemoveRemotePool { } export const TokenPool_RemoveRemotePool = { - PREFIX: 0xdbf0a2df, + PREFIX: 0x426b8cc4, create(args: { queryId: uint64 @@ -1590,7 +1590,7 @@ export const TokenPool_RemoveRemotePool = { } }, fromSlice(s: c.Slice): TokenPool_RemoveRemotePool { - loadAndCheckPrefix32(s, 0xdbf0a2df, 'TokenPool_RemoveRemotePool'); + loadAndCheckPrefix32(s, 0x426b8cc4, 'TokenPool_RemoveRemotePool'); return { $: 'TokenPool_RemoveRemotePool', queryId: s.loadUintBig(64), @@ -1599,7 +1599,7 @@ export const TokenPool_RemoveRemotePool = { } }, store(self: TokenPool_RemoveRemotePool, b: c.Builder): void { - b.storeUint(0xdbf0a2df, 32); + b.storeUint(0x426b8cc4, 32); b.storeUint(self.queryId, 64); b.storeUint(self.remoteChainSelector, 64); storeCellRef(self.remotePoolAddress, b, CrossChainAddress.store); @@ -1610,7 +1610,7 @@ export const TokenPool_RemoveRemotePool = { } /** - > struct (0x4eea060b) TokenPool_SetDynamicConfig { + > struct (0xd7712810) TokenPool_SetDynamicConfig { > queryId: uint64 > router: address > rateLimitAdmin: address? @@ -1626,7 +1626,7 @@ export interface TokenPool_SetDynamicConfig { } export const TokenPool_SetDynamicConfig = { - PREFIX: 0x4eea060b, + PREFIX: 0xd7712810, create(args: { queryId: uint64 @@ -1642,7 +1642,7 @@ export const TokenPool_SetDynamicConfig = { } }, fromSlice(s: c.Slice): TokenPool_SetDynamicConfig { - loadAndCheckPrefix32(s, 0x4eea060b, 'TokenPool_SetDynamicConfig'); + loadAndCheckPrefix32(s, 0xd7712810, 'TokenPool_SetDynamicConfig'); return { $: 'TokenPool_SetDynamicConfig', queryId: s.loadUintBig(64), @@ -1652,7 +1652,7 @@ export const TokenPool_SetDynamicConfig = { } }, store(self: TokenPool_SetDynamicConfig, b: c.Builder): void { - b.storeUint(0x4eea060b, 32); + b.storeUint(0xd7712810, 32); b.storeUint(self.queryId, 64); b.storeAddress(self.router); b.storeAddress(self.rateLimitAdmin); @@ -1664,7 +1664,7 @@ export const TokenPool_SetDynamicConfig = { } /** - > struct (0x29b46fc6) TokenPool_SetAllowedFinalityConfig { + > struct (0x3c50a39b) TokenPool_SetAllowedFinalityConfig { > queryId: uint64 > allowedFinalityConfig: uint32 > } @@ -1676,7 +1676,7 @@ export interface TokenPool_SetAllowedFinalityConfig { } export const TokenPool_SetAllowedFinalityConfig = { - PREFIX: 0x29b46fc6, + PREFIX: 0x3c50a39b, create(args: { queryId: uint64 @@ -1688,7 +1688,7 @@ export const TokenPool_SetAllowedFinalityConfig = { } }, fromSlice(s: c.Slice): TokenPool_SetAllowedFinalityConfig { - loadAndCheckPrefix32(s, 0x29b46fc6, 'TokenPool_SetAllowedFinalityConfig'); + loadAndCheckPrefix32(s, 0x3c50a39b, 'TokenPool_SetAllowedFinalityConfig'); return { $: 'TokenPool_SetAllowedFinalityConfig', queryId: s.loadUintBig(64), @@ -1696,7 +1696,7 @@ export const TokenPool_SetAllowedFinalityConfig = { } }, store(self: TokenPool_SetAllowedFinalityConfig, b: c.Builder): void { - b.storeUint(0x29b46fc6, 32); + b.storeUint(0x3c50a39b, 32); b.storeUint(self.queryId, 64); b.storeUint(self.allowedFinalityConfig, 32); }, @@ -1706,7 +1706,7 @@ export const TokenPool_SetAllowedFinalityConfig = { } /** - > struct (0x3a028da2) TokenPool_SetRateLimitConfig { + > struct (0x4fe2d26c) TokenPool_SetRateLimitConfig { > queryId: uint64 > updates: SnakedCell > } @@ -1718,7 +1718,7 @@ export interface TokenPool_SetRateLimitConfig { } export const TokenPool_SetRateLimitConfig = { - PREFIX: 0x3a028da2, + PREFIX: 0x4fe2d26c, create(args: { queryId: uint64 @@ -1730,7 +1730,7 @@ export const TokenPool_SetRateLimitConfig = { } }, fromSlice(s: c.Slice): TokenPool_SetRateLimitConfig { - loadAndCheckPrefix32(s, 0x3a028da2, 'TokenPool_SetRateLimitConfig'); + loadAndCheckPrefix32(s, 0x4fe2d26c, 'TokenPool_SetRateLimitConfig'); return { $: 'TokenPool_SetRateLimitConfig', queryId: s.loadUintBig(64), @@ -1738,7 +1738,7 @@ export const TokenPool_SetRateLimitConfig = { } }, store(self: TokenPool_SetRateLimitConfig, b: c.Builder): void { - b.storeUint(0x3a028da2, 32); + b.storeUint(0x4fe2d26c, 32); b.storeUint(self.queryId, 64); b.storeRef(self.updates); }, @@ -1748,7 +1748,7 @@ export const TokenPool_SetRateLimitConfig = { } /** - > struct (0x10c4b4a1) TokenPool_ApplyTokenTransferFeeConfigUpdates { + > struct (0x30a1d1f7) TokenPool_ApplyTokenTransferFeeConfigUpdates { > queryId: uint64 > updates: SnakedCell > disableChainSelectors: SnakedCell @@ -1762,7 +1762,7 @@ export interface TokenPool_ApplyTokenTransferFeeConfigUpdates { } export const TokenPool_ApplyTokenTransferFeeConfigUpdates = { - PREFIX: 0x10c4b4a1, + PREFIX: 0x30a1d1f7, create(args: { queryId: uint64 @@ -1775,7 +1775,7 @@ export const TokenPool_ApplyTokenTransferFeeConfigUpdates = { } }, fromSlice(s: c.Slice): TokenPool_ApplyTokenTransferFeeConfigUpdates { - loadAndCheckPrefix32(s, 0x10c4b4a1, 'TokenPool_ApplyTokenTransferFeeConfigUpdates'); + loadAndCheckPrefix32(s, 0x30a1d1f7, 'TokenPool_ApplyTokenTransferFeeConfigUpdates'); return { $: 'TokenPool_ApplyTokenTransferFeeConfigUpdates', queryId: s.loadUintBig(64), @@ -1784,7 +1784,7 @@ export const TokenPool_ApplyTokenTransferFeeConfigUpdates = { } }, store(self: TokenPool_ApplyTokenTransferFeeConfigUpdates, b: c.Builder): void { - b.storeUint(0x10c4b4a1, 32); + b.storeUint(0x30a1d1f7, 32); b.storeUint(self.queryId, 64); b.storeRef(self.updates); b.storeRef(self.disableChainSelectors); @@ -1795,7 +1795,7 @@ export const TokenPool_ApplyTokenTransferFeeConfigUpdates = { } /** - > struct (0x7a9c4aa5) TokenPool_UpdateRampAccess { + > struct (0xe30764be) TokenPool_UpdateRampAccess { > queryId: uint64 > updates: SnakedCell > } @@ -1807,7 +1807,7 @@ export interface TokenPool_UpdateRampAccess { } export const TokenPool_UpdateRampAccess = { - PREFIX: 0x7a9c4aa5, + PREFIX: 0xe30764be, create(args: { queryId: uint64 @@ -1819,7 +1819,7 @@ export const TokenPool_UpdateRampAccess = { } }, fromSlice(s: c.Slice): TokenPool_UpdateRampAccess { - loadAndCheckPrefix32(s, 0x7a9c4aa5, 'TokenPool_UpdateRampAccess'); + loadAndCheckPrefix32(s, 0xe30764be, 'TokenPool_UpdateRampAccess'); return { $: 'TokenPool_UpdateRampAccess', queryId: s.loadUintBig(64), @@ -1827,7 +1827,7 @@ export const TokenPool_UpdateRampAccess = { } }, store(self: TokenPool_UpdateRampAccess, b: c.Builder): void { - b.storeUint(0x7a9c4aa5, 32); + b.storeUint(0xe30764be, 32); b.storeUint(self.queryId, 64); b.storeRef(self.updates); }, @@ -1837,7 +1837,7 @@ export const TokenPool_UpdateRampAccess = { } /** - > struct (0x12345678) TokenPool_SetRMNProxy { + > struct (0x9929b642) TokenPool_SetRMNProxy { > queryId: uint64 > rmnProxy: address > } @@ -1849,7 +1849,7 @@ export interface TokenPool_SetRMNProxy { } export const TokenPool_SetRMNProxy = { - PREFIX: 0x12345678, + PREFIX: 0x9929b642, create(args: { queryId: uint64 @@ -1861,7 +1861,7 @@ export const TokenPool_SetRMNProxy = { } }, fromSlice(s: c.Slice): TokenPool_SetRMNProxy { - loadAndCheckPrefix32(s, 0x12345678, 'TokenPool_SetRMNProxy'); + loadAndCheckPrefix32(s, 0x9929b642, 'TokenPool_SetRMNProxy'); return { $: 'TokenPool_SetRMNProxy', queryId: s.loadUintBig(64), @@ -1869,7 +1869,7 @@ export const TokenPool_SetRMNProxy = { } }, store(self: TokenPool_SetRMNProxy, b: c.Builder): void { - b.storeUint(0x12345678, 32); + b.storeUint(0x9929b642, 32); b.storeUint(self.queryId, 64); b.storeAddress(self.rmnProxy); }, @@ -1879,7 +1879,7 @@ export const TokenPool_SetRMNProxy = { } /** - > struct (0x823dadf2) TokenPool_UpdateCursedSubjects { + > struct (0x2c906eb7) TokenPool_UpdateCursedSubjects { > queryId: uint64 > cursedSubjects: CursedSubjects > } @@ -1891,7 +1891,7 @@ export interface TokenPool_UpdateCursedSubjects { } export const TokenPool_UpdateCursedSubjects = { - PREFIX: 0x823dadf2, + PREFIX: 0x2c906eb7, create(args: { queryId: uint64 @@ -1903,7 +1903,7 @@ export const TokenPool_UpdateCursedSubjects = { } }, fromSlice(s: c.Slice): TokenPool_UpdateCursedSubjects { - loadAndCheckPrefix32(s, 0x823dadf2, 'TokenPool_UpdateCursedSubjects'); + loadAndCheckPrefix32(s, 0x2c906eb7, 'TokenPool_UpdateCursedSubjects'); return { $: 'TokenPool_UpdateCursedSubjects', queryId: s.loadUintBig(64), @@ -1911,7 +1911,7 @@ export const TokenPool_UpdateCursedSubjects = { } }, store(self: TokenPool_UpdateCursedSubjects, b: c.Builder): void { - b.storeUint(0x823dadf2, 32); + b.storeUint(0x2c906eb7, 32); b.storeUint(self.queryId, 64); CursedSubjects.store(self.cursedSubjects, b); }, @@ -1921,7 +1921,7 @@ export const TokenPool_UpdateCursedSubjects = { } /** - > struct (0x19e65bea) TokenPool_LockOrBurnResponse { + > struct (0x6c060424) TokenPool_LockOrBurnResponse { > queryId: uint64 > out: Cell > destTokenAmount: uint256 @@ -1935,7 +1935,7 @@ export interface TokenPool_LockOrBurnResponse { } export const TokenPool_LockOrBurnResponse = { - PREFIX: 0x19e65bea, + PREFIX: 0x6c060424, create(args: { queryId: uint64 @@ -1948,7 +1948,7 @@ export const TokenPool_LockOrBurnResponse = { } }, fromSlice(s: c.Slice): TokenPool_LockOrBurnResponse { - loadAndCheckPrefix32(s, 0x19e65bea, 'TokenPool_LockOrBurnResponse'); + loadAndCheckPrefix32(s, 0x6c060424, 'TokenPool_LockOrBurnResponse'); return { $: 'TokenPool_LockOrBurnResponse', queryId: s.loadUintBig(64), @@ -1957,7 +1957,7 @@ export const TokenPool_LockOrBurnResponse = { } }, store(self: TokenPool_LockOrBurnResponse, b: c.Builder): void { - b.storeUint(0x19e65bea, 32); + b.storeUint(0x6c060424, 32); b.storeUint(self.queryId, 64); storeCellRef(self.out, b, TokenPool_LockOrBurnOutV1.store); b.storeUint(self.destTokenAmount, 256); @@ -1968,7 +1968,7 @@ export const TokenPool_LockOrBurnResponse = { } /** - > struct (0x7d0ffd89) TokenPool_ReleaseOrMint { + > struct (0x351f77e3) TokenPool_ReleaseOrMint { > queryId: uint64 > request: Cell > requestedFinalityConfig: uint32 @@ -1984,7 +1984,7 @@ export interface TokenPool_ReleaseOrMint { } export const TokenPool_ReleaseOrMint = { - PREFIX: 0x7d0ffd89, + PREFIX: 0x351f77e3, create(args: { queryId: uint64 @@ -1999,7 +1999,7 @@ export const TokenPool_ReleaseOrMint = { } }, fromSlice(s: c.Slice): TokenPool_ReleaseOrMint { - loadAndCheckPrefix32(s, 0x7d0ffd89, 'TokenPool_ReleaseOrMint'); + loadAndCheckPrefix32(s, 0x351f77e3, 'TokenPool_ReleaseOrMint'); return { $: 'TokenPool_ReleaseOrMint', queryId: s.loadUintBig(64), @@ -2009,7 +2009,7 @@ export const TokenPool_ReleaseOrMint = { } }, store(self: TokenPool_ReleaseOrMint, b: c.Builder): void { - b.storeUint(0x7d0ffd89, 32); + b.storeUint(0x351f77e3, 32); b.storeUint(self.queryId, 64); storeCellRef(self.request, b, TokenPool_ReleaseOrMintInV1.store); b.storeUint(self.requestedFinalityConfig, 32); @@ -2021,7 +2021,7 @@ export const TokenPool_ReleaseOrMint = { } /** - > struct (0x7ec43aee) TokenPool_ReleaseOrMintResponse { + > struct (0x78dc2232) TokenPool_ReleaseOrMintResponse { > queryId: uint64 > out: Cell > } @@ -2033,7 +2033,7 @@ export interface TokenPool_ReleaseOrMintResponse { } export const TokenPool_ReleaseOrMintResponse = { - PREFIX: 0x7ec43aee, + PREFIX: 0x78dc2232, create(args: { queryId: uint64 @@ -2045,7 +2045,7 @@ export const TokenPool_ReleaseOrMintResponse = { } }, fromSlice(s: c.Slice): TokenPool_ReleaseOrMintResponse { - loadAndCheckPrefix32(s, 0x7ec43aee, 'TokenPool_ReleaseOrMintResponse'); + loadAndCheckPrefix32(s, 0x78dc2232, 'TokenPool_ReleaseOrMintResponse'); return { $: 'TokenPool_ReleaseOrMintResponse', queryId: s.loadUintBig(64), @@ -2053,7 +2053,7 @@ export const TokenPool_ReleaseOrMintResponse = { } }, store(self: TokenPool_ReleaseOrMintResponse, b: c.Builder): void { - b.storeUint(0x7ec43aee, 32); + b.storeUint(0x78dc2232, 32); b.storeUint(self.queryId, 64); storeCellRef(self.out, b, TokenPool_ReleaseOrMintOutV1.store); }, @@ -2557,7 +2557,7 @@ export const TokenPool_CursedSubjectsUpdated = { } /** - > struct (0x93c174a1) BurnMintTokenPool_ClaimMinterAdmin { + > struct (0x39898e4d) BurnMintTokenPool_ClaimMinterAdmin { > queryId: uint64 > } */ @@ -2567,7 +2567,7 @@ export interface BurnMintTokenPool_ClaimMinterAdmin { } export const BurnMintTokenPool_ClaimMinterAdmin = { - PREFIX: 0x93c174a1, + PREFIX: 0x39898e4d, create(args: { queryId: uint64 @@ -2578,14 +2578,14 @@ export const BurnMintTokenPool_ClaimMinterAdmin = { } }, fromSlice(s: c.Slice): BurnMintTokenPool_ClaimMinterAdmin { - loadAndCheckPrefix32(s, 0x93c174a1, 'BurnMintTokenPool_ClaimMinterAdmin'); + loadAndCheckPrefix32(s, 0x39898e4d, 'BurnMintTokenPool_ClaimMinterAdmin'); return { $: 'BurnMintTokenPool_ClaimMinterAdmin', queryId: s.loadUintBig(64), } }, store(self: BurnMintTokenPool_ClaimMinterAdmin, b: c.Builder): void { - b.storeUint(0x93c174a1, 32); + b.storeUint(0x39898e4d, 32); b.storeUint(self.queryId, 64); }, toCell(self: BurnMintTokenPool_ClaimMinterAdmin): c.Cell { @@ -2908,7 +2908,7 @@ function calculateDeployedAddress(code: c.Cell, data: c.Cell, options: DeployedA } export class BurnMintTokenPool implements c.Contract { - static CodeCell = c.Cell.fromBase64('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'); + static CodeCell = c.Cell.fromBase64('te6ccgECZwEAFlcAART/APSkE/S88sgLAQIBYgIDAgLMBAUCASAeHwIBIAYHAgEgMjMCASAICQIBIBgZAgEgCgsAV1IW6SW3DggmkAAAAAAAAAAAAAAAAAAAEigwb0Dm+hMZJbf+ABgwb0Dm+hMYBO0+JHyQO1E0NTU9AT0BNEj0NTU+kjTB/QE9ATRgQCFbW1tbW1tbZLwCACBAIZWE1YTVhNWE/iS+JcQXxBOED0QLBBbEEoQORAoEFcQRhA1ECRWGvAKPl8JBOMCXwok1ywhzExybOMC1ywjmxaE5OMC1ywmqZO23IAwNDg8BqTtou371ywnkNvtDI5E1ywnzxTyVJRbcNsx4YIAwoojbrPy9CGCAMKKBMcFE/L0IG0D1ws/iwIByMs/FfpSEvpSycjPhyAUznHPC2ETzMlw+wDjDX+AXAFw9PQHDAJM3NzeZMDk5EFheJBBF4gPIzBLM+lLLBxP0APQAycjMzBL0APQAye1UAMg1BNcLP/iSJNDU1DH6SDHTBzH0BDH0BDHR0NT6SDHUMdMfMdHQ+kj6UDHRAYIAwogCxwXy9IIK+vCAI9D6SNQx0cjPhYj6UgH6AoIQ+4jhGc8Liss/yXH7AALIzMz0APQAye1UAfo1BNM/MfoA+lD4kiXQ+kjU0YIAoPD4KCPIz4QCEvpS+lLJWMjPhNDMzPkWyM+KAEDL/89QI8cF8vQC9AQhbpgxIMcAkjBt4JLR0OKCAKDyIW6z8vTXLCfT7SIk8r/TP9TTH/QE+lDRA9DU0z/6SNP/+kjRIYIAoPMOuh3y9BAATo4bNQTXCz/4khBFEDQQI/AJA8jMEsz0APQAye1U4F8FhA8BxwDy9AH+ggCg8Stus/L0ggCg9FONgED0Dm+hMbPy9C7Q1NT6SNMH9AT0BNGBAIVtbW1tbW1tkvAIAIEAhlYdVh1WIYE6PVYRViDHBfL0gTo5VhZWEIBA9A5voTHy9IE6OlYS0PQEMfQEMfQE0VYX8AOz8vQpbrOcViFUcyFWEFYaL9pg3hEB/lYR0PQE9AQx9AQx0VYWAYBA9A5voZP6SNGSMG3igTo+IW6z8vSBOj4BVh/HBfL0K26zn1YhVGMzU/ARIlYaVhHacJJXHeJWEVYRVhFWEVYRVhFWJlOHViVWFVYVVhVWFVYVVhVWFVYVVhVWFVYpVilWKVYpVjVWMPAPbDMzMzQSAv40NFOyoTNWEI5NgTo4U+eAQPQOb6ES8vTU9ATU1NEB0NTU0QHQ03/TP9IA03/Tf9ErVhLwBATIy38Tyz/KAMt/y3/JyMzMyQPIzBL0ABLMzFQg6IBA9EPjDSZus44aVhlTJFYYKFYTVhNWE1YTVh9WGlYaLlYT2tDeMTU9Wzs/ExQB7irQ1DH6SDHUMdMf0VYRAfAGgTo4U+eAQPQOb6ES8vTU9ATU1NEg0NTU0QHQ03/TP9IA03/Tf9EijixfBgHQ1NTRAdDTf9M/0gDTf9N/0StWEvAEBMjLfxPLP8oAy3/Lf8nIzMzJAeMNA8jMEvQAzMxUIOiAQPRDFQH+VxKBOjhTboBA9A5voRLy9NT0BDHUMdQx0VYSyMv/yQTIzBPM+lIBEREBywcc9AAW9ADJA8jMEss/+lITy/8Y+lLJCsjMFszJAcj6VBnMGMwkzwv/EvpSyVQgZYBA9BeCCvrwgPgobcjPhYgX+lJY+gKCEFlfB7zPC4oXyz9QAxYAMmwWK1YS8AQEyMt/E8s/ygDLf8t/ycjMzMkALvoCFfpUEvQAyXH7AALIzMz0APQAye1UAGZsEtM/+kgwggDCiFE0xwUT8vSCAMKJUyPHBbPy9CGLAsjPhyDOcM8LYRLLPxL6Uslw+wACASAaGwIBIBwdAKsMCOzkX+VIMAAwwDikTDgIvgjJqEgjhg2U2C8lYFmvPLw4FFSqBagUkDwBQX4IwWRMOIhuZWBZr3y8OBTULmOERVfBSCVgWa+8vDhMIFmvvLw4BWhBIAANFy5kTDgMYAApCGRW+GBOkYhlAK6wwCTbCFw4vL0gAE8cXqTIsIAjhwicbDAAZ+BOkKE/yOpBCK+8vRmqAHeIKgCqwAC6DAxgAgEgICECASAuLwIBICIjAgEgLC0CASAkJQBBtbUdqJoamoY+gIY+gIY6OhqGOoY/SQY6YP6Ahj6AhjowAgEgJicCAUgqKwAtrSp2omhqGOoY+gIY+gJowCB6BzfQmMACAUgoKQBvpXXaiaGpqGPoCGPoCGOjoahjqfSQY6YOY+gIY+gIY6Oh6Ahj6AnoCGOjAIHoHN9DJ/SRoyRg28UAP6cj2omhqahj6Ahj6Ahjo6GoY6hj9JGmDmPoCGPoCGOjAGKpX40JWxpbmsuY2hhaW4udG9uLmNjaXAuQnVybk1pbnRUb2tlblBvb2yCLUwLjEuMIACyp3e1E0NQx1DH0BPQEMdGAQPQOb6ExAGW0o72omhqahj6Ahj6Ahjo6GpqGP0kGOmDmPoCGPoCGOjoan0kGOoY6Y+Y6Oh9JH0oGOjAAcbdw3aiaGpqGPoCGPoCGOjoahjqfSQY6YOY+gIY+gIY6Oh6AnoCGPoCGOjAIHoHN9DJ/SRoyRg28UABXuD7e1E0NTUMfQEMfQEMdHQ1NQx+kgx0wcx9AQx9AQx0dDUMfpI1DHTHzHRgCAVgwMQBdsuB7UTQ1NQx9AQx9AQx0dDUMdT6SDHTBzH0BDH0BDHR0PQEMfQEMfQE0QHwA7OAAT7Ice1E0NTUMfQEMfQEMdHQ1DHUMfpIMdMHMfQE9AQx0YBA9A5voTGACASA0NQIBIGFiAgEgNjcCASA8PQL3DEyOzs8gTpFDcMAHfL0ggCg9lOtgED0Dm+hMbPy9C7Q+kjU0VNRyM+EAhL6UvpSyQHIz4TQzMz5FsjPigBAy//PUAfIzBbLP1JA+lITy//6UswZ9AAX9ADJBMjL/8kCyPpUFMzMEvpSyVQgJoBA9BeCEAX14QAgbfgoiYDg5AvcUxOAQPQOb6HjAjBTEoBA9A5voYIAoPcB8vTU0dD6UNTU+kjRBIIAoPkFxwUU8vRSNYBA9FswBNDUMdM/+kjT/zH6SNQx9AQx9AQx0STQ0//R+CjI+lIT+lLJAcj6UhLL/8zJyM+PGAAEghDpwAyXzwv3cM8LYRLLP8zJgOjsAAUAAeMjPkF41FGYnzws/UAr6AhL6VPpUz4QgF87JyM+FiBX6UgH6AoAVzwuKEss/E/pSUAP6AhLMyXH7AIEAhQD+1NHQ+lDU1NP/+kjRBYIAoPgGxwUV8vRSR4BA9FswAdDUMdM/+kjT/zH6SNHI+lL6UiTPC//JyM+PGAAEghA33W9uzwv3cM8LYRLLP8zJcPsAIW6TNV8DjiWCCJiWgMjPhYgT+lJY+gKCEGwGBCTPC4oTyz8UzBPL/8mAQfsA4gBYcPsAIG6SXwOOIYIImJaAyM+FiBL6UgH6AoIQeNwiMs8LihLLP8zJgEH7AOIESQxINcsIre56bzjAtcsIL4SFuTjAtcsIhNcZiTjAtcsJruJQISA+P0BBAHkVxBfD2wxAdDU+kgx1NMfMdEB0PpI+lAx0SLHBZFb4ND6SDH6UPpQMdGBOj4hbrOVAscFwwCTbCFw4vL0gAfQx1NdMVhbQ1PpIMdQx0x8x0dD6SPpQMdEDggDCiATHBRPy9NBwkiCzjkWVIddJwgCOLgHTP1IQERSAQPRbgTo4AfL0yM+PGAAEghAnkIKLzwv3cM8LYRLLP8lw+wAREgHoIddKlAHXTNCTMH8B4gHoW9BwkiCziuhbf0IB/jHTPzHTP9dMVhbQ1PpIMdQx0x8x0dD6SPpQMdEDggDCiATHBRPy9IE6OCFWE4BA9A5voTHy9IE6OCFWE4BA9A5voRLy9NT0BNTU0YE6NybQ0wchwUHyhQGqAtcY0ddJwwDy9CXQ0wchwUHyhQGqAtcY0cjOcfkEA4E6P1MUgwdHAv4x0z8x0z/XTFYW0NT6SDHUMdMfMdHQ+kj6UDHRA4IAwogExwUT8vSBOjghVhOAQPQOb6Ex8vSBOjghVhOAQPQOb6ES8vTU9ATU1NEl0NMHIcFB8oUBqgLXGNHIznH5BANQA4MH9FuBOkAB8vQDyMwT9AASzMxREBETgED0Q8iJSEkE/I5oMdM/MfpI+lD6UDARF9DU+kjUMdMf0SLQ+kj6UDHRBoIAwogHxwUW8vQjyPpSUjD6VFYZAfpUyQLIzPpSzBPLH8kByPpSEvpUAREVAfpUycjPjxgABIIQtzXjDM8L93HPC2HMyXD7AH/g1ywh4oUc3OMC1ywifxaTZOMCiUpLTE0BLJUh10nCAIroIddKlAHXTNCTMH8B4gFDAf4B0z/U1NQB0NQB0NMAAcMAAdN/03/RA9QB0NMAAcMAAdN/03/RA9GBOjco0NMHIcFB8oUBqgLXGNHXScMA8vSBOjsqVhyAQPQOb6Exs/L0bfgjJcjLf8s/FsoAFMt/Fct/yfgjI8jLf8s/FcoAEst/y3/JAsjMEszJ+CNwyMt/RAHiyz9wzwuAcM8Lf8n4I3DIy3/LP3DPC4Bwzwt/yQHIzMzJJAbQcJIgs46WlSHXScIAiugh10qUAddM0JMwfwHiAehbyM+PGAAEghDtN8S8zwv3cM8LYSfPCz8VzMlw+wAEyMz0ABPMzFkRE4BA9EMREQFFAfoB0wchwUHyhQGqAtcYIddJgTpCIak4AvLyUSLXGQKrAsjLBxLOyYE6NyHQ0wchwUHyhQGqAtcY0ddJwwDy9CDQ0wchwUHyhQGqAtcY0cjOcfkEA4E6P1MXgwf0Dm+hMbPy9FRBF4MH9BfIz48YAASCEL8NGrbPC/dwzwthKkYAFM8LPxbMyXD7AAEAfvQOb6Exs/L0VEYUgwf0FwPIzBP0ABLMzFEQEROAQPRDyM+PGAAEghC/DRq2zwv3cM8LYQEREgHLP8zJcPsAfwAFxgABADbPFoIQvBTH6M8L93DPC2EBERIByz/MyXD7AH8AnjHTPzHXCx8RFdDU+kjU0x8x0SLQ+kj6UDHRBIIAwogFxwUU8vRWFgLIzPpSEszLH8nIz48YAASCEEJqcTvPC/dwzwthAREVAcsfyXD7AH8BmjHXTFYVAVYVAVYVAVYVAVYVAVYVAVYVAVYVAVYVAVYVAVYVAVYVAVYVAVYVAVYVAVYVAVYVAVYVAVYVAVYVAREV8AvQlCDHALOK6DB/TgAIMKHR9wTk1yeO1DHU10xWFtDU+kgx1DHTHzHR0PpI+lAx0QOCAMKIBMcFE/L00JQgxwCziugw0JQgxwCzjh0g10sBkTCbgTS8AcAB8vTXTNDi0z8REIBA9FswD+gwf+DXLCcYOyX04wLXLCTJTbIU4wLXLCFkg3W8UVJTVAL+INdLAZEwm4E0vAHAAfL010zQ4tM/0gDU1IE6OCVWFoBA9A5voRLy9NT0BNTU0QeOP9DUMdQx0QTQ0gDTf9N/0fgjIsjLf8s/E8oAy3/Lf8kD0NIA03/Tf9H4IyLIy3/LPxPKAMt/y3/JA8jME8zJBOMNAsjME/QAE8wSzFkREk9QAH4G0NQx1DHRBNDSANN/03/R+CMiyMt/yz8TygDLf8t/yQPQ0gDTf9N/0fgjIsjLf8s/E8oAy3/Lf8kDyMwTzMkADIBA9EMREADgINdLAZEwm4E0vAHAAfL010zQ4tM/0gDT/9P/0x/TH9MP0w+BOjgpVhuAQPQOb6Ex8vSBOjUo8vSBOjQjgScQufL0gTo0IoEnELny9IE6NSXCAPL0B8jKABbL/xTL/xLLH8sfyw/LD1kREoBA9EMREAGsMddMERXQ1PpI1NMf0QPQ+kj6UNGCAMKIUWLHBRby9Mj6UhT6VMnIzPpSEszLH8kRE9D0BPQE9ATRERbQlCDHALOK6DAByPQA9AABERQB9ADJERIRE39VAHox0z8x+kgwERXQ1PpIMdTTH9Ei0PpI+lAx0QSCAMKIBccFFPL0AcjMAREWAfpSAREVAcwBERQByx/JERN/A/yOTjHTPzH0BYE6PlYW0NQx+kjUMdMfMdETxwUS8vQRE9D0BPQE9AQx0QHI9AD0AAEREwH0AMnIz48YAASCECdeAjTPC/dwzwthyXD7ABESf+DXLCGo+78c4wLXLCObFoTkMZJbcOBWFdDU+kjU0x/RA9D6SPpQ0UEGJfAB4wJWV1gA1CDXSwGRMJuBNLwBwAHy9NdM0OLTP/pQ+lAibpdSNoBA9FswmyLI+lJUIEeAQPRD4iFul1I1gED0WzCbIcj6UlQgRoBA9EPiA8jLPxL6VPpUycjPjxgABIIQnFq7lc8L93HPC2HMyXD7AFgD/jHTP9TTH/pQMCLQ1NM/+kjT//pI1PQE9ATRgTo9Vh8lxwXy9IE6OSdWHoBA9A5voTHy9IE6OlYg0PQEMfQEMfQE0SjwA7Py9C3DAJZWE26zwwCRcOKfVhpWGlYaVhpWGitWGdpg3lYf0PQEMfQE9AQx0VJwgED0Dm+h4w+BOj5ZWlsAPjRXGBEXyPpSEvpUycjMAREWAfpSzAERFAHLH8kRE38ADBBFXwXHAAAG+kjRAAQwbQH8IW6z8vSBOj5RHscF8vQtwwCWVhRus8MAkXDijhFWGlYaVhpWGlYaVhEsVhvacN6BOkBWIVYhViFWIVYhViFWIVYhViFWIVYhViFWIVYhViFWIVYhViFWIVYhVhtWGPAM8vRWIFYgViBWIFYgViBWIFYgViBWIFYgViBWIFYgXAP+ViBWIFYgViBWIFYgVhXwDVYhAVYhAVYhAVYhAVYhAVYhAVYhAVYhAVYhAVYhAVYhAVYhAVYhAVYhAVYhAVYhAVYhAVYhAVYhAVYhAVYZAfAOKsMAK+MPL8MAllYTbrPDAJFw4o4ZVhxWHFYcVhxWHFR+3FR+3FR+3FYZViLa8F1eXwHwViLQ1DH6SDHUMdMf0VLA8AaBOjgpViCAQPQOb6ES8vTU9ATU1NEg0NTU0dDTf9M/0gDTf9N/0SKOLF8GAdDU1NHQ03/TP9IA03/Tf9EqVirwBATIy38Tyz/KAMt/y3/JAcjMzMkB4w0DyMwS9ADMzFKSESCAQPRDYACegTo4KVYggED0Dm+hEvL01PQE1NTRAdDU1NHQ03/TP9IA03/Tf9EqVirwBATIy38Tyz/KAMt/y3/JAcjMzMkDyMwS9AASzMxSkhEggED0QwCO3lOxgTpFVhLDAJZWE26zwwCRcOLy9BEVER4RFREUER0RFBETERwRExESERsREhERERoREQIRIFADVhuAFnXbOBBNEDxLqX8ANGwWKlYq8AQEyMt/E8s/ygDLf8t/yQHIzMzJAgEgY2QCASBlZgBxFcTVxFfD2wjgED0Dm+hkltw4dQx9ATUMdQx0QHQ0wchwUHyhQGqAtcY0cjOcfkEAwGDB/QOb6ExgAGEVxBfD2wiMiFukTHgMNCBOkEh10mDB7qXIddKwADDAJFw4vL00//RgTpBIYQHu/L0gAIUVxNXEF8PMzNTArqSMDHgUwK8nlihgTpCIcFO8vTwB6kE4BKhgTpCIcFO8vTwB4E6QiGZhP8iqQQjvsMAkX/i8vSogAHsMTJs82xENAKAQPQOb6GTXwNw4dIA0/8x0/8x0x8x0x8x0w/TD9ECk18EcOEClzGogScQqQTgMKiBJxCpBIA=='); static Errors = { 'Common_Error.CrossChainAddressOutOfRange': 5, diff --git a/contracts/wrappers/gen/ccip/pools/LockReleaseTokenPool.ts b/contracts/wrappers/gen/ccip/pools/LockReleaseTokenPool.ts index f2b9935e6..9af0d3112 100644 --- a/contracts/wrappers/gen/ccip/pools/LockReleaseTokenPool.ts +++ b/contracts/wrappers/gen/ccip/pools/LockReleaseTokenPool.ts @@ -1280,7 +1280,7 @@ export const TokenPool_ReleaseOrMintOutV1 = { } /** - > struct (0xdc0b6ff5) TokenPool_ApplyChainUpdates { + > struct (0x56f73d37) TokenPool_ApplyChainUpdates { > queryId: uint64 > remoteChainSelectorsToRemove: SnakedCell > chainsToAdd: SnakedCell @@ -1294,7 +1294,7 @@ export interface TokenPool_ApplyChainUpdates { } export const TokenPool_ApplyChainUpdates = { - PREFIX: 0xdc0b6ff5, + PREFIX: 0x56f73d37, create(args: { queryId: uint64 @@ -1307,7 +1307,7 @@ export const TokenPool_ApplyChainUpdates = { } }, fromSlice(s: c.Slice): TokenPool_ApplyChainUpdates { - loadAndCheckPrefix32(s, 0xdc0b6ff5, 'TokenPool_ApplyChainUpdates'); + loadAndCheckPrefix32(s, 0x56f73d37, 'TokenPool_ApplyChainUpdates'); return { $: 'TokenPool_ApplyChainUpdates', queryId: s.loadUintBig(64), @@ -1316,7 +1316,7 @@ export const TokenPool_ApplyChainUpdates = { } }, store(self: TokenPool_ApplyChainUpdates, b: c.Builder): void { - b.storeUint(0xdc0b6ff5, 32); + b.storeUint(0x56f73d37, 32); b.storeUint(self.queryId, 64); b.storeRef(self.remoteChainSelectorsToRemove); b.storeRef(self.chainsToAdd); @@ -1327,7 +1327,7 @@ export const TokenPool_ApplyChainUpdates = { } /** - > struct (0x5fd2c8b6) TokenPool_AddRemotePool { + > struct (0x17c242dc) TokenPool_AddRemotePool { > queryId: uint64 > remoteChainSelector: uint64 > remotePoolAddress: Cell @@ -1341,7 +1341,7 @@ export interface TokenPool_AddRemotePool { } export const TokenPool_AddRemotePool = { - PREFIX: 0x5fd2c8b6, + PREFIX: 0x17c242dc, create(args: { queryId: uint64 @@ -1354,7 +1354,7 @@ export const TokenPool_AddRemotePool = { } }, fromSlice(s: c.Slice): TokenPool_AddRemotePool { - loadAndCheckPrefix32(s, 0x5fd2c8b6, 'TokenPool_AddRemotePool'); + loadAndCheckPrefix32(s, 0x17c242dc, 'TokenPool_AddRemotePool'); return { $: 'TokenPool_AddRemotePool', queryId: s.loadUintBig(64), @@ -1363,7 +1363,7 @@ export const TokenPool_AddRemotePool = { } }, store(self: TokenPool_AddRemotePool, b: c.Builder): void { - b.storeUint(0x5fd2c8b6, 32); + b.storeUint(0x17c242dc, 32); b.storeUint(self.queryId, 64); b.storeUint(self.remoteChainSelector, 64); storeCellRef(self.remotePoolAddress, b, CrossChainAddress.store); @@ -1374,7 +1374,7 @@ export const TokenPool_AddRemotePool = { } /** - > struct (0xdbf0a2df) TokenPool_RemoveRemotePool { + > struct (0x426b8cc4) TokenPool_RemoveRemotePool { > queryId: uint64 > remoteChainSelector: uint64 > remotePoolAddress: Cell @@ -1388,7 +1388,7 @@ export interface TokenPool_RemoveRemotePool { } export const TokenPool_RemoveRemotePool = { - PREFIX: 0xdbf0a2df, + PREFIX: 0x426b8cc4, create(args: { queryId: uint64 @@ -1401,7 +1401,7 @@ export const TokenPool_RemoveRemotePool = { } }, fromSlice(s: c.Slice): TokenPool_RemoveRemotePool { - loadAndCheckPrefix32(s, 0xdbf0a2df, 'TokenPool_RemoveRemotePool'); + loadAndCheckPrefix32(s, 0x426b8cc4, 'TokenPool_RemoveRemotePool'); return { $: 'TokenPool_RemoveRemotePool', queryId: s.loadUintBig(64), @@ -1410,7 +1410,7 @@ export const TokenPool_RemoveRemotePool = { } }, store(self: TokenPool_RemoveRemotePool, b: c.Builder): void { - b.storeUint(0xdbf0a2df, 32); + b.storeUint(0x426b8cc4, 32); b.storeUint(self.queryId, 64); b.storeUint(self.remoteChainSelector, 64); storeCellRef(self.remotePoolAddress, b, CrossChainAddress.store); @@ -1421,7 +1421,7 @@ export const TokenPool_RemoveRemotePool = { } /** - > struct (0x4eea060b) TokenPool_SetDynamicConfig { + > struct (0xd7712810) TokenPool_SetDynamicConfig { > queryId: uint64 > router: address > rateLimitAdmin: address? @@ -1437,7 +1437,7 @@ export interface TokenPool_SetDynamicConfig { } export const TokenPool_SetDynamicConfig = { - PREFIX: 0x4eea060b, + PREFIX: 0xd7712810, create(args: { queryId: uint64 @@ -1453,7 +1453,7 @@ export const TokenPool_SetDynamicConfig = { } }, fromSlice(s: c.Slice): TokenPool_SetDynamicConfig { - loadAndCheckPrefix32(s, 0x4eea060b, 'TokenPool_SetDynamicConfig'); + loadAndCheckPrefix32(s, 0xd7712810, 'TokenPool_SetDynamicConfig'); return { $: 'TokenPool_SetDynamicConfig', queryId: s.loadUintBig(64), @@ -1463,7 +1463,7 @@ export const TokenPool_SetDynamicConfig = { } }, store(self: TokenPool_SetDynamicConfig, b: c.Builder): void { - b.storeUint(0x4eea060b, 32); + b.storeUint(0xd7712810, 32); b.storeUint(self.queryId, 64); b.storeAddress(self.router); b.storeAddress(self.rateLimitAdmin); @@ -1475,7 +1475,7 @@ export const TokenPool_SetDynamicConfig = { } /** - > struct (0x29b46fc6) TokenPool_SetAllowedFinalityConfig { + > struct (0x3c50a39b) TokenPool_SetAllowedFinalityConfig { > queryId: uint64 > allowedFinalityConfig: uint32 > } @@ -1487,7 +1487,7 @@ export interface TokenPool_SetAllowedFinalityConfig { } export const TokenPool_SetAllowedFinalityConfig = { - PREFIX: 0x29b46fc6, + PREFIX: 0x3c50a39b, create(args: { queryId: uint64 @@ -1499,7 +1499,7 @@ export const TokenPool_SetAllowedFinalityConfig = { } }, fromSlice(s: c.Slice): TokenPool_SetAllowedFinalityConfig { - loadAndCheckPrefix32(s, 0x29b46fc6, 'TokenPool_SetAllowedFinalityConfig'); + loadAndCheckPrefix32(s, 0x3c50a39b, 'TokenPool_SetAllowedFinalityConfig'); return { $: 'TokenPool_SetAllowedFinalityConfig', queryId: s.loadUintBig(64), @@ -1507,7 +1507,7 @@ export const TokenPool_SetAllowedFinalityConfig = { } }, store(self: TokenPool_SetAllowedFinalityConfig, b: c.Builder): void { - b.storeUint(0x29b46fc6, 32); + b.storeUint(0x3c50a39b, 32); b.storeUint(self.queryId, 64); b.storeUint(self.allowedFinalityConfig, 32); }, @@ -1517,7 +1517,7 @@ export const TokenPool_SetAllowedFinalityConfig = { } /** - > struct (0x3a028da2) TokenPool_SetRateLimitConfig { + > struct (0x4fe2d26c) TokenPool_SetRateLimitConfig { > queryId: uint64 > updates: SnakedCell > } @@ -1529,7 +1529,7 @@ export interface TokenPool_SetRateLimitConfig { } export const TokenPool_SetRateLimitConfig = { - PREFIX: 0x3a028da2, + PREFIX: 0x4fe2d26c, create(args: { queryId: uint64 @@ -1541,7 +1541,7 @@ export const TokenPool_SetRateLimitConfig = { } }, fromSlice(s: c.Slice): TokenPool_SetRateLimitConfig { - loadAndCheckPrefix32(s, 0x3a028da2, 'TokenPool_SetRateLimitConfig'); + loadAndCheckPrefix32(s, 0x4fe2d26c, 'TokenPool_SetRateLimitConfig'); return { $: 'TokenPool_SetRateLimitConfig', queryId: s.loadUintBig(64), @@ -1549,7 +1549,7 @@ export const TokenPool_SetRateLimitConfig = { } }, store(self: TokenPool_SetRateLimitConfig, b: c.Builder): void { - b.storeUint(0x3a028da2, 32); + b.storeUint(0x4fe2d26c, 32); b.storeUint(self.queryId, 64); b.storeRef(self.updates); }, @@ -1559,7 +1559,7 @@ export const TokenPool_SetRateLimitConfig = { } /** - > struct (0x10c4b4a1) TokenPool_ApplyTokenTransferFeeConfigUpdates { + > struct (0x30a1d1f7) TokenPool_ApplyTokenTransferFeeConfigUpdates { > queryId: uint64 > updates: SnakedCell > disableChainSelectors: SnakedCell @@ -1573,7 +1573,7 @@ export interface TokenPool_ApplyTokenTransferFeeConfigUpdates { } export const TokenPool_ApplyTokenTransferFeeConfigUpdates = { - PREFIX: 0x10c4b4a1, + PREFIX: 0x30a1d1f7, create(args: { queryId: uint64 @@ -1586,7 +1586,7 @@ export const TokenPool_ApplyTokenTransferFeeConfigUpdates = { } }, fromSlice(s: c.Slice): TokenPool_ApplyTokenTransferFeeConfigUpdates { - loadAndCheckPrefix32(s, 0x10c4b4a1, 'TokenPool_ApplyTokenTransferFeeConfigUpdates'); + loadAndCheckPrefix32(s, 0x30a1d1f7, 'TokenPool_ApplyTokenTransferFeeConfigUpdates'); return { $: 'TokenPool_ApplyTokenTransferFeeConfigUpdates', queryId: s.loadUintBig(64), @@ -1595,7 +1595,7 @@ export const TokenPool_ApplyTokenTransferFeeConfigUpdates = { } }, store(self: TokenPool_ApplyTokenTransferFeeConfigUpdates, b: c.Builder): void { - b.storeUint(0x10c4b4a1, 32); + b.storeUint(0x30a1d1f7, 32); b.storeUint(self.queryId, 64); b.storeRef(self.updates); b.storeRef(self.disableChainSelectors); @@ -1606,7 +1606,7 @@ export const TokenPool_ApplyTokenTransferFeeConfigUpdates = { } /** - > struct (0x7a9c4aa5) TokenPool_UpdateRampAccess { + > struct (0xe30764be) TokenPool_UpdateRampAccess { > queryId: uint64 > updates: SnakedCell > } @@ -1618,7 +1618,7 @@ export interface TokenPool_UpdateRampAccess { } export const TokenPool_UpdateRampAccess = { - PREFIX: 0x7a9c4aa5, + PREFIX: 0xe30764be, create(args: { queryId: uint64 @@ -1630,7 +1630,7 @@ export const TokenPool_UpdateRampAccess = { } }, fromSlice(s: c.Slice): TokenPool_UpdateRampAccess { - loadAndCheckPrefix32(s, 0x7a9c4aa5, 'TokenPool_UpdateRampAccess'); + loadAndCheckPrefix32(s, 0xe30764be, 'TokenPool_UpdateRampAccess'); return { $: 'TokenPool_UpdateRampAccess', queryId: s.loadUintBig(64), @@ -1638,7 +1638,7 @@ export const TokenPool_UpdateRampAccess = { } }, store(self: TokenPool_UpdateRampAccess, b: c.Builder): void { - b.storeUint(0x7a9c4aa5, 32); + b.storeUint(0xe30764be, 32); b.storeUint(self.queryId, 64); b.storeRef(self.updates); }, @@ -1648,7 +1648,7 @@ export const TokenPool_UpdateRampAccess = { } /** - > struct (0x12345678) TokenPool_SetRMNProxy { + > struct (0x9929b642) TokenPool_SetRMNProxy { > queryId: uint64 > rmnProxy: address > } @@ -1660,7 +1660,7 @@ export interface TokenPool_SetRMNProxy { } export const TokenPool_SetRMNProxy = { - PREFIX: 0x12345678, + PREFIX: 0x9929b642, create(args: { queryId: uint64 @@ -1672,7 +1672,7 @@ export const TokenPool_SetRMNProxy = { } }, fromSlice(s: c.Slice): TokenPool_SetRMNProxy { - loadAndCheckPrefix32(s, 0x12345678, 'TokenPool_SetRMNProxy'); + loadAndCheckPrefix32(s, 0x9929b642, 'TokenPool_SetRMNProxy'); return { $: 'TokenPool_SetRMNProxy', queryId: s.loadUintBig(64), @@ -1680,7 +1680,7 @@ export const TokenPool_SetRMNProxy = { } }, store(self: TokenPool_SetRMNProxy, b: c.Builder): void { - b.storeUint(0x12345678, 32); + b.storeUint(0x9929b642, 32); b.storeUint(self.queryId, 64); b.storeAddress(self.rmnProxy); }, @@ -1690,7 +1690,7 @@ export const TokenPool_SetRMNProxy = { } /** - > struct (0x823dadf2) TokenPool_UpdateCursedSubjects { + > struct (0x2c906eb7) TokenPool_UpdateCursedSubjects { > queryId: uint64 > cursedSubjects: CursedSubjects > } @@ -1702,7 +1702,7 @@ export interface TokenPool_UpdateCursedSubjects { } export const TokenPool_UpdateCursedSubjects = { - PREFIX: 0x823dadf2, + PREFIX: 0x2c906eb7, create(args: { queryId: uint64 @@ -1714,7 +1714,7 @@ export const TokenPool_UpdateCursedSubjects = { } }, fromSlice(s: c.Slice): TokenPool_UpdateCursedSubjects { - loadAndCheckPrefix32(s, 0x823dadf2, 'TokenPool_UpdateCursedSubjects'); + loadAndCheckPrefix32(s, 0x2c906eb7, 'TokenPool_UpdateCursedSubjects'); return { $: 'TokenPool_UpdateCursedSubjects', queryId: s.loadUintBig(64), @@ -1722,7 +1722,7 @@ export const TokenPool_UpdateCursedSubjects = { } }, store(self: TokenPool_UpdateCursedSubjects, b: c.Builder): void { - b.storeUint(0x823dadf2, 32); + b.storeUint(0x2c906eb7, 32); b.storeUint(self.queryId, 64); CursedSubjects.store(self.cursedSubjects, b); }, @@ -1732,7 +1732,7 @@ export const TokenPool_UpdateCursedSubjects = { } /** - > struct (0x19e65bea) TokenPool_LockOrBurnResponse { + > struct (0x6c060424) TokenPool_LockOrBurnResponse { > queryId: uint64 > out: Cell > destTokenAmount: uint256 @@ -1746,7 +1746,7 @@ export interface TokenPool_LockOrBurnResponse { } export const TokenPool_LockOrBurnResponse = { - PREFIX: 0x19e65bea, + PREFIX: 0x6c060424, create(args: { queryId: uint64 @@ -1759,7 +1759,7 @@ export const TokenPool_LockOrBurnResponse = { } }, fromSlice(s: c.Slice): TokenPool_LockOrBurnResponse { - loadAndCheckPrefix32(s, 0x19e65bea, 'TokenPool_LockOrBurnResponse'); + loadAndCheckPrefix32(s, 0x6c060424, 'TokenPool_LockOrBurnResponse'); return { $: 'TokenPool_LockOrBurnResponse', queryId: s.loadUintBig(64), @@ -1768,7 +1768,7 @@ export const TokenPool_LockOrBurnResponse = { } }, store(self: TokenPool_LockOrBurnResponse, b: c.Builder): void { - b.storeUint(0x19e65bea, 32); + b.storeUint(0x6c060424, 32); b.storeUint(self.queryId, 64); storeCellRef(self.out, b, TokenPool_LockOrBurnOutV1.store); b.storeUint(self.destTokenAmount, 256); @@ -1779,7 +1779,7 @@ export const TokenPool_LockOrBurnResponse = { } /** - > struct (0x7d0ffd89) TokenPool_ReleaseOrMint { + > struct (0x351f77e3) TokenPool_ReleaseOrMint { > queryId: uint64 > request: Cell > requestedFinalityConfig: uint32 @@ -1795,7 +1795,7 @@ export interface TokenPool_ReleaseOrMint { } export const TokenPool_ReleaseOrMint = { - PREFIX: 0x7d0ffd89, + PREFIX: 0x351f77e3, create(args: { queryId: uint64 @@ -1810,7 +1810,7 @@ export const TokenPool_ReleaseOrMint = { } }, fromSlice(s: c.Slice): TokenPool_ReleaseOrMint { - loadAndCheckPrefix32(s, 0x7d0ffd89, 'TokenPool_ReleaseOrMint'); + loadAndCheckPrefix32(s, 0x351f77e3, 'TokenPool_ReleaseOrMint'); return { $: 'TokenPool_ReleaseOrMint', queryId: s.loadUintBig(64), @@ -1820,7 +1820,7 @@ export const TokenPool_ReleaseOrMint = { } }, store(self: TokenPool_ReleaseOrMint, b: c.Builder): void { - b.storeUint(0x7d0ffd89, 32); + b.storeUint(0x351f77e3, 32); b.storeUint(self.queryId, 64); storeCellRef(self.request, b, TokenPool_ReleaseOrMintInV1.store); b.storeUint(self.requestedFinalityConfig, 32); @@ -1832,7 +1832,7 @@ export const TokenPool_ReleaseOrMint = { } /** - > struct (0x7ec43aee) TokenPool_ReleaseOrMintResponse { + > struct (0x78dc2232) TokenPool_ReleaseOrMintResponse { > queryId: uint64 > out: Cell > } @@ -1844,7 +1844,7 @@ export interface TokenPool_ReleaseOrMintResponse { } export const TokenPool_ReleaseOrMintResponse = { - PREFIX: 0x7ec43aee, + PREFIX: 0x78dc2232, create(args: { queryId: uint64 @@ -1856,7 +1856,7 @@ export const TokenPool_ReleaseOrMintResponse = { } }, fromSlice(s: c.Slice): TokenPool_ReleaseOrMintResponse { - loadAndCheckPrefix32(s, 0x7ec43aee, 'TokenPool_ReleaseOrMintResponse'); + loadAndCheckPrefix32(s, 0x78dc2232, 'TokenPool_ReleaseOrMintResponse'); return { $: 'TokenPool_ReleaseOrMintResponse', queryId: s.loadUintBig(64), @@ -1864,7 +1864,7 @@ export const TokenPool_ReleaseOrMintResponse = { } }, store(self: TokenPool_ReleaseOrMintResponse, b: c.Builder): void { - b.storeUint(0x7ec43aee, 32); + b.storeUint(0x78dc2232, 32); b.storeUint(self.queryId, 64); storeCellRef(self.out, b, TokenPool_ReleaseOrMintOutV1.store); }, @@ -1874,7 +1874,7 @@ export const TokenPool_ReleaseOrMintResponse = { } /** - > struct (0x41a1702b) TokenPool_ReleaseOrMintFailure { + > struct (0xef0cb36e) TokenPool_ReleaseOrMintFailure { > queryId: uint64 > errorCode: uint16 > } @@ -1886,7 +1886,7 @@ export interface TokenPool_ReleaseOrMintFailure { } export const TokenPool_ReleaseOrMintFailure = { - PREFIX: 0x41a1702b, + PREFIX: 0xef0cb36e, create(args: { queryId: uint64 @@ -1898,7 +1898,7 @@ export const TokenPool_ReleaseOrMintFailure = { } }, fromSlice(s: c.Slice): TokenPool_ReleaseOrMintFailure { - loadAndCheckPrefix32(s, 0x41a1702b, 'TokenPool_ReleaseOrMintFailure'); + loadAndCheckPrefix32(s, 0xef0cb36e, 'TokenPool_ReleaseOrMintFailure'); return { $: 'TokenPool_ReleaseOrMintFailure', queryId: s.loadUintBig(64), @@ -1906,7 +1906,7 @@ export const TokenPool_ReleaseOrMintFailure = { } }, store(self: TokenPool_ReleaseOrMintFailure, b: c.Builder): void { - b.storeUint(0x41a1702b, 32); + b.storeUint(0xef0cb36e, 32); b.storeUint(self.queryId, 64); b.storeUint(self.errorCode, 16); }, @@ -2659,7 +2659,7 @@ function calculateDeployedAddress(code: c.Cell, data: c.Cell, options: DeployedA } export class LockReleaseTokenPool implements c.Contract { - static CodeCell = c.Cell.fromBase64('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'); + static CodeCell = c.Cell.fromBase64('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'); static Errors = { 'Common_Error.CrossChainAddressOutOfRange': 5, diff --git a/contracts/wrappers/gen/ccip/pools/TokenPool.ts b/contracts/wrappers/gen/ccip/pools/TokenPool.ts index c405df142..2ac4a903b 100644 --- a/contracts/wrappers/gen/ccip/pools/TokenPool.ts +++ b/contracts/wrappers/gen/ccip/pools/TokenPool.ts @@ -726,7 +726,7 @@ export const TokenPool_ReleaseOrMintInV1 = { } /** - > struct (0xdc0b6ff5) TokenPool_ApplyChainUpdates { + > struct (0x56f73d37) TokenPool_ApplyChainUpdates { > queryId: uint64 > remoteChainSelectorsToRemove: SnakedCell > chainsToAdd: SnakedCell @@ -740,7 +740,7 @@ export interface TokenPool_ApplyChainUpdates { } export const TokenPool_ApplyChainUpdates = { - PREFIX: 0xdc0b6ff5, + PREFIX: 0x56f73d37, create(args: { queryId: uint64 @@ -753,7 +753,7 @@ export const TokenPool_ApplyChainUpdates = { } }, fromSlice(s: c.Slice): TokenPool_ApplyChainUpdates { - loadAndCheckPrefix32(s, 0xdc0b6ff5, 'TokenPool_ApplyChainUpdates'); + loadAndCheckPrefix32(s, 0x56f73d37, 'TokenPool_ApplyChainUpdates'); return { $: 'TokenPool_ApplyChainUpdates', queryId: s.loadUintBig(64), @@ -762,7 +762,7 @@ export const TokenPool_ApplyChainUpdates = { } }, store(self: TokenPool_ApplyChainUpdates, b: c.Builder): void { - b.storeUint(0xdc0b6ff5, 32); + b.storeUint(0x56f73d37, 32); b.storeUint(self.queryId, 64); b.storeRef(self.remoteChainSelectorsToRemove); b.storeRef(self.chainsToAdd); @@ -773,7 +773,7 @@ export const TokenPool_ApplyChainUpdates = { } /** - > struct (0x5fd2c8b6) TokenPool_AddRemotePool { + > struct (0x17c242dc) TokenPool_AddRemotePool { > queryId: uint64 > remoteChainSelector: uint64 > remotePoolAddress: Cell @@ -787,7 +787,7 @@ export interface TokenPool_AddRemotePool { } export const TokenPool_AddRemotePool = { - PREFIX: 0x5fd2c8b6, + PREFIX: 0x17c242dc, create(args: { queryId: uint64 @@ -800,7 +800,7 @@ export const TokenPool_AddRemotePool = { } }, fromSlice(s: c.Slice): TokenPool_AddRemotePool { - loadAndCheckPrefix32(s, 0x5fd2c8b6, 'TokenPool_AddRemotePool'); + loadAndCheckPrefix32(s, 0x17c242dc, 'TokenPool_AddRemotePool'); return { $: 'TokenPool_AddRemotePool', queryId: s.loadUintBig(64), @@ -809,7 +809,7 @@ export const TokenPool_AddRemotePool = { } }, store(self: TokenPool_AddRemotePool, b: c.Builder): void { - b.storeUint(0x5fd2c8b6, 32); + b.storeUint(0x17c242dc, 32); b.storeUint(self.queryId, 64); b.storeUint(self.remoteChainSelector, 64); storeCellRef(self.remotePoolAddress, b, CrossChainAddress.store); @@ -820,7 +820,7 @@ export const TokenPool_AddRemotePool = { } /** - > struct (0xdbf0a2df) TokenPool_RemoveRemotePool { + > struct (0x426b8cc4) TokenPool_RemoveRemotePool { > queryId: uint64 > remoteChainSelector: uint64 > remotePoolAddress: Cell @@ -834,7 +834,7 @@ export interface TokenPool_RemoveRemotePool { } export const TokenPool_RemoveRemotePool = { - PREFIX: 0xdbf0a2df, + PREFIX: 0x426b8cc4, create(args: { queryId: uint64 @@ -847,7 +847,7 @@ export const TokenPool_RemoveRemotePool = { } }, fromSlice(s: c.Slice): TokenPool_RemoveRemotePool { - loadAndCheckPrefix32(s, 0xdbf0a2df, 'TokenPool_RemoveRemotePool'); + loadAndCheckPrefix32(s, 0x426b8cc4, 'TokenPool_RemoveRemotePool'); return { $: 'TokenPool_RemoveRemotePool', queryId: s.loadUintBig(64), @@ -856,7 +856,7 @@ export const TokenPool_RemoveRemotePool = { } }, store(self: TokenPool_RemoveRemotePool, b: c.Builder): void { - b.storeUint(0xdbf0a2df, 32); + b.storeUint(0x426b8cc4, 32); b.storeUint(self.queryId, 64); b.storeUint(self.remoteChainSelector, 64); storeCellRef(self.remotePoolAddress, b, CrossChainAddress.store); @@ -867,7 +867,7 @@ export const TokenPool_RemoveRemotePool = { } /** - > struct (0x4eea060b) TokenPool_SetDynamicConfig { + > struct (0xd7712810) TokenPool_SetDynamicConfig { > queryId: uint64 > router: address > rateLimitAdmin: address? @@ -883,7 +883,7 @@ export interface TokenPool_SetDynamicConfig { } export const TokenPool_SetDynamicConfig = { - PREFIX: 0x4eea060b, + PREFIX: 0xd7712810, create(args: { queryId: uint64 @@ -899,7 +899,7 @@ export const TokenPool_SetDynamicConfig = { } }, fromSlice(s: c.Slice): TokenPool_SetDynamicConfig { - loadAndCheckPrefix32(s, 0x4eea060b, 'TokenPool_SetDynamicConfig'); + loadAndCheckPrefix32(s, 0xd7712810, 'TokenPool_SetDynamicConfig'); return { $: 'TokenPool_SetDynamicConfig', queryId: s.loadUintBig(64), @@ -909,7 +909,7 @@ export const TokenPool_SetDynamicConfig = { } }, store(self: TokenPool_SetDynamicConfig, b: c.Builder): void { - b.storeUint(0x4eea060b, 32); + b.storeUint(0xd7712810, 32); b.storeUint(self.queryId, 64); b.storeAddress(self.router); b.storeAddress(self.rateLimitAdmin); @@ -921,7 +921,7 @@ export const TokenPool_SetDynamicConfig = { } /** - > struct (0x29b46fc6) TokenPool_SetAllowedFinalityConfig { + > struct (0x3c50a39b) TokenPool_SetAllowedFinalityConfig { > queryId: uint64 > allowedFinalityConfig: uint32 > } @@ -933,7 +933,7 @@ export interface TokenPool_SetAllowedFinalityConfig { } export const TokenPool_SetAllowedFinalityConfig = { - PREFIX: 0x29b46fc6, + PREFIX: 0x3c50a39b, create(args: { queryId: uint64 @@ -945,7 +945,7 @@ export const TokenPool_SetAllowedFinalityConfig = { } }, fromSlice(s: c.Slice): TokenPool_SetAllowedFinalityConfig { - loadAndCheckPrefix32(s, 0x29b46fc6, 'TokenPool_SetAllowedFinalityConfig'); + loadAndCheckPrefix32(s, 0x3c50a39b, 'TokenPool_SetAllowedFinalityConfig'); return { $: 'TokenPool_SetAllowedFinalityConfig', queryId: s.loadUintBig(64), @@ -953,7 +953,7 @@ export const TokenPool_SetAllowedFinalityConfig = { } }, store(self: TokenPool_SetAllowedFinalityConfig, b: c.Builder): void { - b.storeUint(0x29b46fc6, 32); + b.storeUint(0x3c50a39b, 32); b.storeUint(self.queryId, 64); b.storeUint(self.allowedFinalityConfig, 32); }, @@ -963,7 +963,7 @@ export const TokenPool_SetAllowedFinalityConfig = { } /** - > struct (0x3a028da2) TokenPool_SetRateLimitConfig { + > struct (0x4fe2d26c) TokenPool_SetRateLimitConfig { > queryId: uint64 > updates: SnakedCell > } @@ -975,7 +975,7 @@ export interface TokenPool_SetRateLimitConfig { } export const TokenPool_SetRateLimitConfig = { - PREFIX: 0x3a028da2, + PREFIX: 0x4fe2d26c, create(args: { queryId: uint64 @@ -987,7 +987,7 @@ export const TokenPool_SetRateLimitConfig = { } }, fromSlice(s: c.Slice): TokenPool_SetRateLimitConfig { - loadAndCheckPrefix32(s, 0x3a028da2, 'TokenPool_SetRateLimitConfig'); + loadAndCheckPrefix32(s, 0x4fe2d26c, 'TokenPool_SetRateLimitConfig'); return { $: 'TokenPool_SetRateLimitConfig', queryId: s.loadUintBig(64), @@ -995,7 +995,7 @@ export const TokenPool_SetRateLimitConfig = { } }, store(self: TokenPool_SetRateLimitConfig, b: c.Builder): void { - b.storeUint(0x3a028da2, 32); + b.storeUint(0x4fe2d26c, 32); b.storeUint(self.queryId, 64); b.storeRef(self.updates); }, @@ -1005,7 +1005,7 @@ export const TokenPool_SetRateLimitConfig = { } /** - > struct (0x10c4b4a1) TokenPool_ApplyTokenTransferFeeConfigUpdates { + > struct (0x30a1d1f7) TokenPool_ApplyTokenTransferFeeConfigUpdates { > queryId: uint64 > updates: SnakedCell > disableChainSelectors: SnakedCell @@ -1019,7 +1019,7 @@ export interface TokenPool_ApplyTokenTransferFeeConfigUpdates { } export const TokenPool_ApplyTokenTransferFeeConfigUpdates = { - PREFIX: 0x10c4b4a1, + PREFIX: 0x30a1d1f7, create(args: { queryId: uint64 @@ -1032,7 +1032,7 @@ export const TokenPool_ApplyTokenTransferFeeConfigUpdates = { } }, fromSlice(s: c.Slice): TokenPool_ApplyTokenTransferFeeConfigUpdates { - loadAndCheckPrefix32(s, 0x10c4b4a1, 'TokenPool_ApplyTokenTransferFeeConfigUpdates'); + loadAndCheckPrefix32(s, 0x30a1d1f7, 'TokenPool_ApplyTokenTransferFeeConfigUpdates'); return { $: 'TokenPool_ApplyTokenTransferFeeConfigUpdates', queryId: s.loadUintBig(64), @@ -1041,7 +1041,7 @@ export const TokenPool_ApplyTokenTransferFeeConfigUpdates = { } }, store(self: TokenPool_ApplyTokenTransferFeeConfigUpdates, b: c.Builder): void { - b.storeUint(0x10c4b4a1, 32); + b.storeUint(0x30a1d1f7, 32); b.storeUint(self.queryId, 64); b.storeRef(self.updates); b.storeRef(self.disableChainSelectors); @@ -1052,7 +1052,7 @@ export const TokenPool_ApplyTokenTransferFeeConfigUpdates = { } /** - > struct (0x7a9c4aa5) TokenPool_UpdateRampAccess { + > struct (0xe30764be) TokenPool_UpdateRampAccess { > queryId: uint64 > updates: SnakedCell > } @@ -1064,7 +1064,7 @@ export interface TokenPool_UpdateRampAccess { } export const TokenPool_UpdateRampAccess = { - PREFIX: 0x7a9c4aa5, + PREFIX: 0xe30764be, create(args: { queryId: uint64 @@ -1076,7 +1076,7 @@ export const TokenPool_UpdateRampAccess = { } }, fromSlice(s: c.Slice): TokenPool_UpdateRampAccess { - loadAndCheckPrefix32(s, 0x7a9c4aa5, 'TokenPool_UpdateRampAccess'); + loadAndCheckPrefix32(s, 0xe30764be, 'TokenPool_UpdateRampAccess'); return { $: 'TokenPool_UpdateRampAccess', queryId: s.loadUintBig(64), @@ -1084,7 +1084,7 @@ export const TokenPool_UpdateRampAccess = { } }, store(self: TokenPool_UpdateRampAccess, b: c.Builder): void { - b.storeUint(0x7a9c4aa5, 32); + b.storeUint(0xe30764be, 32); b.storeUint(self.queryId, 64); b.storeRef(self.updates); }, @@ -1094,7 +1094,7 @@ export const TokenPool_UpdateRampAccess = { } /** - > struct (0x12345678) TokenPool_SetRMNProxy { + > struct (0x9929b642) TokenPool_SetRMNProxy { > queryId: uint64 > rmnProxy: address > } @@ -1106,7 +1106,7 @@ export interface TokenPool_SetRMNProxy { } export const TokenPool_SetRMNProxy = { - PREFIX: 0x12345678, + PREFIX: 0x9929b642, create(args: { queryId: uint64 @@ -1118,7 +1118,7 @@ export const TokenPool_SetRMNProxy = { } }, fromSlice(s: c.Slice): TokenPool_SetRMNProxy { - loadAndCheckPrefix32(s, 0x12345678, 'TokenPool_SetRMNProxy'); + loadAndCheckPrefix32(s, 0x9929b642, 'TokenPool_SetRMNProxy'); return { $: 'TokenPool_SetRMNProxy', queryId: s.loadUintBig(64), @@ -1126,7 +1126,7 @@ export const TokenPool_SetRMNProxy = { } }, store(self: TokenPool_SetRMNProxy, b: c.Builder): void { - b.storeUint(0x12345678, 32); + b.storeUint(0x9929b642, 32); b.storeUint(self.queryId, 64); b.storeAddress(self.rmnProxy); }, @@ -1136,7 +1136,7 @@ export const TokenPool_SetRMNProxy = { } /** - > struct (0x823dadf2) TokenPool_UpdateCursedSubjects { + > struct (0x2c906eb7) TokenPool_UpdateCursedSubjects { > queryId: uint64 > cursedSubjects: CursedSubjects > } @@ -1148,7 +1148,7 @@ export interface TokenPool_UpdateCursedSubjects { } export const TokenPool_UpdateCursedSubjects = { - PREFIX: 0x823dadf2, + PREFIX: 0x2c906eb7, create(args: { queryId: uint64 @@ -1160,7 +1160,7 @@ export const TokenPool_UpdateCursedSubjects = { } }, fromSlice(s: c.Slice): TokenPool_UpdateCursedSubjects { - loadAndCheckPrefix32(s, 0x823dadf2, 'TokenPool_UpdateCursedSubjects'); + loadAndCheckPrefix32(s, 0x2c906eb7, 'TokenPool_UpdateCursedSubjects'); return { $: 'TokenPool_UpdateCursedSubjects', queryId: s.loadUintBig(64), @@ -1168,7 +1168,7 @@ export const TokenPool_UpdateCursedSubjects = { } }, store(self: TokenPool_UpdateCursedSubjects, b: c.Builder): void { - b.storeUint(0x823dadf2, 32); + b.storeUint(0x2c906eb7, 32); b.storeUint(self.queryId, 64); CursedSubjects.store(self.cursedSubjects, b); }, @@ -1178,7 +1178,7 @@ export const TokenPool_UpdateCursedSubjects = { } /** - > struct (0x7d0ffd89) TokenPool_ReleaseOrMint { + > struct (0x351f77e3) TokenPool_ReleaseOrMint { > queryId: uint64 > request: Cell > requestedFinalityConfig: uint32 @@ -1194,7 +1194,7 @@ export interface TokenPool_ReleaseOrMint { } export const TokenPool_ReleaseOrMint = { - PREFIX: 0x7d0ffd89, + PREFIX: 0x351f77e3, create(args: { queryId: uint64 @@ -1209,7 +1209,7 @@ export const TokenPool_ReleaseOrMint = { } }, fromSlice(s: c.Slice): TokenPool_ReleaseOrMint { - loadAndCheckPrefix32(s, 0x7d0ffd89, 'TokenPool_ReleaseOrMint'); + loadAndCheckPrefix32(s, 0x351f77e3, 'TokenPool_ReleaseOrMint'); return { $: 'TokenPool_ReleaseOrMint', queryId: s.loadUintBig(64), @@ -1219,7 +1219,7 @@ export const TokenPool_ReleaseOrMint = { } }, store(self: TokenPool_ReleaseOrMint, b: c.Builder): void { - b.storeUint(0x7d0ffd89, 32); + b.storeUint(0x351f77e3, 32); b.storeUint(self.queryId, 64); storeCellRef(self.request, b, TokenPool_ReleaseOrMintInV1.store); b.storeUint(self.requestedFinalityConfig, 32); From 44767d21d41311f9704976c92b91baae6e3e6abd Mon Sep 17 00:00:00 2001 From: Kristijan Date: Thu, 11 Jun 2026 14:21:27 +0200 Subject: [PATCH 12/16] Use wrappers/gen/ccip/pools/BurnMintTokenPool.ts --- .../contracts/ccip/pools/token_pool.tolk | 94 ++--- .../ccip/pools/token_pool_contract.tolk | 6 + .../ccip/pools/BurnMintTokenPool.spec.ts | 332 ++++++++++++------ .../tests/ccip/pools/TokenPool.behavior.ts | 19 +- .../tests/ccip/router/Router.getFee.spec.ts | 1 - contracts/wrappers/ccip/BurnMintTokenPool.ts | 177 ---------- .../gen/ccip/pools/BurnMintTokenPool.ts | 2 +- .../gen/ccip/pools/LockReleaseTokenPool.ts | 2 +- .../wrappers/gen/ccip/pools/TokenPool.ts | 272 ++++++++++++++ 9 files changed, 544 insertions(+), 361 deletions(-) delete mode 100644 contracts/wrappers/ccip/BurnMintTokenPool.ts diff --git a/contracts/contracts/ccip/pools/token_pool.tolk b/contracts/contracts/ccip/pools/token_pool.tolk index 0ceee4b92..f2e415ade 100644 --- a/contracts/contracts/ccip/pools/token_pool.tolk +++ b/contracts/contracts/ccip/pools/token_pool.tolk @@ -277,45 +277,33 @@ fun TokenPool.removeRemotePool( fun TokenPool.applyChainUpdates( mutate self, sender: address, - remoteChainSelectorsToRemove: cell, - chainsToAdd: cell, + remoteChainSelectorsToRemove: SnakedCell, + chainsToAdd: SnakedCell, ) { self.data.adminConfig.load().ownable.load().requireOwner(sender); - var removeSlice = remoteChainSelectorsToRemove.beginParse(); - var removeDone = false; - while (!removeDone) { - while (removeSlice.remainingBitsCount() > 0) { - val remoteChainSelector = removeSlice.loadUint(64); - val deleted = self.data.remoteChainConfigs.delete(remoteChainSelector); - assert(deleted, TokenPool_Error.NonExistentChain); + var rmIter = remoteChainSelectorsToRemove.iter(); + while (!rmIter.empty()) { + val remoteChainSelector = rmIter.next(); + val deleted = self.data.remoteChainConfigs.delete(remoteChainSelector); + assert(deleted, TokenPool_Error.NonExistentChain); - emit(TOKEN_POOL_CHAIN_REMOVED_TOPIC, TokenPool_ChainRemoved { - remoteChainSelector, - }); - } - - if (removeSlice.remainingRefsCount() == 0) { - removeDone = true; - } else { - removeSlice = removeSlice.loadRef().beginParse(); - } + emit(TOKEN_POOL_CHAIN_REMOVED_TOPIC, TokenPool_ChainRemoved { + remoteChainSelector, + }); } - var addSlice = chainsToAdd.beginParse(); - var addDone = false; - while (!addDone) { - while (addSlice.remainingBitsCount() > 0) { - val remoteChainSelector = addSlice.loadUint(64); - val remotePoolAddresses = addSlice.loadRef(); - val remoteTokenAddress = addSlice.loadRef() as Cell; - var rateLimitConfigs = addSlice.loadRef().beginParse(); - val outboundRateLimiterConfig = RateLimiter_rateLimitConfigFromCell(rateLimitConfigs.loadRef()); - val inboundRateLimiterConfig = RateLimiter_rateLimitConfigFromCell(rateLimitConfigs.loadRef()); - rateLimitConfigs.assertEnd(); - - assert(!TokenPool_isEmptyCrossChainAddress(remoteTokenAddress), TokenPool_Error.ZeroAddressInvalid); - assert(!self.data.remoteChainConfigs.get(remoteChainSelector).isFound, TokenPool_Error.ChainAlreadyExists); + var addIter = chainsToAdd.iter(); + while (!addIter.empty()) { + val chainUpdate = addIter.next(); + val remoteChainSelector = chainUpdate.remoteChainSelector; + val remoteTokenAddress = chainUpdate.remoteTokenAddress; + var rateLimitConfigs = chainUpdate.rateLimitConfigs.load(); + val outboundRateLimiterConfig = rateLimitConfigs.outbound.load(); + val inboundRateLimiterConfig = rateLimitConfigs.inbound.load(); + + assert(!TokenPool_isEmptyCrossChainAddress(remoteTokenAddress), TokenPool_Error.ZeroAddressInvalid); + assert(!self.data.remoteChainConfigs.get(remoteChainSelector).isFound, TokenPool_Error.ChainAlreadyExists); var remotePools: map> = createEmptyMap(); var config = TokenPool_RemoteChainConfig { @@ -339,39 +327,23 @@ fun TokenPool.applyChainUpdates( }.toCell(), }; - var remotePoolsSlice = remotePoolAddresses.beginParse(); - var remotePoolsDone = false; - while (!remotePoolsDone) { - while (remotePoolsSlice.remainingBitsCount() > 0) { - val remotePoolAddress = TokenPool_boxCrossChainAddress(CrossChainAddress.unpackFromSlice(mutate remotePoolsSlice)); - self._setRemotePool(mutate config, remotePoolAddress); - - emit(TOKEN_POOL_REMOTE_POOL_ADDED_TOPIC, TokenPool_RemotePoolAdded { - remoteChainSelector, - remotePoolAddress, - }); - } - - if (remotePoolsSlice.remainingRefsCount() == 0) { - remotePoolsDone = true; - } else { - remotePoolsSlice = remotePoolsSlice.loadRef().beginParse(); - } - } + var remotePoolAddressesIter = chainUpdate.remotePoolAddresses.iter(); + while (!remotePoolAddressesIter.empty()) { + val remotePoolAddress = remotePoolAddressesIter.next().toCell(); + self._setRemotePool(mutate config, remotePoolAddress); - emit(TOKEN_POOL_CHAIN_ADDED_TOPIC, TokenPool_ChainAdded { + emit(TOKEN_POOL_REMOTE_POOL_ADDED_TOPIC, TokenPool_RemotePoolAdded { remoteChainSelector, - remoteTokenAddress, + remotePoolAddress, }); - - self.data.remoteChainConfigs.set(remoteChainSelector, config); } - if (addSlice.remainingRefsCount() == 0) { - addDone = true; - } else { - addSlice = addSlice.loadRef().beginParse(); - } + emit(TOKEN_POOL_CHAIN_ADDED_TOPIC, TokenPool_ChainAdded { + remoteChainSelector, + remoteTokenAddress, + }); + + self.data.remoteChainConfigs.set(remoteChainSelector, config); } } diff --git a/contracts/contracts/ccip/pools/token_pool_contract.tolk b/contracts/contracts/ccip/pools/token_pool_contract.tolk index 850bcc163..43246aa77 100644 --- a/contracts/contracts/ccip/pools/token_pool_contract.tolk +++ b/contracts/contracts/ccip/pools/token_pool_contract.tolk @@ -14,6 +14,12 @@ contract TokenPool { storage: TokenPool_Data incomingMessages: TokenPool_InMessage // TODO: all incoming messages should be registered + + // TODO: should be used in hooks of the core library, + // but for now we need to register them here. + forceAbiExport: TokenPool_LockOrBurn + | TokenPool_LockOrBurnResponse + | TokenPool_ReleaseOrMintResponse } fun onInternalMessage(in: InMessage) { diff --git a/contracts/tests/ccip/pools/BurnMintTokenPool.spec.ts b/contracts/tests/ccip/pools/BurnMintTokenPool.spec.ts index 5d90016be..4767035f4 100644 --- a/contracts/tests/ccip/pools/BurnMintTokenPool.spec.ts +++ b/contracts/tests/ccip/pools/BurnMintTokenPool.spec.ts @@ -1,17 +1,39 @@ import '@ton/test-utils' import { Blockchain, SandboxContract, TreasuryContract } from '@ton/sandbox' -import { Address, Cell, toNano } from '@ton/core' +import { Address, beginCell, Cell, Dictionary, toNano } from '@ton/core' +import { asSnakedCell, asSnakedCellEmpty } from '../../../src/utils' import { JettonMinter, JettonWallet } from '../../../wrappers/examples/jetton' -import { - BurnMintTokenPool, - codec as poolCodec, - opcodes as poolOpcodes, -} from '../../../wrappers/ccip/BurnMintTokenPool' import { CCTJettonMinter } from '../../../wrappers/ccip/CCTJettonMinter' import { CCTJettonMinterCode, CCTJettonWalletCode } from '../../../wrappers/ccip/CCTJettonCode' -import { runTokenPoolBehaviorTests } from './TokenPool.behavior' -import { TokenPool } from '../../../wrappers/gen/ccip/pools/TokenPool' import { setupGenBindings } from '../../../wrappers/gen' +import { + Ownable2Step, + CrossChainAddress, + CursedSubjects, + RateLimiter_Config, + TokenPool, + TokenPool_Data, + TokenPool_AdminConfig, + TokenPool_RampUpdate, + TokenPool_RateLimitConfigPair, + TokenPool_ChainUpdate, + TokenPool_LockOrBurn, + TokenPool_LockOrBurnInV1, + TokenPool_LockOrBurnResponse, + TokenPool_ReleaseOrMintInV1, + TokenPool_ReleaseOrMintResponse, + TokenPool_MirroredPolicy, + TokenPool_DynamicConfig, +} from '../../../wrappers/gen/ccip/pools/TokenPool' +import { BurnMintTokenPool, JettonClient } from '../../../wrappers/gen/ccip/pools/BurnMintTokenPool' +import { runTokenPoolBehaviorTests } from './TokenPool.behavior' + +import * as rtOld from '../../../wrappers/ccip/Router' + +function crossChainAddressFromBuffer(buffer: Buffer): CrossChainAddress { + const addrSlice = rtOld.builder.data.crossChainAddress.encode(buffer).asSlice() + return CrossChainAddress.fromSlice(addrSlice) +} describe('BurnMintTokenPool', () => { let blockchain: Blockchain @@ -29,12 +51,16 @@ describe('BurnMintTokenPool', () => { let userWallet: (address: Address) => Promise> const remoteChainSelector = 91000001n - const sourcePoolAddress = poolCodec.crossChainAddressFromBuffer(Buffer.from('source-pool')) - const destTokenAddress = poolCodec.crossChainAddressFromBuffer(Buffer.from('dest-token')) - const receiverAddress = poolCodec.crossChainAddressFromBuffer(Buffer.from('receiver')) + let sourcePoolAddress: CrossChainAddress + let destTokenAddress: CrossChainAddress + let receiverAddress: CrossChainAddress beforeAll(async () => { setupGenBindings() + + sourcePoolAddress = crossChainAddressFromBuffer(Buffer.from('source-pool')) + destTokenAddress = crossChainAddressFromBuffer(Buffer.from('dest-token')) + receiverAddress = crossChainAddressFromBuffer(Buffer.from('receiver')) }) beforeEach(async () => { @@ -62,51 +88,117 @@ describe('BurnMintTokenPool', () => { await cctMinter.sendDeploy(deployer.getSender(), toNano('1')) cctMinterRuntime = blockchain.openContract(JettonMinter.createFromAddress(cctMinter.address)) - const poolCode = await BurnMintTokenPool.code() burnMintPool = blockchain.openContract( - BurnMintTokenPool.createFromConfig( - { - owner: deployer.address, - token: cctMinter.address, - tokenDecimals: 9, - rmnProxy: deployer.address, - router: deployer.address, - jettonClient: { + BurnMintTokenPool.fromStorage({ + poolData: { + ref: TokenPool_Data.create({ + adminConfig: { + ref: TokenPool_AdminConfig.create({ + ownable: { + ref: Ownable2Step.create({ owner: deployer.address, pendingOwner: null }), + }, + rmnProxy: deployer.address, + dynamicConfig: { + ref: TokenPool_DynamicConfig.create({ + router: deployer.address, + rateLimitAdmin: null, + feeAdmin: null, + }), + }, + allowedFinalityConfig: 0n, + }), + }, + mirroredPolicy: { + ref: TokenPool_MirroredPolicy.create({ + onRamps: Dictionary.empty(Dictionary.Keys.BigInt(64)), + offRamps: Dictionary.empty(Dictionary.Keys.BigInt(64)), + cursedSubjects: CursedSubjects.create({ + data: Dictionary.empty(Dictionary.Keys.BigInt(128)), + }), + }), + }, + token: cctMinter.address, + tokenDecimals: 9n, + remoteChainConfigs: Dictionary.empty(Dictionary.Keys.BigInt(64)), + tokenTransferFeeConfigs: Dictionary.empty(Dictionary.Keys.BigInt(64)), + }), + }, + jettonClient: { + ref: JettonClient.create({ masterAddress: cctMinter.address, jettonWalletCode: cctWalletCode, - }, + }), }, - poolCode, - ), + pendingMints: Dictionary.empty(Dictionary.Keys.BigInt(64)), + pendingBurns: Dictionary.empty(Dictionary.Keys.BigInt(64)), + }), ) await burnMintPool.sendDeploy(deployer.getSender(), toNano('2')) // Standard TokenPool interface pool = blockchain.openContract(TokenPool.fromAddress(burnMintPool.address)) - await burnMintPool.sendApplyChainUpdates(deployer.getSender(), toNano('0.2'), { - queryId: 1n, - remove: [], - add: [ + { + const r = await burnMintPool.sendTokenPoolApplyChainUpdates( + deployer.getSender(), + toNano('0.2'), { - remoteChainSelector, - remotePoolAddresses: [sourcePoolAddress], - remoteTokenAddress: destTokenAddress, - outboundRateLimiterConfig: { isEnabled: true, capacity: toNano('100'), rate: 1n }, - inboundRateLimiterConfig: { isEnabled: true, capacity: toNano('100'), rate: 1n }, + queryId: 1n, + remoteChainSelectorsToRemove: asSnakedCellEmpty(), + chainsToAdd: asSnakedCell( + [ + TokenPool_ChainUpdate.create({ + remoteChainSelector, + remotePoolAddresses: asSnakedCell([sourcePoolAddress], (item) => { + let b = beginCell() + CrossChainAddress.store(item, b) + return b + }), + remoteTokenAddress: { ref: destTokenAddress }, + rateLimitConfigs: { + ref: TokenPool_RateLimitConfigPair.create({ + outbound: { + ref: RateLimiter_Config.create({ + isEnabled: true, + capacity: toNano('100'), + rate: 1n, + }), + }, + inbound: { + ref: RateLimiter_Config.create({ + isEnabled: true, + capacity: toNano('100'), + rate: 1n, + }), + }, + }), + }, + }), + ], + (item) => TokenPool_ChainUpdate.toCell(item).asBuilder(), + ), }, - ], - }) + ) + + expect(r.transactions).toHaveTransaction({ + from: deployer.address, + to: burnMintPool.address, + success: true, + }) + } - await burnMintPool.sendUpdateRampAccess(deployer.getSender(), toNano('0.2'), { + await burnMintPool.sendTokenPoolUpdateRampAccess(deployer.getSender(), toNano('0.2'), { queryId: 2n, - updates: [ - { - remoteChainSelector, - onRamp: deployer.address, - offRamp: offRamp.address, - }, - ], + updates: asSnakedCell( + [ + TokenPool_RampUpdate.create({ + remoteChainSelector, + onRamp: deployer.address, + offRamp: offRamp.address, + }), + ], + (item) => TokenPool_RampUpdate.toCell(item).asBuilder(), + ), }) // Mint user-side test balance before handing minter admin to the pool. @@ -157,10 +249,10 @@ describe('BurnMintTokenPool', () => { success: true, }) - const claimAdminResult = await burnMintPool.sendClaimMinterAdmin( + const claimAdminResult = await burnMintPool.sendBurnMintTokenPoolClaimMinterAdmin( deployer.getSender(), toNano('0.2'), - 202n, + { queryId: 202n }, ) expect(claimAdminResult.transactions).toHaveTransaction({ from: burnMintPool.address, @@ -188,9 +280,7 @@ describe('BurnMintTokenPool', () => { recipient, remoteChainSelector, unsupportedChainSelector: remoteChainSelector + 1n, - unknownSourcePoolAddress: poolCodec.crossChainAddressFromBuffer( - Buffer.from('unknown-source-pool'), - ), + unknownSourcePoolAddress: crossChainAddressFromBuffer(Buffer.from('unknown-source-pool')), remoteTokenAddress: destTokenAddress, onRampAddress: deployer.address, destTokenAddress, @@ -204,10 +294,10 @@ describe('BurnMintTokenPool', () => { }) it('rejects claim-minter-admin from non-owner sender', async () => { - const result = await burnMintPool.sendClaimMinterAdmin( + const result = await burnMintPool.sendBurnMintTokenPoolClaimMinterAdmin( unauthorized.getSender(), toNano('0.2'), - 302n, + { queryId: 302n }, ) expect(result.transactions).toHaveTransaction({ @@ -229,21 +319,23 @@ describe('BurnMintTokenPool', () => { responseDestination: unauthorized.address, customPayload: null, forwardTonAmount: toNano('0.2'), - forwardPayload: poolCodec.lockOrBurnPayload - .encode({ + forwardPayload: TokenPool_LockOrBurn.toCell( + TokenPool_LockOrBurn.create({ queryId: 303n, request: { - receiver: receiverAddress, - remoteChainSelector, - originalSender: unauthorized.address, - amount: toNano('1'), - localToken: cctMinter.address, + ref: TokenPool_LockOrBurnInV1.create({ + receiver: { ref: receiverAddress }, + remoteChainSelector, + originalSender: unauthorized.address, + amount: toNano('1'), + localToken: cctMinter.address, + }), }, - requestedFinalityConfig: 0, + requestedFinalityConfig: 0n, tokenArgs: null, replyTo: unauthorized.address, - }) - .endCell(), + }), + ), }, }) @@ -266,21 +358,23 @@ describe('BurnMintTokenPool', () => { responseDestination: deployer.address, customPayload: null, forwardTonAmount: toNano('0.2'), - forwardPayload: poolCodec.lockOrBurnPayload - .encode({ + forwardPayload: TokenPool_LockOrBurn.toCell( + TokenPool_LockOrBurn.create({ queryId: 304n, request: { - receiver: receiverAddress, - remoteChainSelector, - originalSender: deployer.address, - amount: toNano('1'), - localToken: cctMinter.address, + ref: TokenPool_LockOrBurnInV1.create({ + receiver: { ref: receiverAddress }, + remoteChainSelector, + originalSender: deployer.address, + amount: toNano('1'), + localToken: cctMinter.address, + }), }, - requestedFinalityConfig: 0, + requestedFinalityConfig: 0n, tokenArgs: null, replyTo: deployer.address, - }) - .endCell(), + }), + ), }, }) @@ -304,21 +398,23 @@ describe('BurnMintTokenPool', () => { responseDestination: deployer.address, customPayload: null, forwardTonAmount: toNano('0.2'), - forwardPayload: poolCodec.lockOrBurnPayload - .encode({ + forwardPayload: TokenPool_LockOrBurn.toCell( + TokenPool_LockOrBurn.create({ queryId: 11n, request: { - receiver: receiverAddress, - remoteChainSelector, - originalSender: deployer.address, - amount: toNano('3'), - localToken: cctMinter.address, + ref: TokenPool_LockOrBurnInV1.create({ + receiver: { ref: receiverAddress }, + remoteChainSelector, + originalSender: deployer.address, + amount: toNano('3'), + localToken: cctMinter.address, + }), }, - requestedFinalityConfig: 0, + requestedFinalityConfig: 0n, tokenArgs: null, replyTo: deployer.address, - }) - .endCell(), + }), + ), }, }) @@ -335,26 +431,32 @@ describe('BurnMintTokenPool', () => { from: burnMintPool.address, to: deployer.address, success: true, - op: poolOpcodes.out.lockOrBurnResponse, + op: TokenPool_LockOrBurnResponse.PREFIX, }) }) it('mints tokens on releaseOrMint path and clears pending mint on confirmation', async () => { - const result = await burnMintPool.sendReleaseOrMint(offRamp.getSender(), toNano('0.6'), { - queryId: 22n, - request: { - originalSender: sourcePoolAddress, - remoteChainSelector, - receiver: recipient.address, - sourceDenominatedAmount: toNano('2'), - localToken: cctMinter.address, - sourcePoolAddress, - sourcePoolData: null, - offchainTokenData: null, + const result = await burnMintPool.sendTokenPoolReleaseOrMint( + offRamp.getSender(), + toNano('0.6'), + { + queryId: 22n, + request: { + ref: TokenPool_ReleaseOrMintInV1.create({ + originalSender: { ref: sourcePoolAddress }, + remoteChainSelector, + receiver: recipient.address, + sourceDenominatedAmount: toNano('2'), + localToken: cctMinter.address, + sourcePoolAddress: { ref: sourcePoolAddress }, + sourcePoolData: null, + offchainTokenData: null, + }), + }, + requestedFinalityConfig: 0n, + replyTo: deployer.address, }, - requestedFinalityConfig: 0, - replyTo: deployer.address, - }) + ) expect(result.transactions).toHaveTransaction({ from: offRamp.address, @@ -374,31 +476,37 @@ describe('BurnMintTokenPool', () => { from: burnMintPool.address, to: deployer.address, success: true, - op: poolOpcodes.out.releaseOrMintResponse, + op: TokenPool_ReleaseOrMintResponse.PREFIX, body(body) { if (!body) return false - const response = poolCodec.releaseOrMintResponse.load(body.beginParse()) - return response.queryId === 22n && response.destinationAmount === toNano('2') + const response = TokenPool_ReleaseOrMintResponse.fromSlice(body.beginParse()) + return response.queryId === 22n && response.out.ref.destinationAmount === toNano('2') }, }) }) it('mints on releaseOrMint with null replyTo without emitting response message', async () => { - const result = await burnMintPool.sendReleaseOrMint(offRamp.getSender(), toNano('0.6'), { - queryId: 305n, - request: { - originalSender: sourcePoolAddress, - remoteChainSelector, - receiver: recipient.address, - sourceDenominatedAmount: toNano('1'), - localToken: cctMinter.address, - sourcePoolAddress, - sourcePoolData: null, - offchainTokenData: null, + const result = await burnMintPool.sendTokenPoolReleaseOrMint( + offRamp.getSender(), + toNano('0.6'), + { + queryId: 305n, + request: { + ref: TokenPool_ReleaseOrMintInV1.create({ + originalSender: { ref: sourcePoolAddress }, + remoteChainSelector, + receiver: recipient.address, + sourceDenominatedAmount: toNano('1'), + localToken: cctMinter.address, + sourcePoolAddress: { ref: sourcePoolAddress }, + sourcePoolData: null, + offchainTokenData: null, + }), + }, + requestedFinalityConfig: 0n, + replyTo: null, }, - requestedFinalityConfig: 0, - replyTo: null, - }) + ) expect(result.transactions).toHaveTransaction({ from: offRamp.address, @@ -415,7 +523,7 @@ describe('BurnMintTokenPool', () => { return ( tx.inMessage?.info?.src?.equals?.(burnMintPool.address) && tx.inMessage?.body?.beginParse?.().preloadUint?.(32) === - poolOpcodes.out.releaseOrMintResponse + TokenPool_ReleaseOrMintResponse.PREFIX ) }) expect(releaseResponses.length).toBe(0) diff --git a/contracts/tests/ccip/pools/TokenPool.behavior.ts b/contracts/tests/ccip/pools/TokenPool.behavior.ts index 789e7ccab..bc53fcf4b 100644 --- a/contracts/tests/ccip/pools/TokenPool.behavior.ts +++ b/contracts/tests/ccip/pools/TokenPool.behavior.ts @@ -2,6 +2,7 @@ import '@ton/test-utils' import { SandboxContract, TreasuryContract } from '@ton/sandbox' import { Address, beginCell, Cell, Dictionary, DictionaryValue, Sender, toNano } from '@ton/core' import { + CrossChainAddress, CursedSubjects, TokenPool, TokenPool_ChainUpdate, @@ -21,8 +22,8 @@ export type TokenPoolBehaviorContext = { recipient: SandboxContract onRampAddress: Address remoteChainSelector: bigint - destTokenAddress: Cell - sourcePoolAddress: Cell + destTokenAddress: CrossChainAddress + sourcePoolAddress: CrossChainAddress localToken: Address } @@ -31,12 +32,12 @@ function releaseRequest( overrides: Partial = {}, ): TokenPool_ReleaseOrMintInV1 { return TokenPool_ReleaseOrMintInV1.create({ - originalSender: { ref: ctx.sourcePoolAddress.beginParse() }, + originalSender: { ref: ctx.sourcePoolAddress }, remoteChainSelector: ctx.remoteChainSelector, receiver: ctx.recipient.address, sourceDenominatedAmount: 1n, localToken: ctx.localToken, - sourcePoolAddress: { ref: ctx.sourcePoolAddress.beginParse() }, + sourcePoolAddress: { ref: ctx.sourcePoolAddress }, sourcePoolData: null, offchainTokenData: null, ...overrides, @@ -479,10 +480,12 @@ export function runTokenPoolBehaviorTests( [ TokenPool_ChainUpdate.create({ remoteChainSelector: ctx.remoteChainSelector, - remotePoolAddresses: asSnakedCell([ctx.sourcePoolAddress.beginParse()], (item) => - item.asBuilder(), - ), - remoteTokenAddress: { ref: ctx.destTokenAddress.beginParse() }, + remotePoolAddresses: asSnakedCell([ctx.sourcePoolAddress], (item) => { + let b = beginCell() + CrossChainAddress.store(item, b) + return b + }), + remoteTokenAddress: { ref: ctx.destTokenAddress }, rateLimitConfigs: { ref: TokenPool_RateLimitConfigPair.create({ outbound: { diff --git a/contracts/tests/ccip/router/Router.getFee.spec.ts b/contracts/tests/ccip/router/Router.getFee.spec.ts index 32d190453..62714f02c 100644 --- a/contracts/tests/ccip/router/Router.getFee.spec.ts +++ b/contracts/tests/ccip/router/Router.getFee.spec.ts @@ -4,7 +4,6 @@ import { Blockchain, SandboxContract, TreasuryContract } from '@ton/sandbox' import { asSnakeDataUint, fromSnakeData, WRAPPED_NATIVE } from '../../../src/utils' import * as coverage from '../../coverage/coverage' -import * as rtOld from '../../../wrappers/ccip/Router' import * as rt from '../../../wrappers/gen/ccip/Router' import * as or from '../../../wrappers/ccip/OnRamp' import { diff --git a/contracts/wrappers/ccip/BurnMintTokenPool.ts b/contracts/wrappers/ccip/BurnMintTokenPool.ts deleted file mode 100644 index 0bcfcf6c7..000000000 --- a/contracts/wrappers/ccip/BurnMintTokenPool.ts +++ /dev/null @@ -1,177 +0,0 @@ -import { - Address, - beginCell, - Cell, - Contract, - contractAddress, - ContractProvider, - Sender, - SendMode, -} from '@ton/core' -import { crc32 } from 'zlib' -import { facilityId, errorCode } from '../utils' -import { contractCode } from '../codeLoader' -import { - codec, - createJettonClientData, - createTokenPoolData, - opcodes, - sendApplyChainUpdates, - sendReleaseOrMint, - sendUpdateCursedSubjects, - sendUpdateRampAccess, - type ChainUpdate, - type JettonClientConfig, - type RampAccess, - type TokenPoolConfig, - type ReleaseOrMintInV1, - type LockOrBurnInV1, - type LockOrBurnPayload, -} from './TokenPool' - -export const FACILITY_NAME = 'link.chain.ton.ccip.BurnMintTokenPool' -export const FACILITY_ID = facilityId(crc32(FACILITY_NAME)) -export const ERROR_CODE = errorCode(crc32(FACILITY_NAME)) -export const CONTRACT_VERSION = '0.1.0' - -export type Config = TokenPoolConfig & { - jettonClient: JettonClientConfig -} - -export class BurnMintTokenPool implements Contract { - constructor( - readonly address: Address, - readonly init?: { code: Cell; data: Cell }, - ) {} - - static createFromAddress(address: Address) { - return new BurnMintTokenPool(address) - } - - static createFromConfig(config: Config, code: Cell, workchain = 0) { - const data = beginCell() - .storeRef(createTokenPoolData(config)) - .storeRef(createJettonClientData(config.jettonClient)) - .storeDict(null) - .storeDict(null) - .endCell() - - const init = { code, data } - return new BurnMintTokenPool(contractAddress(workchain, init), init) - } - - static code(): Promise { - return contractCode.ccip.local('ccip.pools.BurnMintTokenPool') - } - - async sendDeploy(provider: ContractProvider, via: Sender, value: bigint) { - await provider.internal(via, { - value, - sendMode: SendMode.PAY_GAS_SEPARATELY, - body: Cell.EMPTY, - }) - } - - async sendApplyChainUpdates( - provider: ContractProvider, - via: Sender, - value: bigint, - body: { queryId: bigint; remove: bigint[]; add: ChainUpdate[] }, - ) { - await sendApplyChainUpdates(provider, via, value, body) - } - - async sendUpdateRampAccess( - provider: ContractProvider, - via: Sender, - value: bigint, - body: { queryId: bigint; updates: RampAccess[] }, - ) { - await sendUpdateRampAccess(provider, via, value, body) - } - - async sendUpdateCursedSubjects( - provider: ContractProvider, - via: Sender, - value: bigint, - body: { queryId: bigint; cursedSubjects: bigint[] }, - ) { - await sendUpdateCursedSubjects(provider, via, value, body) - } - - async sendReleaseOrMint( - provider: ContractProvider, - via: Sender, - value: bigint, - body: { - queryId: bigint - request: ReleaseOrMintInV1 - requestedFinalityConfig?: number - replyTo?: Address | null - }, - ) { - await sendReleaseOrMint(provider, via, value, body) - } - - async sendClaimMinterAdmin( - provider: ContractProvider, - via: Sender, - value: bigint, - queryId: bigint = 0n, - ) { - await provider.internal(via, { - value, - sendMode: SendMode.PAY_GAS_SEPARATELY, - body: beginCell() - .storeUint(BURN_MINT_CLAIM_MINTER_ADMIN_OPCODE, 32) - .storeUint(queryId, 64) - .endCell(), - }) - } - - async getHasPendingBurn(provider: ContractProvider, queryId: bigint) { - return provider - .get('hasPendingBurn', [{ type: 'int', value: queryId }]) - .then((res) => res.stack.readBoolean()) - } - - async getHasPendingMint(provider: ContractProvider, queryId: bigint) { - return provider - .get('hasPendingMint', [{ type: 'int', value: queryId }]) - .then((res) => res.stack.readBoolean()) - } - - async getVerifyNotCursed(provider: ContractProvider, subject: bigint) { - return provider - .get('verifyNotCursed', [{ type: 'int', value: subject }]) - .then((res) => res.stack.readBoolean()) - } - - async getOnRamp(provider: ContractProvider, remoteChainSelector: bigint) { - return provider - .get('onRamp', [{ type: 'int', value: remoteChainSelector }]) - .then((res) => res.stack.readAddressOpt()) - } - - async getOffRamp(provider: ContractProvider, remoteChainSelector: bigint) { - return provider - .get('offRamp', [{ type: 'int', value: remoteChainSelector }]) - .then((res) => res.stack.readAddressOpt()) - } - - async getIsSupportedChain(provider: ContractProvider, remoteChainSelector: bigint) { - return provider - .get('isSupportedChain', [{ type: 'int', value: remoteChainSelector }]) - .then((res) => res.stack.readBoolean()) - } -} - -export { codec, opcodes } -export type { - ChainUpdate, - JettonClientConfig, - LockOrBurnInV1, - LockOrBurnPayload, - RampAccess, - ReleaseOrMintInV1, -} diff --git a/contracts/wrappers/gen/ccip/pools/BurnMintTokenPool.ts b/contracts/wrappers/gen/ccip/pools/BurnMintTokenPool.ts index 9a0746ed5..bc3f37ae4 100644 --- a/contracts/wrappers/gen/ccip/pools/BurnMintTokenPool.ts +++ b/contracts/wrappers/gen/ccip/pools/BurnMintTokenPool.ts @@ -2908,7 +2908,7 @@ function calculateDeployedAddress(code: c.Cell, data: c.Cell, options: DeployedA } export class BurnMintTokenPool implements c.Contract { - static CodeCell = c.Cell.fromBase64('te6ccgECZwEAFlcAART/APSkE/S88sgLAQIBYgIDAgLMBAUCASAeHwIBIAYHAgEgMjMCASAICQIBIBgZAgEgCgsAV1IW6SW3DggmkAAAAAAAAAAAAAAAAAAAEigwb0Dm+hMZJbf+ABgwb0Dm+hMYBO0+JHyQO1E0NTU9AT0BNEj0NTU+kjTB/QE9ATRgQCFbW1tbW1tbZLwCACBAIZWE1YTVhNWE/iS+JcQXxBOED0QLBBbEEoQORAoEFcQRhA1ECRWGvAKPl8JBOMCXwok1ywhzExybOMC1ywjmxaE5OMC1ywmqZO23IAwNDg8BqTtou371ywnkNvtDI5E1ywnzxTyVJRbcNsx4YIAwoojbrPy9CGCAMKKBMcFE/L0IG0D1ws/iwIByMs/FfpSEvpSycjPhyAUznHPC2ETzMlw+wDjDX+AXAFw9PQHDAJM3NzeZMDk5EFheJBBF4gPIzBLM+lLLBxP0APQAycjMzBL0APQAye1UAMg1BNcLP/iSJNDU1DH6SDHTBzH0BDH0BDHR0NT6SDHUMdMfMdHQ+kj6UDHRAYIAwogCxwXy9IIK+vCAI9D6SNQx0cjPhYj6UgH6AoIQ+4jhGc8Liss/yXH7AALIzMz0APQAye1UAfo1BNM/MfoA+lD4kiXQ+kjU0YIAoPD4KCPIz4QCEvpS+lLJWMjPhNDMzPkWyM+KAEDL/89QI8cF8vQC9AQhbpgxIMcAkjBt4JLR0OKCAKDyIW6z8vTXLCfT7SIk8r/TP9TTH/QE+lDRA9DU0z/6SNP/+kjRIYIAoPMOuh3y9BAATo4bNQTXCz/4khBFEDQQI/AJA8jMEsz0APQAye1U4F8FhA8BxwDy9AH+ggCg8Stus/L0ggCg9FONgED0Dm+hMbPy9C7Q1NT6SNMH9AT0BNGBAIVtbW1tbW1tkvAIAIEAhlYdVh1WIYE6PVYRViDHBfL0gTo5VhZWEIBA9A5voTHy9IE6OlYS0PQEMfQEMfQE0VYX8AOz8vQpbrOcViFUcyFWEFYaL9pg3hEB/lYR0PQE9AQx9AQx0VYWAYBA9A5voZP6SNGSMG3igTo+IW6z8vSBOj4BVh/HBfL0K26zn1YhVGMzU/ARIlYaVhHacJJXHeJWEVYRVhFWEVYRVhFWJlOHViVWFVYVVhVWFVYVVhVWFVYVVhVWFVYpVilWKVYpVjVWMPAPbDMzMzQSAv40NFOyoTNWEI5NgTo4U+eAQPQOb6ES8vTU9ATU1NEB0NTU0QHQ03/TP9IA03/Tf9ErVhLwBATIy38Tyz/KAMt/y3/JyMzMyQPIzBL0ABLMzFQg6IBA9EPjDSZus44aVhlTJFYYKFYTVhNWE1YTVh9WGlYaLlYT2tDeMTU9Wzs/ExQB7irQ1DH6SDHUMdMf0VYRAfAGgTo4U+eAQPQOb6ES8vTU9ATU1NEg0NTU0QHQ03/TP9IA03/Tf9EijixfBgHQ1NTRAdDTf9M/0gDTf9N/0StWEvAEBMjLfxPLP8oAy3/Lf8nIzMzJAeMNA8jMEvQAzMxUIOiAQPRDFQH+VxKBOjhTboBA9A5voRLy9NT0BDHUMdQx0VYSyMv/yQTIzBPM+lIBEREBywcc9AAW9ADJA8jMEss/+lITy/8Y+lLJCsjMFszJAcj6VBnMGMwkzwv/EvpSyVQgZYBA9BeCCvrwgPgobcjPhYgX+lJY+gKCEFlfB7zPC4oXyz9QAxYAMmwWK1YS8AQEyMt/E8s/ygDLf8t/ycjMzMkALvoCFfpUEvQAyXH7AALIzMz0APQAye1UAGZsEtM/+kgwggDCiFE0xwUT8vSCAMKJUyPHBbPy9CGLAsjPhyDOcM8LYRLLPxL6Uslw+wACASAaGwIBIBwdAKsMCOzkX+VIMAAwwDikTDgIvgjJqEgjhg2U2C8lYFmvPLw4FFSqBagUkDwBQX4IwWRMOIhuZWBZr3y8OBTULmOERVfBSCVgWa+8vDhMIFmvvLw4BWhBIAANFy5kTDgMYAApCGRW+GBOkYhlAK6wwCTbCFw4vL0gAE8cXqTIsIAjhwicbDAAZ+BOkKE/yOpBCK+8vRmqAHeIKgCqwAC6DAxgAgEgICECASAuLwIBICIjAgEgLC0CASAkJQBBtbUdqJoamoY+gIY+gIY6OhqGOoY/SQY6YP6Ahj6AhjowAgEgJicCAUgqKwAtrSp2omhqGOoY+gIY+gJowCB6BzfQmMACAUgoKQBvpXXaiaGpqGPoCGPoCGOjoahjqfSQY6YOY+gIY+gIY6Oh6Ahj6AnoCGOjAIHoHN9DJ/SRoyRg28UAP6cj2omhqahj6Ahj6Ahjo6GoY6hj9JGmDmPoCGPoCGOjAGKpX40JWxpbmsuY2hhaW4udG9uLmNjaXAuQnVybk1pbnRUb2tlblBvb2yCLUwLjEuMIACyp3e1E0NQx1DH0BPQEMdGAQPQOb6ExAGW0o72omhqahj6Ahj6Ahjo6GpqGP0kGOmDmPoCGPoCGOjoan0kGOoY6Y+Y6Oh9JH0oGOjAAcbdw3aiaGpqGPoCGPoCGOjoahjqfSQY6YOY+gIY+gIY6Oh6AnoCGPoCGOjAIHoHN9DJ/SRoyRg28UABXuD7e1E0NTUMfQEMfQEMdHQ1NQx+kgx0wcx9AQx9AQx0dDUMfpI1DHTHzHRgCAVgwMQBdsuB7UTQ1NQx9AQx9AQx0dDUMdT6SDHTBzH0BDH0BDHR0PQEMfQEMfQE0QHwA7OAAT7Ice1E0NTUMfQEMfQEMdHQ1DHUMfpIMdMHMfQE9AQx0YBA9A5voTGACASA0NQIBIGFiAgEgNjcCASA8PQL3DEyOzs8gTpFDcMAHfL0ggCg9lOtgED0Dm+hMbPy9C7Q+kjU0VNRyM+EAhL6UvpSyQHIz4TQzMz5FsjPigBAy//PUAfIzBbLP1JA+lITy//6UswZ9AAX9ADJBMjL/8kCyPpUFMzMEvpSyVQgJoBA9BeCEAX14QAgbfgoiYDg5AvcUxOAQPQOb6HjAjBTEoBA9A5voYIAoPcB8vTU0dD6UNTU+kjRBIIAoPkFxwUU8vRSNYBA9FswBNDUMdM/+kjT/zH6SNQx9AQx9AQx0STQ0//R+CjI+lIT+lLJAcj6UhLL/8zJyM+PGAAEghDpwAyXzwv3cM8LYRLLP8zJgOjsAAUAAeMjPkF41FGYnzws/UAr6AhL6VPpUz4QgF87JyM+FiBX6UgH6AoAVzwuKEss/E/pSUAP6AhLMyXH7AIEAhQD+1NHQ+lDU1NP/+kjRBYIAoPgGxwUV8vRSR4BA9FswAdDUMdM/+kjT/zH6SNHI+lL6UiTPC//JyM+PGAAEghA33W9uzwv3cM8LYRLLP8zJcPsAIW6TNV8DjiWCCJiWgMjPhYgT+lJY+gKCEGwGBCTPC4oTyz8UzBPL/8mAQfsA4gBYcPsAIG6SXwOOIYIImJaAyM+FiBL6UgH6AoIQeNwiMs8LihLLP8zJgEH7AOIESQxINcsIre56bzjAtcsIL4SFuTjAtcsIhNcZiTjAtcsJruJQISA+P0BBAHkVxBfD2wxAdDU+kgx1NMfMdEB0PpI+lAx0SLHBZFb4ND6SDH6UPpQMdGBOj4hbrOVAscFwwCTbCFw4vL0gAfQx1NdMVhbQ1PpIMdQx0x8x0dD6SPpQMdEDggDCiATHBRPy9NBwkiCzjkWVIddJwgCOLgHTP1IQERSAQPRbgTo4AfL0yM+PGAAEghAnkIKLzwv3cM8LYRLLP8lw+wAREgHoIddKlAHXTNCTMH8B4gHoW9BwkiCziuhbf0IB/jHTPzHTP9dMVhbQ1PpIMdQx0x8x0dD6SPpQMdEDggDCiATHBRPy9IE6OCFWE4BA9A5voTHy9IE6OCFWE4BA9A5voRLy9NT0BNTU0YE6NybQ0wchwUHyhQGqAtcY0ddJwwDy9CXQ0wchwUHyhQGqAtcY0cjOcfkEA4E6P1MUgwdHAv4x0z8x0z/XTFYW0NT6SDHUMdMfMdHQ+kj6UDHRA4IAwogExwUT8vSBOjghVhOAQPQOb6Ex8vSBOjghVhOAQPQOb6ES8vTU9ATU1NEl0NMHIcFB8oUBqgLXGNHIznH5BANQA4MH9FuBOkAB8vQDyMwT9AASzMxREBETgED0Q8iJSEkE/I5oMdM/MfpI+lD6UDARF9DU+kjUMdMf0SLQ+kj6UDHRBoIAwogHxwUW8vQjyPpSUjD6VFYZAfpUyQLIzPpSzBPLH8kByPpSEvpUAREVAfpUycjPjxgABIIQtzXjDM8L93HPC2HMyXD7AH/g1ywh4oUc3OMC1ywifxaTZOMCiUpLTE0BLJUh10nCAIroIddKlAHXTNCTMH8B4gFDAf4B0z/U1NQB0NQB0NMAAcMAAdN/03/RA9QB0NMAAcMAAdN/03/RA9GBOjco0NMHIcFB8oUBqgLXGNHXScMA8vSBOjsqVhyAQPQOb6Exs/L0bfgjJcjLf8s/FsoAFMt/Fct/yfgjI8jLf8s/FcoAEst/y3/JAsjMEszJ+CNwyMt/RAHiyz9wzwuAcM8Lf8n4I3DIy3/LP3DPC4Bwzwt/yQHIzMzJJAbQcJIgs46WlSHXScIAiugh10qUAddM0JMwfwHiAehbyM+PGAAEghDtN8S8zwv3cM8LYSfPCz8VzMlw+wAEyMz0ABPMzFkRE4BA9EMREQFFAfoB0wchwUHyhQGqAtcYIddJgTpCIak4AvLyUSLXGQKrAsjLBxLOyYE6NyHQ0wchwUHyhQGqAtcY0ddJwwDy9CDQ0wchwUHyhQGqAtcY0cjOcfkEA4E6P1MXgwf0Dm+hMbPy9FRBF4MH9BfIz48YAASCEL8NGrbPC/dwzwthKkYAFM8LPxbMyXD7AAEAfvQOb6Exs/L0VEYUgwf0FwPIzBP0ABLMzFEQEROAQPRDyM+PGAAEghC/DRq2zwv3cM8LYQEREgHLP8zJcPsAfwAFxgABADbPFoIQvBTH6M8L93DPC2EBERIByz/MyXD7AH8AnjHTPzHXCx8RFdDU+kjU0x8x0SLQ+kj6UDHRBIIAwogFxwUU8vRWFgLIzPpSEszLH8nIz48YAASCEEJqcTvPC/dwzwthAREVAcsfyXD7AH8BmjHXTFYVAVYVAVYVAVYVAVYVAVYVAVYVAVYVAVYVAVYVAVYVAVYVAVYVAVYVAVYVAVYVAVYVAVYVAVYVAVYVAREV8AvQlCDHALOK6DB/TgAIMKHR9wTk1yeO1DHU10xWFtDU+kgx1DHTHzHR0PpI+lAx0QOCAMKIBMcFE/L00JQgxwCziugw0JQgxwCzjh0g10sBkTCbgTS8AcAB8vTXTNDi0z8REIBA9FswD+gwf+DXLCcYOyX04wLXLCTJTbIU4wLXLCFkg3W8UVJTVAL+INdLAZEwm4E0vAHAAfL010zQ4tM/0gDU1IE6OCVWFoBA9A5voRLy9NT0BNTU0QeOP9DUMdQx0QTQ0gDTf9N/0fgjIsjLf8s/E8oAy3/Lf8kD0NIA03/Tf9H4IyLIy3/LPxPKAMt/y3/JA8jME8zJBOMNAsjME/QAE8wSzFkREk9QAH4G0NQx1DHRBNDSANN/03/R+CMiyMt/yz8TygDLf8t/yQPQ0gDTf9N/0fgjIsjLf8s/E8oAy3/Lf8kDyMwTzMkADIBA9EMREADgINdLAZEwm4E0vAHAAfL010zQ4tM/0gDT/9P/0x/TH9MP0w+BOjgpVhuAQPQOb6Ex8vSBOjUo8vSBOjQjgScQufL0gTo0IoEnELny9IE6NSXCAPL0B8jKABbL/xTL/xLLH8sfyw/LD1kREoBA9EMREAGsMddMERXQ1PpI1NMf0QPQ+kj6UNGCAMKIUWLHBRby9Mj6UhT6VMnIzPpSEszLH8kRE9D0BPQE9ATRERbQlCDHALOK6DAByPQA9AABERQB9ADJERIRE39VAHox0z8x+kgwERXQ1PpIMdTTH9Ei0PpI+lAx0QSCAMKIBccFFPL0AcjMAREWAfpSAREVAcwBERQByx/JERN/A/yOTjHTPzH0BYE6PlYW0NQx+kjUMdMfMdETxwUS8vQRE9D0BPQE9AQx0QHI9AD0AAEREwH0AMnIz48YAASCECdeAjTPC/dwzwthyXD7ABESf+DXLCGo+78c4wLXLCObFoTkMZJbcOBWFdDU+kjU0x/RA9D6SPpQ0UEGJfAB4wJWV1gA1CDXSwGRMJuBNLwBwAHy9NdM0OLTP/pQ+lAibpdSNoBA9FswmyLI+lJUIEeAQPRD4iFul1I1gED0WzCbIcj6UlQgRoBA9EPiA8jLPxL6VPpUycjPjxgABIIQnFq7lc8L93HPC2HMyXD7AFgD/jHTP9TTH/pQMCLQ1NM/+kjT//pI1PQE9ATRgTo9Vh8lxwXy9IE6OSdWHoBA9A5voTHy9IE6OlYg0PQEMfQEMfQE0SjwA7Py9C3DAJZWE26zwwCRcOKfVhpWGlYaVhpWGitWGdpg3lYf0PQEMfQE9AQx0VJwgED0Dm+h4w+BOj5ZWlsAPjRXGBEXyPpSEvpUycjMAREWAfpSzAERFAHLH8kRE38ADBBFXwXHAAAG+kjRAAQwbQH8IW6z8vSBOj5RHscF8vQtwwCWVhRus8MAkXDijhFWGlYaVhpWGlYaVhEsVhvacN6BOkBWIVYhViFWIVYhViFWIVYhViFWIVYhViFWIVYhViFWIVYhViFWIVYhVhtWGPAM8vRWIFYgViBWIFYgViBWIFYgViBWIFYgViBWIFYgXAP+ViBWIFYgViBWIFYgVhXwDVYhAVYhAVYhAVYhAVYhAVYhAVYhAVYhAVYhAVYhAVYhAVYhAVYhAVYhAVYhAVYhAVYhAVYhAVYhAVYhAVYZAfAOKsMAK+MPL8MAllYTbrPDAJFw4o4ZVhxWHFYcVhxWHFR+3FR+3FR+3FYZViLa8F1eXwHwViLQ1DH6SDHUMdMf0VLA8AaBOjgpViCAQPQOb6ES8vTU9ATU1NEg0NTU0dDTf9M/0gDTf9N/0SKOLF8GAdDU1NHQ03/TP9IA03/Tf9EqVirwBATIy38Tyz/KAMt/y3/JAcjMzMkB4w0DyMwS9ADMzFKSESCAQPRDYACegTo4KVYggED0Dm+hEvL01PQE1NTRAdDU1NHQ03/TP9IA03/Tf9EqVirwBATIy38Tyz/KAMt/y3/JAcjMzMkDyMwS9AASzMxSkhEggED0QwCO3lOxgTpFVhLDAJZWE26zwwCRcOLy9BEVER4RFREUER0RFBETERwRExESERsREhERERoREQIRIFADVhuAFnXbOBBNEDxLqX8ANGwWKlYq8AQEyMt/E8s/ygDLf8t/yQHIzMzJAgEgY2QCASBlZgBxFcTVxFfD2wjgED0Dm+hkltw4dQx9ATUMdQx0QHQ0wchwUHyhQGqAtcY0cjOcfkEAwGDB/QOb6ExgAGEVxBfD2wiMiFukTHgMNCBOkEh10mDB7qXIddKwADDAJFw4vL00//RgTpBIYQHu/L0gAIUVxNXEF8PMzNTArqSMDHgUwK8nlihgTpCIcFO8vTwB6kE4BKhgTpCIcFO8vTwB4E6QiGZhP8iqQQjvsMAkX/i8vSogAHsMTJs82xENAKAQPQOb6GTXwNw4dIA0/8x0/8x0x8x0x8x0w/TD9ECk18EcOEClzGogScQqQTgMKiBJxCpBIA=='); + static CodeCell = c.Cell.fromBase64('te6ccgECZgEAFjoAART/APSkE/S88sgLAQIBYgIDAgLMBAUCASAeHwIBIAYHAgEgMjMCASAICQIBIBgZAgEgCgsAV1IW6SW3DggmkAAAAAAAAAAAAAAAAAAAEigwb0Dm+hMZJbf+ABgwb0Dm+hMYBO0+JHyQO1E0NTU9AT0BNEj0NTU+kjTB/QE9ATRgQCFbW1tbW1tbZLwCACBAIZWE1YTVhNWE/iS+JcQXxBOED0QLBBbEEoQORAoEFcQRhA1ECRWGvAKPl8JBOMCXwok1ywhzExybOMC1ywjmxaE5OMC1ywmqZO23IAwNDg8BqTtou371ywnkNvtDI5E1ywnzxTyVJRbcNsx4YIAwoojbrPy9CGCAMKKBMcFE/L0IG0D1ws/iwIByMs/FfpSEvpSycjPhyAUznHPC2ETzMlw+wDjDX+AXAFw9PQHDAJM3NzeZMDk5EFheJBBF4gPIzBLM+lLLBxP0APQAycjMzBL0APQAye1UAMg1BNcLP/iSJNDU1DH6SDHTBzH0BDH0BDHR0NT6SDHUMdMfMdHQ+kj6UDHRAYIAwogCxwXy9IIK+vCAI9D6SNQx0cjPhYj6UgH6AoIQ+4jhGc8Liss/yXH7AALIzMz0APQAye1UAfo1BNM/MfoA+lD4kiXQ+kjU0YIAoPD4KCPIz4QCEvpS+lLJWMjPhNDMzPkWyM+KAEDL/89QI8cF8vQC9AQhbpgxIMcAkjBt4JLR0OKCAKDyIW6z8vTXLCfT7SIk8r/TP9TTH/QE+lDRA9DU0z/6SNP/+kjRIYIAoPMOuh3y9BAATo4bNQTXCz/4khBFEDQQI/AJA8jMEsz0APQAye1U4F8FhA8BxwDy9AH+ggCg8Stus/L0ggCg9FONgED0Dm+hMbPy9C7Q1NT6SNMH9AT0BNGBAIVtbW1tbW1tkvAIAIEAhlYdVh1WIYE6PVYRViDHBfL0gTo5VhZWEIBA9A5voTHy9IE6OlYS0PQEMfQEMfQE0VYX8AOz8vQpbrOcViFUcyFWEFYaL9pg3hEB/lYR0PQE9AQx9AQx0VYWAYBA9A5voZP6SNGSMG3igTo+IW6z8vSBOj4BVh/HBfL0K26zn1YhVGMzU/ARIlYaVhHacJJXHeJWEVYRVhFWEVYRVhFWJlOHViVWFVYVVhVWFVYVVhVWFVYVVhVWFVYpVilWKVYpVjVWMPAPbDMzMzQSAv40NFOyoTNWEI5NgTo4U+eAQPQOb6ES8vTU9ATU1NEB0NTU0QHQ03/TP9IA03/Tf9ErVhLwBATIy38Tyz/KAMt/y3/JyMzMyQPIzBL0ABLMzFQg6IBA9EPjDSZus44aVhlTJFYYKFYTVhNWE1YTVh9WGlYaLlYT2tDeMTU9Wzs/ExQB7irQ1DH6SDHUMdMf0VYRAfAGgTo4U+eAQPQOb6ES8vTU9ATU1NEg0NTU0QHQ03/TP9IA03/Tf9EijixfBgHQ1NTRAdDTf9M/0gDTf9N/0StWEvAEBMjLfxPLP8oAy3/Lf8nIzMzJAeMNA8jMEvQAzMxUIOiAQPRDFQH+VxKBOjhTboBA9A5voRLy9NT0BDHUMdQx0VYSyMv/yQTIzBPM+lIBEREBywcc9AAW9ADJA8jMEss/+lITy/8Y+lLJCsjMFszJAcj6VBnMGMwkzwv/EvpSyVQgZYBA9BeCCvrwgPgobcjPhYgX+lJY+gKCEFlfB7zPC4oXyz9QAxYAMmwWK1YS8AQEyMt/E8s/ygDLf8t/ycjMzMkALvoCFfpUEvQAyXH7AALIzMz0APQAye1UAGZsEtM/+kgwggDCiFE0xwUT8vSCAMKJUyPHBbPy9CGLAsjPhyDOcM8LYRLLPxL6Uslw+wACASAaGwIBIBwdAKsMCOzkX+VIMAAwwDikTDgIvgjJqEgjhg2U2C8lYFmvPLw4FFSqBagUkDwBQX4IwWRMOIhuZWBZr3y8OBTULmOERVfBSCVgWa+8vDhMIFmvvLw4BWhBIAANFy5kTDgMYAApCGRW+GBOkYhlAK6wwCTbCFw4vL0gAE8cXqTIsIAjhwicbDAAZ+BOkKE/yOpBCK+8vRmqAHeIKgCqwAC6DAxgAgEgICECASAuLwIBICIjAgEgLC0CASAkJQBBtbUdqJoamoY+gIY+gIY6OhqGOoY/SQY6YP6Ahj6AhjowAgEgJicCAUgqKwAtrSp2omhqGOoY+gIY+gJowCB6BzfQmMACAUgoKQBvpXXaiaGpqGPoCGPoCGOjoahjqfSQY6YOY+gIY+gIY6Oh6Ahj6AnoCGOjAIHoHN9DJ/SRoyRg28UAP6cj2omhqahj6Ahj6Ahjo6GoY6hj9JGmDmPoCGPoCGOjAGKpX40JWxpbmsuY2hhaW4udG9uLmNjaXAuQnVybk1pbnRUb2tlblBvb2yCLUwLjEuMIACyp3e1E0NQx1DH0BPQEMdGAQPQOb6ExAGW0o72omhqahj6Ahj6Ahjo6GpqGP0kGOmDmPoCGPoCGOjoan0kGOoY6Y+Y6Oh9JH0oGOjAAcbdw3aiaGpqGPoCGPoCGOjoahjqfSQY6YOY+gIY+gIY6Oh6AnoCGPoCGOjAIHoHN9DJ/SRoyRg28UABXuD7e1E0NTUMfQEMfQEMdHQ1NQx+kgx0wcx9AQx9AQx0dDUMfpI1DHTHzHRgCAVgwMQBdsuB7UTQ1NQx9AQx9AQx0dDUMdT6SDHTBzH0BDH0BDHR0PQEMfQEMfQE0QHwA7OAAT7Ice1E0NTUMfQEMfQEMdHQ1DHUMfpIMdMHMfQE9AQx0YBA9A5voTGACASA0NQIBIGBhAgEgNjcCASA8PQL3DEyOzs8gTpFDcMAHfL0ggCg9lOtgED0Dm+hMbPy9C7Q+kjU0VNRyM+EAhL6UvpSyQHIz4TQzMz5FsjPigBAy//PUAfIzBbLP1JA+lITy//6UswZ9AAX9ADJBMjL/8kCyPpUFMzMEvpSyVQgJoBA9BeCEAX14QAgbfgoiYDg5AvcUxOAQPQOb6HjAjBTEoBA9A5voYIAoPcB8vTU0dD6UNTU+kjRBIIAoPkFxwUU8vRSNYBA9FswBNDUMdM/+kjT/zH6SNQx9AQx9AQx0STQ0//R+CjI+lIT+lLJAcj6UhLL/8zJyM+PGAAEghDpwAyXzwv3cM8LYRLLP8zJgOjsAAUAAeMjPkF41FGYnzws/UAr6AhL6VPpUz4QgF87JyM+FiBX6UgH6AoAVzwuKEss/E/pSUAP6AhLMyXH7AIEAhQD+1NHQ+lDU1NP/+kjRBYIAoPgGxwUV8vRSR4BA9FswAdDUMdM/+kjT/zH6SNHI+lL6UiTPC//JyM+PGAAEghA33W9uzwv3cM8LYRLLP8zJcPsAIW6TNV8DjiWCCJiWgMjPhYgT+lJY+gKCEGwGBCTPC4oTyz8UzBPL/8mAQfsA4gBYcPsAIG6SXwOOIYIImJaAyM+FiBL6UgH6AoIQeNwiMs8LihLLP8zJgEH7AOIESQxINcsIre56bzjAtcsIL4SFuTjAtcsIhNcZiTjAtcsJruJQISA+P0BBAHkVxBfD2wxAdDU+kgx1NMfMdEB0PpI+lAx0SLHBZFb4ND6SDH6UPpQMdGBOj4hbrOVAscFwwCTbCFw4vL0gAewx1NdMVhbQ1PpIMdQx0x8x0dD6SPpQMdEDggDCiATHBRPy9NCUIMcAs44/INdLAZEwm4E0vAHAAfL010zQ4tM/UhARE4BA9FuBOjgB8vTIz48YAASCECeQgovPC/dwzwthEss/yXD7ABER6DDQlCDHALOK6DB/QgH+MdM/MdM/10xWFtDU+kgx1DHTHzHR0PpI+lAx0QOCAMKIBMcFE/L0gTo4IVYTgED0Dm+hMfL0gTo4IVYTgED0Dm+hEvL01PQE1NTRgTo3JtDTByHBQfKFAaoC1xjR10nDAPL0JdDTByHBQfKFAaoC1xjRyM5x+QQDgTo/UxSDB0YC/jHTPzHTP9dMVhbQ1PpIMdQx0x8x0dD6SPpQMdEDggDCiATHBRPy9IE6OCFWE4BA9A5voTHy9IE6OCFWE4BA9A5voRLy9NT0BNTU0SXQ0wchwUHyhQGqAtcY0cjOcfkEA1ADgwf0W4E6QAHy9APIzBP0ABLMzFEQEROAQPRDyIlHSAT8jmgx0z8x+kj6UPpQMBEX0NT6SNQx0x/RItD6SPpQMdEGggDCiAfHBRby9CPI+lJSMPpUVhkB+lTJAsjM+lLME8sfyQHI+lIS+lQBERUB+lTJyM+PGAAEghC3NeMMzwv3cc8LYczJcPsAf+DXLCHihRzc4wLXLCJ/FpNk4wKJSUpLTAH+INdLAZEwm4E0vAHAAfL010zQ4tM/1NTUAdDU1NEB0NIA03/Tf9ED0NIA03/Tf9GBOjco0NMHIcFB8oUBqgLXGNHXScMA8vSBOjsqVhuAQPQOb6Exs/L0bfgjJcjLf8s/FsoAFMt/Fct/yfgjJcjLf8s/EsoAFMt/y3/JAsjMEkMBxMzJ+CNwyMt/yz9wzwuAcM8Lf8n4I3DIy3/LP3DPC4Bwzwt/yQHIzMzJJAbQlCDHALOK6DDIz48YAASCEO03xLzPC/dwzwthJ88LPxXMyXD7AATIzPQAE8zMWRESgED0QxEQRAH+INdLAZEwm4E0vAHAAfL010zQ4tMHIcFB8oUBqgLXGMgi10kgqTgC8kWrAiDBQfKFzwsHEs7JgTo3IdDTByHBQfKFAaoC1xjR10nDAPL0INDTByHBQfKFAaoC1xjRyM5x+QQDgTo/UxaDB/QOb6Exs/L0VEEWgwf0F8jPjxgABEUALoIQvw0ats8L93DPC2Epzws/FczJcPsAAH70Dm+hMbPy9FRGFIMH9BcDyMwT9AASzMxREBETgED0Q8jPjxgABIIQvw0ats8L93DPC2EBERIByz/MyXD7AH8ABcYAAQA2zxaCELwUx+jPC/dwzwthARESAcs/zMlw+wB/AJ4x0z8x1wsfERXQ1PpI1NMfMdEi0PpI+lAx0QSCAMKIBccFFPL0VhYCyMz6UhLMyx/JyM+PGAAEghBCanE7zwv3cM8LYQERFQHLH8lw+wB/AZox10xWFQFWFQFWFQFWFQFWFQFWFQFWFQFWFQFWFQFWFQFWFQFWFQFWFQFWFQFWFQFWFQFWFQFWFQFWFQFWFQERFfAL0JQgxwCziugwf00ACDCh0fcE5NcnjtQx1NdMVhbQ1PpIMdQx0x8x0dD6SPpQMdEDggDCiATHBRPy9NCUIMcAs4roMNCUIMcAs44dINdLAZEwm4E0vAHAAfL010zQ4tM/ERCAQPRbMA/oMH/g1ywnGDsl9OMC1ywkyU2yFOMC1ywhZIN1vFBRUlMC/iDXSwGRMJuBNLwBwAHy9NdM0OLTP9IA1NSBOjglVhaAQPQOb6ES8vTU9ATU1NEHjj/Q1DHUMdEE0NIA03/Tf9H4IyLIy3/LPxPKAMt/y3/JA9DSANN/03/R+CMiyMt/yz8TygDLf8t/yQPIzBPMyQTjDQLIzBP0ABPMEsxZERJOTwB+BtDUMdQx0QTQ0gDTf9N/0fgjIsjLf8s/E8oAy3/Lf8kD0NIA03/Tf9H4IyLIy3/LPxPKAMt/y3/JA8jME8zJAAyAQPRDERAA4CDXSwGRMJuBNLwBwAHy9NdM0OLTP9IA0//T/9Mf0x/TD9MPgTo4KVYbgED0Dm+hMfL0gTo1KPL0gTo0I4EnELny9IE6NCKBJxC58vSBOjUlwgDy9AfIygAWy/8Uy/8Syx/LH8sPyw9ZERKAQPRDERABrDHXTBEV0NT6SNTTH9ED0PpI+lDRggDCiFFixwUW8vTI+lIU+lTJyMz6UhLMyx/JERPQ9AT0BPQE0REW0JQgxwCziugwAcj0APQAAREUAfQAyRESERN/VAB6MdM/MfpIMBEV0NT6SDHU0x/RItD6SPpQMdEEggDCiAXHBRTy9AHIzAERFgH6UgERFQHMAREUAcsfyRETfwP8jk4x0z8x9AWBOj5WFtDUMfpI1DHTHzHRE8cFEvL0ERPQ9AT0BPQEMdEByPQA9AABERMB9ADJyM+PGAAEghAnXgI0zwv3cM8LYclw+wAREn/g1ywhqPu/HOMC1ywjmxaE5DGSW3DgVhXQ1PpI1NMf0QPQ+kj6UNFBBiXwAeMCVVZXANQg10sBkTCbgTS8AcAB8vTXTNDi0z/6UPpQIm6XUjaAQPRbMJsiyPpSVCBHgED0Q+IhbpdSNYBA9FswmyHI+lJUIEaAQPRD4gPIyz8S+lT6VMnIz48YAASCEJxau5XPC/dxzwthzMlw+wBYA/4x0z/U0x/6UDAi0NTTP/pI0//6SNT0BPQE0YE6PVYfJccF8vSBOjknVh6AQPQOb6Ex8vSBOjpWIND0BDH0BDH0BNEo8AOz8vQtwwCWVhNus8MAkXDin1YaVhpWGlYaVhorVhnaYN5WH9D0BDH0BPQEMdFScIBA9A5voeMPgTo+WFlaAD40VxgRF8j6UhL6VMnIzAERFgH6UswBERQByx/JERN/AAwQRV8FxwAABvpI0QAEMG0B/CFus/L0gTo+UR7HBfL0LcMAllYUbrPDAJFw4o4RVhpWGlYaVhpWGlYRLFYb2nDegTpAViFWIVYhViFWIVYhViFWIVYhViFWIVYhViFWIVYhViFWIVYhViFWIVYbVhjwDPL0ViBWIFYgViBWIFYgViBWIFYgViBWIFYgViBWIFsD/lYgViBWIFYgViBWIFYV8A1WIQFWIQFWIQFWIQFWIQFWIQFWIQFWIQFWIQFWIQFWIQFWIQFWIQFWIQFWIQFWIQFWIQFWIQFWIQFWIQFWGQHwDirDACvjDy/DAJZWE26zwwCRcOKOGVYcVhxWHFYcVhxUftxUftxUftxWGVYi2vBcXV4B8FYi0NQx+kgx1DHTH9FSwPAGgTo4KVYggED0Dm+hEvL01PQE1NTRINDU1NHQ03/TP9IA03/Tf9EijixfBgHQ1NTR0NN/0z/SANN/03/RKlYq8AQEyMt/E8s/ygDLf8t/yQHIzMzJAeMNA8jMEvQAzMxSkhEggED0Q18AnoE6OClWIIBA9A5voRLy9NT0BNTU0QHQ1NTR0NN/0z/SANN/03/RKlYq8AQEyMt/E8s/ygDLf8t/yQHIzMzJA8jMEvQAEszMUpIRIIBA9EMAjt5TsYE6RVYSwwCWVhNus8MAkXDi8vQRFREeERURFBEdERQRExEcERMREhEbERIREREaERECESBQA1YbgBZ12zgQTRA8S6l/ADRsFipWKvAEBMjLfxPLP8oAy3/Lf8kByMzMyQIBIGJjAgEgZGUAcRXE1cRXw9sI4BA9A5voZJbcOHUMfQE1DHUMdEB0NMHIcFB8oUBqgLXGNHIznH5BAMBgwf0Dm+hMYABhFcQXw9sIjIhbpEx4DDQgTpBIddJgwe6lyHXSsAAwwCRcOLy9NP/0YE6QSGEB7vy9IACFFcTVxBfDzMzUwK6kjAx4FMCvJ5YoYE6QiHBTvL08AepBOASoYE6QiHBTvL08AeBOkIhmYT/IqkEI77DAJF/4vL0qIAB7DEybPNsRDQCgED0Dm+hk18DcOHSANP/MdP/MdMfMdMfMdMP0w/RApNfBHDhApcxqIEnEKkE4DCogScQqQSA='); static Errors = { 'Common_Error.CrossChainAddressOutOfRange': 5, diff --git a/contracts/wrappers/gen/ccip/pools/LockReleaseTokenPool.ts b/contracts/wrappers/gen/ccip/pools/LockReleaseTokenPool.ts index 9af0d3112..b77ef77a7 100644 --- a/contracts/wrappers/gen/ccip/pools/LockReleaseTokenPool.ts +++ b/contracts/wrappers/gen/ccip/pools/LockReleaseTokenPool.ts @@ -2659,7 +2659,7 @@ function calculateDeployedAddress(code: c.Cell, data: c.Cell, options: DeployedA } export class LockReleaseTokenPool implements c.Contract { - static CodeCell = c.Cell.fromBase64('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'); + static CodeCell = c.Cell.fromBase64('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'); static Errors = { 'Common_Error.CrossChainAddressOutOfRange': 5, diff --git a/contracts/wrappers/gen/ccip/pools/TokenPool.ts b/contracts/wrappers/gen/ccip/pools/TokenPool.ts index 2ac4a903b..5a697f680 100644 --- a/contracts/wrappers/gen/ccip/pools/TokenPool.ts +++ b/contracts/wrappers/gen/ccip/pools/TokenPool.ts @@ -653,6 +653,97 @@ export const TokenPool_TokenTransferFeeConfig = { } } +/** + > struct TokenPool_LockOrBurnInV1 { + > receiver: Cell + > remoteChainSelector: uint64 + > originalSender: address + > amount: uint256 + > localToken: address + > } + */ +export interface TokenPool_LockOrBurnInV1 { + readonly $: 'TokenPool_LockOrBurnInV1' + receiver: CellRef + remoteChainSelector: uint64 + originalSender: c.Address + amount: uint256 + localToken: c.Address +} + +export const TokenPool_LockOrBurnInV1 = { + create(args: { + receiver: CellRef + remoteChainSelector: uint64 + originalSender: c.Address + amount: uint256 + localToken: c.Address + }): TokenPool_LockOrBurnInV1 { + return { + $: 'TokenPool_LockOrBurnInV1', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_LockOrBurnInV1 { + return { + $: 'TokenPool_LockOrBurnInV1', + receiver: loadCellRef(s, CrossChainAddress.fromSlice), + remoteChainSelector: s.loadUintBig(64), + originalSender: s.loadAddress(), + amount: s.loadUintBig(256), + localToken: s.loadAddress(), + } + }, + store(self: TokenPool_LockOrBurnInV1, b: c.Builder): void { + storeCellRef(self.receiver, b, CrossChainAddress.store); + b.storeUint(self.remoteChainSelector, 64); + b.storeAddress(self.originalSender); + b.storeUint(self.amount, 256); + b.storeAddress(self.localToken); + }, + toCell(self: TokenPool_LockOrBurnInV1): c.Cell { + return makeCellFrom(self, TokenPool_LockOrBurnInV1.store); + } +} + +/** + > struct TokenPool_LockOrBurnOutV1 { + > destTokenAddress: Cell + > destPoolData: cell + > } + */ +export interface TokenPool_LockOrBurnOutV1 { + readonly $: 'TokenPool_LockOrBurnOutV1' + destTokenAddress: CellRef + destPoolData: c.Cell +} + +export const TokenPool_LockOrBurnOutV1 = { + create(args: { + destTokenAddress: CellRef + destPoolData: c.Cell + }): TokenPool_LockOrBurnOutV1 { + return { + $: 'TokenPool_LockOrBurnOutV1', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_LockOrBurnOutV1 { + return { + $: 'TokenPool_LockOrBurnOutV1', + destTokenAddress: loadCellRef(s, CrossChainAddress.fromSlice), + destPoolData: s.loadRef(), + } + }, + store(self: TokenPool_LockOrBurnOutV1, b: c.Builder): void { + storeCellRef(self.destTokenAddress, b, CrossChainAddress.store); + b.storeRef(self.destPoolData); + }, + toCell(self: TokenPool_LockOrBurnOutV1): c.Cell { + return makeCellFrom(self, TokenPool_LockOrBurnOutV1.store); + } +} + /** > struct TokenPool_ReleaseOrMintInV1 { > originalSender: Cell @@ -725,6 +816,39 @@ export const TokenPool_ReleaseOrMintInV1 = { } } +/** + > struct TokenPool_ReleaseOrMintOutV1 { + > destinationAmount: uint256 + > } + */ +export interface TokenPool_ReleaseOrMintOutV1 { + readonly $: 'TokenPool_ReleaseOrMintOutV1' + destinationAmount: uint256 +} + +export const TokenPool_ReleaseOrMintOutV1 = { + create(args: { + destinationAmount: uint256 + }): TokenPool_ReleaseOrMintOutV1 { + return { + $: 'TokenPool_ReleaseOrMintOutV1', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_ReleaseOrMintOutV1 { + return { + $: 'TokenPool_ReleaseOrMintOutV1', + destinationAmount: s.loadUintBig(256), + } + }, + store(self: TokenPool_ReleaseOrMintOutV1, b: c.Builder): void { + b.storeUint(self.destinationAmount, 256); + }, + toCell(self: TokenPool_ReleaseOrMintOutV1): c.Cell { + return makeCellFrom(self, TokenPool_ReleaseOrMintOutV1.store); + } +} + /** > struct (0x56f73d37) TokenPool_ApplyChainUpdates { > queryId: uint64 @@ -1177,6 +1301,112 @@ export const TokenPool_UpdateCursedSubjects = { } } +/** + > struct (0xfa7da444) TokenPool_LockOrBurn { + > queryId: uint64 + > request: Cell + > requestedFinalityConfig: uint32 + > tokenArgs: cell? + > replyTo: address? + > } + */ +export interface TokenPool_LockOrBurn { + readonly $: 'TokenPool_LockOrBurn' + queryId: uint64 + request: CellRef + requestedFinalityConfig: uint32 + tokenArgs: c.Cell | null + replyTo: c.Address | null +} + +export const TokenPool_LockOrBurn = { + PREFIX: 0xfa7da444, + + create(args: { + queryId: uint64 + request: CellRef + requestedFinalityConfig: uint32 + tokenArgs: c.Cell | null + replyTo: c.Address | null + }): TokenPool_LockOrBurn { + return { + $: 'TokenPool_LockOrBurn', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_LockOrBurn { + loadAndCheckPrefix32(s, 0xfa7da444, 'TokenPool_LockOrBurn'); + return { + $: 'TokenPool_LockOrBurn', + queryId: s.loadUintBig(64), + request: loadCellRef(s, TokenPool_LockOrBurnInV1.fromSlice), + requestedFinalityConfig: s.loadUintBig(32), + tokenArgs: s.loadBoolean() ? s.loadRef() : null, + replyTo: s.loadMaybeAddress(), + } + }, + store(self: TokenPool_LockOrBurn, b: c.Builder): void { + b.storeUint(0xfa7da444, 32); + b.storeUint(self.queryId, 64); + storeCellRef(self.request, b, TokenPool_LockOrBurnInV1.store); + b.storeUint(self.requestedFinalityConfig, 32); + storeTolkNullable(self.tokenArgs, b, + (v,b) => b.storeRef(v) + ); + b.storeAddress(self.replyTo); + }, + toCell(self: TokenPool_LockOrBurn): c.Cell { + return makeCellFrom(self, TokenPool_LockOrBurn.store); + } +} + +/** + > struct (0x6c060424) TokenPool_LockOrBurnResponse { + > queryId: uint64 + > out: Cell + > destTokenAmount: uint256 + > } + */ +export interface TokenPool_LockOrBurnResponse { + readonly $: 'TokenPool_LockOrBurnResponse' + queryId: uint64 + out: CellRef + destTokenAmount: uint256 +} + +export const TokenPool_LockOrBurnResponse = { + PREFIX: 0x6c060424, + + create(args: { + queryId: uint64 + out: CellRef + destTokenAmount: uint256 + }): TokenPool_LockOrBurnResponse { + return { + $: 'TokenPool_LockOrBurnResponse', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_LockOrBurnResponse { + loadAndCheckPrefix32(s, 0x6c060424, 'TokenPool_LockOrBurnResponse'); + return { + $: 'TokenPool_LockOrBurnResponse', + queryId: s.loadUintBig(64), + out: loadCellRef(s, TokenPool_LockOrBurnOutV1.fromSlice), + destTokenAmount: s.loadUintBig(256), + } + }, + store(self: TokenPool_LockOrBurnResponse, b: c.Builder): void { + b.storeUint(0x6c060424, 32); + b.storeUint(self.queryId, 64); + storeCellRef(self.out, b, TokenPool_LockOrBurnOutV1.store); + b.storeUint(self.destTokenAmount, 256); + }, + toCell(self: TokenPool_LockOrBurnResponse): c.Cell { + return makeCellFrom(self, TokenPool_LockOrBurnResponse.store); + } +} + /** > struct (0x351f77e3) TokenPool_ReleaseOrMint { > queryId: uint64 @@ -1230,6 +1460,48 @@ export const TokenPool_ReleaseOrMint = { } } +/** + > struct (0x78dc2232) TokenPool_ReleaseOrMintResponse { + > queryId: uint64 + > out: Cell + > } + */ +export interface TokenPool_ReleaseOrMintResponse { + readonly $: 'TokenPool_ReleaseOrMintResponse' + queryId: uint64 + out: CellRef +} + +export const TokenPool_ReleaseOrMintResponse = { + PREFIX: 0x78dc2232, + + create(args: { + queryId: uint64 + out: CellRef + }): TokenPool_ReleaseOrMintResponse { + return { + $: 'TokenPool_ReleaseOrMintResponse', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_ReleaseOrMintResponse { + loadAndCheckPrefix32(s, 0x78dc2232, 'TokenPool_ReleaseOrMintResponse'); + return { + $: 'TokenPool_ReleaseOrMintResponse', + queryId: s.loadUintBig(64), + out: loadCellRef(s, TokenPool_ReleaseOrMintOutV1.fromSlice), + } + }, + store(self: TokenPool_ReleaseOrMintResponse, b: c.Builder): void { + b.storeUint(0x78dc2232, 32); + b.storeUint(self.queryId, 64); + storeCellRef(self.out, b, TokenPool_ReleaseOrMintOutV1.store); + }, + toCell(self: TokenPool_ReleaseOrMintResponse): c.Cell { + return makeCellFrom(self, TokenPool_ReleaseOrMintResponse.store); + } +} + /** > struct TokenPool_AdminConfig { > ownable: Cell From bd6e8f36a63910ee43fce6da0fd58fdb9aefc485 Mon Sep 17 00:00:00 2001 From: Kristijan Date: Thu, 11 Jun 2026 15:41:39 +0200 Subject: [PATCH 13/16] Remove non-generated token pool bindings --- .../ccip/pools/BurnMintTokenPool.spec.ts | 1 + .../ccip/pools/LockReleaseTokenPool.spec.ts | 334 ++++++++++------ .../wrappers/ccip/LockReleaseTokenPool.ts | 149 ------- contracts/wrappers/ccip/TokenPool.ts | 371 ------------------ 4 files changed, 224 insertions(+), 631 deletions(-) delete mode 100644 contracts/wrappers/ccip/LockReleaseTokenPool.ts delete mode 100644 contracts/wrappers/ccip/TokenPool.ts diff --git a/contracts/tests/ccip/pools/BurnMintTokenPool.spec.ts b/contracts/tests/ccip/pools/BurnMintTokenPool.spec.ts index 4767035f4..27c80f1d5 100644 --- a/contracts/tests/ccip/pools/BurnMintTokenPool.spec.ts +++ b/contracts/tests/ccip/pools/BurnMintTokenPool.spec.ts @@ -51,6 +51,7 @@ describe('BurnMintTokenPool', () => { let userWallet: (address: Address) => Promise> const remoteChainSelector = 91000001n + let sourcePoolAddress: CrossChainAddress let destTokenAddress: CrossChainAddress let receiverAddress: CrossChainAddress diff --git a/contracts/tests/ccip/pools/LockReleaseTokenPool.spec.ts b/contracts/tests/ccip/pools/LockReleaseTokenPool.spec.ts index d27753a58..a1cff9bc9 100644 --- a/contracts/tests/ccip/pools/LockReleaseTokenPool.spec.ts +++ b/contracts/tests/ccip/pools/LockReleaseTokenPool.spec.ts @@ -1,17 +1,42 @@ import '@ton/test-utils' import { Blockchain, SandboxContract, TreasuryContract } from '@ton/sandbox' -import { Address, Cell, beginCell, toNano } from '@ton/core' +import { Address, Cell, beginCell, Dictionary, toNano } from '@ton/core' +import { createEmptyTensorValue, loadMap } from '../../../src/utils/dict' import { JettonMinter, JettonSender, JettonWallet } from '../../../wrappers/examples/jetton' +import * as jetton from '../../../wrappers/jetton/JettonCode' +import { + CrossChainAddress, + CursedSubjects, + RateLimiter_Config, + TokenPool, + TokenPool_Data, + TokenPool_AdminConfig, + TokenPool_DynamicConfig, + TokenPool_MirroredPolicy, + TokenPool_ReleaseOrMintResponse, + TokenPool_LockOrBurn, + TokenPool_LockOrBurnInV1, + TokenPool_ReleaseOrMintInV1, + TokenPool_RateLimitConfigPair, + TokenPool_RampUpdate, + TokenPool_ChainUpdate, + Ownable2Step, +} from '../../../wrappers/gen/ccip/pools/TokenPool' import { + JettonClient, LockReleaseTokenPool, - codec as poolCodec, - opcodes as poolOpcodes, -} from '../../../wrappers/ccip/LockReleaseTokenPool' -import * as jetton from '../../../wrappers/jetton/JettonCode' -import { runTokenPoolBehaviorTests } from './TokenPool.behavior' -import { TokenPool } from '../../../wrappers/gen/ccip/pools/TokenPool' +} from '../../../wrappers/gen/ccip/pools/LockReleaseTokenPool' import { setupGenBindings } from '../../../wrappers/gen' +import * as rtOld from '../../../wrappers/ccip/Router' +import { runTokenPoolBehaviorTests } from './TokenPool.behavior' +import { asSnakedCell, asSnakedCellEmpty } from '../../../src/utils' + +function crossChainAddressFromBuffer(buffer: Buffer): CrossChainAddress { + const addrSlice = rtOld.builder.data.crossChainAddress.encode(buffer).asSlice() + return CrossChainAddress.fromSlice(addrSlice) +} + describe('LockReleaseTokenPool', () => { let blockchain: Blockchain let deployer: SandboxContract @@ -27,12 +52,17 @@ describe('LockReleaseTokenPool', () => { let userWallet: (address: Address) => Promise> const remoteChainSelector = 90000001n - const sourcePoolAddress = poolCodec.crossChainAddressFromBuffer(Buffer.from('source-pool')) - const destTokenAddress = poolCodec.crossChainAddressFromBuffer(Buffer.from('dest-token')) - const receiverAddress = poolCodec.crossChainAddressFromBuffer(Buffer.from('receiver')) + + let sourcePoolAddress: CrossChainAddress + let destTokenAddress: CrossChainAddress + let receiverAddress: CrossChainAddress beforeAll(async () => { setupGenBindings() + + sourcePoolAddress = crossChainAddressFromBuffer(Buffer.from('source-pool')) + destTokenAddress = crossChainAddressFromBuffer(Buffer.from('dest-token')) + receiverAddress = crossChainAddressFromBuffer(Buffer.from('receiver')) }) beforeEach(async () => { @@ -72,43 +102,93 @@ describe('LockReleaseTokenPool', () => { ) await jettonSender.sendDeploy(deployer.getSender(), toNano('1')) - const poolCode = await LockReleaseTokenPool.code() lockReleasePool = blockchain.openContract( - LockReleaseTokenPool.createFromConfig( - { - owner: deployer.address, - token: jettonMinter.address, - tokenDecimals: 9, - rmnProxy: deployer.address, - router: deployer.address, - jettonClient: { + LockReleaseTokenPool.fromStorage({ + poolData: { + ref: TokenPool_Data.create({ + adminConfig: { + ref: TokenPool_AdminConfig.create({ + ownable: { + ref: Ownable2Step.create({ owner: deployer.address, pendingOwner: null }), + }, + rmnProxy: deployer.address, + dynamicConfig: { + ref: TokenPool_DynamicConfig.create({ + router: deployer.address, + rateLimitAdmin: null, + feeAdmin: null, + }), + }, + allowedFinalityConfig: 0n, + }), + }, + mirroredPolicy: { + ref: TokenPool_MirroredPolicy.create({ + onRamps: Dictionary.empty(Dictionary.Keys.BigInt(64)), + offRamps: Dictionary.empty(Dictionary.Keys.BigInt(64)), + cursedSubjects: CursedSubjects.create({ + data: Dictionary.empty(Dictionary.Keys.BigInt(128)), + }), + }), + }, + token: jettonMinter.address, + tokenDecimals: 9n, + remoteChainConfigs: Dictionary.empty(Dictionary.Keys.BigInt(64)), + tokenTransferFeeConfigs: Dictionary.empty(Dictionary.Keys.BigInt(64)), + }), + }, + jettonClient: { + ref: JettonClient.create({ masterAddress: jettonMinter.address, jettonWalletCode, - }, + }), }, - poolCode, - ), + pendingReleases: Dictionary.empty(Dictionary.Keys.BigInt(64)), + }), ) await lockReleasePool.sendDeploy(deployer.getSender(), toNano('2')) // Standard TokenPool interface pool = blockchain.openContract(TokenPool.fromAddress(lockReleasePool.address)) - const applyChains = await lockReleasePool.sendApplyChainUpdates( + const applyChains = await lockReleasePool.sendTokenPoolApplyChainUpdates( deployer.getSender(), toNano('0.2'), { queryId: 1n, - remove: [], - add: [ - { - remoteChainSelector, - remotePoolAddresses: [sourcePoolAddress], - remoteTokenAddress: destTokenAddress, - outboundRateLimiterConfig: { isEnabled: true, capacity: toNano('100'), rate: 1n }, - inboundRateLimiterConfig: { isEnabled: true, capacity: toNano('100'), rate: 1n }, - }, - ], + remoteChainSelectorsToRemove: asSnakedCellEmpty(), + chainsToAdd: asSnakedCell( + [ + TokenPool_ChainUpdate.create({ + remoteChainSelector, + remotePoolAddresses: asSnakedCell([sourcePoolAddress], (item) => { + let b = beginCell() + CrossChainAddress.store(item, b) + return b + }), + remoteTokenAddress: { ref: destTokenAddress }, + rateLimitConfigs: { + ref: TokenPool_RateLimitConfigPair.create({ + outbound: { + ref: RateLimiter_Config.create({ + isEnabled: true, + capacity: toNano('100'), + rate: 1n, + }), + }, + inbound: { + ref: RateLimiter_Config.create({ + isEnabled: true, + capacity: toNano('100'), + rate: 1n, + }), + }, + }), + }, + }), + ], + (item) => TokenPool_ChainUpdate.toCell(item).asBuilder(), + ), }, ) @@ -118,18 +198,21 @@ describe('LockReleaseTokenPool', () => { success: true, }) - const updateRampAccess = await lockReleasePool.sendUpdateRampAccess( + const updateRampAccess = await lockReleasePool.sendTokenPoolUpdateRampAccess( deployer.getSender(), toNano('0.2'), { queryId: 2n, - updates: [ - { - remoteChainSelector, - onRamp: jettonSender.address, - offRamp: offRamp.address, - }, - ], + updates: asSnakedCell( + [ + TokenPool_RampUpdate.create({ + remoteChainSelector, + onRamp: jettonSender.address, + offRamp: offRamp.address, + }), + ], + (item) => TokenPool_RampUpdate.toCell(item).asBuilder(), + ), }, ) @@ -173,9 +256,7 @@ describe('LockReleaseTokenPool', () => { recipient, remoteChainSelector, unsupportedChainSelector: remoteChainSelector + 1n, - unknownSourcePoolAddress: poolCodec.crossChainAddressFromBuffer( - Buffer.from('unknown-source-pool'), - ), + unknownSourcePoolAddress: crossChainAddressFromBuffer(Buffer.from('unknown-source-pool')), remoteTokenAddress: destTokenAddress, onRampAddress: jettonSender.address, destTokenAddress, @@ -199,21 +280,23 @@ describe('LockReleaseTokenPool', () => { destination: lockReleasePool.address, customPayload: beginCell().storeBit(1).endCell(), forwardTonAmount: toNano('0.2'), - forwardPayload: poolCodec.lockOrBurnPayload - .encode({ + forwardPayload: TokenPool_LockOrBurn.toCell( + TokenPool_LockOrBurn.create({ queryId: 44n, request: { - receiver: receiverAddress, - remoteChainSelector, - originalSender: deployer.address, - amount: toNano('2'), - localToken: jettonMinter.address, + ref: TokenPool_LockOrBurnInV1.create({ + receiver: { ref: receiverAddress }, + remoteChainSelector, + originalSender: deployer.address, + amount: toNano('2'), + localToken: jettonMinter.address, + }), }, - requestedFinalityConfig: 0, + requestedFinalityConfig: 0n, tokenArgs: null, replyTo: deployer.address, - }) - .endCell(), + }), + ), }, }) @@ -248,21 +331,27 @@ describe('LockReleaseTokenPool', () => { }) it('reverts releaseOrMint when requested amount exceeds pool liquidity', async () => { - const result = await lockReleasePool.sendReleaseOrMint(offRamp.getSender(), toNano('0.4'), { - queryId: 46n, - request: { - originalSender: sourcePoolAddress, - remoteChainSelector, - receiver: recipient.address, - sourceDenominatedAmount: toNano('999999'), - localToken: jettonMinter.address, - sourcePoolAddress, - sourcePoolData: null, - offchainTokenData: null, + const result = await lockReleasePool.sendTokenPoolReleaseOrMint( + offRamp.getSender(), + toNano('0.4'), + { + queryId: 46n, + request: { + ref: TokenPool_ReleaseOrMintInV1.create({ + originalSender: { ref: sourcePoolAddress }, + remoteChainSelector, + receiver: recipient.address, + sourceDenominatedAmount: toNano('999999'), + localToken: jettonMinter.address, + sourcePoolAddress: { ref: sourcePoolAddress }, + sourcePoolData: null, + offchainTokenData: null, + }), + }, + requestedFinalityConfig: 0n, + replyTo: deployer.address, }, - requestedFinalityConfig: 0, - replyTo: deployer.address, - }) + ) expect(result.transactions).toHaveTransaction({ from: offRamp.address, @@ -284,21 +373,23 @@ describe('LockReleaseTokenPool', () => { destination: lockReleasePool.address, customPayload: beginCell().storeBit(1).endCell(), forwardTonAmount: toNano('0.2'), - forwardPayload: poolCodec.lockOrBurnPayload - .encode({ + forwardPayload: TokenPool_LockOrBurn.toCell( + TokenPool_LockOrBurn.create({ queryId: 11n, request: { - receiver: receiverAddress, - remoteChainSelector, - originalSender: deployer.address, - amount: toNano('3'), - localToken: jettonMinter.address, + ref: TokenPool_LockOrBurnInV1.create({ + receiver: { ref: receiverAddress }, + remoteChainSelector, + originalSender: deployer.address, + amount: toNano('3'), + localToken: jettonMinter.address, + }), }, - requestedFinalityConfig: 0, + requestedFinalityConfig: 0n, tokenArgs: null, replyTo: deployer.address, - }) - .endCell(), + }), + ), }, }) @@ -328,21 +419,27 @@ describe('LockReleaseTokenPool', () => { }, }) - const result = await lockReleasePool.sendReleaseOrMint(offRamp.getSender(), toNano('0.4'), { - queryId: 22n, - request: { - originalSender: sourcePoolAddress, - remoteChainSelector, - receiver: recipient.address, - sourceDenominatedAmount: toNano('2'), - localToken: jettonMinter.address, - sourcePoolAddress, - sourcePoolData: null, - offchainTokenData: null, + const result = await lockReleasePool.sendTokenPoolReleaseOrMint( + offRamp.getSender(), + toNano('0.4'), + { + queryId: 22n, + request: { + ref: TokenPool_ReleaseOrMintInV1.create({ + originalSender: { ref: sourcePoolAddress }, + remoteChainSelector, + receiver: recipient.address, + sourceDenominatedAmount: toNano('2'), + localToken: jettonMinter.address, + sourcePoolAddress: { ref: sourcePoolAddress }, + sourcePoolData: null, + offchainTokenData: null, + }), + }, + requestedFinalityConfig: 0n, + replyTo: deployer.address, }, - requestedFinalityConfig: 0, - replyTo: deployer.address, - }) + ) expect(result.transactions).toHaveTransaction({ from: offRamp.address, @@ -358,20 +455,29 @@ describe('LockReleaseTokenPool', () => { from: lockReleasePool.address, to: deployer.address, success: true, - op: poolOpcodes.out.releaseOrMintResponse, + op: TokenPool_ReleaseOrMintResponse.PREFIX, body(body) { if (!body) return false - const response = poolCodec.releaseOrMintResponse.load(body.beginParse()) - return response.queryId === 22n && response.destinationAmount === toNano('2') + const response = TokenPool_ReleaseOrMintResponse.fromSlice(body.beginParse()) + return response.queryId === 22n && response.out.ref.destinationAmount === toNano('2') }, }) }) it('mirrors cursed state locally and blocks release while cursed', async () => { - const curseUpdate = await lockReleasePool.sendUpdateCursedSubjects( + const curseUpdate = await lockReleasePool.sendTokenPoolUpdateCursedSubjects( deployer.getSender(), toNano('0.2'), - { queryId: 901n, cursedSubjects: [remoteChainSelector] }, + { + queryId: 901n, + cursedSubjects: CursedSubjects.create({ + data: loadMap( + Dictionary.Keys.BigInt(128), + createEmptyTensorValue(), + new Map([[remoteChainSelector, []]]), + ), + }), + }, ) expect(curseUpdate.transactions).toHaveTransaction({ @@ -382,21 +488,27 @@ describe('LockReleaseTokenPool', () => { expect(await lockReleasePool.getVerifyNotCursed(remoteChainSelector)).toBe(false) - const result = await lockReleasePool.sendReleaseOrMint(offRamp.getSender(), toNano('0.3'), { - queryId: 33n, - request: { - originalSender: sourcePoolAddress, - remoteChainSelector, - receiver: recipient.address, - sourceDenominatedAmount: 1n, - localToken: jettonMinter.address, - sourcePoolAddress, - sourcePoolData: null, - offchainTokenData: null, + const result = await lockReleasePool.sendTokenPoolReleaseOrMint( + offRamp.getSender(), + toNano('0.3'), + { + queryId: 33n, + request: { + ref: TokenPool_ReleaseOrMintInV1.create({ + originalSender: { ref: sourcePoolAddress }, + remoteChainSelector, + receiver: recipient.address, + sourceDenominatedAmount: toNano('1'), + localToken: jettonMinter.address, + sourcePoolAddress: { ref: sourcePoolAddress }, + sourcePoolData: null, + offchainTokenData: null, + }), + }, + requestedFinalityConfig: 0n, + replyTo: deployer.address, }, - requestedFinalityConfig: 0, - replyTo: deployer.address, - }) + ) expect(result.transactions).toHaveTransaction({ from: offRamp.address, diff --git a/contracts/wrappers/ccip/LockReleaseTokenPool.ts b/contracts/wrappers/ccip/LockReleaseTokenPool.ts deleted file mode 100644 index 7dae22609..000000000 --- a/contracts/wrappers/ccip/LockReleaseTokenPool.ts +++ /dev/null @@ -1,149 +0,0 @@ -import { - Address, - beginCell, - Cell, - Contract, - contractAddress, - ContractProvider, - Sender, - SendMode, -} from '@ton/core' -import { crc32 } from 'zlib' -import { facilityId, errorCode } from '../utils' -import { contractCode } from '../codeLoader' -import { - codec, - createJettonClientData, - createTokenPoolData, - opcodes, - sendApplyChainUpdates, - sendReleaseOrMint, - sendUpdateCursedSubjects, - sendUpdateRampAccess, - type ChainUpdate, - type CrossChainAddress, - type JettonClientConfig, - type LockOrBurnInV1, - type LockOrBurnPayload, - type RampAccess, - type RateLimitConfig, - type ReleaseOrMintInV1, - type TokenPoolConfig, - type TokenPoolRateLimitConfigArgs, -} from './TokenPool' - -export const FACILITY_NAME = 'link.chain.ton.ccip.LockReleaseTokenPool' -export const FACILITY_ID = facilityId(crc32(FACILITY_NAME)) -export const ERROR_CODE = errorCode(crc32(FACILITY_NAME)) -export const CONTRACT_VERSION = '0.1.0' - -export type Config = TokenPoolConfig & { - jettonClient: JettonClientConfig -} - -export class LockReleaseTokenPool implements Contract { - constructor( - readonly address: Address, - readonly init?: { code: Cell; data: Cell }, - ) {} - - static createFromAddress(address: Address) { - return new LockReleaseTokenPool(address) - } - - static createFromConfig(config: Config, code: Cell, workchain = 0) { - const data = beginCell() - .storeRef(createTokenPoolData(config)) - .storeRef(createJettonClientData(config.jettonClient)) - .storeDict(null) - .endCell() - - const init = { code, data } - return new LockReleaseTokenPool(contractAddress(workchain, init), init) - } - - static code(): Promise { - return contractCode.ccip.local('ccip.pools.LockReleaseTokenPool') - } - - async sendDeploy(provider: ContractProvider, via: Sender, value: bigint) { - await provider.internal(via, { - value, - sendMode: SendMode.PAY_GAS_SEPARATELY, - body: Cell.EMPTY, - }) - } - - async sendApplyChainUpdates( - provider: ContractProvider, - via: Sender, - value: bigint, - body: { queryId: bigint; remove: bigint[]; add: ChainUpdate[] }, - ) { - await sendApplyChainUpdates(provider, via, value, body) - } - - async sendUpdateRampAccess( - provider: ContractProvider, - via: Sender, - value: bigint, - body: { queryId: bigint; updates: RampAccess[] }, - ) { - await sendUpdateRampAccess(provider, via, value, body) - } - - async sendUpdateCursedSubjects( - provider: ContractProvider, - via: Sender, - value: bigint, - body: { queryId: bigint; cursedSubjects: bigint[] }, - ) { - await sendUpdateCursedSubjects(provider, via, value, body) - } - - async sendReleaseOrMint( - provider: ContractProvider, - via: Sender, - value: bigint, - body: { - queryId: bigint - request: ReleaseOrMintInV1 - requestedFinalityConfig?: number - replyTo?: Address | null - }, - ) { - await sendReleaseOrMint(provider, via, value, body) - } - - async getHasPendingRelease(provider: ContractProvider, queryId: bigint) { - return provider - .get('hasPendingRelease', [{ type: 'int', value: queryId }]) - .then((res) => res.stack.readBoolean()) - } - - async getVerifyNotCursed(provider: ContractProvider, subject: bigint) { - return provider - .get('verifyNotCursed', [{ type: 'int', value: subject }]) - .then((res) => res.stack.readBoolean()) - } - - async getOnRamp(provider: ContractProvider, remoteChainSelector: bigint) { - return provider - .get('onRamp', [{ type: 'int', value: remoteChainSelector }]) - .then((res) => res.stack.readAddressOpt()) - } - - async getOffRamp(provider: ContractProvider, remoteChainSelector: bigint) { - return provider - .get('offRamp', [{ type: 'int', value: remoteChainSelector }]) - .then((res) => res.stack.readAddressOpt()) - } - - async getIsSupportedChain(provider: ContractProvider, remoteChainSelector: bigint) { - return provider - .get('isSupportedChain', [{ type: 'int', value: remoteChainSelector }]) - .then((res) => res.stack.readBoolean()) - } -} - -export { codec, opcodes } diff --git a/contracts/wrappers/ccip/TokenPool.ts b/contracts/wrappers/ccip/TokenPool.ts deleted file mode 100644 index e6dfd930c..000000000 --- a/contracts/wrappers/ccip/TokenPool.ts +++ /dev/null @@ -1,371 +0,0 @@ -import { - Address, - beginCell, - Builder, - Cell, - ContractProvider, - Dictionary, - Sender, - SendMode, - Slice, -} from '@ton/core' -import * as ownable2step from '../libraries/access/Ownable2Step' -import { asSnakedCell } from '../../src/utils' -import { - TokenPool_ApplyChainUpdates, - TokenPool_AddRemotePool, - TokenPool_RemoveRemotePool, - TokenPool_SetDynamicConfig, - TokenPool_SetAllowedFinalityConfig, - TokenPool_SetRateLimitConfig, - TokenPool_UpdateRampAccess, - TokenPool_ApplyTokenTransferFeeConfigUpdates, - TokenPool_UpdateCursedSubjects, - TokenPool_ReleaseOrMint, -} from '../gen/ccip/pools/TokenPool' -import { - TokenPool_ReleaseOrMintFailure, - TokenPool_ReleaseOrMintResponse, -} from '../gen/ccip/pools/LockReleaseTokenPool' - -export const opcodes = { - in: { - applyChainUpdates: TokenPool_ApplyChainUpdates.PREFIX, - addRemotePool: TokenPool_AddRemotePool.PREFIX, - removeRemotePool: TokenPool_RemoveRemotePool.PREFIX, - setDynamicConfig: TokenPool_SetDynamicConfig.PREFIX, - setAllowedFinalityConfig: TokenPool_SetAllowedFinalityConfig.PREFIX, - setRateLimitConfig: TokenPool_SetRateLimitConfig.PREFIX, - applyTokenTransferFeeConfigUpdates: TokenPool_ApplyTokenTransferFeeConfigUpdates.PREFIX, - updateRampAccess: TokenPool_UpdateRampAccess.PREFIX, - updateCursedSubjects: TokenPool_UpdateCursedSubjects.PREFIX, - releaseOrMint: TokenPool_ReleaseOrMint.PREFIX, - }, - payload: { - lockOrBurn: 0xfa7da444, - }, - out: { - lockOrBurnResponse: 0x6c060424, - releaseOrMintResponse: TokenPool_ReleaseOrMintResponse.PREFIX, - releaseOrMintFailure: TokenPool_ReleaseOrMintFailure.PREFIX, - }, -} - -export type CrossChainAddress = Cell - -export type JettonClientConfig = { - masterAddress: Address - jettonWalletCode: Cell -} - -export type TokenPoolConfig = { - owner: Address - token: Address - tokenDecimals: number - rmnProxy: Address - router: Address -} - -export type TokenPoolJettonConfig = TokenPoolConfig & { - jettonClient: JettonClientConfig -} - -export type RateLimitConfig = { - isEnabled: boolean - capacity: bigint - rate: bigint -} - -export type ChainUpdate = { - remoteChainSelector: bigint - remotePoolAddresses: CrossChainAddress[] - remoteTokenAddress: CrossChainAddress - outboundRateLimiterConfig: RateLimitConfig - inboundRateLimiterConfig: RateLimitConfig -} - -export type RampAccess = { - remoteChainSelector: bigint - onRamp: Address | null - offRamp: Address | null -} - -export type LockOrBurnInV1 = { - receiver: CrossChainAddress - remoteChainSelector: bigint - originalSender: Address - amount: bigint - localToken: Address -} - -export type LockOrBurnPayload = { - queryId: bigint - request: LockOrBurnInV1 - requestedFinalityConfig: number - tokenArgs: Cell | null - replyTo: Address | null -} - -export type ReleaseOrMintInV1 = { - originalSender: CrossChainAddress - remoteChainSelector: bigint - receiver: Address - sourceDenominatedAmount: bigint - localToken: Address - sourcePoolAddress: CrossChainAddress - sourcePoolData: Cell | null - offchainTokenData: Cell | null -} - -export type TokenPoolRateLimitConfigArgs = { - remoteChainSelector: bigint - fastFinality: boolean - outboundRateLimiterConfig: RateLimitConfig - inboundRateLimiterConfig: RateLimitConfig -} - -export const codec = { - crossChainAddressFromBuffer(data: Buffer): Cell { - return beginCell().storeUint(data.length, 8).storeBuffer(data).endCell() - }, - - rateLimitConfig: { - encode(data: RateLimitConfig): Builder { - return beginCell() - .storeBit(data.isEnabled) - .storeUint(data.capacity, 128) - .storeUint(data.rate, 128) - }, - }, - - lockOrBurnInV1: { - encode(data: LockOrBurnInV1): Builder { - return beginCell() - .storeRef(data.receiver) - .storeUint(data.remoteChainSelector, 64) - .storeAddress(data.originalSender) - .storeUint(data.amount, 256) - .storeAddress(data.localToken) - }, - }, - - releaseOrMintInV1: { - encode(data: ReleaseOrMintInV1): Builder { - return beginCell() - .storeRef(data.originalSender) - .storeUint(data.remoteChainSelector, 64) - .storeAddress(data.receiver) - .storeUint(data.sourceDenominatedAmount, 256) - .storeAddress(data.localToken) - .storeRef(data.sourcePoolAddress) - .storeMaybeRef(data.sourcePoolData) - .storeMaybeRef(data.offchainTokenData) - }, - }, - - lockOrBurnPayload: { - encode(data: LockOrBurnPayload): Builder { - return beginCell() - .storeUint(opcodes.payload.lockOrBurn, 32) - .storeUint(data.queryId, 64) - .storeRef(codec.lockOrBurnInV1.encode(data.request).endCell()) - .storeUint(data.requestedFinalityConfig, 32) - .storeMaybeRef(data.tokenArgs) - .storeAddress(data.replyTo) - }, - }, - - releaseOrMintResponse: { - load(src: Slice): { queryId: bigint; destinationAmount: bigint } { - const op = src.loadUint(32) - if (op !== opcodes.out.releaseOrMintResponse) { - throw new Error('Unexpected opcode: ' + op) - } - const queryId = src.loadUintBig(64) - const out = src.loadRef().beginParse() - return { - queryId, - destinationAmount: out.loadUintBig(256), - } - }, - }, - - releaseOrMintFailure: { - load(src: Slice): { queryId: bigint; errorCode: number } { - const op = src.loadUint(32) - if (op !== opcodes.out.releaseOrMintFailure) { - throw new Error('Unexpected opcode: ' + op) - } - return { - queryId: src.loadUintBig(64), - errorCode: src.loadUint(16), - } - }, - }, - - lockOrBurnResponse: { - load(src: Slice): { queryId: bigint; destinationAmount: bigint } { - const op = src.loadUint(32) - if (op !== opcodes.out.lockOrBurnResponse) { - throw new Error('Unexpected opcode: ' + op) - } - const queryId = src.loadUintBig(64) - const out = src.loadRef().beginParse() - return { - queryId, - destinationAmount: out.loadUintBig(256), - } - }, - }, -} - -export function createTokenPoolData(config: TokenPoolConfig): Cell { - const dynamicConfig = beginCell() - .storeAddress(config.router) - .storeAddress(null) - .storeAddress(null) - .endCell() - - const adminConfig = beginCell() - .storeRef( - ownable2step.builder.data.traitData - .encode({ - owner: config.owner, - pendingOwner: null, - }) - .asCell(), - ) - .storeAddress(config.rmnProxy) - .storeRef(dynamicConfig) - .storeUint(0, 32) - .endCell() - - return beginCell() - .storeRef(adminConfig) - .storeRef( - beginCell() - .storeDict(Dictionary.empty(Dictionary.Keys.BigUint(64), Dictionary.Values.Address())) - .storeDict(Dictionary.empty(Dictionary.Keys.BigUint(64), Dictionary.Values.Address())) - .storeDict(Dictionary.empty()) - .endCell(), - ) - .storeAddress(config.token) - .storeUint(config.tokenDecimals, 8) - .storeDict(Dictionary.empty(Dictionary.Keys.BigUint(64), Dictionary.Values.Cell())) - .storeDict(Dictionary.empty(Dictionary.Keys.BigUint(64), Dictionary.Values.Cell())) - .endCell() -} - -export function createJettonClientData(config: JettonClientConfig): Cell { - return beginCell().storeAddress(config.masterAddress).storeRef(config.jettonWalletCode).endCell() -} - -export async function sendApplyChainUpdates( - provider: ContractProvider, - via: Sender, - value: bigint, - body: { queryId: bigint; remove: bigint[]; add: ChainUpdate[] }, -) { - await provider.internal(via, { - value, - sendMode: SendMode.PAY_GAS_SEPARATELY, - body: beginCell() - .storeUint(opcodes.in.applyChainUpdates, 32) - .storeUint(body.queryId, 64) - .storeRef(asSnakeUint64(body.remove)) - .storeRef(asSnakeChainUpdates(body.add)) - .endCell(), - }) -} - -export async function sendUpdateRampAccess( - provider: ContractProvider, - via: Sender, - value: bigint, - body: { queryId: bigint; updates: RampAccess[] }, -) { - await provider.internal(via, { - value, - sendMode: SendMode.PAY_GAS_SEPARATELY, - body: beginCell() - .storeUint(opcodes.in.updateRampAccess, 32) - .storeUint(body.queryId, 64) - .storeRef(asSnakeRampAccess(body.updates)) - .endCell(), - }) -} - -export async function sendUpdateCursedSubjects( - provider: ContractProvider, - via: Sender, - value: bigint, - body: { queryId: bigint; cursedSubjects: bigint[] }, -) { - const dict = Dictionary.empty(Dictionary.Keys.BigInt(128), Dictionary.Values.Bool()) - body.cursedSubjects.forEach((subject) => dict.set(subject, true)) - await provider.internal(via, { - value, - sendMode: SendMode.PAY_GAS_SEPARATELY, - body: beginCell() - .storeUint(opcodes.in.updateCursedSubjects, 32) - .storeUint(body.queryId, 64) - .storeDict(dict) - .endCell(), - }) -} - -export async function sendReleaseOrMint( - provider: ContractProvider, - via: Sender, - value: bigint, - body: { - queryId: bigint - request: ReleaseOrMintInV1 - requestedFinalityConfig?: number - replyTo?: Address | null - }, -) { - await provider.internal(via, { - value, - sendMode: SendMode.PAY_GAS_SEPARATELY, - body: beginCell() - .storeUint(opcodes.in.releaseOrMint, 32) - .storeUint(body.queryId, 64) - .storeRef(codec.releaseOrMintInV1.encode(body.request).endCell()) - .storeUint(body.requestedFinalityConfig ?? 0, 32) - .storeAddress(body.replyTo ?? null) - .endCell(), - }) -} - -function asSnakeUint64(items: bigint[]): Cell { - return asSnakedCell(items, (item) => beginCell().storeUint(item, 64)) -} - -function asSnakeCrossChainAddresses(items: Cell[]): Cell { - return asSnakedCell(items, (item) => beginCell().storeSlice(item.beginParse())) -} - -function asSnakeChainUpdates(items: ChainUpdate[]): Cell { - return asSnakedCell(items, (item) => - beginCell() - .storeUint(item.remoteChainSelector, 64) - .storeRef(asSnakeCrossChainAddresses(item.remotePoolAddresses)) - .storeRef(item.remoteTokenAddress) - .storeRef( - beginCell() - .storeRef(codec.rateLimitConfig.encode(item.outboundRateLimiterConfig).endCell()) - .storeRef(codec.rateLimitConfig.encode(item.inboundRateLimiterConfig).endCell()) - .endCell(), - ), - ) -} - -function asSnakeRampAccess(items: RampAccess[]): Cell { - return asSnakedCell(items, (item) => - beginCell() - .storeUint(item.remoteChainSelector, 64) - .storeAddress(item.onRamp) - .storeAddress(item.offRamp), - ) -} From 07f97ebe93a8d6e63b6fbbf2609cb2fe3dbdf464 Mon Sep 17 00:00:00 2001 From: Kristijan Date: Thu, 11 Jun 2026 18:59:28 +0200 Subject: [PATCH 14/16] Polish applyChainUpdates fn --- .../contracts/ccip/pools/rate_limiter.tolk | 2 +- .../contracts/ccip/pools/token_pool.tolk | 70 +++++++++---------- .../ccip/pools/token_pool_contract.tolk | 2 +- contracts/contracts/ccip/pools/types.tolk | 4 +- .../gen/ccip/pools/BurnMintTokenPool.ts | 2 +- .../gen/ccip/pools/LockReleaseTokenPool.ts | 2 +- 6 files changed, 40 insertions(+), 42 deletions(-) diff --git a/contracts/contracts/ccip/pools/rate_limiter.tolk b/contracts/contracts/ccip/pools/rate_limiter.tolk index 8c88322e8..24a46fa57 100644 --- a/contracts/contracts/ccip/pools/rate_limiter.tolk +++ b/contracts/contracts/ccip/pools/rate_limiter.tolk @@ -25,7 +25,7 @@ struct RateLimiter_TokenBucket { rate: uint128 // ──────╯ Number of tokens per second that the bucket is refilled. } -fun RateLimiter_tokenBucketFromConfig(config: RateLimiter_Config): RateLimiter_TokenBucket { +fun RateLimiter_TokenBucket.fromConfig(config: RateLimiter_Config): RateLimiter_TokenBucket { return RateLimiter_TokenBucket { tokens: config.capacity, lastUpdated: blockchain.now(), diff --git a/contracts/contracts/ccip/pools/token_pool.tolk b/contracts/contracts/ccip/pools/token_pool.tolk index f2e415ade..a91786498 100644 --- a/contracts/contracts/ccip/pools/token_pool.tolk +++ b/contracts/contracts/ccip/pools/token_pool.tolk @@ -274,6 +274,12 @@ fun TokenPool.removeRemotePool( }); } +/// Sets the permissions for a list of chains selectors. Actual senders for these chains +/// need to be allowed on the Router to interact with this pool. +/// @param remoteChainSelectorsToRemove A list of chain selectors to remove. +/// @param chainsToAdd A list of chains and their new permission status & rate limits. Rate limits +/// are only used when the chain is being added through `allowed` being true. +/// @dev Only callable by the owner fun TokenPool.applyChainUpdates( mutate self, sender: address, @@ -288,48 +294,41 @@ fun TokenPool.applyChainUpdates( val deleted = self.data.remoteChainConfigs.delete(remoteChainSelector); assert(deleted, TokenPool_Error.NonExistentChain); - emit(TOKEN_POOL_CHAIN_REMOVED_TOPIC, TokenPool_ChainRemoved { - remoteChainSelector, - }); + emit(TOKEN_POOL_CHAIN_REMOVED_TOPIC, TokenPool_ChainRemoved { remoteChainSelector }); } var addIter = chainsToAdd.iter(); while (!addIter.empty()) { - val chainUpdate = addIter.next(); - val remoteChainSelector = chainUpdate.remoteChainSelector; - val remoteTokenAddress = chainUpdate.remoteTokenAddress; - var rateLimitConfigs = chainUpdate.rateLimitConfigs.load(); - val outboundRateLimiterConfig = rateLimitConfigs.outbound.load(); - val inboundRateLimiterConfig = rateLimitConfigs.inbound.load(); - + val newChain = addIter.next(); + val remoteTokenAddress = newChain.remoteTokenAddress; assert(!TokenPool_isEmptyCrossChainAddress(remoteTokenAddress), TokenPool_Error.ZeroAddressInvalid); + + val remoteChainSelector = newChain.remoteChainSelector; assert(!self.data.remoteChainConfigs.get(remoteChainSelector).isFound, TokenPool_Error.ChainAlreadyExists); - var remotePools: map> = createEmptyMap(); + val rlConfigDefault = RateLimiter_Config { + isEnabled: false, + capacity: 0, + rate: 0, + }; + + var rateLimitConfigs = newChain.rateLimitConfigs.load(); var config = TokenPool_RemoteChainConfig { remoteTokenAddress, - remotePools, + remotePools: createEmptyMap(), rateLimiters: TokenPool_RateLimiterPair { - outbound: RateLimiter_tokenBucketFromConfig(outboundRateLimiterConfig).toCell(), - inbound: RateLimiter_tokenBucketFromConfig(inboundRateLimiterConfig).toCell(), + outbound: RateLimiter_TokenBucket.fromConfig(rateLimitConfigs.outbound.load()).toCell(), + inbound: RateLimiter_TokenBucket.fromConfig(rateLimitConfigs.inbound.load()).toCell(), }.toCell(), fastFinalityRateLimiters: TokenPool_RateLimiterPair { - outbound: RateLimiter_tokenBucketFromConfig(RateLimiter_Config { - isEnabled: false, - capacity: 0, - rate: 0, - }).toCell(), - inbound: RateLimiter_tokenBucketFromConfig(RateLimiter_Config { - isEnabled: false, - capacity: 0, - rate: 0, - }).toCell(), + outbound: RateLimiter_TokenBucket.fromConfig(rlConfigDefault).toCell(), + inbound: RateLimiter_TokenBucket.fromConfig(rlConfigDefault).toCell(), }.toCell(), }; - var remotePoolAddressesIter = chainUpdate.remotePoolAddresses.iter(); - while (!remotePoolAddressesIter.empty()) { - val remotePoolAddress = remotePoolAddressesIter.next().toCell(); + var rpAddrIter = newChain.remotePoolAddresses.iter(); + while (!rpAddrIter.empty()) { + val remotePoolAddress = rpAddrIter.next().toCell(); self._setRemotePool(mutate config, remotePoolAddress); emit(TOKEN_POOL_REMOTE_POOL_ADDED_TOPIC, TokenPool_RemotePoolAdded { @@ -338,13 +337,15 @@ fun TokenPool.applyChainUpdates( }); } + self.data.remoteChainConfigs.set(remoteChainSelector, config); + emit(TOKEN_POOL_CHAIN_ADDED_TOPIC, TokenPool_ChainAdded { remoteChainSelector, remoteTokenAddress, }); - - self.data.remoteChainConfigs.set(remoteChainSelector, config); } + + // TODO: reply back to sender with excess } fun TokenPool.applyRampAccessUpdates( @@ -404,8 +405,7 @@ fun TokenPool.setCursedSubjects( mirroredPolicy.cursedSubjects = cursedSubjects; self.data.mirroredPolicy = mirroredPolicy.toCell(); - emit(TOKEN_POOL_CURSED_SUBJECTS_UPDATED_TOPIC, TokenPool_CursedSubjectsUpdated {}); -} + emit(TOKEN_POOL_CURSED_SUBJECTS_UPDATED_TOPIC, TokenPool_CursedSubjectsUpdated {})} fun TokenPool.onInternalMessage(mutate self, msgSender: address, msgValue: coins, msgBody: slice): bool { val msg = lazy TokenPool_InMessage.fromSlice(msgBody); @@ -937,14 +937,14 @@ fun TokenPool.setRateLimitConfig( if (update.fastFinality) { var fastRateLimiters = config.fastFinalityRateLimiters.load(); // TODO: use setter RateLimiter._setTokenBucketConfig - fastRateLimiters.outbound = RateLimiter_tokenBucketFromConfig(update.outboundRateLimiterConfig.load()).toCell(); - fastRateLimiters.inbound = RateLimiter_tokenBucketFromConfig(update.inboundRateLimiterConfig.load()).toCell(); + fastRateLimiters.outbound = RateLimiter_TokenBucket.fromConfig(update.outboundRateLimiterConfig.load()).toCell(); + fastRateLimiters.inbound = RateLimiter_TokenBucket.fromConfig(update.inboundRateLimiterConfig.load()).toCell(); config.fastFinalityRateLimiters = fastRateLimiters.toCell(); } else { var rateLimiters = config.rateLimiters.load(); // TODO: use setter RateLimiter._setTokenBucketConfig - rateLimiters.outbound = RateLimiter_tokenBucketFromConfig(update.outboundRateLimiterConfig.load()).toCell(); - rateLimiters.inbound = RateLimiter_tokenBucketFromConfig(update.inboundRateLimiterConfig.load()).toCell(); + rateLimiters.outbound = RateLimiter_TokenBucket.fromConfig(update.outboundRateLimiterConfig.load()).toCell(); + rateLimiters.inbound = RateLimiter_TokenBucket.fromConfig(update.inboundRateLimiterConfig.load()).toCell(); config.rateLimiters = rateLimiters.toCell(); } self.data.remoteChainConfigs.set(update.remoteChainSelector, config); diff --git a/contracts/contracts/ccip/pools/token_pool_contract.tolk b/contracts/contracts/ccip/pools/token_pool_contract.tolk index 43246aa77..eb965d7be 100644 --- a/contracts/contracts/ccip/pools/token_pool_contract.tolk +++ b/contracts/contracts/ccip/pools/token_pool_contract.tolk @@ -22,7 +22,7 @@ contract TokenPool { | TokenPool_ReleaseOrMintResponse } -fun onInternalMessage(in: InMessage) { +fun onInternalMessage(_: InMessage) { throw 0xFFFF; // template for bindings, should not be deployed } diff --git a/contracts/contracts/ccip/pools/types.tolk b/contracts/contracts/ccip/pools/types.tolk index ae249d139..211f7025b 100644 --- a/contracts/contracts/ccip/pools/types.tolk +++ b/contracts/contracts/ccip/pools/types.tolk @@ -62,9 +62,7 @@ struct TokenPool_RemoteChainConfig { // TODO: EnumerableSet.Bytes32Set remotePools; remotePools: map>; // Set of remote pool hashes, ABI encoded in the case of a remote EVM chain. rateLimiters: Cell; // Rate limiter configs. - - // TODO: N/A in EVM RemoteChainConfig - fastFinalityRateLimiters: Cell; + fastFinalityRateLimiters: Cell; // Rate limiter configs for fast finality transfers. } struct TokenPool_RateLimitConfigArgs { diff --git a/contracts/wrappers/gen/ccip/pools/BurnMintTokenPool.ts b/contracts/wrappers/gen/ccip/pools/BurnMintTokenPool.ts index bc3f37ae4..0a1647e62 100644 --- a/contracts/wrappers/gen/ccip/pools/BurnMintTokenPool.ts +++ b/contracts/wrappers/gen/ccip/pools/BurnMintTokenPool.ts @@ -2908,7 +2908,7 @@ function calculateDeployedAddress(code: c.Cell, data: c.Cell, options: DeployedA } export class BurnMintTokenPool implements c.Contract { - static CodeCell = c.Cell.fromBase64('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'); + static CodeCell = c.Cell.fromBase64('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'); static Errors = { 'Common_Error.CrossChainAddressOutOfRange': 5, diff --git a/contracts/wrappers/gen/ccip/pools/LockReleaseTokenPool.ts b/contracts/wrappers/gen/ccip/pools/LockReleaseTokenPool.ts index b77ef77a7..e153d29e0 100644 --- a/contracts/wrappers/gen/ccip/pools/LockReleaseTokenPool.ts +++ b/contracts/wrappers/gen/ccip/pools/LockReleaseTokenPool.ts @@ -2659,7 +2659,7 @@ function calculateDeployedAddress(code: c.Cell, data: c.Cell, options: DeployedA } export class LockReleaseTokenPool implements c.Contract { - static CodeCell = c.Cell.fromBase64('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'); + static CodeCell = c.Cell.fromBase64('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'); static Errors = { 'Common_Error.CrossChainAddressOutOfRange': 5, From 454b78c4e05865cf1daff8c4c77a958cf794e8cc Mon Sep 17 00:00:00 2001 From: Kristijan Date: Thu, 11 Jun 2026 19:22:29 +0200 Subject: [PATCH 15/16] Move pow10(n) to math.tolk --- .../contracts/ccip/pools/rate_limiter.tolk | 13 --------- .../contracts/ccip/pools/token_pool.tolk | 28 ++++--------------- contracts/contracts/ccip/pools/types.tolk | 3 -- contracts/contracts/lib/math.tolk | 23 +++++++++++++++ .../gen/ccip/pools/BurnMintTokenPool.ts | 2 +- .../gen/ccip/pools/LockReleaseTokenPool.ts | 2 +- 6 files changed, 30 insertions(+), 41 deletions(-) diff --git a/contracts/contracts/ccip/pools/rate_limiter.tolk b/contracts/contracts/ccip/pools/rate_limiter.tolk index 24a46fa57..b14ccfadf 100644 --- a/contracts/contracts/ccip/pools/rate_limiter.tolk +++ b/contracts/contracts/ccip/pools/rate_limiter.tolk @@ -35,19 +35,6 @@ fun RateLimiter_TokenBucket.fromConfig(config: RateLimiter_Config): RateLimiter_ }; } -fun RateLimiter_rateLimitConfigFromCell(data: cell): RateLimiter_Config { - var cs = data.beginParse(); - val isEnabled = cs.loadUint(1) != 0; - val capacity = cs.loadUint(128); - val rate = cs.loadUint(128); - cs.assertEnd(); - return RateLimiter_Config { - isEnabled, - capacity, - rate, - }; -} - /// @notice _consume removes the given tokens from the pool, lowering the rate tokens allowed to be /// consumed for subsequent calls. /// @param requestTokens The total tokens to be consumed from the bucket. diff --git a/contracts/contracts/ccip/pools/token_pool.tolk b/contracts/contracts/ccip/pools/token_pool.tolk index a91786498..1746af39b 100644 --- a/contracts/contracts/ccip/pools/token_pool.tolk +++ b/contracts/contracts/ccip/pools/token_pool.tolk @@ -1,6 +1,7 @@ // SPDX-License-Identifier: BUSL-1.1 import "@stdlib/lisp-lists" +import "../../lib/math" import "../../lib/utils" import "../../lib/jetton/messages.tolk" import "../../lib/access/ownable_2step.tolk" @@ -690,7 +691,7 @@ fun TokenPool.parseRemoteDecimals(self, sourcePoolData: cell?): uint8 { assert(s.remainingBitsCount() == 256 && s.remainingRefsCount() == 0, TokenPool_Error.InvalidRemoteChainDecimals); val remoteDecimals = s.loadUint(256); s.assertEnd(); - assert(remoteDecimals <= TOKEN_POOL_MAX_UINT8, TokenPool_Error.InvalidRemoteChainDecimals); + assert(remoteDecimals <= MAX_UINT8, TokenPool_Error.InvalidRemoteChainDecimals); return remoteDecimals as uint8; } @@ -711,7 +712,7 @@ fun TokenPool.calculateLocalAmount(self, remoteAmount: uint256, remoteDecimal if (remoteDecimals > self.data.tokenDecimals) { val decimalsDiff = remoteDecimals - self.data.tokenDecimals; // This is a safety check to prevent overflow in the next calculation. - assert(decimalsDiff <= TOKEN_POOL_MAX_EXP10, TokenPool_Error.OverflowDetected); + assert(decimalsDiff <= MAX_EXP10, TokenPool_Error.OverflowDetected); return remoteAmount / pow10(decimalsDiff); } @@ -720,9 +721,9 @@ fun TokenPool.calculateLocalAmount(self, remoteAmount: uint256, remoteDecimal // More than 77 would never fit in a uint256 and would cause an overflow. // We also check if the resulting amount would overflow. val decimalsDiff = self.data.tokenDecimals - remoteDecimals; - assert(decimalsDiff <= TOKEN_POOL_MAX_EXP10, TokenPool_Error.OverflowDetected); + assert(decimalsDiff <= MAX_EXP10, TokenPool_Error.OverflowDetected); val scale = pow10(decimalsDiff); - assert(scale == 0 || remoteAmount <= TOKEN_POOL_MAX_UINT256 / scale, TokenPool_Error.OverflowDetected); + assert(scale == 0 || remoteAmount <= MAX_UINT256 / scale, TokenPool_Error.OverflowDetected); return remoteAmount * scale; } @@ -1005,22 +1006,3 @@ fun TokenPool_boxCrossChainAddress(addressBytes: CrossChainAddress): Cell; } - -// TODO: move to common utils library -// @dev Calculates 10^n for n <= 77 in O(log n). For n > 77, it would overflow uint256. -fun pow10(n: uint8): uint256 { - var result: uint256 = 1; - var base: uint256 = 10; - - while (n > 0) { - if ((n & 1) == 1) { - // Check for potential overflow before multiplication - assert(result == 0 || base <= TOKEN_POOL_MAX_UINT256 / result, TokenPool_Error.OverflowDetected); - result *= base; - } - base *= base; - n >>= 1; - } - - return result; -} diff --git a/contracts/contracts/ccip/pools/types.tolk b/contracts/contracts/ccip/pools/types.tolk index 211f7025b..308863f49 100644 --- a/contracts/contracts/ccip/pools/types.tolk +++ b/contracts/contracts/ccip/pools/types.tolk @@ -9,9 +9,6 @@ const TOKEN_POOL_WAIT_FOR_FINALITY_FLAG: uint32 = 0; const TOKEN_POOL_DEFAULT_FINALITY: uint32 = TOKEN_POOL_WAIT_FOR_FINALITY_FLAG; /// The division factor for bps. This also represents the maximum bps fee. const TOKEN_POOL_BPS_DIVIDER: uint256 = 10000; -const TOKEN_POOL_MAX_UINT8: uint8 = 0xFF; // 255 -const TOKEN_POOL_MAX_UINT256: uint256 = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; -const TOKEN_POOL_MAX_EXP10: uint8 = 77; // The number of bytes in the return data for a pool v1 releaseOrMint call. // This should match the size of the ReleaseOrMintOutV1 struct. diff --git a/contracts/contracts/lib/math.tolk b/contracts/contracts/lib/math.tolk index a53a897f3..00c3f36e4 100644 --- a/contracts/contracts/lib/math.tolk +++ b/contracts/contracts/lib/math.tolk @@ -26,6 +26,11 @@ const INT_MIN: int = -(1 << 255) - (1 << 255); // 2^(15×8) - 1 = 2^120 - 1 const COIN_MAX: int = (1 << 120) - 1; +const MAX_UINT8: uint8 = 0xFF; // 255 +const MAX_UINT256: uint256 = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; + +const MAX_EXP10: uint8 = 77; + // Returns (result, errorCode), where errorCode is 0 if no error. fun safeAdd(a: int, b: int): (int, int) { // Check for positive overflow: a > INT_MAX - b @@ -114,3 +119,21 @@ fun mustCastToCoin(value: int, errCode: int): coins { } return value; } + +// @dev Calculates 10^n for n <= 77 in O(log n). For n > 77, it would overflow uint256. +fun pow10(n: uint8): uint256 { + var result: uint256 = 1; + var base: uint256 = 10; + + while (n > 0) { + if ((n & 1) == 1) { + // Check for potential overflow before multiplication + assert(result == 0 || base <= MAX_UINT256 / result, 4); // exit code 4: Integer overflow + result *= base; + } + base *= base; + n >>= 1; + } + + return result; +} diff --git a/contracts/wrappers/gen/ccip/pools/BurnMintTokenPool.ts b/contracts/wrappers/gen/ccip/pools/BurnMintTokenPool.ts index 0a1647e62..41686195b 100644 --- a/contracts/wrappers/gen/ccip/pools/BurnMintTokenPool.ts +++ b/contracts/wrappers/gen/ccip/pools/BurnMintTokenPool.ts @@ -2908,7 +2908,7 @@ function calculateDeployedAddress(code: c.Cell, data: c.Cell, options: DeployedA } export class BurnMintTokenPool implements c.Contract { - static CodeCell = c.Cell.fromBase64('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'); + static CodeCell = c.Cell.fromBase64('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'); static Errors = { 'Common_Error.CrossChainAddressOutOfRange': 5, diff --git a/contracts/wrappers/gen/ccip/pools/LockReleaseTokenPool.ts b/contracts/wrappers/gen/ccip/pools/LockReleaseTokenPool.ts index e153d29e0..ce319c550 100644 --- a/contracts/wrappers/gen/ccip/pools/LockReleaseTokenPool.ts +++ b/contracts/wrappers/gen/ccip/pools/LockReleaseTokenPool.ts @@ -2659,7 +2659,7 @@ function calculateDeployedAddress(code: c.Cell, data: c.Cell, options: DeployedA } export class LockReleaseTokenPool implements c.Contract { - static CodeCell = c.Cell.fromBase64('te6ccgECZwEAFZoAART/APSkE/S88sgLAQIBYgIDAgLMBAUCASAGBwIBIBobAgEgODkCASAICQIBIBQVAgEgCgsCASAQEQIBIAwNADu1tR2omhqahj6Ahjo6GoY6hj9JBjpg/oCGPoCGOjACAWoODwBpsFfjQobGluay5jaGFpbi50b24uY2NpcC5Mb2NrUmVsZWFzZVRva2VuUG9vbIItTAuMS4wiAAaaV12omhqahj6Ahjo6GoY6n0kGOmDmPoCGPoCGOjoegIY+gJ6AhjowCB6BzfQyf0kaMkYNvFADmnI9qJoamoY+gIY6OhqGOoY/SRpg5j6Ahj6AhjowBftKO9qJoamoY+gIY6Ohqahj9JBjpg5j6Ahj6Ahjo6Gp9JBjqGOmPmOjofSR9KBjowAgN7YBITAF2jr7UTQ1NQx9AQx0dDU1DH6SDHTBzH0BDH0BDHR0NT6SDHUMdMfMdHQ+kgx+lDRgBpohu1E0NTUMfQEMdHQ1DHU+kgx0wcx9AQx9AQx0dD0BPQEMfQEMdGAQPQOb6GT+kjRkjBt4oAUbg+3tRNDU1DH0BDHR0NTUMfpIMdMHMfQEMfQEMdHQ1DH6SNQx0x8x0YAgFYFhcAV7Lge1E0NTUMfQEMdHQ1DHU+kgx0wcx9AQx9AQx0dD0BDH0BDH0BNEB8AOzgAgFYGBkASKhx7UTQ1NQx9AQx0dDUMdQx+kgx0wcx9AT0BDHRgED0Dm+hMQAmqqjtRNDUMdQx9ATRgED0Dm+hMQIBIBwdAgEgMjMCASAeHwBXUhbpJbcOCCaQAAAAAAAAAAAAAAAAAAASKDBvQOb6Exklt/4AGDBvQOb6ExgE0z4keMC7UTQ1NT0BNEi0NTU+kjTB/QE9ATRgQCFbW1tbW1tbZLwCACBAIZWElYSVhL4kviXEE4QPRAsEEsQOhApEEgQNxAmEEUQNBAjVhjwCT1fCQPjAl8JI9csI5sWhOTjAtcsJqmTttyAgISIjAak7aLt+9csJ5Db7QyORNcsJ88U8lSUW3DbMeGCAMKKI26z8vQhggDCigTHBRPy9CBtA9cLP4sCAcjLPxX6UhL6UsnIz4cgFM5xzwthE8zJcPsA4w1/gMQH20x8x1ywgfFP1LI7s7UTQ1NT0BNED1ws/+JIi0PpI1NGBZsP4KMjPhAL6UhP6UskByM+E0MzM+RbIz4oAQMv/z1ASxwXy9FMDgED0Dm+hgWbBAfL01NHQ+lDUMdQx+kgx0VIVgED0WzAkbpI0MOMOAcjMzPQAye1U4PI/JABOOzvDAJI2NpY4OBBXEEbiA8jMEsz6UssHEvQA9ADJyMwSzPQAye1UAfw0A9M/MfoA+lD4kiTQ+kjU0YFmvPgoyM+EAvpSE/pSyQHIz4TQzMz5FsjPigBAy//PUBLHBfL09AQhbpgxIMcAkjBt4JLR0OKBZr4hbrPy9NcsJ9PtIiTyv9M/1NMf9AT6UNED0NTTP/pI0//6SNEhgWa/DLob8vSBZr0pbrMlARbjAl8EhA8BxwDy9C0ASIIImJaAyM+FiBb6UlAF+gKCEO8Ms27PC4rLP8+Jmw7JgEH7AAL68vQr0NTU+kjTB/QE9ATRgQCFbW1tbW1tbZLwCACBAIZWGlYdgTo9VhBWHccF8vSBOjlWFS+AQPQOb6Ex8vSBOjpWEdD0BDH0BDH0BNFWFvADs/L0KG6zmlYdVHIcVhgt2lDeVhDQ9AT0BDH0BDHRVhUBgED0Dm+hkjBt4w1aJgT+gTo+IW6z8vSBOj4BVhzHBfL0Km6znVYdVHIcVh5WGVYQ2mDeVhFWEVYRVhFWEVYRViNTh1YUVhRWFFYUVhRWFFYUVhRWFFYUVihWKFYoVihWMlYv8A5sMzMzNDQ0U7KhM1YQ4w8mbrPjADE1OVs3ODg4PYE6OFNFgED0Dm+hEicoKSoB7irQ1DH6SDHUMdMf0VYRAfAGgTo4U+eAQPQOb6ES8vTU9ATU1NEg0NTU0QHQ03/TP9IA03/Tf9EijixfBgHQ1NTRAdDTf9M/0gDTf9N/0StWEvAEBMjLfxPLP8oAy3/Lf8nIzMzJAeMNA8jMEvQAzMxUIOiAQPRDKwCagTo4U+eAQPQOb6ES8vTU9ATU1NEB0NTU0QHQ03/TP9IA03/Tf9ErVhLwBATIy38Tyz/KAMt/y3/JyMzMyQPIzBL0ABLMzFQg6IBA9EMAMFYWVHJFVhJWElYSVhJWHFYZVhktVhLawAH+8vTU9AQx1DHUMdEmyMv/yQLIzB7MF/pSFcsHE/QAEvQAyQfI+lIW+lIhzwv/ycjPjxgABIIQN91vbs8L93DPC2EWyz8VzMlw+wAhbpNfBDKOKoIImJaAB8jMzMnIz4WIEvpSUAb6AoIQbAYEJM8Liss/FMwTy//JgEH7AOIByCwAMmwWK1YS8AQEyMt/E8s/ygDLf8t/ycjMzMkADszM9ADJ7VQD/jQD1ws/+JJTFIBA9A5voYFmwQHy9NTR0PpQ1NT6SNEEgWbCBccFFPL0UjeAQPRbMAbQ1DHTP/pI0/8x+kjUMfQEMfQEMdEk0NP/0fgoyPpSE/pSyQHI+lISy//MycjPjxgABIIQ6cAMl88L93DPC2ESyz/MyXD7ACBu4w8ByMwuLzAABF8DAEKCCJiWgMjPhYgS+lIB+gKCEHjcIjLPC4oSyz/MyYBB+wAADMz0AMntVABmbBLTP/pIMIIAwohRNMcFE/L0ggDCiVMjxwWz8vQhiwLIz4cgznDPC2ESyz8S+lLJcPsAAgEgNDUCASA2NwCrDAjs5F/lSDAAMMA4pEw4CL4IyahII4YNlNgvJWBZrzy8OBRUqgWoFJA8AUF+CMFkTDiIbmVgWa98vDgU1C5jhEVXwUglYFmvvLw4TCBZr7y8OAVoQSAADRcuZEw4DGAAKQhkVvhgTpGIZQCusMAk2whcOLy9IABPHF6kyLCAI4cInGwwAGfgTpChP8jqQQivvL0ZqgB3iCoAqsAAugwMYAIBIDo7AgEgY2QCASA8PQIBIGFiAfcMTI7OzyBOkUNwwAd8vSBZsBTrYBA9A5voTGz8vQt0PpI1NFTUcjPhAIS+lL6UskhyM+E0MzM+RbIz4oAQMv/z1AIyMwXyz9SUPpSFMv/EvpSzBr0ABj0AMkFyMv/yQPI+lQVzBLM+lLJVCA3gED0F4IK+vCAcfgo+CjIgPgRJDEg1ywit7npvOMC1ywgvhIW5OMC1ywiE1xmJOMC1ywmu4lAhIEBBQkMBponPFvpSGPpSyVAEyM+E0MzM+RbIz4oAQMv/z1BtiwTIz5A+KfqWF8s/UAn6Ahb6Uhb6VBb0AM+EIBLOycjPhYgT+lJQA/oCcc8LaszJAfsAgQCFPwACAAHsMdTXTFYV0NT6SDHUMdMfMdHQ+kj6UDHRA4IAwogExwUT8vTQlCDHALOOPyDXSwGRMJuBNLwBwAHy9NdM0OLTP1IQERKAQPRbgTo4AfL0yM+PGAAEghAnkIKLzwv3cM8LYRLLP8lw+wAREOgw0JQgxwCziugwf0QB/jHTPzHTP9dMVhXQ1PpIMdQx0x8x0dD6SPpQMdEDggDCiATHBRPy9IE6OCFWEoBA9A5voTHy9IE6OCFWEoBA9A5voRLy9NT0BNTU0YE6NybQ0wchwUHyhQGqAtcY0ddJwwDy9CXQ0wchwUHyhQGqAtcY0cjOcfkEA4E6P1MUgwdIAv4x0z8x0z/XTFYV0NT6SDHUMdMfMdHQ+kj6UDHRA4IAwogExwUT8vSBOjghVhKAQPQOb6Ex8vSBOjghVhKAQPQOb6ES8vTU9ATU1NEl0NMHIcFB8oUBqgLXGNHIznH5BANQA4MH9FuBOkAB8vQDyMwT9AASzMxREBESgED0Q8iJSUoE/I5oMdM/MfpI+lD6UDARFtDU+kjUMdMf0SLQ+kj6UDHRBoIAwogHxwUW8vQjyPpSUjD6VFYYAfpUyQLIzPpSzBPLH8kByPpSEvpUAREUAfpUycjPjxgABIIQtzXjDM8L93HPC2HMyXD7AH/g1ywh4oUc3OMC1ywifxaTZOMCiUtMTU4B/iDXSwGRMJuBNLwBwAHy9NdM0OLTP9TU1IE6NyPQ0wchwUHyhQGqAtcY0ddJwwDy9IE6OyVWFYBA9A5voTGz8vQB0NTU0W0C0NIA03/Tf9H4IyLIy3/LPxPKAMt/y3/JAdDSANN/03/R+CMiyMt/yz8TygDLf8t/yQHIzMzJ+CNFAcJwyMt/yz9wzwuAcM8Lf8n4I3DIy3/LP3DPC4Bwzwt/yQHIzMzJJAbQlCDHALOK6DAFyMwS9ADME8xSMhETgED0Q8jPjxgABIIQ7TfEvM8L93DPC2ETyz8BEREBzMlw+wAPRgH+INdLAZEwm4E0vAHAAfL010zQ4tMHIcFB8oUBqgLXGMgi10kgqTgC8kWrAiDBQfKFzwsHEs7JgTo3IdDTByHBQfKFAaoC1xjR10nDAPL0INDTByHBQfKFAaoC1xjRyM5x+QQDgTo/UxaDB/QOb6Exs/L0VEEWgwf0F8jPjxgABEcALoIQvw0ats8L93DPC2Epzws/FczJcPsAAH70Dm+hMbPy9FRGFIMH9BcDyMwT9AASzMxREBESgED0Q8jPjxgABIIQvw0ats8L93DPC2EBEREByz/MyXD7AH8ABcYAAQA2zxaCELwUx+jPC/dwzwthARERAcs/zMlw+wB/AJ4x0z8x1wsfERTQ1PpI1NMfMdEi0PpI+lAx0QSCAMKIBccFFPL0VhUCyMz6UhLMyx/JyM+PGAAEghBCanE7zwv3cM8LYQERFAHLH8lw+wB/AZQx10xWFAFWFAFWFAFWFAFWFAFWFAFWFAFWFAFWFAFWFAFWFAFWFAFWFAFWFAFWFAFWFAFWFAFWFAFWFAERFPAK0JQgxwCziugwf08ACDCh0fcE4tcnjtMx1NdMVhXQ1PpIMdQx0x8x0dD6SPpQMdEDggDCiATHBRPy9NCUIMcAs4roMNCUIMcAs44cINdLAZEwm4E0vAHAAfL010zQ4tM/D4BA9FswDugwf+DXLCcYOyX04wLXLCTJTbIU4wLXLCFkg3W8UlNUVQL+INdLAZEwm4E0vAHAAfL010zQ4tM/0gDU1IE6OCVWFYBA9A5voRLy9NT0BNTU0QeOP9DUMdQx0QTQ0gDTf9N/0fgjIsjLf8s/E8oAy3/Lf8kD0NIA03/Tf9H4IyLIy3/LPxPKAMt/y3/JA8jME8zJBOMNAsjME/QAE8wSzFkREVBRAH4G0NQx1DHRBNDSANN/03/R+CMiyMt/yz8TygDLf8t/yQPQ0gDTf9N/0fgjIsjLf8s/E8oAy3/Lf8kDyMwTzMkACoBA9EMPAN4g10sBkTCbgTS8AcAB8vTXTNDi0z/SANP/0//TH9Mf0w/TD4E6OClWGoBA9A5voTHy9IE6NSjy9IE6NCOBJxC58vSBOjQigScQufL0gTo1JcIA8vQHyMoAFsv/FMv/Essfyx/LD8sPWRERgED0Qw8BrDHXTBEU0NT6SNTTH9ED0PpI+lDRggDCiFFixwUW8vTI+lIU+lTJyMz6UhLMyx/JERLQ9AT0BPQE0REV0JQgxwCziugwAcj0APQAARETAfQAyRERERJ/VgB6MdM/MfpIMBEU0NT6SDHU0x/RItD6SPpQMdEEggDCiAXHBRTy9AHIzAERFQH6UgERFAHMARETAcsfyRESfwP8jk4x0z8x9AWBOj5WFdDUMfpI1DHTHzHRE8cFEvL0ERLQ9AT0BPQEMdEByPQA9AABERIB9ADJyM+PGAAEghAnXgI0zwv3cM8LYclw+wAREX/g1ywhqPu/HOMC1ywjmxaE5DGSW3DgVhTQ1PpI1NMf0QPQ+kj6UNFBBiXwAeMCV1hZANQg10sBkTCbgTS8AcAB8vTXTNDi0z/6UPpQIm6XUjaAQPRbMJsiyPpSVCBHgED0Q+IhbpdSNYBA9FswmyHI+lJUIEaAQPRD4gPIyz8S+lT6VMnIz48YAASCEJxau5XPC/dxzwthzMlw+wBYAvox0z/U0x/6UDAi0NTTP/pI0//6SNT0BPQE0YE6PVYeJccF8vSBOjknVh2AQPQOb6Ex8vSBOjpWH9D0BDH0BDH0BNEo8AOz8vQtwwCWVhNus8MAkXDinVYZVhlWGVYZKlYY2lDeVh7Q9AQx9AT0BDHRUnCAQPQOb6GSMG3jDVpbAD40VxcRFsj6UhL6VMnIzAERFQH6UswBERMByx/JERJ/AAwQRV8FxwAABvpI0QH8gTo+IW6z8vSBOj5RHscF8vQtwwCWVhRus8MAkXDin1YZVhlWGVYZVhArVhraYN6BOkBWIFYgViBWIFYgViBWIFYgViBWIFYgViBWIFYgViBWIFYgViBWIFYaVhfwC/L0Vh9WH1YfVh9WH1YfVh9WH1YfVh9WH1YfVh9WH1YfXAP8Vh9WH1YfVh9WFPAMViABViABViABViABViABViABViABViABViABViABViABViABViABViABViABViABViABViABViABVhgB8A0qwwAr4w8vwwCWVhNus8MAkXDijhdWG1YbVhtWG1R9y1R9y1R9y1YYViHa4N5TsYE6RVYSXV5fAfBWIdDUMfpIMdQx0x/RUsDwBoE6OClWH4BA9A5voRLy9NT0BNTU0SDQ1NTR0NN/0z/SANN/03/RIo4sXwYB0NTU0dDTf9M/0gDTf9N/0SpWKfAEBMjLfxPLP8oAy3/Lf8kByMzMyQHjDQPIzBL0AMzMUpIRH4BA9ENgAJ6BOjgpVh+AQPQOb6ES8vTU9ATU1NEB0NTU0dDTf9M/0gDTf9N/0SpWKfAEBMjLfxPLP8oAy3/Lf8kByMzMyQPIzBL0ABLMzFKSER+AQPRDAG7DAJZWE26zwwCRcOLy9BEUER0RFBETERwRExESERsREhERERoREQIRH1ADVhuAFXTbOBA8S6l/ADRsFipWKfAEBMjLfxPLP8oAy3/Lf8kByMzMyQB5FcQXw9sIQHQ1PpIMdTTHzHRAdD6SPpQMdEixwWRW+DQ+kgx+lD6UDHRgTo+IW6zlQLHBcMAk2whcOLy9IABzFcRVxFfDjMzAYBA9A5voZJbcOHUMfQE1DHUMdEB0NMHIcFB8oUBqgLXGNHIznH5BAMBgwf0Dm+hMYAIBIGVmAH9DEybMMzM2xENFqAQPQOb6GTXwNw4dIA0/8x0/8x0x8x0x8x0w/TD9ECk18EcOEDlzKogScQqQTgMKiBJxCpBIAF8VxFfD2wiIW6RMeAw0IE6QSHXSYMHupch10rAAMMAkXDi8vTT/9GBOkEhhAe78vSAAgxXE1cRXw8zUxK6kmwh4FMSvJ4CoYE6QiHBTvL08AepBOACooE6QiHBTvL08AeBOkIhmYT/IqkEI77DAJF/4vL0qIA=='); + static CodeCell = c.Cell.fromBase64('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'); static Errors = { 'Common_Error.CrossChainAddressOutOfRange': 5, From 51c799ef25326d17dad6ef94b28232f42883229c Mon Sep 17 00:00:00 2001 From: Kristijan Date: Fri, 12 Jun 2026 12:43:51 +0200 Subject: [PATCH 16/16] TokePool share flow structure - init --- contracts/contracts/ccip/common/messages.tolk | 9 -- .../pools/burn_mint_token_pool/contract.tolk | 51 +++---- .../pools/burn_mint_token_pool/errors.tolk | 3 - .../pools/burn_mint_token_pool/messages.tolk | 3 +- .../pools/burn_mint_token_pool/storage.tolk | 6 +- .../pools/burn_mint_token_pool/types.tolk | 2 +- contracts/contracts/ccip/pools/errors.tolk | 3 + .../lock_release_token_pool/contract.tolk | 52 +++---- .../pools/lock_release_token_pool/errors.tolk | 5 +- .../lock_release_token_pool/messages.tolk | 3 +- .../lock_release_token_pool/storage.tolk | 6 +- .../pools/lock_release_token_pool/types.tolk | 2 +- contracts/contracts/ccip/pools/messages.tolk | 2 +- .../contracts/ccip/pools/token_pool.tolk | 132 ++++++++++++++++-- .../gen/ccip/pools/BurnMintTokenPool.ts | 21 ++- .../gen/ccip/pools/LockReleaseTokenPool.ts | 48 ++++--- 16 files changed, 214 insertions(+), 134 deletions(-) delete mode 100644 contracts/contracts/ccip/common/messages.tolk diff --git a/contracts/contracts/ccip/common/messages.tolk b/contracts/contracts/ccip/common/messages.tolk deleted file mode 100644 index 03a448bc8..000000000 --- a/contracts/contracts/ccip/common/messages.tolk +++ /dev/null @@ -1,9 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 - -// nolint:opcode -struct (0x7362d09c) Common_JettonTransferNotification { - queryId: uint64; - amount: coins; - sender: address; - forwardPayload: cell?; // could also be RemainingBitsAndRefs -} diff --git a/contracts/contracts/ccip/pools/burn_mint_token_pool/contract.tolk b/contracts/contracts/ccip/pools/burn_mint_token_pool/contract.tolk index 24a498341..4b08816fb 100644 --- a/contracts/contracts/ccip/pools/burn_mint_token_pool/contract.tolk +++ b/contracts/contracts/ccip/pools/burn_mint_token_pool/contract.tolk @@ -1,13 +1,13 @@ // SPDX-License-Identifier: BUSL-1.1 tolk 1.4.1 -import "../../../lib/utils.tolk" -import "../../../lib/access/ownable_2step.tolk" -import "../../../lib/jetton/jetton_client.tolk" -import "../../../lib/jetton/messages.tolk" -import "../../../lib/jetton/jetton-utils.tolk" +import "../../../lib/utils" +import "../../../lib/access/ownable_2step" +import "../../../lib/jetton/jetton_client" +import "../../../lib/jetton/messages" +import "../../../lib/jetton/jetton-utils" import "../../rmn_remote/lib" -import "../token_pool.tolk" +import "../token_pool" import "../types" import "../messages" import "../events" @@ -44,10 +44,6 @@ fun onInternalMessage(in: InMessage) { onClaimMinterAdmin(mutate st, in.senderAddress, msg); st.store(); } - TransferNotificationForRecipient => { - onJettonTransferNotification(mutate st, msg, in.senderAddress); - st.store(); - } ReturnExcessesBack => { onReturnExcessesBack(mutate st, msg, in.senderAddress); st.store(); @@ -77,28 +73,16 @@ fun onClaimMinterAdmin( /// @notice Token pool used for burn and mint tokens. This uses a burn and mint mechanism. /// @dev One token per BurnMintTokenPool. In this variant the pool contract owns the Jetton wallet and the Jetton minter admin role. -fun onJettonTransferNotification( - mutate st: Storage, - msg: TransferNotificationForRecipient, +fun doLockOrBurn( + st: Storage, sender: address, -) { - val jettonClient = st.jettonClient.load(); - assert(jettonClient.isWallet(sender), Error.IncorrectJettonSender); - - val payload = loadForwardPayloadAsSlice(msg.forwardPayload); - assert(payload != null, Error.MissingForwardPayload); - - val requestMsg = TokenPool_LockOrBurn.fromSlice(payload!); - val request = requestMsg.request.load(); - assert(request.amount == msg.jettonAmount, Error.AmountMismatch); - assert(msg.transferInitiator != null, Error.MissingTransferInitiator); + _: TransferNotificationForRecipient, + requestMsg: TokenPool_LockOrBurn, + prepared: TokenPool_LockOrBurnPrepared, +): Storage { assert(!st.pendingBurns.get(requestMsg.queryId).isFound, Error.PendingBurnAlreadyExists); - val transferInitiator = msg.transferInitiator!; - - var pool = loadPool(st); - val prepared = pool.prepareLockOrBurn(transferInitiator, request, requestMsg.requestedFinalityConfig, requestMsg.tokenArgs); - st.poolData = pool.data.toCell(); + val jettonClient = st.jettonClient.load(); st.pendingBurns.set(requestMsg.queryId, BurnMintTokenPool_PendingBurn { replyTo: requestMsg.replyTo, request: prepared.request.toCell(), @@ -118,9 +102,11 @@ fun onJettonTransferNotification( customPayload: null, }, }).send(SEND_MODE_PAY_FEES_SEPARATELY); + + return st; } -fun hookHandleReleaseOrMintMessage( +fun handleReleaseOrMintMessage( ctx: Storage?, sender: address, msg: TokenPool_ReleaseOrMint, @@ -250,7 +236,10 @@ fun loadPool(st: Storage): TokenPool { postflightCheck: null, applyLockOrBurn: null, applyReleaseOrMint: null, - handleReleaseOrMintMessage: hookHandleReleaseOrMintMessage, + onLockOrBurn: null, + validateLockOrBurn: null, + doLockOrBurn, + handleReleaseOrMintMessage, }, }; } diff --git a/contracts/contracts/ccip/pools/burn_mint_token_pool/errors.tolk b/contracts/contracts/ccip/pools/burn_mint_token_pool/errors.tolk index bf72b0e44..b175b8f58 100644 --- a/contracts/contracts/ccip/pools/burn_mint_token_pool/errors.tolk +++ b/contracts/contracts/ccip/pools/burn_mint_token_pool/errors.tolk @@ -5,9 +5,6 @@ const BurnMintTokenPool_FACILITY_ID = 412; // (crc32() % 640) + 10 enum Error { IncorrectJettonSender = BurnMintTokenPool_FACILITY_ID * 100 - MissingTransferInitiator - MissingForwardPayload - AmountMismatch PendingBurnAlreadyExists PendingBurnNotFound PendingMintAlreadyExists diff --git a/contracts/contracts/ccip/pools/burn_mint_token_pool/messages.tolk b/contracts/contracts/ccip/pools/burn_mint_token_pool/messages.tolk index fa92f10b1..ec9ec2dd9 100644 --- a/contracts/contracts/ccip/pools/burn_mint_token_pool/messages.tolk +++ b/contracts/contracts/ccip/pools/burn_mint_token_pool/messages.tolk @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -import "../../../lib/jetton/messages.tolk" +import "../../../lib/jetton/messages" import "../messages" struct (0x39898e4d) BurnMintTokenPool_ClaimMinterAdmin { @@ -7,6 +7,5 @@ struct (0x39898e4d) BurnMintTokenPool_ClaimMinterAdmin { } type BurnMintTokenPool_InMessage = - | TransferNotificationForRecipient | BurnMintTokenPool_ClaimMinterAdmin | ReturnExcessesBack; diff --git a/contracts/contracts/ccip/pools/burn_mint_token_pool/storage.tolk b/contracts/contracts/ccip/pools/burn_mint_token_pool/storage.tolk index 50003bb3e..40697d580 100644 --- a/contracts/contracts/ccip/pools/burn_mint_token_pool/storage.tolk +++ b/contracts/contracts/ccip/pools/burn_mint_token_pool/storage.tolk @@ -1,8 +1,8 @@ // SPDX-License-Identifier: BUSL-1.1 -import "../../../lib/jetton/jetton_client.tolk" -import "../../../lib/access/ownable_2step.tolk" +import "../../../lib/jetton/jetton_client" +import "../../../lib/access/ownable_2step" import "../../rmn_remote/lib" -import "../token_pool.tolk" +import "../token_pool" import "../types" import "types" diff --git a/contracts/contracts/ccip/pools/burn_mint_token_pool/types.tolk b/contracts/contracts/ccip/pools/burn_mint_token_pool/types.tolk index f4c7fb8aa..c77b2b188 100644 --- a/contracts/contracts/ccip/pools/burn_mint_token_pool/types.tolk +++ b/contracts/contracts/ccip/pools/burn_mint_token_pool/types.tolk @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -import "../../../lib/jetton/jetton_client.tolk" +import "../../../lib/jetton/jetton_client" import "../../rmn_remote/lib" import "../types" diff --git a/contracts/contracts/ccip/pools/errors.tolk b/contracts/contracts/ccip/pools/errors.tolk index 86038d7e7..c2cbae147 100644 --- a/contracts/contracts/ccip/pools/errors.tolk +++ b/contracts/contracts/ccip/pools/errors.tolk @@ -25,6 +25,9 @@ enum TokenPool_Error { UnsupportedOperation // (); // TODO: extra + MissingForwardPayload + MissingTransferInitiator + AmountMismatch InvalidRequestedFinality RateLimitExceeded } diff --git a/contracts/contracts/ccip/pools/lock_release_token_pool/contract.tolk b/contracts/contracts/ccip/pools/lock_release_token_pool/contract.tolk index 8f814ff32..9a066ecd7 100644 --- a/contracts/contracts/ccip/pools/lock_release_token_pool/contract.tolk +++ b/contracts/contracts/ccip/pools/lock_release_token_pool/contract.tolk @@ -1,13 +1,13 @@ // SPDX-License-Identifier: BUSL-1.1 tolk 1.4.1 -import "../../../lib/utils.tolk" -import "../../../lib/access/ownable_2step.tolk" -import "../../../lib/jetton/messages.tolk" -import "../../../lib/jetton/jetton-utils.tolk" -import "../../../lib/jetton/jetton_client.tolk" +import "../../../lib/utils" +import "../../../lib/access/ownable_2step" +import "../../../lib/jetton/messages" +import "../../../lib/jetton/jetton-utils" +import "../../../lib/jetton/jetton_client" import "../../rmn_remote/lib" -import "../token_pool.tolk" +import "../token_pool" import "../types" import "../messages" import "../events" @@ -44,10 +44,6 @@ fun onInternalMessage(in: InMessage) { val msg = lazy LockReleaseTokenPool_InMessage.fromSlice(in.body); match (msg) { - TransferNotificationForRecipient => { - onJettonTransferNotification(mutate st, msg, in.senderAddress); - st.store(); - } ReturnExcessesBack => { onReturnExcessesBack(mutate st, msg, in.senderAddress); st.store(); @@ -71,32 +67,19 @@ fun onBouncedMessage(in: InMessageBounced) { /// @notice Token pool used for tokens on their native chain. This uses a lock and release mechanism. /// @dev One token per LockReleaseTokenPool. In this non-lockbox variant the pool contract's Jetton wallet holds custody directly. -fun onJettonTransferNotification( - mutate st: Storage, - msg: TransferNotificationForRecipient, +fun doLockOrBurn( + st: Storage, // TODO: should be TokenPool so I get access to hooks and context sender: address, -) { - val jettonClient = st.jettonClient.load(); - assert(jettonClient.isWallet(sender), Error.IncorrectJettonSender); - - val payload = loadForwardPayloadAsSlice(msg.forwardPayload); - assert(payload != null, Error.MissingForwardPayload); - - val requestMsg = TokenPool_LockOrBurn.fromSlice(payload!); + msg: TransferNotificationForRecipient, + requestMsg: TokenPool_LockOrBurn, + prepared: TokenPool_LockOrBurnPrepared, +): Storage { var request = requestMsg.request.load(); - assert(request.amount == msg.jettonAmount, Error.AmountMismatch); - assert(msg.transferInitiator != null, Error.MissingTransferInitiator); - val transferInitiator = msg.transferInitiator!; - - var pool = loadPool(st); - val prepared = pool.prepareLockOrBurn(transferInitiator, request, requestMsg.requestedFinalityConfig, requestMsg.tokenArgs); - st.poolData = pool.data.toCell(); - emit(TOKEN_POOL_LOCKED_OR_BURNED_TOPIC, TokenPool_LockedOrBurned { remoteChainSelector: request.remoteChainSelector, details: TokenPool_LockedOrBurnedDetails { token: request.localToken, - sender: transferInitiator, + sender: msg.transferInitiator!, amount: prepared.destTokenAmount, }.toCell(), }); @@ -113,9 +96,11 @@ fun onJettonTransferNotification( }, }).send(SEND_MODE_PAY_FEES_SEPARATELY | SEND_MODE_CARRY_ALL_REMAINING_MESSAGE_VALUE); } + + return st; } -fun hookHandleReleaseOrMintMessage( +fun handleReleaseOrMintMessage( ctx: Storage?, sender: address, msg: TokenPool_ReleaseOrMint, @@ -233,7 +218,10 @@ fun loadPool(st: Storage): TokenPool { postflightCheck: null, applyLockOrBurn: null, applyReleaseOrMint: null, - handleReleaseOrMintMessage: hookHandleReleaseOrMintMessage, + onLockOrBurn: null, + validateLockOrBurn: null, + doLockOrBurn, + handleReleaseOrMintMessage, }, }; } diff --git a/contracts/contracts/ccip/pools/lock_release_token_pool/errors.tolk b/contracts/contracts/ccip/pools/lock_release_token_pool/errors.tolk index 200f3e3d2..98f3b4771 100644 --- a/contracts/contracts/ccip/pools/lock_release_token_pool/errors.tolk +++ b/contracts/contracts/ccip/pools/lock_release_token_pool/errors.tolk @@ -1,14 +1,11 @@ // SPDX-License-Identifier: BUSL-1.1 -import "../../../lib/utils.tolk" +import "../../../lib/utils" const LockReleaseTokenPool_FACILITY_NAME = "link.chain.ton.ccip.LockReleaseTokenPool"; const LockReleaseTokenPool_FACILITY_ID = 263; // (crc32() % 640) + 10 enum Error { IncorrectJettonSender = LockReleaseTokenPool_FACILITY_ID * 100 - MissingTransferInitiator - MissingForwardPayload - AmountMismatch PendingReleaseAlreadyExists PendingReleaseNotFound UnexpectedReleaseConfirmationSender diff --git a/contracts/contracts/ccip/pools/lock_release_token_pool/messages.tolk b/contracts/contracts/ccip/pools/lock_release_token_pool/messages.tolk index ae18afc9d..0d5d3747a 100644 --- a/contracts/contracts/ccip/pools/lock_release_token_pool/messages.tolk +++ b/contracts/contracts/ccip/pools/lock_release_token_pool/messages.tolk @@ -1,9 +1,8 @@ // SPDX-License-Identifier: BUSL-1.1 -import "../../../lib/jetton/messages.tolk" +import "../../../lib/jetton/messages" import "../messages" type LockReleaseTokenPool_InMessage = - | TransferNotificationForRecipient | ReturnExcessesBack; type LockReleaseTokenPool_BouncedMessage = AskToTransfer; diff --git a/contracts/contracts/ccip/pools/lock_release_token_pool/storage.tolk b/contracts/contracts/ccip/pools/lock_release_token_pool/storage.tolk index 04b087890..b01b51136 100644 --- a/contracts/contracts/ccip/pools/lock_release_token_pool/storage.tolk +++ b/contracts/contracts/ccip/pools/lock_release_token_pool/storage.tolk @@ -1,9 +1,9 @@ // SPDX-License-Identifier: BUSL-1.1 -import "../../../lib/jetton/jetton_client.tolk" -import "../../../lib/access/ownable_2step.tolk" +import "../../../lib/jetton/jetton_client" +import "../../../lib/access/ownable_2step" import "../../rmn_remote/lib" import "../types" -import "../token_pool.tolk" +import "../token_pool" import "types" diff --git a/contracts/contracts/ccip/pools/lock_release_token_pool/types.tolk b/contracts/contracts/ccip/pools/lock_release_token_pool/types.tolk index 6c8da4d9d..e27c3ee91 100644 --- a/contracts/contracts/ccip/pools/lock_release_token_pool/types.tolk +++ b/contracts/contracts/ccip/pools/lock_release_token_pool/types.tolk @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -import "../../../lib/jetton/jetton_client.tolk" +import "../../../lib/jetton/jetton_client" import "../types" const LockReleaseTokenPool_CONTRACT_NAME = "link.chain.ton.ccip.LockReleaseTokenPool".literalSlice(); diff --git a/contracts/contracts/ccip/pools/messages.tolk b/contracts/contracts/ccip/pools/messages.tolk index 61e336a1f..33d8353b0 100644 --- a/contracts/contracts/ccip/pools/messages.tolk +++ b/contracts/contracts/ccip/pools/messages.tolk @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -import "../../lib/jetton/messages.tolk" +import "../../lib/jetton/messages" import "../../lib/utils" import "../common/types" import "../rmn_remote/lib" diff --git a/contracts/contracts/ccip/pools/token_pool.tolk b/contracts/contracts/ccip/pools/token_pool.tolk index 1746af39b..9fb71ed30 100644 --- a/contracts/contracts/ccip/pools/token_pool.tolk +++ b/contracts/contracts/ccip/pools/token_pool.tolk @@ -3,8 +3,9 @@ import "@stdlib/lisp-lists" import "../../lib/math" import "../../lib/utils" -import "../../lib/jetton/messages.tolk" -import "../../lib/access/ownable_2step.tolk" +import "../../lib/jetton/messages" +import "../../lib/jetton/jetton_client" +import "../../lib/access/ownable_2step" import "../common/types" import "../rmn_remote/lib" @@ -51,6 +52,11 @@ struct TokenPool_Hooks { postflightCheck: ((T?, TokenPool_ReleaseOrMintInV1, uint256, uint32) -> void)?; applyLockOrBurn: ((T?, TokenPool_LockOrBurnPrepared) -> void)?; applyReleaseOrMint: ((T?, TokenPool_ReleaseOrMintPrepared) -> void)?; + + // LockOrBurn flow + onLockOrBurn: ((T, address, TransferNotificationForRecipient) -> T)?; + validateLockOrBurn: ((T, address, TokenPool_LockOrBurnInV1, uint32, cell?) -> (T, TokenPool_LockOrBurnPrepared))?; + doLockOrBurn: ((T, address, TransferNotificationForRecipient, TokenPool_LockOrBurn, TokenPool_LockOrBurnPrepared) -> T)?; handleReleaseOrMintMessage: ((T?, address, TokenPool_ReleaseOrMint, TokenPool_ReleaseOrMintPrepared) -> T?)?; } @@ -459,7 +465,8 @@ fun TokenPool.onInternalMessage(mutate self, msgSender: address, msgValue: co return true; } TransferNotificationForRecipient => { - return false; // TODO: handle me, should host fwdPayload = TokenPool_LockOrBurn + self.onLockOrBurn(msgSender, msg); + return true; } else => { var adminConfig = self.data.adminConfig.load(); @@ -577,13 +584,33 @@ fun TokenPool.getFeeAmount( return (request.amount * (feeConfig.finalityTransferFeeBps as uint256)) / TOKEN_POOL_BPS_DIVIDER; } -fun TokenPool.prepareLockOrBurn( +/// Validates the lock or burn input for correctness on +/// - token to be locked or burned +/// - RMN curse status +/// - if the sender is a valid onRamp +/// - rate limiting for either default or FTF transfer messages. +/// - preflight checks hooks (if enabled) +/// @param lockOrBurnIn The input to validate. +/// @param requestedFinality The requested finality speed according to the FinalityCodec encoding. +/// @param tokenArgs Additional token arguments passed in by the sender of the message. +/// @param feeAmount The fee amount deducted from the transfer amount. +/// @dev This function should always be called before executing a lock or burn. Not doing so would allow +/// for various exploits. +fun TokenPool.validateLockOrBurn( mutate self, sender: address, request: TokenPool_LockOrBurnInV1, requestedFinalityConfig: uint32 = TOKEN_POOL_DEFAULT_FINALITY, tokenArgs: cell? = null, ): TokenPool_LockOrBurnPrepared { + if (self.hooks != null && self.hooks.validateLockOrBurn != null) { + val (newContext, prepared) + = self.hooks.validateLockOrBurn(self.context!, sender, request, requestedFinalityConfig, tokenArgs); + self.context = newContext; + + return prepared; + } + assert(self.isSupportedToken(request.localToken), TokenPool_Error.InvalidToken); self.requireSupportedChain(request.remoteChainSelector); self.ensureNotCursed(request.remoteChainSelector); @@ -599,6 +626,7 @@ fun TokenPool.prepareLockOrBurn( self.consumeOutboundRateLimit(request.remoteChainSelector, destTokenAmount); } + // TODO: preflightCheck needs to indicate if we can continue or wait for an async trigger (to continue) self.preflightCheck(request, requestedFinalityConfig, tokenArgs, destTokenAmount); return TokenPool_LockOrBurnPrepared { @@ -615,20 +643,98 @@ fun TokenPool.prepareLockOrBurn( }; } -fun TokenPool.lockOrBurn( +fun TokenPool.onLockOrBurn( mutate self, sender: address, - request: TokenPool_LockOrBurnInV1, - requestedFinalityConfig: uint32 = TOKEN_POOL_DEFAULT_FINALITY, - tokenArgs: cell? = null, -): TokenPool_LockOrBurnPrepared { - val prepared = self.prepareLockOrBurn(sender, request, requestedFinalityConfig, tokenArgs); - if (self.hooks != null && self.hooks.applyLockOrBurn != null) { - self.hooks.applyLockOrBurn(self.context, prepared); + msg: TransferNotificationForRecipient, +): void { + if (self.hooks != null && self.hooks.onLockOrBurn != null) { + self.context = self.hooks.onLockOrBurn(self.context!, sender, msg); + + return; } - return prepared; + + // TODO: hooks in this flow + // - lockOrBurn (this) + // - _getFee + // - _validateLockOrBurn + // - _lockOrBurn + + // val jettonClient = st.jettonClient.load(); + // assert(jettonClient.isWallet(sender), Error.IncorrectJettonSender); + + val payload = loadForwardPayloadAsSlice(msg.forwardPayload); + assert(payload != null, TokenPool_Error.MissingForwardPayload); + + val requestMsg = TokenPool_LockOrBurn.fromSlice(payload!); + val request = requestMsg.request.load(); + assert(request.amount == msg.jettonAmount, TokenPool_Error.AmountMismatch); + assert(msg.transferInitiator != null, TokenPool_Error.MissingTransferInitiator); + + val transferInitiator = msg.transferInitiator!; + + // TODO: should indicate if we need to wait for an async callback before proceeding (e.g., preflight check) + val prepared = self.validateLockOrBurn(transferInitiator, request, requestMsg.requestedFinalityConfig, requestMsg.tokenArgs); + + // TODO: should indicate if we need to wait for an async callback before proceeding (e.g., burn process) + self.doLockOrBurn(sender, msg, requestMsg, prepared); } +// /// Contains the specific lock or burn token logic for a pool. +// /// @dev overriding this method allows us to create pools with different lock/burn signatures +// /// without duplicating the underlying logic. +// /// @param remoteChainSelector The selector of the remote chain. +// /// @param amount The amount of tokens to lock or burn. +// fun TokenPool.doLockOrBurn( +// mutate self, +// sender: address, +// uint64 remoteChainSelector, +// uint256 amount, +// ): void {} + +// TODO: should be simplified to above fun signature +fun TokenPool.doLockOrBurn( + mutate self, + sender: address, + msg: TransferNotificationForRecipient, + requestMsg: TokenPool_LockOrBurn, + prepared: TokenPool_LockOrBurnPrepared, +): bool { + var wait = false; + if (self.hooks != null && self.hooks.doLockOrBurn != null) { + // TODO: hooks.doLockOrBurn should indicate if we need to wait for an async callback before proceeding + self.context = self.hooks.doLockOrBurn(self.context!, sender, msg, requestMsg, prepared); + } + + return wait; +} + + +// function lockOrBurn( +// Pool.LockOrBurnInV1 calldata lockOrBurnIn, +// bytes4 requestedFinalityConfig, +// bytes calldata tokenArgs +// ) public virtual returns (Pool.LockOrBurnOutV1 memory, uint256 destTokenAmount) { +// uint256 feeAmount = _getFee(lockOrBurnIn, requestedFinalityConfig); +// _validateLockOrBurn(lockOrBurnIn, requestedFinalityConfig, tokenArgs, feeAmount); +// destTokenAmount = lockOrBurnIn.amount - feeAmount; +// _lockOrBurn(lockOrBurnIn.remoteChainSelector, destTokenAmount); + +// emit LockedOrBurned({ +// remoteChainSelector: lockOrBurnIn.remoteChainSelector, +// token: lockOrBurnIn.localToken, +// sender: msg.sender, +// amount: destTokenAmount +// }); + +// return ( +// Pool.LockOrBurnOutV1({ +// destTokenAddress: getRemoteToken(lockOrBurnIn.remoteChainSelector), destPoolData: _encodeLocalDecimals() +// }), +// destTokenAmount +// ); +// } + fun TokenPool.prepareReleaseOrMint( mutate self, sender: address, diff --git a/contracts/wrappers/gen/ccip/pools/BurnMintTokenPool.ts b/contracts/wrappers/gen/ccip/pools/BurnMintTokenPool.ts index 41686195b..738ab7768 100644 --- a/contracts/wrappers/gen/ccip/pools/BurnMintTokenPool.ts +++ b/contracts/wrappers/gen/ccip/pools/BurnMintTokenPool.ts @@ -2908,7 +2908,7 @@ function calculateDeployedAddress(code: c.Cell, data: c.Cell, options: DeployedA } export class BurnMintTokenPool implements c.Contract { - static CodeCell = c.Cell.fromBase64('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'); + static CodeCell = c.Cell.fromBase64('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'); static Errors = { 'Common_Error.CrossChainAddressOutOfRange': 5, @@ -2927,19 +2927,18 @@ export class BurnMintTokenPool implements c.Contract { 'TokenPool_Error.InvalidRemoteChainDecimals': 14913, 'TokenPool_Error.OverflowDetected': 14914, 'TokenPool_Error.UnsupportedOperation': 14917, - 'TokenPool_Error.InvalidRequestedFinality': 14918, + 'TokenPool_Error.MissingForwardPayload': 14918, + 'TokenPool_Error.MissingTransferInitiator': 14919, + 'TokenPool_Error.AmountMismatch': 14920, + 'TokenPool_Error.InvalidRequestedFinality': 14921, 'RateLimiter_Error.BucketOverfilled': 26300, 'RateLimiter_Error.TokenMaxCapacityExceeded': 26301, 'RateLimiter_Error.TokenRateLimitReached': 26302, - 'Error.IncorrectJettonSender': 41200, - 'Error.MissingTransferInitiator': 41201, - 'Error.MissingForwardPayload': 41202, - 'Error.AmountMismatch': 41203, - 'Error.PendingBurnAlreadyExists': 41204, - 'Error.PendingMintAlreadyExists': 41206, - 'Error.PendingMintNotFound': 41207, - 'Error.UnexpectedBurnConfirmationSender': 41208, - 'Error.UnexpectedMintConfirmationSender': 41209, + 'Error.PendingBurnAlreadyExists': 41201, + 'Error.PendingMintAlreadyExists': 41203, + 'Error.PendingMintNotFound': 41204, + 'Error.UnexpectedBurnConfirmationSender': 41205, + 'Error.UnexpectedMintConfirmationSender': 41206, 'Ownable2Step_Error.OnlyCallableByOwner': 49800, 'Ownable2Step_Error.CannotTransferToSelf': 49801, 'Ownable2Step_Error.MustBeProposedOwner': 49802, diff --git a/contracts/wrappers/gen/ccip/pools/LockReleaseTokenPool.ts b/contracts/wrappers/gen/ccip/pools/LockReleaseTokenPool.ts index ce319c550..c39662042 100644 --- a/contracts/wrappers/gen/ccip/pools/LockReleaseTokenPool.ts +++ b/contracts/wrappers/gen/ccip/pools/LockReleaseTokenPool.ts @@ -2409,6 +2409,23 @@ export const TokenPool_CursedSubjectsUpdated = { } } +/** + > type LockReleaseTokenPool_InMessage = ReturnExcessesBack + */ +export type LockReleaseTokenPool_InMessage = ReturnExcessesBack + +export const LockReleaseTokenPool_InMessage = { + fromSlice(s: c.Slice): LockReleaseTokenPool_InMessage { + return ReturnExcessesBack.fromSlice(s); + }, + store(self: LockReleaseTokenPool_InMessage, b: c.Builder): void { + ReturnExcessesBack.store(self, b); + }, + toCell(self: LockReleaseTokenPool_InMessage): c.Cell { + return makeCellFrom(self, LockReleaseTokenPool_InMessage.store); + } +} + /** > struct LockReleaseTokenPool_PendingRelease { > replyTo: address? @@ -2659,7 +2676,7 @@ function calculateDeployedAddress(code: c.Cell, data: c.Cell, options: DeployedA } export class LockReleaseTokenPool implements c.Contract { - static CodeCell = c.Cell.fromBase64('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'); + static CodeCell = c.Cell.fromBase64('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QHQ0wchwUHyhQGqAtcY0cjOcfkEAwGDB/QOb6ExgAGMVxBfDzRbbCIhbpEx4DDQgTpBIddJgwe6lyHXSsAAwwCRcOLy9NP/0YE6QSGEB7vy9IACHFcSVxBfDzJsM1MCupIwMeBTAryeWKGBOkIhwU7y9PAEqQTgEqGBOkIhwU7y9PAEgTpCIZmE/yKpBCO+wwCRf+Ly9KiAB9QlwwCVKW6zwwCRcOKOG1cRBxETBwYREgYFEREFVQMRECjag07cgQCFDOAg9AQhbpgxIMcAkjBt4JLR0OKBOkYhbrPy9NcsJ9PtIiTyv9M/1NMf9AT6UNEj0NTTP/pI0//6SNGBOkhTLbry9IE6Ryxus/L0KxEbESURG4GsB/BEaESQRGhEZESMRGREYESIRGBEXESERFxEWESARFhEVER8RFREUER4RFBETER0RExESERwREhERESUREREQESQREA8RIw8OESIODREhDQwRIAwLER8LChEeCgkRHQkIERwIBxElBwYRJAZVQFYcVibwECzDAJUubrPDAJFw4mwBqI4oXwwJER8JCBEeCAcRHQcGERwGBREbBQQRGgQDERkDAhEYAlcWVxZfCOMNCxEVCwoRFAoJERMJCBESCAcREQcGERAGEF8QThA9TBoIBkS0GRcVE20A9lcYERgRGhEYERcRGREXERYRGhEWERURKBEVERQRJxEUERMRJhETERIRJRESERERJBERERARIxEQDxEiDw4RIQ4NESoNDBEpDFUKERlWKoAZc9s4ERERFBERERARExEQDxESDw4REQ4NERANEM8QvhC9ELwQO0A0gQCFAg=='); static Errors = { 'Common_Error.CrossChainAddressOutOfRange': 5, @@ -2678,18 +2695,17 @@ export class LockReleaseTokenPool implements c.Contract { 'TokenPool_Error.InvalidRemoteChainDecimals': 14913, 'TokenPool_Error.OverflowDetected': 14914, 'TokenPool_Error.UnsupportedOperation': 14917, - 'TokenPool_Error.InvalidRequestedFinality': 14918, + 'TokenPool_Error.MissingForwardPayload': 14918, + 'TokenPool_Error.MissingTransferInitiator': 14919, + 'TokenPool_Error.AmountMismatch': 14920, + 'TokenPool_Error.InvalidRequestedFinality': 14921, 'RateLimiter_Error.BucketOverfilled': 26300, - 'Error.IncorrectJettonSender': 26300, - 'Error.MissingTransferInitiator': 26301, + 'Error.PendingReleaseAlreadyExists': 26301, 'RateLimiter_Error.TokenMaxCapacityExceeded': 26301, + 'Error.PendingReleaseNotFound': 26302, 'RateLimiter_Error.TokenRateLimitReached': 26302, - 'Error.MissingForwardPayload': 26302, - 'Error.AmountMismatch': 26303, - 'Error.PendingReleaseAlreadyExists': 26304, - 'Error.PendingReleaseNotFound': 26305, - 'Error.UnexpectedReleaseConfirmationSender': 26306, - 'Error.UnexpectedReleaseBounce': 26307, + 'Error.UnexpectedReleaseConfirmationSender': 26303, + 'Error.UnexpectedReleaseBounce': 26304, 'Ownable2Step_Error.OnlyCallableByOwner': 49800, 'Ownable2Step_Error.CannotTransferToSelf': 49801, 'Ownable2Step_Error.MustBeProposedOwner': 49802, @@ -2825,10 +2841,8 @@ export class LockReleaseTokenPool implements c.Contract { return TransferNotificationForRecipient.toCell(TransferNotificationForRecipient.create(body)); } - static createCellOfReturnExcessesBack(body: { - queryId: uint64 - }) { - return ReturnExcessesBack.toCell(ReturnExcessesBack.create(body)); + static createCellOfLockReleaseTokenPoolInMessage(body: LockReleaseTokenPool_InMessage) { + return LockReleaseTokenPool_InMessage.toCell(body); } async sendDeploy(provider: ContractProvider, via: Sender, msgValue: coins, extraOptions?: ExtraSendOptions) { @@ -2981,12 +2995,10 @@ export class LockReleaseTokenPool implements c.Contract { }); } - async sendReturnExcessesBack(provider: ContractProvider, via: Sender, msgValue: coins, body: { - queryId: uint64 - }, extraOptions?: ExtraSendOptions) { + async sendLockReleaseTokenPoolInMessage(provider: ContractProvider, via: Sender, msgValue: coins, body: LockReleaseTokenPool_InMessage, extraOptions?: ExtraSendOptions) { return provider.internal(via, { value: msgValue, - body: ReturnExcessesBack.toCell(ReturnExcessesBack.create(body)), + body: LockReleaseTokenPool_InMessage.toCell(body), ...extraOptions }); }