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/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..507f674e0 --- /dev/null +++ b/contracts/contracts/ccip/cct/JettonWallet.tolk @@ -0,0 +1,163 @@ +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: "SmartContract Chainlink Limited SEZC" + version: "0.0.1" + description: "link.chain.ton.ccip.cct.JettonWallet" + + storage: WalletStorage + incomingMessages: AllowedMessageToWallet +} + +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/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/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/pools/burn_mint_token_pool/contract.tolk b/contracts/contracts/ccip/pools/burn_mint_token_pool/contract.tolk new file mode 100644 index 000000000..4b08816fb --- /dev/null +++ b/contracts/contracts/ccip/pools/burn_mint_token_pool/contract.tolk @@ -0,0 +1,291 @@ +// SPDX-License-Identifier: BUSL-1.1 +tolk 1.4.1 + +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" +import "../types" +import "../messages" +import "../events" +import "../errors" + +import "messages" +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: TokenPool_InMessage | BurnMintTokenPool_InMessage // TODO: all incoming messages should be registered +} + +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_InMessage.fromSlice(in.body); + match (msg) { + BurnMintTokenPool_ClaimMinterAdmin => { + onClaimMinterAdmin(mutate st, in.senderAddress, msg); + 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 doLockOrBurn( + st: Storage, + sender: address, + _: TransferNotificationForRecipient, + requestMsg: TokenPool_LockOrBurn, + prepared: TokenPool_LockOrBurnPrepared, +): Storage { + assert(!st.pendingBurns.get(requestMsg.queryId).isFound, Error.PendingBurnAlreadyExists); + + val jettonClient = st.jettonClient.load(); + 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); + + return st; +} + +fun handleReleaseOrMintMessage( + 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, + onLockOrBurn: null, + validateLockOrBurn: null, + doLockOrBurn, + handleReleaseOrMintMessage, + }, + }; +} + +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 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); +} + +get fun owner(): address { + return Storage.load().poolData.load().adminConfig.load().ownable.load().owner; +} diff --git a/contracts/contracts/ccip/pools/burn_mint_token_pool/errors.tolk b/contracts/contracts/ccip/pools/burn_mint_token_pool/errors.tolk new file mode 100644 index 000000000..b175b8f58 --- /dev/null +++ b/contracts/contracts/ccip/pools/burn_mint_token_pool/errors.tolk @@ -0,0 +1,14 @@ +// 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 + PendingBurnAlreadyExists + PendingBurnNotFound + PendingMintAlreadyExists + PendingMintNotFound + UnexpectedBurnConfirmationSender + UnexpectedMintConfirmationSender +} \ No newline at end of file diff --git a/contracts/contracts/ccip/pools/burn_mint_token_pool/messages.tolk b/contracts/contracts/ccip/pools/burn_mint_token_pool/messages.tolk new file mode 100644 index 000000000..ec9ec2dd9 --- /dev/null +++ b/contracts/contracts/ccip/pools/burn_mint_token_pool/messages.tolk @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: BUSL-1.1 +import "../../../lib/jetton/messages" +import "../messages" + +struct (0x39898e4d) BurnMintTokenPool_ClaimMinterAdmin { + queryId: uint64; +} + +type BurnMintTokenPool_InMessage = + | 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 new file mode 100644 index 000000000..40697d580 --- /dev/null +++ b/contracts/contracts/ccip/pools/burn_mint_token_pool/storage.tolk @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: BUSL-1.1 +import "../../../lib/jetton/jetton_client" +import "../../../lib/access/ownable_2step" +import "../../rmn_remote/lib" +import "../token_pool" +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/pools/burn_mint_token_pool/types.tolk b/contracts/contracts/ccip/pools/burn_mint_token_pool/types.tolk new file mode 100644 index 000000000..c77b2b188 --- /dev/null +++ b/contracts/contracts/ccip/pools/burn_mint_token_pool/types.tolk @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: BUSL-1.1 +import "../../../lib/jetton/jetton_client" +import "../../rmn_remote/lib" +import "../types" + +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"); +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/pools/errors.tolk b/contracts/contracts/ccip/pools/errors.tolk new file mode 100644 index 000000000..c2cbae147 --- /dev/null +++ b/contracts/contracts/ccip/pools/errors.tolk @@ -0,0 +1,38 @@ +// 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 + MissingForwardPayload + MissingTransferInitiator + AmountMismatch + InvalidRequestedFinality + RateLimitExceeded +} + +@inline +fun TokenPool_errorCode(local: uint16): uint16 { + return getErrorCode(stringCrc32("link.chain.ton.ccip.TokenPool"), local); +} diff --git a/contracts/contracts/ccip/pools/events.tolk b/contracts/contracts/ccip/pools/events.tolk new file mode 100644 index 000000000..6ae2141ad --- /dev/null +++ b/contracts/contracts/ccip/pools/events.tolk @@ -0,0 +1,124 @@ +// 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"); +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/pools/lock_release_token_pool/contract.tolk b/contracts/contracts/ccip/pools/lock_release_token_pool/contract.tolk new file mode 100644 index 000000000..9a066ecd7 --- /dev/null +++ b/contracts/contracts/ccip/pools/lock_release_token_pool/contract.tolk @@ -0,0 +1,273 @@ +// SPDX-License-Identifier: BUSL-1.1 +tolk 1.4.1 + +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" +import "../types" +import "../messages" +import "../events" +import "../errors" + +import "messages" +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: 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); + 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_InMessage.fromSlice(in.body); + match (msg) { + 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 doLockOrBurn( + st: Storage, // TODO: should be TokenPool so I get access to hooks and context + sender: address, + msg: TransferNotificationForRecipient, + requestMsg: TokenPool_LockOrBurn, + prepared: TokenPool_LockOrBurnPrepared, +): Storage { + var request = requestMsg.request.load(); + emit(TOKEN_POOL_LOCKED_OR_BURNED_TOPIC, TokenPool_LockedOrBurned { + remoteChainSelector: request.remoteChainSelector, + details: TokenPool_LockedOrBurnedDetails { + token: request.localToken, + sender: msg.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); + } + + return st; +} + +fun handleReleaseOrMintMessage( + 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, + onLockOrBurn: null, + validateLockOrBurn: null, + doLockOrBurn, + handleReleaseOrMintMessage, + }, + }; +} + +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 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); +} + +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(); +} diff --git a/contracts/contracts/ccip/pools/lock_release_token_pool/errors.tolk b/contracts/contracts/ccip/pools/lock_release_token_pool/errors.tolk new file mode 100644 index 000000000..98f3b4771 --- /dev/null +++ b/contracts/contracts/ccip/pools/lock_release_token_pool/errors.tolk @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: BUSL-1.1 +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 + PendingReleaseAlreadyExists + PendingReleaseNotFound + UnexpectedReleaseConfirmationSender + UnexpectedReleaseBounce +} diff --git a/contracts/contracts/ccip/pools/lock_release_token_pool/events.tolk b/contracts/contracts/ccip/pools/lock_release_token_pool/events.tolk new file mode 100644 index 000000000..52817d6e9 --- /dev/null +++ b/contracts/contracts/ccip/pools/lock_release_token_pool/events.tolk @@ -0,0 +1,39 @@ +// 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; +} diff --git a/contracts/contracts/ccip/pools/lock_release_token_pool/messages.tolk b/contracts/contracts/ccip/pools/lock_release_token_pool/messages.tolk new file mode 100644 index 000000000..0d5d3747a --- /dev/null +++ b/contracts/contracts/ccip/pools/lock_release_token_pool/messages.tolk @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: BUSL-1.1 +import "../../../lib/jetton/messages" +import "../messages" + +type LockReleaseTokenPool_InMessage = + | 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 new file mode 100644 index 000000000..b01b51136 --- /dev/null +++ b/contracts/contracts/ccip/pools/lock_release_token_pool/storage.tolk @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: BUSL-1.1 +import "../../../lib/jetton/jetton_client" +import "../../../lib/access/ownable_2step" +import "../../rmn_remote/lib" +import "../types" +import "../token_pool" + +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/pools/lock_release_token_pool/types.tolk b/contracts/contracts/ccip/pools/lock_release_token_pool/types.tolk new file mode 100644 index 000000000..e27c3ee91 --- /dev/null +++ b/contracts/contracts/ccip/pools/lock_release_token_pool/types.tolk @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: BUSL-1.1 +import "../../../lib/jetton/jetton_client" +import "../types" + +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"); + +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/pools/messages.tolk b/contracts/contracts/ccip/pools/messages.tolk new file mode 100644 index 000000000..33d8353b0 --- /dev/null +++ b/contracts/contracts/ccip/pools/messages.tolk @@ -0,0 +1,117 @@ +// SPDX-License-Identifier: BUSL-1.1 +import "../../lib/jetton/messages" +import "../../lib/utils" +import "../common/types" +import "../rmn_remote/lib" + +import "types" + +struct (0x56f73d37) TokenPool_ApplyChainUpdates { + queryId: uint64; + remoteChainSelectorsToRemove: SnakedCell; + chainsToAdd: SnakedCell; +} + +struct (0x17c242dc) TokenPool_AddRemotePool { + queryId: uint64; + remoteChainSelector: uint64; + remotePoolAddress: Cell; +} + +struct (0x426b8cc4) TokenPool_RemoveRemotePool { + queryId: uint64; + remoteChainSelector: uint64; + remotePoolAddress: Cell; +} + +struct (0xd7712810) TokenPool_SetDynamicConfig { + queryId: uint64; + router: address; + rateLimitAdmin: address? = null; + feeAdmin: address? = null; +} + +struct (0x3c50a39b) TokenPool_SetAllowedFinalityConfig { + queryId: uint64; + allowedFinalityConfig: uint32; +} + +struct (0x4fe2d26c) TokenPool_SetRateLimitConfig { + queryId: uint64; + updates: SnakedCell; +} + +struct (0x30a1d1f7) TokenPool_ApplyTokenTransferFeeConfigUpdates { + queryId: uint64; + updates: SnakedCell; + disableChainSelectors: SnakedCell; +} + +struct (0xe30764be) TokenPool_UpdateRampAccess { + queryId: uint64; + updates: SnakedCell; +} + +/// Sets the RMN proxy address, a role which is responsible for updating the cursed subjects list. +struct (0x9929b642) TokenPool_SetRMNProxy { + queryId: uint64; + rmnProxy: address; +} + +struct (0x2c906eb7) TokenPool_UpdateCursedSubjects { + queryId: uint64; + 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 (0xfa7da444) TokenPool_LockOrBurn { + queryId: uint64; + request: Cell; // TODO: consider renaming + requestedFinalityConfig: uint32; + tokenArgs: cell?; + replyTo: address?; +} + +struct (0x6c060424) 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 (0x351f77e3) TokenPool_ReleaseOrMint { + queryId: uint64; + request: Cell; + requestedFinalityConfig: uint32; + replyTo: address? = null; +} + +struct (0x78dc2232) TokenPool_ReleaseOrMintResponse { + queryId: uint64; + out: Cell; +} + +struct (0xef0cb36e) 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_SetRMNProxy + | TokenPool_UpdateCursedSubjects + | TokenPool_ReleaseOrMint + | TransferNotificationForRecipient; // fwdPayload = TokenPool_LockOrBurn diff --git a/contracts/contracts/ccip/pools/rate_limiter.tolk b/contracts/contracts/ccip/pools/rate_limiter.tolk new file mode 100644 index 000000000..b14ccfadf --- /dev/null +++ b/contracts/contracts/ccip/pools/rate_limiter.tolk @@ -0,0 +1,147 @@ +// 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 // 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: 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_TokenBucket.fromConfig(config: RateLimiter_Config): RateLimiter_TokenBucket { + return RateLimiter_TokenBucket { + tokens: config.capacity, + lastUpdated: blockchain.now(), + isEnabled: config.isEnabled, + capacity: config.capacity, + rate: config.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. +/// @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; + } + + 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(); + } + + 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; + } + } +} + +/// @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 new file mode 100644 index 000000000..9fb71ed30 --- /dev/null +++ b/contracts/contracts/ccip/pools/token_pool.tolk @@ -0,0 +1,1114 @@ +// SPDX-License-Identifier: BUSL-1.1 +import "@stdlib/lisp-lists" + +import "../../lib/math" +import "../../lib/utils" +import "../../lib/jetton/messages" +import "../../lib/jetton/jetton_client" +import "../../lib/access/ownable_2step" +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)?; + + // 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?)?; +} + +struct TokenPool { + data: TokenPool_Data; + context: T? = null; + hooks: TokenPool_Hooks? = null; +} + +@inline +fun TokenPool.load(context: T? = null, hooks: TokenPool_Hooks? = null): TokenPool { + val data = TokenPool_Data.fromContractData(); + return TokenPool { data, 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); + + // TODO: check if address is valid (not zero) + // 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, + }); +} + +/// 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, + remoteChainSelectorsToRemove: SnakedCell, + chainsToAdd: SnakedCell, +) { + self.data.adminConfig.load().ownable.load().requireOwner(sender); + + 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 }); + } + + var addIter = chainsToAdd.iter(); + while (!addIter.empty()) { + 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); + + val rlConfigDefault = RateLimiter_Config { + isEnabled: false, + capacity: 0, + rate: 0, + }; + + var rateLimitConfigs = newChain.rateLimitConfigs.load(); + var config = TokenPool_RemoteChainConfig { + remoteTokenAddress, + remotePools: createEmptyMap(), + rateLimiters: TokenPool_RateLimiterPair { + outbound: RateLimiter_TokenBucket.fromConfig(rateLimitConfigs.outbound.load()).toCell(), + inbound: RateLimiter_TokenBucket.fromConfig(rateLimitConfigs.inbound.load()).toCell(), + }.toCell(), + fastFinalityRateLimiters: TokenPool_RateLimiterPair { + outbound: RateLimiter_TokenBucket.fromConfig(rlConfigDefault).toCell(), + inbound: RateLimiter_TokenBucket.fromConfig(rlConfigDefault).toCell(), + }.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 { + remoteChainSelector, + remotePoolAddress, + }); + } + + self.data.remoteChainConfigs.set(remoteChainSelector, config); + + emit(TOKEN_POOL_CHAIN_ADDED_TOPIC, TokenPool_ChainAdded { + remoteChainSelector, + remoteTokenAddress, + }); + } + + // TODO: reply back to sender with excess +} + +fun TokenPool.applyRampAccessUpdates( + mutate self, + sender: address, + updates: SnakedCell, +) { + 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 iter = updates.iter(); + while (!iter.empty()) { + val update = iter.next(); + + 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, + }); + } + + 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, + 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); + return true; + } + TokenPool_ApplyTokenTransferFeeConfigUpdates => { + self.applyTokenTransferFeeConfigUpdates(msgSender, msg.updates, msg.disableChainSelectors); + return true; + } + TokenPool_UpdateRampAccess => { + 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; + } + 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; + } + TransferNotificationForRecipient => { + self.onLockOrBurn(msgSender, msg); + 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; +} + +/// 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); + + val entry = self.data.tokenTransferFeeConfigs.get(destChainSelector); + if (!entry.isFound) { + return (0, 0, 0, 0, false); + } + + 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); + } + + 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, + ); +} + +/// @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; +} + +/// 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); + 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); + } + + // 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 { + request, + requestedFinalityConfig, + tokenArgs, + feeAmount, + destTokenAmount, + usingFastFinality, + out: TokenPool_LockOrBurnOutV1 { + destTokenAddress: self.getRemoteToken(request.remoteChainSelector), + destPoolData: self.encodeLocalDecimals(), + }, + }; +} + +fun TokenPool.onLockOrBurn( + mutate self, + sender: address, + msg: TransferNotificationForRecipient, +): void { + if (self.hooks != null && self.hooks.onLockOrBurn != null) { + self.context = self.hooks.onLockOrBurn(self.context!, sender, msg); + + return; + } + + // 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, + 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 { + // 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 s = sourcePoolData!.beginParse(); + assert(s.remainingBitsCount() == 256 && s.remainingRefsCount() == 0, TokenPool_Error.InvalidRemoteChainDecimals); + val remoteDecimals = s.loadUint(256); + s.assertEnd(); + assert(remoteDecimals <= 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; + } + + 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 <= MAX_EXP10, TokenPool_Error.OverflowDetected); + + 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 <= MAX_EXP10, TokenPool_Error.OverflowDetected); + val scale = pow10(decimalsDiff); + assert(scale == 0 || remoteAmount <= MAX_UINT256 / scale, TokenPool_Error.OverflowDetected); + + return remoteAmount * scale; +} + +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(); + bucket._consume(amount, self.data.token); + 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(); + bucket._consume(amount, self.data.token); + 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(); + bucket._consume(amount, self.data.token); + rateLimiters.outbound = bucket.toCell(); + config.rateLimiters = rateLimiters.toCell(); + } else { + fastBucket._consume(amount, self.data.token); + 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(); + bucket._consume(amount, self.data.token); + rateLimiters.inbound = bucket.toCell(); + config.rateLimiters = rateLimiters.toCell(); + } else { + fastBucket._consume(amount, self.data.token); + 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_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_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); + + // 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); +} + +// TODO: withdrawFeeTokens + +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; +} 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..eb965d7be --- /dev/null +++ b/contracts/contracts/ccip/pools/token_pool_contract.tolk @@ -0,0 +1,71 @@ +// 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 + + // 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(_: 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/contracts/ccip/pools/types.tolk b/contracts/contracts/ccip/pools/types.tolk new file mode 100644 index 000000000..308863f49 --- /dev/null +++ b/contracts/contracts/ccip/pools/types.tolk @@ -0,0 +1,164 @@ +// SPDX-License-Identifier: BUSL-1.1 +import "../../lib/utils" +import "../common/types" +import "../rmn_remote/lib" + +import "rate_limiter" + +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; + +// 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. + fastFinalityRateLimiters: Cell; // Rate limiter configs for fast finality transfers. +} + +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/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/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 new file mode 100644 index 000000000..27c80f1d5 --- /dev/null +++ b/contracts/tests/ccip/pools/BurnMintTokenPool.spec.ts @@ -0,0 +1,533 @@ +import '@ton/test-utils' +import { Blockchain, SandboxContract, TreasuryContract } from '@ton/sandbox' +import { Address, beginCell, Cell, Dictionary, toNano } from '@ton/core' +import { asSnakedCell, asSnakedCellEmpty } from '../../../src/utils' +import { JettonMinter, JettonWallet } from '../../../wrappers/examples/jetton' +import { CCTJettonMinter } from '../../../wrappers/ccip/CCTJettonMinter' +import { CCTJettonMinterCode, CCTJettonWalletCode } from '../../../wrappers/ccip/CCTJettonCode' +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 + let deployer: SandboxContract + let offRamp: SandboxContract + let unauthorized: SandboxContract + let recipient: SandboxContract + + let cctMinter: SandboxContract + let cctMinterRuntime: SandboxContract + let burnMintPool: SandboxContract + let pool: SandboxContract + let cctWalletCode: Cell + + let userWallet: (address: Address) => Promise> + + const remoteChainSelector = 91000001n + + 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 () => { + 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)) + + burnMintPool = blockchain.openContract( + 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, + }), + }, + 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)) + + { + const r = await burnMintPool.sendTokenPoolApplyChainUpdates( + deployer.getSender(), + toNano('0.2'), + { + 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.sendTokenPoolUpdateRampAccess(deployer.getSender(), toNano('0.2'), { + queryId: 2n, + 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. + 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.sendBurnMintTokenPoolClaimMinterAdmin( + deployer.getSender(), + toNano('0.2'), + { queryId: 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, + deployer, + offRamp, + altOffRamp: deployer, + unauthorized, + recipient, + remoteChainSelector, + unsupportedChainSelector: remoteChainSelector + 1n, + unknownSourcePoolAddress: 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.sendBurnMintTokenPoolClaimMinterAdmin( + unauthorized.getSender(), + toNano('0.2'), + { queryId: 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: TokenPool_LockOrBurn.toCell( + TokenPool_LockOrBurn.create({ + queryId: 303n, + request: { + ref: TokenPool_LockOrBurnInV1.create({ + receiver: { ref: receiverAddress }, + remoteChainSelector, + originalSender: unauthorized.address, + amount: toNano('1'), + localToken: cctMinter.address, + }), + }, + requestedFinalityConfig: 0n, + tokenArgs: null, + replyTo: unauthorized.address, + }), + ), + }, + }) + + 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: TokenPool_LockOrBurn.toCell( + TokenPool_LockOrBurn.create({ + queryId: 304n, + request: { + ref: TokenPool_LockOrBurnInV1.create({ + receiver: { ref: receiverAddress }, + remoteChainSelector, + originalSender: deployer.address, + amount: toNano('1'), + localToken: cctMinter.address, + }), + }, + requestedFinalityConfig: 0n, + tokenArgs: null, + replyTo: deployer.address, + }), + ), + }, + }) + + 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: TokenPool_LockOrBurn.toCell( + TokenPool_LockOrBurn.create({ + queryId: 11n, + request: { + ref: TokenPool_LockOrBurnInV1.create({ + receiver: { ref: receiverAddress }, + remoteChainSelector, + originalSender: deployer.address, + amount: toNano('3'), + localToken: cctMinter.address, + }), + }, + requestedFinalityConfig: 0n, + tokenArgs: null, + replyTo: deployer.address, + }), + ), + }, + }) + + 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: TokenPool_LockOrBurnResponse.PREFIX, + }) + }) + + it('mints tokens on releaseOrMint path and clears pending mint on confirmation', async () => { + 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, + }, + ) + + 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: TokenPool_ReleaseOrMintResponse.PREFIX, + body(body) { + if (!body) return false + 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.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, + }, + ) + + 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) === + TokenPool_ReleaseOrMintResponse.PREFIX + ) + }) + expect(releaseResponses.length).toBe(0) + expect(await burnMintPool.getHasPendingMint(305n)).toBe(false) + }) +}) diff --git a/contracts/tests/ccip/pools/LockReleaseTokenPool.spec.ts b/contracts/tests/ccip/pools/LockReleaseTokenPool.spec.ts new file mode 100644 index 000000000..a1cff9bc9 --- /dev/null +++ b/contracts/tests/ccip/pools/LockReleaseTokenPool.spec.ts @@ -0,0 +1,519 @@ +import '@ton/test-utils' +import { Blockchain, SandboxContract, TreasuryContract } from '@ton/sandbox' +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, +} 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 + let offRamp: SandboxContract + let recipient: SandboxContract + + let jettonMinter: SandboxContract + let jettonSender: SandboxContract + let lockReleasePool: SandboxContract + let pool: SandboxContract + let jettonWalletCode: Cell + + let userWallet: (address: Address) => Promise> + + const remoteChainSelector = 90000001n + + 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 () => { + 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')) + + lockReleasePool = blockchain.openContract( + 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, + }), + }, + 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.sendTokenPoolApplyChainUpdates( + deployer.getSender(), + toNano('0.2'), + { + 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(applyChains.transactions).toHaveTransaction({ + from: deployer.address, + to: lockReleasePool.address, + success: true, + }) + + const updateRampAccess = await lockReleasePool.sendTokenPoolUpdateRampAccess( + deployer.getSender(), + toNano('0.2'), + { + queryId: 2n, + updates: asSnakedCell( + [ + TokenPool_RampUpdate.create({ + remoteChainSelector, + onRamp: jettonSender.address, + offRamp: offRamp.address, + }), + ], + (item) => TokenPool_RampUpdate.toCell(item).asBuilder(), + ), + }, + ) + + 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, + deployer, + offRamp, + altOffRamp: deployer, + unauthorized: recipient, + recipient, + remoteChainSelector, + unsupportedChainSelector: remoteChainSelector + 1n, + unknownSourcePoolAddress: 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: TokenPool_LockOrBurn.toCell( + TokenPool_LockOrBurn.create({ + queryId: 44n, + request: { + ref: TokenPool_LockOrBurnInV1.create({ + receiver: { ref: receiverAddress }, + remoteChainSelector, + originalSender: deployer.address, + amount: toNano('2'), + localToken: jettonMinter.address, + }), + }, + requestedFinalityConfig: 0n, + tokenArgs: null, + replyTo: deployer.address, + }), + ), + }, + }) + + 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.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, + }, + ) + + 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: TokenPool_LockOrBurn.toCell( + TokenPool_LockOrBurn.create({ + queryId: 11n, + request: { + ref: TokenPool_LockOrBurnInV1.create({ + receiver: { ref: receiverAddress }, + remoteChainSelector, + originalSender: deployer.address, + amount: toNano('3'), + localToken: jettonMinter.address, + }), + }, + requestedFinalityConfig: 0n, + tokenArgs: null, + replyTo: deployer.address, + }), + ), + }, + }) + + 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.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, + }, + ) + + 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: TokenPool_ReleaseOrMintResponse.PREFIX, + body(body) { + if (!body) return false + 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.sendTokenPoolUpdateCursedSubjects( + deployer.getSender(), + toNano('0.2'), + { + queryId: 901n, + cursedSubjects: CursedSubjects.create({ + data: loadMap( + Dictionary.Keys.BigInt(128), + createEmptyTensorValue(), + new Map([[remoteChainSelector, []]]), + ), + }), + }, + ) + + expect(curseUpdate.transactions).toHaveTransaction({ + from: deployer.address, + to: lockReleasePool.address, + success: true, + }) + + expect(await lockReleasePool.getVerifyNotCursed(remoteChainSelector)).toBe(false) + + 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, + }, + ) + + expect(result.transactions).toHaveTransaction({ + from: offRamp.address, + to: lockReleasePool.address, + success: false, + }) + }) +}) diff --git a/contracts/tests/ccip/pools/TokenPool.behavior.ts b/contracts/tests/ccip/pools/TokenPool.behavior.ts new file mode 100644 index 000000000..bc53fcf4b --- /dev/null +++ b/contracts/tests/ccip/pools/TokenPool.behavior.ts @@ -0,0 +1,522 @@ +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, + 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: SandboxContract + deployer: SandboxContract + offRamp: SandboxContract + unauthorized: SandboxContract + recipient: SandboxContract + onRampAddress: Address + remoteChainSelector: bigint + destTokenAddress: CrossChainAddress + sourcePoolAddress: CrossChainAddress + localToken: Address +} + +function releaseRequest( + ctx: TokenPoolBehaviorContext, + overrides: Partial = {}, +): TokenPool_ReleaseOrMintInV1 { + return TokenPool_ReleaseOrMintInV1.create({ + originalSender: { ref: ctx.sourcePoolAddress }, + remoteChainSelector: ctx.remoteChainSelector, + receiver: ctx.recipient.address, + sourceDenominatedAmount: 1n, + localToken: ctx.localToken, + sourcePoolAddress: { ref: 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.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, + to: ctx.pool.address, + success: false, + }) + }) + + it('reverts releaseOrMint while chain is cursed', async () => { + const ctx = await setup() + + await ctx.pool.sendTokenPoolUpdateCursedSubjects(ctx.deployer.getSender(), toNano('0.2'), { + queryId: 901n, + 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.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, + 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.sendTokenPoolApplyChainUpdates( + ctx.unauthorized.getSender(), + toNano('0.2'), + { + queryId: 903n, + remoteChainSelectorsToRemove: asSnakedCellEmpty(), + chainsToAdd: asSnakedCellEmpty(), + }, + ) + + 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.sendTokenPoolUpdateRampAccess( + ctx.unauthorized.getSender(), + toNano('0.2'), + { + queryId: 904n, + 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.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.sendTokenPoolUpdateCursedSubjects( + ctx.unauthorized.getSender(), + toNano('0.2'), + { + queryId: 904n, + cursedSubjects: CursedSubjects.create({ + data: loadMap( + Dictionary.Keys.BigInt(128), + createEmptyTensorValue(), + new Map([[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.sendTokenPoolUpdateCursedSubjects(ctx.deployer.getSender(), toNano('0.2'), { + queryId: 901n, + 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.sendTokenPoolUpdateCursedSubjects(ctx.deployer.getSender(), toNano('0.2'), { + queryId: 902n, + 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.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, + 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.sendTokenPoolApplyChainUpdates(ctx.deployer.getSender(), toNano('0.2'), { + queryId: 906n, + remoteChainSelectorsToRemove: asSnakedCell([ctx.remoteChainSelector], (item: bigint) => + beginCell().storeUint(item, 64), + ), + chainsToAdd: asSnakedCellEmpty(), + }) + + 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, + to: ctx.pool.address, + success: false, + }) + }) + + it('rejects removing a non-existent chain', async () => { + const ctx = await setup() + 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, + to: ctx.pool.address, + success: false, + }) + }) + + it('can replace off-ramp mapping via updateRampAccess', async () => { + const ctx = await setup() + 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, + 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.sendTokenPoolUpdateRampAccess(ctx.deployer.getSender(), toNano('0.2'), { + queryId: 910n, + 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.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, + 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() + .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, + 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.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, + to: ctx.pool.address, + success: false, + }) + }) + + it('clears existing off-ramp when update passes null off-ramp', async () => { + const ctx = await setup() + await ctx.pool.sendTokenPoolUpdateRampAccess(ctx.deployer.getSender(), toNano('0.2'), { + queryId: 914n, + 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() + }) + + it('rejects existing off-ramp sender after null off-ramp update', async () => { + const ctx = await setup() + await ctx.pool.sendTokenPoolUpdateRampAccess(ctx.deployer.getSender(), toNano('0.2'), { + queryId: 915n, + updates: asSnakedCell( + [ + TokenPool_RampUpdate.create({ + remoteChainSelector: ctx.remoteChainSelector, + onRamp: ctx.onRampAddress, + offRamp: null, + }), + ], + (item) => TokenPool_RampUpdate.toCell(item).asBuilder(), + ), + }) + + 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, + to: ctx.pool.address, + success: false, + }) + }) + + it('can re-add chain after remove via applyChainUpdates', async () => { + const ctx = await setup() + + await ctx.pool.sendTokenPoolApplyChainUpdates(ctx.deployer.getSender(), toNano('0.2'), { + queryId: 917n, + remoteChainSelectorsToRemove: asSnakedCell([ctx.remoteChainSelector], (item) => + beginCell().storeUint(item, 64), + ), + chainsToAdd: asSnakedCellEmpty(), + }) + + const addResult = await ctx.pool.sendTokenPoolApplyChainUpdates( + ctx.deployer.getSender(), + toNano('0.2'), + { + queryId: 918n, + remoteChainSelectorsToRemove: asSnakedCell([], (item) => beginCell().storeUint(item, 64)), + chainsToAdd: asSnakedCell( + [ + TokenPool_ChainUpdate.create({ + remoteChainSelector: ctx.remoteChainSelector, + remotePoolAddresses: asSnakedCell([ctx.sourcePoolAddress], (item) => { + let b = beginCell() + CrossChainAddress.store(item, b) + return b + }), + remoteTokenAddress: { ref: ctx.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(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/tests/ccip/router/Router.getFee.spec.ts b/contracts/tests/ccip/router/Router.getFee.spec.ts index f1e1c4d5f..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 { @@ -13,6 +12,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 +25,8 @@ describe('Router', () => { let onRamp: SandboxContract beforeAll(async () => { + setupGenBindings() + blockchain = await Blockchain.create() blockchain.verbosity = { print: true, @@ -39,22 +41,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/ccip.cct.JettonMinter.compile.ts b/contracts/wrappers/ccip.cct.JettonMinter.compile.ts new file mode 100644 index 000000000..229320137 --- /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, +} diff --git a/contracts/wrappers/ccip.cct.JettonWallet.compile.ts b/contracts/wrappers/ccip.cct.JettonWallet.compile.ts new file mode 100644 index 000000000..4694eb8ad --- /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, +} diff --git a/contracts/wrappers/ccip.pools.BurnMintTokenPool.compile.ts b/contracts/wrappers/ccip.pools.BurnMintTokenPool.compile.ts new file mode 100644 index 000000000..dca1ee093 --- /dev/null +++ b/contracts/wrappers/ccip.pools.BurnMintTokenPool.compile.ts @@ -0,0 +1,7 @@ +import { CompilerConfig } from '@ton/blueprint' + +export const compile: CompilerConfig = { + lang: 'tolk', + entrypoint: 'contracts/ccip/pools/burn_mint_token_pool/contract.tolk', + withStackComments: true, +} diff --git a/contracts/wrappers/ccip.pools.LockReleaseTokenPool.compile.ts b/contracts/wrappers/ccip.pools.LockReleaseTokenPool.compile.ts new file mode 100644 index 000000000..84b478484 --- /dev/null +++ b/contracts/wrappers/ccip.pools.LockReleaseTokenPool.compile.ts @@ -0,0 +1,7 @@ +import { CompilerConfig } from '@ton/blueprint' + +export const compile: CompilerConfig = { + lang: 'tolk', + entrypoint: 'contracts/ccip/pools/lock_release_token_pool/contract.tolk', + withStackComments: true, +} diff --git a/contracts/wrappers/ccip/CCTJettonCode.ts b/contracts/wrappers/ccip/CCTJettonCode.ts new file mode 100644 index 000000000..807206fc2 --- /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') +} diff --git a/contracts/wrappers/ccip/CCTJettonMinter.ts b/contracts/wrappers/ccip/CCTJettonMinter.ts new file mode 100644 index 000000000..b8103138a --- /dev/null +++ b/contracts/wrappers/ccip/CCTJettonMinter.ts @@ -0,0 +1,122 @@ +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/gen/ccip/pools/BurnMintTokenPool.ts b/contracts/wrappers/gen/ccip/pools/BurnMintTokenPool.ts new file mode 100644 index 000000000..738ab7768 --- /dev/null +++ b/contracts/wrappers/gen/ccip/pools/BurnMintTokenPool.ts @@ -0,0 +1,3336 @@ +// 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 + +/** + > 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); + } +} + +/** + > 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_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_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 (0x56f73d37) 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: 0x56f73d37, + + create(args: { + queryId: uint64 + remoteChainSelectorsToRemove: SnakedCell + chainsToAdd: SnakedCell + }): TokenPool_ApplyChainUpdates { + return { + $: 'TokenPool_ApplyChainUpdates', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_ApplyChainUpdates { + loadAndCheckPrefix32(s, 0x56f73d37, '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(0x56f73d37, 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 (0x17c242dc) 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: 0x17c242dc, + + create(args: { + queryId: uint64 + remoteChainSelector: uint64 + remotePoolAddress: CellRef + }): TokenPool_AddRemotePool { + return { + $: 'TokenPool_AddRemotePool', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_AddRemotePool { + loadAndCheckPrefix32(s, 0x17c242dc, '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(0x17c242dc, 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 (0x426b8cc4) 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: 0x426b8cc4, + + create(args: { + queryId: uint64 + remoteChainSelector: uint64 + remotePoolAddress: CellRef + }): TokenPool_RemoveRemotePool { + return { + $: 'TokenPool_RemoveRemotePool', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_RemoveRemotePool { + loadAndCheckPrefix32(s, 0x426b8cc4, '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(0x426b8cc4, 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 (0xd7712810) 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: 0xd7712810, + + 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, 0xd7712810, '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(0xd7712810, 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 (0x3c50a39b) TokenPool_SetAllowedFinalityConfig { + > queryId: uint64 + > allowedFinalityConfig: uint32 + > } + */ +export interface TokenPool_SetAllowedFinalityConfig { + readonly $: 'TokenPool_SetAllowedFinalityConfig' + queryId: uint64 + allowedFinalityConfig: uint32 +} + +export const TokenPool_SetAllowedFinalityConfig = { + PREFIX: 0x3c50a39b, + + create(args: { + queryId: uint64 + allowedFinalityConfig: uint32 + }): TokenPool_SetAllowedFinalityConfig { + return { + $: 'TokenPool_SetAllowedFinalityConfig', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_SetAllowedFinalityConfig { + loadAndCheckPrefix32(s, 0x3c50a39b, 'TokenPool_SetAllowedFinalityConfig'); + return { + $: 'TokenPool_SetAllowedFinalityConfig', + queryId: s.loadUintBig(64), + allowedFinalityConfig: s.loadUintBig(32), + } + }, + store(self: TokenPool_SetAllowedFinalityConfig, b: c.Builder): void { + b.storeUint(0x3c50a39b, 32); + b.storeUint(self.queryId, 64); + b.storeUint(self.allowedFinalityConfig, 32); + }, + toCell(self: TokenPool_SetAllowedFinalityConfig): c.Cell { + return makeCellFrom(self, TokenPool_SetAllowedFinalityConfig.store); + } +} + +/** + > struct (0x4fe2d26c) TokenPool_SetRateLimitConfig { + > queryId: uint64 + > updates: SnakedCell + > } + */ +export interface TokenPool_SetRateLimitConfig { + readonly $: 'TokenPool_SetRateLimitConfig' + queryId: uint64 + updates: SnakedCell +} + +export const TokenPool_SetRateLimitConfig = { + PREFIX: 0x4fe2d26c, + + create(args: { + queryId: uint64 + updates: SnakedCell + }): TokenPool_SetRateLimitConfig { + return { + $: 'TokenPool_SetRateLimitConfig', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_SetRateLimitConfig { + loadAndCheckPrefix32(s, 0x4fe2d26c, 'TokenPool_SetRateLimitConfig'); + return { + $: 'TokenPool_SetRateLimitConfig', + queryId: s.loadUintBig(64), + updates: s.loadRef(), + } + }, + store(self: TokenPool_SetRateLimitConfig, b: c.Builder): void { + b.storeUint(0x4fe2d26c, 32); + b.storeUint(self.queryId, 64); + b.storeRef(self.updates); + }, + toCell(self: TokenPool_SetRateLimitConfig): c.Cell { + return makeCellFrom(self, TokenPool_SetRateLimitConfig.store); + } +} + +/** + > struct (0x30a1d1f7) 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: 0x30a1d1f7, + + create(args: { + queryId: uint64 + updates: SnakedCell + disableChainSelectors: SnakedCell + }): TokenPool_ApplyTokenTransferFeeConfigUpdates { + return { + $: 'TokenPool_ApplyTokenTransferFeeConfigUpdates', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_ApplyTokenTransferFeeConfigUpdates { + loadAndCheckPrefix32(s, 0x30a1d1f7, '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(0x30a1d1f7, 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 (0xe30764be) TokenPool_UpdateRampAccess { + > queryId: uint64 + > updates: SnakedCell + > } + */ +export interface TokenPool_UpdateRampAccess { + readonly $: 'TokenPool_UpdateRampAccess' + queryId: uint64 + updates: SnakedCell +} + +export const TokenPool_UpdateRampAccess = { + PREFIX: 0xe30764be, + + create(args: { + queryId: uint64 + updates: SnakedCell + }): TokenPool_UpdateRampAccess { + return { + $: 'TokenPool_UpdateRampAccess', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_UpdateRampAccess { + loadAndCheckPrefix32(s, 0xe30764be, 'TokenPool_UpdateRampAccess'); + return { + $: 'TokenPool_UpdateRampAccess', + queryId: s.loadUintBig(64), + updates: s.loadRef(), + } + }, + store(self: TokenPool_UpdateRampAccess, b: c.Builder): void { + b.storeUint(0xe30764be, 32); + b.storeUint(self.queryId, 64); + b.storeRef(self.updates); + }, + toCell(self: TokenPool_UpdateRampAccess): c.Cell { + return makeCellFrom(self, TokenPool_UpdateRampAccess.store); + } +} + +/** + > struct (0x9929b642) TokenPool_SetRMNProxy { + > queryId: uint64 + > rmnProxy: address + > } + */ +export interface TokenPool_SetRMNProxy { + readonly $: 'TokenPool_SetRMNProxy' + queryId: uint64 + rmnProxy: c.Address +} + +export const TokenPool_SetRMNProxy = { + PREFIX: 0x9929b642, + + create(args: { + queryId: uint64 + rmnProxy: c.Address + }): TokenPool_SetRMNProxy { + return { + $: 'TokenPool_SetRMNProxy', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_SetRMNProxy { + loadAndCheckPrefix32(s, 0x9929b642, 'TokenPool_SetRMNProxy'); + return { + $: 'TokenPool_SetRMNProxy', + queryId: s.loadUintBig(64), + rmnProxy: s.loadAddress(), + } + }, + store(self: TokenPool_SetRMNProxy, b: c.Builder): void { + b.storeUint(0x9929b642, 32); + b.storeUint(self.queryId, 64); + b.storeAddress(self.rmnProxy); + }, + toCell(self: TokenPool_SetRMNProxy): c.Cell { + return makeCellFrom(self, TokenPool_SetRMNProxy.store); + } +} + +/** + > struct (0x2c906eb7) TokenPool_UpdateCursedSubjects { + > queryId: uint64 + > cursedSubjects: CursedSubjects + > } + */ +export interface TokenPool_UpdateCursedSubjects { + readonly $: 'TokenPool_UpdateCursedSubjects' + queryId: uint64 + cursedSubjects: CursedSubjects +} + +export const TokenPool_UpdateCursedSubjects = { + PREFIX: 0x2c906eb7, + + create(args: { + queryId: uint64 + cursedSubjects: CursedSubjects + }): TokenPool_UpdateCursedSubjects { + return { + $: 'TokenPool_UpdateCursedSubjects', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_UpdateCursedSubjects { + loadAndCheckPrefix32(s, 0x2c906eb7, 'TokenPool_UpdateCursedSubjects'); + return { + $: 'TokenPool_UpdateCursedSubjects', + queryId: s.loadUintBig(64), + cursedSubjects: CursedSubjects.fromSlice(s), + } + }, + store(self: TokenPool_UpdateCursedSubjects, b: c.Builder): void { + b.storeUint(0x2c906eb7, 32); + b.storeUint(self.queryId, 64); + CursedSubjects.store(self.cursedSubjects, b); + }, + toCell(self: TokenPool_UpdateCursedSubjects): c.Cell { + return makeCellFrom(self, TokenPool_UpdateCursedSubjects.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 + > 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: 0x351f77e3, + + 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, 0x351f77e3, '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(0x351f77e3, 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 (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_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 (0x39898e4d) BurnMintTokenPool_ClaimMinterAdmin { + > queryId: uint64 + > } + */ +export interface BurnMintTokenPool_ClaimMinterAdmin { + readonly $: 'BurnMintTokenPool_ClaimMinterAdmin' + queryId: uint64 +} + +export const BurnMintTokenPool_ClaimMinterAdmin = { + PREFIX: 0x39898e4d, + + create(args: { + queryId: uint64 + }): BurnMintTokenPool_ClaimMinterAdmin { + return { + $: 'BurnMintTokenPool_ClaimMinterAdmin', + ...args + } + }, + fromSlice(s: c.Slice): BurnMintTokenPool_ClaimMinterAdmin { + loadAndCheckPrefix32(s, 0x39898e4d, 'BurnMintTokenPool_ClaimMinterAdmin'); + return { + $: 'BurnMintTokenPool_ClaimMinterAdmin', + queryId: s.loadUintBig(64), + } + }, + store(self: BurnMintTokenPool_ClaimMinterAdmin, b: c.Builder): void { + b.storeUint(0x39898e4d, 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_Config { + > isEnabled: bool + > capacity: uint128 + > rate: uint128 + > } + */ +export interface RateLimiter_Config { + readonly $: 'RateLimiter_Config' + isEnabled: boolean + capacity: uint128 + rate: uint128 +} + +export const RateLimiter_Config = { + create(args: { + isEnabled: boolean + capacity: uint128 + rate: uint128 + }): RateLimiter_Config { + return { + $: 'RateLimiter_Config', + ...args + } + }, + fromSlice(s: c.Slice): RateLimiter_Config { + return { + $: 'RateLimiter_Config', + isEnabled: s.loadBoolean(), + capacity: s.loadUintBig(128), + rate: s.loadUintBig(128), + } + }, + store(self: RateLimiter_Config, b: c.Builder): void { + b.storeBit(self.isEnabled); + b.storeUint(self.capacity, 128); + b.storeUint(self.rate, 128); + }, + toCell(self: RateLimiter_Config): c.Cell { + return makeCellFrom(self, RateLimiter_Config.store); + } +} + +/** + > struct RateLimiter_TokenBucket { + > tokens: uint128 + > lastUpdated: uint64 + > isEnabled: bool + > capacity: uint128 + > rate: uint128 + > } + */ +export interface RateLimiter_TokenBucket { + readonly $: 'RateLimiter_TokenBucket' + tokens: uint128 + lastUpdated: uint64 + isEnabled: boolean + capacity: uint128 + rate: uint128 +} + +export const RateLimiter_TokenBucket = { + create(args: { + tokens: uint128 + lastUpdated: uint64 + isEnabled: boolean + capacity: uint128 + rate: uint128 + }): RateLimiter_TokenBucket { + return { + $: 'RateLimiter_TokenBucket', + ...args + } + }, + fromSlice(s: c.Slice): RateLimiter_TokenBucket { + return { + $: 'RateLimiter_TokenBucket', + tokens: s.loadUintBig(128), + lastUpdated: s.loadUintBig(64), + isEnabled: s.loadBoolean(), + capacity: s.loadUintBig(128), + rate: s.loadUintBig(128), + } + }, + store(self: RateLimiter_TokenBucket, b: c.Builder): void { + b.storeUint(self.tokens, 128); + b.storeUint(self.lastUpdated, 64); + b.storeBit(self.isEnabled); + b.storeUint(self.capacity, 128); + b.storeUint(self.rate, 128); + }, + 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('te6ccgECcAEAGCIAART/APSkE/S88sgLAQIBYgIDAgLLBAUCASAoKQIBIAYHAgFiGRoCASAICQIBIDw9AgEgCgsCASATFAIBIAwNAFdSFukltw4IJpAAAAAAAAAAAAAAAAAAABIoMG9A5voTGSW3/gAYMG9A5voTGAP3PiR8kDtRNDU1PQE9ATRI9DU1PpI0wf0BPQE0YEAhW1tbW1tbW1tbZLwCACS8AkAgQCGVhZWFlYWVhb4kviXBRESBQQREQQDERADEC8QXhBNEDwQKxBaEEkQOBAnEFYQRRA0ECNWHfALVxFfDATjAl8KJNcsIcxMcmzjAoA4PEAGpO2i7fvXLCeQ2+0MjkTXLCfPFPJUlFtw2zHhggDCiiNus/L0IYIAwooExwUT8vQgbQPXCz+LAgHIyz8V+lIS+lLJyM+HIBTOcc8LYRPMyXD7AOMNf4BIAXD09AcMAkzc3N5kwOTkQWF4kEEXiA8jMEsz6UssHE/QA9ADJyMzMEvQA9ADJ7VQAyDUE1ws/+JIk0NTUMfpIMdMHMfQEMfQEMdHQ1PpIMdQx0x8x0dD6SPpQMdEBggDCiALHBfL0ggr68IAj0PpI1DHRyM+FiPpSAfoCghD7iOEZzwuKyz/JcfsAAsjMzPQA9ADJ7VQBVInXJ44bNQTXCz/4khBFEDQQI/AKA8jMEsz0APQAye1U4F8FhA8BxwDy9BEACNUydtsAZmwS0z/6SDCCAMKIUTTHBRPy9IIAwolTI8cFs/L0IYsCyM+HIM5wzwthEss/EvpSyXD7AAIBIBUWAgEgFxgASRxepMiwgCOGSJxsMABnIT/IqkEIb7yhGaoAd4gqAKrAALoMDGAAqwwI7ORf5UgwADDAOKRMOAi+CMmoSCOGDZTYLyVgWa88vDgUVKoFqBSQPAGBfgjBZEw4iG5lYFmvfLw4FNQuY4RFV8FIJWBZr7y8OEwgWa+8vDgFaEEgAA0XLmRMOAxgACkIZFb4YE6SSGUArrDAJNsIXDi8vSACASAbHAB/QxMmzzbDNsRDQCgED0Dm+hk18DcOHSANP/MdP/MdMfMdMfMdMP0w/RApNfBHDhApcxqIEnEKkE4DCogScQqQSAH3CXDAJUpbrPDAJFw4o4iVxEIERQIBxETBwYREgYFEREFVQMREFYU2pQQP07cgQCFDOAg9AQhbpgxIMcAkjBt4JLR0OKBOkYhbrPy9NcsJ9PtIiTyv9M/1NMf9AT6UNEj0NTTP/pI0//6SNGBOkhTLbry9IE6Ryxus/L0K4B0D9wowwCVK26zwwCRcOKONVcUCxEXCwoRFgoJERUJCBEUCFUGERNWFoAMgBDbOA8RGw8OERoODREZDQwRGAyBAIURGFWw4IE6PVYdJMcF8vSBOjkmVhyAQPQOb6Ex8vSBOjpWHtD0BDH0BDH0BNEn8AOz8vQowwCRcOMN4wCAgISIB/hEcESYRHBEbESURGxEaESQRGhEZESMRGREYESIRGBEXESERFxEWESARFhEVER8RFREUER4RFBETER0RExESESYREhERESUREREQESQREA8RIw8OESIODREhDQwRIAwLER8LChEeCgkRHQkIESYIBxElBwYRJAZVQFYmVibwESweAbbDAJUubrPDAJFw4o4oXwwJESAJCBEfCAcRHgcGER0GBREcBQQRGwQDERoDAhEZAlcXVxdfCOMNDBEWDAsRFQsKERQKCRETCQgREggHEREHBhEQBhBfEE4QPVWSHwD6VxgRGREbERkRGBEaERgRFxEbERcRFhEaERYRFREoERURFBEnERQRExEmERMREhElERIREREkEREREBEjERAPESIPDhErDg0RKg0MESkMVQoRG1YqgBp02zgREREVEREREBEUERAPERMPDhESDg0REQ1ePBDOEFxVE4EAhQIADFYRbrPDAAAeVhhWGFYYVhhWGCpWF9pgAfxWHdD0BPQEMfQEMdFSYIBA9A5voZP6SNGSMG3igTo+IW6z8vSBOj5RGccF8vQowwCWVhNus8MAkXDijhVWGAFWGAFWGAFWGAFWGFQQylYZ2nCRN+JWHVYdVh1WHVYdVh1WHVYdVh1WHVYdVh1WHVYdVh1WHVYdVh1WHVYdVh0jA/xWHVYdVhxWHFYcVhxWHFYc8BJTMKEiwwAjjk+BOjgoVh6AQPQOb6ES8vTU9ATU1NEB0NTU0QHQ03/TP9IA03/Tf9EqVijwBQTIy38Tyz/KAMt/y3/JyMzMyQPIzBL0ABLMzFKCER6AQPRD4w0qwwCWVhJus8MAkXDi4wCBOjgkJSYB8lYg0NQx+kgx1DHTH9FSQPAHgTo4KFYegED0Dm+hEvL01PQE1NTRINDU1NEB0NN/0z/SANN/03/RIo4sXwYB0NTU0QHQ03/TP9IA03/Tf9EqVijwBQTIy38Tyz/KAMt/y3/JyMzMyQHjDQPIzBL0AMzMUoIRHoBA9EMnAC5WGlYaVhpWGlYaVH3LVH3LVhQtVh/a0ABUU4GAQPQOb6ES8vTU9AQx1DHUMdFWHsjL/8kCER4CEKsQmhCJEHgQZxBWADJsFipWKPAFBMjLfxPLP8oAy3/Lf8nIzMzJAgEgKisCASA4OQIBICwtAgEgNjcCASAuLwBBtbUdqJoamoY+gIY+gIY6OhqGOoY/SQY6YP6Ahj6AhjowAgEgMDECAUg0NQAtrSp2omhqGOoY+gIY+gJowCB6BzfQmMACAUgyMwBvpXXaiaGpqGPoCGPoCGOjoahjqfSQY6YOY+gIY+gIY6Oh6Ahj6AnoCGOjAIHoHN9DJ/SRoyRg28UAP6cj2omhqahj6Ahj6Ahjo6GoY6hj9JGmDmPoCGPoCGOjAGKpX40JWxpbmsuY2hhaW4udG9uLmNjaXAuQnVybk1pbnRUb2tlblBvb2yCLUwLjEuMIACyp3e1E0NQx1DH0BPQEMdGAQPQOb6ExAGW0o72omhqahj6Ahj6Ahjo6GpqGP0kGOmDmPoCGPoCGOjoan0kGOoY6Y+Y6Oh9JH0oGOjAAcbdw3aiaGpqGPoCGPoCGOjoahjqfSQY6YOY+gIY+gIY6Oh6AnoCGPoCGOjAIHoHN9DJ/SRoyRg28UABXuD7e1E0NTUMfQEMfQEMdHQ1NQx+kgx0wcx9AQx9AQx0dDUMfpI1DHTHzHRgCAVg6OwBdsuB7UTQ1NQx9AQx9AQx0dDUMdT6SDHTBzH0BDH0BDHR0PQEMfQEMfQE0QHwA7OAAT7Ice1E0NTUMfQEMfQEMdHQ1DHUMfpIMdMHMfQE9AQx0YBA9A5voTGACASA+PwIBIGprAgEgQEECASBERQDxDJsMzk5OTo6OjqCAKDxU22AQPQOb6Exs/L0LdD6SNQx0QHIzBrLPxj6UhbL/xT6UskEyMwTzMkEyPpUE8wTzCLPC/8T+lLJVCAmgED0F4IK+vCA+ChtyM+FiBb6Ulj6AoIQWV8HvM8LihPLP1AF+gL6VPQAyXH7AIAL3DEyOzs8gTpFDcMAHfL0ggCg81OtgED0Dm+hMbPy9C7Q+kjU0VNRyM+EAhL6UvpSyQHIz4TQzMz5FsjPigBAy//PUAfIzBbLP1JA+lITy//6UswZ9AAX9ADJBMjL/8kCyPpUFMzMEvpSyVQgJoBA9BeCEAX14QAgbfgoiYEJDAAFAAHjIz5BeNRRmJ88LP1AK+gIS+lT6VM+EIBfOycjPhYgV+lIB+gKAFc8LihLLPxP6UlAD+gISzMlx+wCBAIUC9xTE4BA9A5voeMCMFMSgED0Dm+hggCg9AHy9NTR0PpQ1NT6SNEEggCg9gXHBRTy9FI1gED0WzAE0NQx0z/6SNP/MfpI1DH0BDH0BDHRJNDT/9H4KMj6UhP6UskByPpSEsv/zMnIz48YAASCEOnADJfPC/dwzwthEss/zMmBGRwRJDEg1ywit7npvOMC1ywgvhIW5OMC1ywiE1xmJOMC1ywmu4lAhIEhJSksA/tTR0PpQ1NTT//pI0QWCAKD1BscFFfL0UkeAQPRbMAHQ1DHTP/pI0/8x+kjRyPpS+lIkzwv/ycjPjxgABIIQN91vbs8L93DPC2ESyz/MyXD7ACFukzVfA44lggiYloDIz4WIE/pSWPoCghBsBgQkzwuKE8s/FMwTy//JgEH7AOIAWHD7ACBukl8DjiGCCJiWgMjPhYgS+lIB+gKCEHjcIjLPC4oSyz/MyYBB+wDiAewx1NdMVhnQ1PpIMdQx0x8x0dD6SPpQMdEDggDCiATHBRPy9NCUIMcAs44/INdLAZEwm4E0vAHAAfL010zQ4tM/UhARFoBA9FuBOjgB8vTIz48YAASCECeQgovPC/dwzwthEss/yXD7ABEU6DDQlCDHALOK6DB/TAH+MdM/MdM/10xWGdDU+kgx1DHTHzHR0PpI+lAx0QOCAMKIBMcFE/L0gTo4IVYWgED0Dm+hMfL0gTo4IVYWgED0Dm+hEvL01PQE1NTRgTo3JtDTByHBQfKFAaoC1xjR10nDAPL0JdDTByHBQfKFAaoC1xjRyM5x+QQDgTo/UxSDB1AC/jHTPzHTP9dMVhnQ1PpIMdQx0x8x0dD6SPpQMdEDggDCiATHBRPy9IE6OCFWFoBA9A5voTHy9IE6OCFWFoBA9A5voRLy9NT0BNTU0SXQ0wchwUHyhQGqAtcY0cjOcfkEA1ADgwf0W4E6QAHy9APIzBP0ABLMzFEQERaAQPRDyIlRUgT8jmgx0z8x+kj6UPpQMBEa0NT6SNQx0x/RItD6SPpQMdEGggDCiAfHBRby9CPI+lJSMPpUVhwB+lTJAsjM+lLME8sfyQHI+lIS+lQBERgB+lTJyM+PGAAEghC3NeMMzwv3cc8LYczJcPsAf+DXLCHihRzc4wLXLCJ/FpNk4wKJU1RVVgH+INdLAZEwm4E0vAHAAfL010zQ4tM/1NTUgTo3I9DTByHBQfKFAaoC1xjR10nDAPL0gTo7JVYZgED0Dm+hMbPy9AHQ1NTRbQLQ0gDTf9N/0fgjIsjLf8s/E8oAy3/Lf8kB0NIA03/Tf9H4IyLIy3/LPxPKAMt/y3/JAcjMzMn4I00BxHDIy3/LP3DPC4Bwzwt/yfgjcMjLf8s/cM8LgHDPC3/JAcjMzMkkBtCUIMcAs4roMAXIzBL0AMwTzFIyEReAQPRDyM+PGAAEghDtN8S8zwv3cM8LYRPLPwERFQHMyXD7ABETTgH+INdLAZEwm4E0vAHAAfL010zQ4tMHIcFB8oUBqgLXGMgi10kgqTgC8kWrAiDBQfKFzwsHEs7JgTo3IdDTByHBQfKFAaoC1xjR10nDAPL0INDTByHBQfKFAaoC1xjRyM5x+QQDgTo/UxaDB/QOb6Exs/L0VEEWgwf0F8jPjxgABE8ALoIQvw0ats8L93DPC2Epzws/FczJcPsAAH70Dm+hMbPy9FRGFIMH9BcDyMwT9AASzMxREBEWgED0Q8jPjxgABIIQvw0ats8L93DPC2EBERUByz/MyXD7AH8ABcYAAQA2zxaCELwUx+jPC/dwzwthAREVAcs/zMlw+wB/AJ4x0z8x1wsfERjQ1PpI1NMfMdEi0PpI+lAx0QSCAMKIBccFFPL0VhkCyMz6UhLMyx/JyM+PGAAEghBCanE7zwv3cM8LYQERGAHLH8lw+wB/Aawx10xWGAFWGAFWGAFWGAFWGAFWGAFWGAFWGAFWGAFWGAFWGAFWGAFWGAFWGAFWGAFWGAFWGAFWGAFWGAFWGAFWGAFWGAFWGAERGPAM0JQgxwCziugwf1cACDCh0fcE5tcnjtUx1NdMVhnQ1PpIMdQx0x8x0dD6SPpQMdEDggDCiATHBRPy9NCUIMcAs4roMNCUIMcAs44eINdLAZEwm4E0vAHAAfL010zQ4tM/EROAQPRbMBES6DB/4NcsJxg7JfTjAtcsJMlNshTjAtcsIWSDdbxaW1xdAv4g10sBkTCbgTS8AcAB8vTXTNDi0z/SANTUgTo4JVYZgED0Dm+hEvL01PQE1NTRB44/0NQx1DHRBNDSANN/03/R+CMiyMt/yz8TygDLf8t/yQPQ0gDTf9N/0fgjIsjLf8s/E8oAy3/Lf8kDyMwTzMkE4w0CyMwT9AATzBLMWREVWFkAfgbQ1DHUMdEE0NIA03/Tf9H4IyLIy3/LPxPKAMt/y3/JA9DSANN/03/R+CMiyMt/yz8TygDLf8t/yQPIzBPMyQAMgED0QxETAOAg10sBkTCbgTS8AcAB8vTXTNDi0z/SANP/0//TH9Mf0w/TD4E6OClWHoBA9A5voTHy9IE6NSjy9IE6NCOBJxC58vSBOjQigScQufL0gTo1JcIA8vQHyMoAFsv/FMv/Essfyx/LD8sPWREVgED0QxETAawx10wRGNDU+kjU0x/RA9D6SPpQ0YIAwohRYscFFvL0yPpSFPpUycjM+lISzMsfyREW0PQE9AT0BNERGdCUIMcAs4roMAHI9AD0AAERFwH0AMkRFREWf14AejHTPzH6SDARGNDU+kgx1NMf0SLQ+kj6UDHRBIIAwogFxwUU8vQByMwBERkB+lIBERgBzAERFwHLH8kRFn8C/o5OMdM/MfQFgTo+VhnQ1DH6SNQx0x8x0RPHBRLy9BEW0PQE9AT0BDHRAcj0APQAAREWAfQAycjPjxgABIIQJ14CNM8L93DPC2HJcPsAERV/4NcsIaj7vxzjAtcsI5sWhOSaMdM/+gD6UPAQf+AwVhjQ1PpI1NMf0QPQ+kj6UNFfYADUINdLAZEwm4E0vAHAAfL010zQ4tM/+lD6UCJul1I2gED0WzCbIsj6UlQgR4BA9EPiIW6XUjWAQPRbMJshyPpSVCBGgED0Q+IDyMs/EvpU+lTJyM+PGAAEghCcWruVzwv3cc8LYczJcPsAWAP+MdM/1NMf+lAwItDU0z/6SNP/+kjU9AT0BNGBOj1WIiXHBfL0gTo5J1YhgED0Dm+hMfL0gTo6ViPQ9AQx9AQx9ATRKPADs/L0LcMAllYWbrPDAJFw4p9WHVYdVh1WHVYdK1Yc2mDeViLQ9AQx9AT0BDHRUnCAQPQOb6HjD4E6PmFiYwBaQQYl8AGOHzRXGxEayPpSEvpUycjMAREZAfpSzAERFwHLH8kRFn/gEEVfBccAAAb6SNEABDBtAfwhbrPy9IE6PlEexwXy9C3DAJZWF26zwwCRcOKOEVYdVh1WHVYdVh1WESxWHtpw3oE6QFYkViRWJFYkViRWJFYkViRWJFYkViRWJFYkViRWJFYkViRWJFYkViRWJFYkViRWHlYb8A3y9FYjViNWI1YjViNWI1YjViNWI1YjViNkBPpWI1YjViNWI1YjViNWI1YjViNWI1YjViNWGPAOViQBViQBViQBViQBViQBViQBViQBViQBViQBViQBViQBViQBViQBViQBViQBViQBViQBViQBViQBViQBViQBViQBViQBVhwB8A8qwwAr4w8vwwCWVhZus8MAkXDi4wBTsWVmZ2gB8FYl0NQx+kgx1DHTH9FSwPAHgTo4KVYjgED0Dm+hEvL01PQE1NTRINDU1NHQ03/TP9IA03/Tf9EijixfBgHQ1NTR0NN/0z/SANN/03/RKlYt8AUEyMt/E8s/ygDLf8t/yQHIzMzJAeMNA8jMEvQAzMxSkhEjgED0Q2kAnoE6OClWI4BA9A5voRLy9NT0BNTU0QHQ1NTR0NN/0z/SANN/03/RKlYt8AUEyMt/E8s/ygDLf8t/yQHIzMzJA8jMEvQAEszMUpIRI4BA9EMAMlYfVh9WH1YfVh9UftxUftxUftxWGVYl2vAAjIE6RVYSwwCWVhNus8MAkXDi8vQRFREhERURFBEgERQRExEfERMREhEeERIREREdERECESNQA1YegBZ12zgEERAEED9O3H8ANGwWKlYt8AUEyMt/E8s/ygDLf8t/yQHIzMzJAgEgbG0CASBubwB5FcQXw9sYQHQ1PpIMdTTHzHRAdD6SPpQMdEixwWRW+DQ+kgx+lD6UDHRgTo+IW6zlQLHBcMAk2whcOLy9IAB3FcSVxBfDzJsMzMBgED0Dm+hkltw4dQx9ATUMdQx0QHQ0wchwUHyhQGqAtcY0cjOcfkEAwGDB/QOb6ExgAGUVxBfDzVfA2wiIW6RMeAw0IE6QSHXSYMHupch10rAAMMAkXDi8vTT/9GBOkEhhAe78vSAAiRXElcQXw81NVszUxK6kmwh4FMSvJ4CoYE6QiHBTvL08ASpBOACooE6QiHBTvL08ASBOkIhmYT/IqkEI77DAJF/4vL0qIA=='); + + 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.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.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, + } + + 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 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 + transferInitiator: c.Address | null + forwardPayload: ForwardPayloadRemainder + }) { + return TransferNotificationForRecipient.toCell(TransferNotificationForRecipient.create(body)); + } + + static createCellOfBurnMintTokenPoolClaimMinterAdmin(body: { + queryId: uint64 + }) { + return BurnMintTokenPool_ClaimMinterAdmin.toCell(BurnMintTokenPool_ClaimMinterAdmin.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 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 + transferInitiator: c.Address | null + forwardPayload: ForwardPayloadRemainder + }, extraOptions?: ExtraSendOptions) { + return provider.internal(via, { + value: msgValue, + body: TransferNotificationForRecipient.toCell(TransferNotificationForRecipient.create(body)), + ...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 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 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(); + } +} diff --git a/contracts/wrappers/gen/ccip/pools/LockReleaseTokenPool.ts b/contracts/wrappers/gen/ccip/pools/LockReleaseTokenPool.ts new file mode 100644 index 000000000..c39662042 --- /dev/null +++ b/contracts/wrappers/gen/ccip/pools/LockReleaseTokenPool.ts @@ -0,0 +1,3082 @@ +// 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 + +/** + > 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); + } +} + +/** + > 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_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_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 (0x56f73d37) 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: 0x56f73d37, + + create(args: { + queryId: uint64 + remoteChainSelectorsToRemove: SnakedCell + chainsToAdd: SnakedCell + }): TokenPool_ApplyChainUpdates { + return { + $: 'TokenPool_ApplyChainUpdates', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_ApplyChainUpdates { + loadAndCheckPrefix32(s, 0x56f73d37, '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(0x56f73d37, 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 (0x17c242dc) 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: 0x17c242dc, + + create(args: { + queryId: uint64 + remoteChainSelector: uint64 + remotePoolAddress: CellRef + }): TokenPool_AddRemotePool { + return { + $: 'TokenPool_AddRemotePool', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_AddRemotePool { + loadAndCheckPrefix32(s, 0x17c242dc, '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(0x17c242dc, 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 (0x426b8cc4) 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: 0x426b8cc4, + + create(args: { + queryId: uint64 + remoteChainSelector: uint64 + remotePoolAddress: CellRef + }): TokenPool_RemoveRemotePool { + return { + $: 'TokenPool_RemoveRemotePool', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_RemoveRemotePool { + loadAndCheckPrefix32(s, 0x426b8cc4, '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(0x426b8cc4, 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 (0xd7712810) 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: 0xd7712810, + + 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, 0xd7712810, '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(0xd7712810, 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 (0x3c50a39b) TokenPool_SetAllowedFinalityConfig { + > queryId: uint64 + > allowedFinalityConfig: uint32 + > } + */ +export interface TokenPool_SetAllowedFinalityConfig { + readonly $: 'TokenPool_SetAllowedFinalityConfig' + queryId: uint64 + allowedFinalityConfig: uint32 +} + +export const TokenPool_SetAllowedFinalityConfig = { + PREFIX: 0x3c50a39b, + + create(args: { + queryId: uint64 + allowedFinalityConfig: uint32 + }): TokenPool_SetAllowedFinalityConfig { + return { + $: 'TokenPool_SetAllowedFinalityConfig', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_SetAllowedFinalityConfig { + loadAndCheckPrefix32(s, 0x3c50a39b, 'TokenPool_SetAllowedFinalityConfig'); + return { + $: 'TokenPool_SetAllowedFinalityConfig', + queryId: s.loadUintBig(64), + allowedFinalityConfig: s.loadUintBig(32), + } + }, + store(self: TokenPool_SetAllowedFinalityConfig, b: c.Builder): void { + b.storeUint(0x3c50a39b, 32); + b.storeUint(self.queryId, 64); + b.storeUint(self.allowedFinalityConfig, 32); + }, + toCell(self: TokenPool_SetAllowedFinalityConfig): c.Cell { + return makeCellFrom(self, TokenPool_SetAllowedFinalityConfig.store); + } +} + +/** + > struct (0x4fe2d26c) TokenPool_SetRateLimitConfig { + > queryId: uint64 + > updates: SnakedCell + > } + */ +export interface TokenPool_SetRateLimitConfig { + readonly $: 'TokenPool_SetRateLimitConfig' + queryId: uint64 + updates: SnakedCell +} + +export const TokenPool_SetRateLimitConfig = { + PREFIX: 0x4fe2d26c, + + create(args: { + queryId: uint64 + updates: SnakedCell + }): TokenPool_SetRateLimitConfig { + return { + $: 'TokenPool_SetRateLimitConfig', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_SetRateLimitConfig { + loadAndCheckPrefix32(s, 0x4fe2d26c, 'TokenPool_SetRateLimitConfig'); + return { + $: 'TokenPool_SetRateLimitConfig', + queryId: s.loadUintBig(64), + updates: s.loadRef(), + } + }, + store(self: TokenPool_SetRateLimitConfig, b: c.Builder): void { + b.storeUint(0x4fe2d26c, 32); + b.storeUint(self.queryId, 64); + b.storeRef(self.updates); + }, + toCell(self: TokenPool_SetRateLimitConfig): c.Cell { + return makeCellFrom(self, TokenPool_SetRateLimitConfig.store); + } +} + +/** + > struct (0x30a1d1f7) 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: 0x30a1d1f7, + + create(args: { + queryId: uint64 + updates: SnakedCell + disableChainSelectors: SnakedCell + }): TokenPool_ApplyTokenTransferFeeConfigUpdates { + return { + $: 'TokenPool_ApplyTokenTransferFeeConfigUpdates', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_ApplyTokenTransferFeeConfigUpdates { + loadAndCheckPrefix32(s, 0x30a1d1f7, '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(0x30a1d1f7, 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 (0xe30764be) TokenPool_UpdateRampAccess { + > queryId: uint64 + > updates: SnakedCell + > } + */ +export interface TokenPool_UpdateRampAccess { + readonly $: 'TokenPool_UpdateRampAccess' + queryId: uint64 + updates: SnakedCell +} + +export const TokenPool_UpdateRampAccess = { + PREFIX: 0xe30764be, + + create(args: { + queryId: uint64 + updates: SnakedCell + }): TokenPool_UpdateRampAccess { + return { + $: 'TokenPool_UpdateRampAccess', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_UpdateRampAccess { + loadAndCheckPrefix32(s, 0xe30764be, 'TokenPool_UpdateRampAccess'); + return { + $: 'TokenPool_UpdateRampAccess', + queryId: s.loadUintBig(64), + updates: s.loadRef(), + } + }, + store(self: TokenPool_UpdateRampAccess, b: c.Builder): void { + b.storeUint(0xe30764be, 32); + b.storeUint(self.queryId, 64); + b.storeRef(self.updates); + }, + toCell(self: TokenPool_UpdateRampAccess): c.Cell { + return makeCellFrom(self, TokenPool_UpdateRampAccess.store); + } +} + +/** + > struct (0x9929b642) TokenPool_SetRMNProxy { + > queryId: uint64 + > rmnProxy: address + > } + */ +export interface TokenPool_SetRMNProxy { + readonly $: 'TokenPool_SetRMNProxy' + queryId: uint64 + rmnProxy: c.Address +} + +export const TokenPool_SetRMNProxy = { + PREFIX: 0x9929b642, + + create(args: { + queryId: uint64 + rmnProxy: c.Address + }): TokenPool_SetRMNProxy { + return { + $: 'TokenPool_SetRMNProxy', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_SetRMNProxy { + loadAndCheckPrefix32(s, 0x9929b642, 'TokenPool_SetRMNProxy'); + return { + $: 'TokenPool_SetRMNProxy', + queryId: s.loadUintBig(64), + rmnProxy: s.loadAddress(), + } + }, + store(self: TokenPool_SetRMNProxy, b: c.Builder): void { + b.storeUint(0x9929b642, 32); + b.storeUint(self.queryId, 64); + b.storeAddress(self.rmnProxy); + }, + toCell(self: TokenPool_SetRMNProxy): c.Cell { + return makeCellFrom(self, TokenPool_SetRMNProxy.store); + } +} + +/** + > struct (0x2c906eb7) TokenPool_UpdateCursedSubjects { + > queryId: uint64 + > cursedSubjects: CursedSubjects + > } + */ +export interface TokenPool_UpdateCursedSubjects { + readonly $: 'TokenPool_UpdateCursedSubjects' + queryId: uint64 + cursedSubjects: CursedSubjects +} + +export const TokenPool_UpdateCursedSubjects = { + PREFIX: 0x2c906eb7, + + create(args: { + queryId: uint64 + cursedSubjects: CursedSubjects + }): TokenPool_UpdateCursedSubjects { + return { + $: 'TokenPool_UpdateCursedSubjects', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_UpdateCursedSubjects { + loadAndCheckPrefix32(s, 0x2c906eb7, 'TokenPool_UpdateCursedSubjects'); + return { + $: 'TokenPool_UpdateCursedSubjects', + queryId: s.loadUintBig(64), + cursedSubjects: CursedSubjects.fromSlice(s), + } + }, + store(self: TokenPool_UpdateCursedSubjects, b: c.Builder): void { + b.storeUint(0x2c906eb7, 32); + b.storeUint(self.queryId, 64); + CursedSubjects.store(self.cursedSubjects, b); + }, + toCell(self: TokenPool_UpdateCursedSubjects): c.Cell { + return makeCellFrom(self, TokenPool_UpdateCursedSubjects.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 + > 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: 0x351f77e3, + + 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, 0x351f77e3, '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(0x351f77e3, 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 (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 (0xef0cb36e) TokenPool_ReleaseOrMintFailure { + > queryId: uint64 + > errorCode: uint16 + > } + */ +export interface TokenPool_ReleaseOrMintFailure { + readonly $: 'TokenPool_ReleaseOrMintFailure' + queryId: uint64 + errorCode: uint16 +} + +export const TokenPool_ReleaseOrMintFailure = { + PREFIX: 0xef0cb36e, + + create(args: { + queryId: uint64 + errorCode: uint16 + }): TokenPool_ReleaseOrMintFailure { + return { + $: 'TokenPool_ReleaseOrMintFailure', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_ReleaseOrMintFailure { + loadAndCheckPrefix32(s, 0xef0cb36e, 'TokenPool_ReleaseOrMintFailure'); + return { + $: 'TokenPool_ReleaseOrMintFailure', + queryId: s.loadUintBig(64), + errorCode: s.loadUintBig(16), + } + }, + store(self: TokenPool_ReleaseOrMintFailure, b: c.Builder): void { + b.storeUint(0xef0cb36e, 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); + } +} + +/** + > 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? + > 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_Config { + > isEnabled: bool + > capacity: uint128 + > rate: uint128 + > } + */ +export interface RateLimiter_Config { + readonly $: 'RateLimiter_Config' + isEnabled: boolean + capacity: uint128 + rate: uint128 +} + +export const RateLimiter_Config = { + create(args: { + isEnabled: boolean + capacity: uint128 + rate: uint128 + }): RateLimiter_Config { + return { + $: 'RateLimiter_Config', + ...args + } + }, + fromSlice(s: c.Slice): RateLimiter_Config { + return { + $: 'RateLimiter_Config', + isEnabled: s.loadBoolean(), + capacity: s.loadUintBig(128), + rate: s.loadUintBig(128), + } + }, + store(self: RateLimiter_Config, b: c.Builder): void { + b.storeBit(self.isEnabled); + b.storeUint(self.capacity, 128); + b.storeUint(self.rate, 128); + }, + toCell(self: RateLimiter_Config): c.Cell { + return makeCellFrom(self, RateLimiter_Config.store); + } +} + +/** + > struct RateLimiter_TokenBucket { + > tokens: uint128 + > lastUpdated: uint64 + > isEnabled: bool + > capacity: uint128 + > rate: uint128 + > } + */ +export interface RateLimiter_TokenBucket { + readonly $: 'RateLimiter_TokenBucket' + tokens: uint128 + lastUpdated: uint64 + isEnabled: boolean + capacity: uint128 + rate: uint128 +} + +export const RateLimiter_TokenBucket = { + create(args: { + tokens: uint128 + lastUpdated: uint64 + isEnabled: boolean + capacity: uint128 + rate: uint128 + }): RateLimiter_TokenBucket { + return { + $: 'RateLimiter_TokenBucket', + ...args + } + }, + fromSlice(s: c.Slice): RateLimiter_TokenBucket { + return { + $: 'RateLimiter_TokenBucket', + tokens: s.loadUintBig(128), + lastUpdated: s.loadUintBig(64), + isEnabled: s.loadBoolean(), + capacity: s.loadUintBig(128), + rate: s.loadUintBig(128), + } + }, + store(self: RateLimiter_TokenBucket, b: c.Builder): void { + b.storeUint(self.tokens, 128); + b.storeUint(self.lastUpdated, 64); + b.storeBit(self.isEnabled); + b.storeUint(self.capacity, 128); + b.storeUint(self.rate, 128); + }, + 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('te6ccgECbgEAF3cAART/APSkE/S88sgLAQIBYgIDAgLLBAUCASAmJwIBIAYHAgHOHR4CASAICQIBIDo7AgEgCgsCASAXGAIBIAwNAFdSFukltw4IJpAAAAAAAAAAAAAAAAAAABIoMG9A5voTGSW3/gAYMG9A5voTGAT1PiR4wLtRNDU1PQE0SLQ1NT6SNMH9AT0BNGBAIVtbW1tbW1tbW2S8AgAkvAJAIEAhlYVVhVWFfiS+JcEEREEAxEQAxAvEE4QPRAsEEsQOhApEEgQNxAmEEUQNBAjVhvwClcQXwwD4wJfCSPXLCapk7bc4wJfBIQPAccAgDg8QEQGpO2i7fvXLCeQ2+0MjkTXLCfPFPJUlFtw2zHhggDCiiNus/L0IYIAwooExwUT8vQgbQPXCz+LAgHIyz8V+lIS+lLJyM+HIBTOcc8LYRPMyXD7AOMNf4BYB9tMfMdcsIHxT9SyO7O1E0NTU9ATRA9cLP/iSItD6SNTRgWbA+CjIz4QC+lIT+lLJAcjPhNDMzPkWyM+KAEDL/89QEscF8vRTA4BA9A5voYFmvgHy9NTR0PpQ1DHUMfpIMdFSFYBA9FswJG6SNDDjDgHIzMz0AMntVODyPxIATjs7wwCSNjaWODgQVxBG4gPIzBLM+lLLBxL0APQAycjMEsz0AMntVAP+NAPXCz/4klMUgED0Dm+hgWa+AfL01NHQ+lDU1PpI0QSBZr8FxwUU8vRSN4BA9FswBtDUMdM/+kjT/zH6SNQx9AQx9AQx0STQ0//R+CjI+lIT+lLJAcj6UhLL/8zJyM+PGAAEghDpwAyXzwv3cM8LYRLLP8zJcPsAIG7jDwHIzBMUFQAE8vQASIIImJaAyM+FiBb6UlAF+gKCEO8Ms27PC4rLP8+JmwLJgEH7AAAEXwMAQoIImJaAyM+FiBL6UgH6AoIQeNwiMs8LihLLP8zJgEH7AAAMzPQAye1UAGZsEtM/+kgwggDCiFE0xwUT8vSCAMKJUyPHBbPy9CGLAsjPhyDOcM8LYRLLPxL6Uslw+wACASAZGgIBIBscAEkcXqTIsIAjhkicbDAAZyE/yKpBCG+8oRmqAHeIKgCqwAC6DAxgAKsMCOzkX+VIMAAwwDikTDgIvgjJqEgjhg2U2C8lYFmvPLw4FFSqBagUkDwBgX4IwWRMOIhuZWBZr3y8OBTULmOERVfBSCVgWa+8vDhMIFmvvLw4BWhBIAANFy5kTDgMYAApCGRW+GBOkkhlAK6wwCTbCFw4vL0gAvUKMMAlStus8MAkXDijilXFAoRFgoJERUJCBEUCFUGERNWFtq/DhEaDg0RGQ0MERgMgQCFERhVsOCBOj1WHCTHBfL0gTo5JlYbgED0Dm+hMfL0gTo6Vh3Q9AQx9AQx9ATRJ/ADs/L0KMMAllYRbrPDAJFw4uMAVhzQ9ASAfIAB/DEybPMzM2xENFqAQPQOb6GTXwNw4dIA0/8x0/8x0x8x0x8x0w/TD9ECk18EcOEDlzKogScQqQTgMKiBJxCpBIAAaVhdWF1YXVhcpVhbaUAH89AQx9AQx0VJggED0Dm+hk/pI0ZIwbeKBOj4hbrPy9IE6PlEZxwXy9CjDAJZWE26zwwCRcOKOElYXAVYXAVYXAVYXVBC5VhjaYJE34lYcVhxWHFYcVhxWHFYcVhxWHFYcVhxWHFYcVhxWHFYcVhxWHFYcVhxWHFYcVhtWG1YbIQP+VhtWG1Yb8BFTMKEiwwAjjk+BOjgoVh2AQPQOb6ES8vTU9ATU1NEB0NTU0QHQ03/TP9IA03/Tf9EqVifwBQTIy38Tyz/KAMt/y3/JyMzMyQPIzBL0ABLMzFKCER2AQPRD4w0qwwCWVhJus8MAkXDi4wCBOjhTgYBA9A5voRLy9CIjJAHyVh/Q1DH6SDHUMdMf0VJA8AeBOjgoVh2AQPQOb6ES8vTU9ATU1NEg0NTU0QHQ03/TP9IA03/Tf9EijixfBgHQ1NTRAdDTf9M/0gDTf9N/0SpWJ/AFBMjLfxPLP8oAy3/Lf8nIzMzJAeMNA8jMEvQAzMxSghEdgED0QyUAKlYZVhlWGVYZVHy6VHy6VhMsVh7awAA+1PQEMdQx1DHRVh3Iy//JAhEdAhCrEJoQiRB4EGcQVgAybBYqVifwBQTIy38Tyz/KAMt/y3/JyMzMyQIBICgpAgEgNDUCASAqKwIBIDAxAgEgLC0AO7W1HaiaGpqGPoCGOjoahjqGP0kGOmD+gIY+gIY6MAIBai4vAGmwV+NChsaW5rLmNoYWluLnRvbi5jY2lwLkxvY2tSZWxlYXNlVG9rZW5Qb29sgi1MC4xLjCIABppXXaiaGpqGPoCGOjoahjqfSQY6YOY+gIY+gIY6Oh6Ahj6AnoCGOjAIHoHN9DJ/SRoyRg28UAOacj2omhqahj6Ahjo6GoY6hj9JGmDmPoCGPoCGOjAF+0o72omhqahj6Ahjo6GpqGP0kGOmDmPoCGPoCGOjoan0kGOoY6Y+Y6Oh9JH0oGOjACA3tgMjMAXaOvtRNDU1DH0BDHR0NTUMfpIMdMHMfQEMfQEMdHQ1PpIMdQx0x8x0dD6SDH6UNGAGmiG7UTQ1NQx9AQx0dDUMdT6SDHTBzH0BDH0BDHR0PQE9AQx9AQx0YBA9A5voZP6SNGSMG3igBRuD7e1E0NTUMfQEMdHQ1NQx+kgx0wcx9AQx9AQx0dDUMfpI1DHTHzHRgCAVg2NwBXsuB7UTQ1NQx9AQx0dDUMdT6SDHTBzH0BDH0BDHR0PQEMfQEMfQE0QHwA7OACAVg4OQBIqHHtRNDU1DH0BDHR0NQx1DH6SDHTBzH0BPQEMdGAQPQOb6ExACaqqO1E0NQx1DH0BNGAQPQOb6ExAgEgPD0CASBlZgIBID4/AgEgQkMA5QybGMzMzQ0Njc3N9DUMdM/+kgx0/8x+kjRyPpSFPpSJc8L/8nIz48YAASCEDfdb27PC/dwzwthFMs/E8zJcPsAIm6SXwWOKoIImJaABcjMzMnIz4WIE/pSUAT6AoIQbAYEJM8LihPLPxLMy//JgEH7AOKAB9wxMjs7PIE6RQ3DAB3y9IFmvVOtgED0Dm+hMbPy9C3Q+kjU0VNRyM+EAhL6UvpSySHIz4TQzMz5FsjPigBAy//PUAjIzBfLP1JQ+lIUy/8S+lLMGvQAGPQAyQXIy//JA8j6VBXMEsz6UslUIDeAQPQXggr68IBx+Cj4KMiBAAaaJzxb6Uhj6UslQBMjPhNDMzPkWyM+KAEDL/89QbYsEyM+QPin6lhfLP1AJ+gIW+lIW+lQW9ADPhCASzsnIz4WIE/pSUAP6AnHPC2rMyQH7AIEAhUEAAgAESQxINcsIre56bzjAtcsIL4SFuTjAtcsIhNcZiTjAtcsJruJQISBERUZHAHkVxBfD2xRAdDU+kgx1NMfMdEB0PpI+lAx0SLHBZFb4ND6SDH6UPpQMdGBOj4hbrOVAscFwwCTbCFw4vL0gAewx1NdMVhjQ1PpIMdQx0x8x0dD6SPpQMdEDggDCiATHBRPy9NCUIMcAs44/INdLAZEwm4E0vAHAAfL010zQ4tM/UhARFYBA9FuBOjgB8vTIz48YAASCECeQgovPC/dwzwthEss/yXD7ABET6DDQlCDHALOK6DB/SAH+MdM/MdM/10xWGNDU+kgx1DHTHzHR0PpI+lAx0QOCAMKIBMcFE/L0gTo4IVYVgED0Dm+hMfL0gTo4IVYVgED0Dm+hEvL01PQE1NTRgTo3JtDTByHBQfKFAaoC1xjR10nDAPL0JdDTByHBQfKFAaoC1xjRyM5x+QQDgTo/UxSDB0wC/jHTPzHTP9dMVhjQ1PpIMdQx0x8x0dD6SPpQMdEDggDCiATHBRPy9IE6OCFWFYBA9A5voTHy9IE6OCFWFYBA9A5voRLy9NT0BNTU0SXQ0wchwUHyhQGqAtcY0cjOcfkEA1ADgwf0W4E6QAHy9APIzBP0ABLMzFEQERWAQPRDyIlNTgT8jmgx0z8x+kj6UPpQMBEZ0NT6SNQx0x/RItD6SPpQMdEGggDCiAfHBRby9CPI+lJSMPpUVhsB+lTJAsjM+lLME8sfyQHI+lIS+lQBERcB+lTJyM+PGAAEghC3NeMMzwv3cc8LYczJcPsAf+DXLCHihRzc4wLXLCJ/FpNk4wKJT1BRUgH+INdLAZEwm4E0vAHAAfL010zQ4tM/1NTUgTo3I9DTByHBQfKFAaoC1xjR10nDAPL0gTo7JVYYgED0Dm+hMbPy9AHQ1NTRbQLQ0gDTf9N/0fgjIsjLf8s/E8oAy3/Lf8kB0NIA03/Tf9H4IyLIy3/LPxPKAMt/y3/JAcjMzMn4I0kBxHDIy3/LP3DPC4Bwzwt/yfgjcMjLf8s/cM8LgHDPC3/JAcjMzMkkBtCUIMcAs4roMAXIzBL0AMwTzFIyERaAQPRDyM+PGAAEghDtN8S8zwv3cM8LYRPLPwERFAHMyXD7ABESSgH+INdLAZEwm4E0vAHAAfL010zQ4tMHIcFB8oUBqgLXGMgi10kgqTgC8kWrAiDBQfKFzwsHEs7JgTo3IdDTByHBQfKFAaoC1xjR10nDAPL0INDTByHBQfKFAaoC1xjRyM5x+QQDgTo/UxaDB/QOb6Exs/L0VEEWgwf0F8jPjxgABEsALoIQvw0ats8L93DPC2Epzws/FczJcPsAAH70Dm+hMbPy9FRGFIMH9BcDyMwT9AASzMxREBEVgED0Q8jPjxgABIIQvw0ats8L93DPC2EBERQByz/MyXD7AH8ABcYAAQA2zxaCELwUx+jPC/dwzwthAREUAcs/zMlw+wB/AJ4x0z8x1wsfERfQ1PpI1NMfMdEi0PpI+lAx0QSCAMKIBccFFPL0VhgCyMz6UhLMyx/JyM+PGAAEghBCanE7zwv3cM8LYQERFwHLH8lw+wB/AaYx10xWFwFWFwFWFwFWFwFWFwFWFwFWFwFWFwFWFwFWFwFWFwFWFwFWFwFWFwFWFwFWFwFWFwFWFwFWFwFWFwFWFwFWFwERF/AL0JQgxwCziugwf1MACDCh0fcE5tcnjtUx1NdMVhjQ1PpIMdQx0x8x0dD6SPpQMdEDggDCiATHBRPy9NCUIMcAs4roMNCUIMcAs44eINdLAZEwm4E0vAHAAfL010zQ4tM/ERKAQPRbMBER6DB/4NcsJxg7JfTjAtcsJMlNshTjAtcsIWSDdbxWV1hZAv4g10sBkTCbgTS8AcAB8vTXTNDi0z/SANTUgTo4JVYYgED0Dm+hEvL01PQE1NTRB44/0NQx1DHRBNDSANN/03/R+CMiyMt/yz8TygDLf8t/yQPQ0gDTf9N/0fgjIsjLf8s/E8oAy3/Lf8kDyMwTzMkE4w0CyMwT9AATzBLMWREUVFUAfgbQ1DHUMdEE0NIA03/Tf9H4IyLIy3/LPxPKAMt/y3/JA9DSANN/03/R+CMiyMt/yz8TygDLf8t/yQPIzBPMyQAMgED0QxESAOAg10sBkTCbgTS8AcAB8vTXTNDi0z/SANP/0//TH9Mf0w/TD4E6OClWHYBA9A5voTHy9IE6NSjy9IE6NCOBJxC58vSBOjQigScQufL0gTo1JcIA8vQHyMoAFsv/FMv/Essfyx/LD8sPWREUgED0QxESAawx10wRF9DU+kjU0x/RA9D6SPpQ0YIAwohRYscFFvL0yPpSFPpUycjM+lISzMsfyREV0PQE9AT0BNERGNCUIMcAs4roMAHI9AD0AAERFgH0AMkRFBEVf1oAejHTPzH6SDARF9DU+kgx1NMf0SLQ+kj6UDHRBIIAwogFxwUU8vQByMwBERgB+lIBERcBzAERFgHLH8kRFX8C/o5OMdM/MfQFgTo+VhjQ1DH6SNQx0x8x0RPHBRLy9BEV0PQE9AT0BDHRAcj0APQAAREVAfQAycjPjxgABIIQJ14CNM8L93DPC2HJcPsAERR/4NcsIaj7vxzjAtcsI5sWhOSaMdM/+gD6UPAPf+AwVhfQ1PpI1NMf0QPQ+kj6UNFbXADUINdLAZEwm4E0vAHAAfL010zQ4tM/+lD6UCJul1I2gED0WzCbIsj6UlQgR4BA9EPiIW6XUjWAQPRbMJshyPpSVCBGgED0Q+IDyMs/EvpU+lTJyM+PGAAEghCcWruVzwv3cc8LYczJcPsAWAL6MdM/1NMf+lAwItDU0z/6SNP/+kjU9AT0BNGBOj1WISXHBfL0gTo5J1YggED0Dm+hMfL0gTo6ViLQ9AQx9AQx9ATRKPADs/L0LcMAllYWbrPDAJFw4p1WHFYcVhxWHCpWG9pQ3lYh0PQEMfQE9AQx0VJwgED0Dm+hkjBt4w1dXgBaQQYl8AGOHzRXGhEZyPpSEvpUycjMAREYAfpSzAERFgHLH8kRFX/gEEVfBccAAAb6SNEB/IE6PiFus/L0gTo+UR7HBfL0LcMAllYXbrPDAJFw4p9WHFYcVhxWHFYQK1Yd2mDegTpAViNWI1YjViNWI1YjViNWI1YjViNWI1YjViNWI1YjViNWI1YjViNWI1YjViNWHVYa8Azy9FYiViJWIlYiViJWIlYiViJWIlYiViJWIl8E+lYiViJWIlYiViJWIlYiViJWIlYiVhfwDVYjAVYjAVYjAVYjAVYjAVYjAVYjAVYjAVYjAVYjAVYjAVYjAVYjAVYjAVYjAVYjAVYjAVYjAVYjAVYjAVYjAVYjAVYbAfAOKsMAK+MPL8MAllYWbrPDAJFw4uMAU7GBOkVWEsMAYGFiYwHwViTQ1DH6SDHUMdMf0VLA8AeBOjgpViKAQPQOb6ES8vTU9ATU1NEg0NTU0dDTf9M/0gDTf9N/0SKOLF8GAdDU1NHQ03/TP9IA03/Tf9EqVizwBQTIy38Tyz/KAMt/y3/JAcjMzMkB4w0DyMwS9ADMzFKSESKAQPRDZACegTo4KVYigED0Dm+hEvL01PQE1NTRAdDU1NHQ03/TP9IA03/Tf9EqVizwBQTIy38Tyz/KAMt/y3/JAcjMzMkDyMwS9AASzMxSkhEigED0QwAuVh5WHlYeVh5UfctUfctUfctWGFYk2uAAapZWE26zwwCRcOLy9BEUESARFBETER8RExESER4REhERER0REQIRIlADVh6AFXTbOBA/Ttx/ADRsFipWLPAFBMjLfxPLP8oAy3/Lf8kByMzMyQIBIGdoAgEgaWoAdRXElcQXw9sMzNZgED0Dm+hkltw4dQx9ATUMdQx0QHQ0wchwUHyhQGqAtcY0cjOcfkEAwGDB/QOb6ExgAGMVxBfDzRbbCIhbpEx4DDQgTpBIddJgwe6lyHXSsAAwwCRcOLy9NP/0YE6QSGEB7vy9IACHFcSVxBfDzJsM1MCupIwMeBTAryeWKGBOkIhwU7y9PAEqQTgEqGBOkIhwU7y9PAEgTpCIZmE/yKpBCO+wwCRf+Ly9KiAB9QlwwCVKW6zwwCRcOKOG1cRBxETBwYREgYFEREFVQMRECjag07cgQCFDOAg9AQhbpgxIMcAkjBt4JLR0OKBOkYhbrPy9NcsJ9PtIiTyv9M/1NMf9AT6UNEj0NTTP/pI0//6SNGBOkhTLbry9IE6Ryxus/L0KxEbESURG4GsB/BEaESQRGhEZESMRGREYESIRGBEXESERFxEWESARFhEVER8RFREUER4RFBETER0RExESERwREhERESUREREQESQREA8RIw8OESIODREhDQwRIAwLER8LChEeCgkRHQkIERwIBxElBwYRJAZVQFYcVibwECzDAJUubrPDAJFw4mwBqI4oXwwJER8JCBEeCAcRHQcGERwGBREbBQQRGgQDERkDAhEYAlcWVxZfCOMNCxEVCwoRFAoJERMJCBESCAcREQcGERAGEF8QThA9TBoIBkS0GRcVE20A9lcYERgRGhEYERcRGREXERYRGhEWERURKBEVERQRJxEUERMRJhETERIRJRESERERJBERERARIxEQDxEiDw4RIQ4NESoNDBEpDFUKERlWKoAZc9s4ERERFBERERARExEQDxESDw4REQ4NERANEM8QvhC9ELwQO0A0gQCFAg=='); + + 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.MissingForwardPayload': 14918, + 'TokenPool_Error.MissingTransferInitiator': 14919, + 'TokenPool_Error.AmountMismatch': 14920, + 'TokenPool_Error.InvalidRequestedFinality': 14921, + 'RateLimiter_Error.BucketOverfilled': 26300, + 'Error.PendingReleaseAlreadyExists': 26301, + 'RateLimiter_Error.TokenMaxCapacityExceeded': 26301, + 'Error.PendingReleaseNotFound': 26302, + 'RateLimiter_Error.TokenRateLimitReached': 26302, + 'Error.UnexpectedReleaseConfirmationSender': 26303, + 'Error.UnexpectedReleaseBounce': 26304, + '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 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 + transferInitiator: c.Address | null + forwardPayload: ForwardPayloadRemainder + }) { + return TransferNotificationForRecipient.toCell(TransferNotificationForRecipient.create(body)); + } + + static createCellOfLockReleaseTokenPoolInMessage(body: LockReleaseTokenPool_InMessage) { + return LockReleaseTokenPool_InMessage.toCell(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 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 + transferInitiator: c.Address | null + forwardPayload: ForwardPayloadRemainder + }, extraOptions?: ExtraSendOptions) { + return provider.internal(via, { + value: msgValue, + body: TransferNotificationForRecipient.toCell(TransferNotificationForRecipient.create(body)), + ...extraOptions + }); + } + + async sendLockReleaseTokenPoolInMessage(provider: ContractProvider, via: Sender, msgValue: coins, body: LockReleaseTokenPool_InMessage, extraOptions?: ExtraSendOptions) { + return provider.internal(via, { + value: msgValue, + body: LockReleaseTokenPool_InMessage.toCell(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 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() + ); + } +} diff --git a/contracts/wrappers/gen/ccip/pools/TokenPool.ts b/contracts/wrappers/gen/ccip/pools/TokenPool.ts new file mode 100644 index 000000000..5a697f680 --- /dev/null +++ b/contracts/wrappers/gen/ccip/pools/TokenPool.ts @@ -0,0 +1,2279 @@ +// 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 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 '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_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 (0x56f73d37) 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: 0x56f73d37, + + create(args: { + queryId: uint64 + remoteChainSelectorsToRemove: SnakedCell + chainsToAdd: SnakedCell + }): TokenPool_ApplyChainUpdates { + return { + $: 'TokenPool_ApplyChainUpdates', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_ApplyChainUpdates { + loadAndCheckPrefix32(s, 0x56f73d37, '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(0x56f73d37, 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 (0x17c242dc) 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: 0x17c242dc, + + create(args: { + queryId: uint64 + remoteChainSelector: uint64 + remotePoolAddress: CellRef + }): TokenPool_AddRemotePool { + return { + $: 'TokenPool_AddRemotePool', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_AddRemotePool { + loadAndCheckPrefix32(s, 0x17c242dc, '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(0x17c242dc, 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 (0x426b8cc4) 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: 0x426b8cc4, + + create(args: { + queryId: uint64 + remoteChainSelector: uint64 + remotePoolAddress: CellRef + }): TokenPool_RemoveRemotePool { + return { + $: 'TokenPool_RemoveRemotePool', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_RemoveRemotePool { + loadAndCheckPrefix32(s, 0x426b8cc4, '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(0x426b8cc4, 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 (0xd7712810) 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: 0xd7712810, + + 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, 0xd7712810, '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(0xd7712810, 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 (0x3c50a39b) TokenPool_SetAllowedFinalityConfig { + > queryId: uint64 + > allowedFinalityConfig: uint32 + > } + */ +export interface TokenPool_SetAllowedFinalityConfig { + readonly $: 'TokenPool_SetAllowedFinalityConfig' + queryId: uint64 + allowedFinalityConfig: uint32 +} + +export const TokenPool_SetAllowedFinalityConfig = { + PREFIX: 0x3c50a39b, + + create(args: { + queryId: uint64 + allowedFinalityConfig: uint32 + }): TokenPool_SetAllowedFinalityConfig { + return { + $: 'TokenPool_SetAllowedFinalityConfig', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_SetAllowedFinalityConfig { + loadAndCheckPrefix32(s, 0x3c50a39b, 'TokenPool_SetAllowedFinalityConfig'); + return { + $: 'TokenPool_SetAllowedFinalityConfig', + queryId: s.loadUintBig(64), + allowedFinalityConfig: s.loadUintBig(32), + } + }, + store(self: TokenPool_SetAllowedFinalityConfig, b: c.Builder): void { + b.storeUint(0x3c50a39b, 32); + b.storeUint(self.queryId, 64); + b.storeUint(self.allowedFinalityConfig, 32); + }, + toCell(self: TokenPool_SetAllowedFinalityConfig): c.Cell { + return makeCellFrom(self, TokenPool_SetAllowedFinalityConfig.store); + } +} + +/** + > struct (0x4fe2d26c) TokenPool_SetRateLimitConfig { + > queryId: uint64 + > updates: SnakedCell + > } + */ +export interface TokenPool_SetRateLimitConfig { + readonly $: 'TokenPool_SetRateLimitConfig' + queryId: uint64 + updates: SnakedCell +} + +export const TokenPool_SetRateLimitConfig = { + PREFIX: 0x4fe2d26c, + + create(args: { + queryId: uint64 + updates: SnakedCell + }): TokenPool_SetRateLimitConfig { + return { + $: 'TokenPool_SetRateLimitConfig', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_SetRateLimitConfig { + loadAndCheckPrefix32(s, 0x4fe2d26c, 'TokenPool_SetRateLimitConfig'); + return { + $: 'TokenPool_SetRateLimitConfig', + queryId: s.loadUintBig(64), + updates: s.loadRef(), + } + }, + store(self: TokenPool_SetRateLimitConfig, b: c.Builder): void { + b.storeUint(0x4fe2d26c, 32); + b.storeUint(self.queryId, 64); + b.storeRef(self.updates); + }, + toCell(self: TokenPool_SetRateLimitConfig): c.Cell { + return makeCellFrom(self, TokenPool_SetRateLimitConfig.store); + } +} + +/** + > struct (0x30a1d1f7) 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: 0x30a1d1f7, + + create(args: { + queryId: uint64 + updates: SnakedCell + disableChainSelectors: SnakedCell + }): TokenPool_ApplyTokenTransferFeeConfigUpdates { + return { + $: 'TokenPool_ApplyTokenTransferFeeConfigUpdates', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_ApplyTokenTransferFeeConfigUpdates { + loadAndCheckPrefix32(s, 0x30a1d1f7, '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(0x30a1d1f7, 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 (0xe30764be) TokenPool_UpdateRampAccess { + > queryId: uint64 + > updates: SnakedCell + > } + */ +export interface TokenPool_UpdateRampAccess { + readonly $: 'TokenPool_UpdateRampAccess' + queryId: uint64 + updates: SnakedCell +} + +export const TokenPool_UpdateRampAccess = { + PREFIX: 0xe30764be, + + create(args: { + queryId: uint64 + updates: SnakedCell + }): TokenPool_UpdateRampAccess { + return { + $: 'TokenPool_UpdateRampAccess', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_UpdateRampAccess { + loadAndCheckPrefix32(s, 0xe30764be, 'TokenPool_UpdateRampAccess'); + return { + $: 'TokenPool_UpdateRampAccess', + queryId: s.loadUintBig(64), + updates: s.loadRef(), + } + }, + store(self: TokenPool_UpdateRampAccess, b: c.Builder): void { + b.storeUint(0xe30764be, 32); + b.storeUint(self.queryId, 64); + b.storeRef(self.updates); + }, + toCell(self: TokenPool_UpdateRampAccess): c.Cell { + return makeCellFrom(self, TokenPool_UpdateRampAccess.store); + } +} + +/** + > struct (0x9929b642) TokenPool_SetRMNProxy { + > queryId: uint64 + > rmnProxy: address + > } + */ +export interface TokenPool_SetRMNProxy { + readonly $: 'TokenPool_SetRMNProxy' + queryId: uint64 + rmnProxy: c.Address +} + +export const TokenPool_SetRMNProxy = { + PREFIX: 0x9929b642, + + create(args: { + queryId: uint64 + rmnProxy: c.Address + }): TokenPool_SetRMNProxy { + return { + $: 'TokenPool_SetRMNProxy', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_SetRMNProxy { + loadAndCheckPrefix32(s, 0x9929b642, 'TokenPool_SetRMNProxy'); + return { + $: 'TokenPool_SetRMNProxy', + queryId: s.loadUintBig(64), + rmnProxy: s.loadAddress(), + } + }, + store(self: TokenPool_SetRMNProxy, b: c.Builder): void { + b.storeUint(0x9929b642, 32); + b.storeUint(self.queryId, 64); + b.storeAddress(self.rmnProxy); + }, + toCell(self: TokenPool_SetRMNProxy): c.Cell { + return makeCellFrom(self, TokenPool_SetRMNProxy.store); + } +} + +/** + > struct (0x2c906eb7) TokenPool_UpdateCursedSubjects { + > queryId: uint64 + > cursedSubjects: CursedSubjects + > } + */ +export interface TokenPool_UpdateCursedSubjects { + readonly $: 'TokenPool_UpdateCursedSubjects' + queryId: uint64 + cursedSubjects: CursedSubjects +} + +export const TokenPool_UpdateCursedSubjects = { + PREFIX: 0x2c906eb7, + + create(args: { + queryId: uint64 + cursedSubjects: CursedSubjects + }): TokenPool_UpdateCursedSubjects { + return { + $: 'TokenPool_UpdateCursedSubjects', + ...args + } + }, + fromSlice(s: c.Slice): TokenPool_UpdateCursedSubjects { + loadAndCheckPrefix32(s, 0x2c906eb7, 'TokenPool_UpdateCursedSubjects'); + return { + $: 'TokenPool_UpdateCursedSubjects', + queryId: s.loadUintBig(64), + cursedSubjects: CursedSubjects.fromSlice(s), + } + }, + store(self: TokenPool_UpdateCursedSubjects, b: c.Builder): void { + b.storeUint(0x2c906eb7, 32); + b.storeUint(self.queryId, 64); + CursedSubjects.store(self.cursedSubjects, b); + }, + toCell(self: TokenPool_UpdateCursedSubjects): c.Cell { + return makeCellFrom(self, TokenPool_UpdateCursedSubjects.store); + } +} + +/** + > 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 + > 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: 0x351f77e3, + + 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, 0x351f77e3, '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(0x351f77e3, 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 (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 + > 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); + } +} + +/** + > 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 + > capacity: uint128 + > rate: uint128 + > } + */ +export interface RateLimiter_Config { + readonly $: 'RateLimiter_Config' + isEnabled: boolean + capacity: uint128 + rate: uint128 +} + +export const RateLimiter_Config = { + create(args: { + isEnabled: boolean + capacity: uint128 + rate: uint128 + }): RateLimiter_Config { + return { + $: 'RateLimiter_Config', + ...args + } + }, + fromSlice(s: c.Slice): RateLimiter_Config { + return { + $: 'RateLimiter_Config', + isEnabled: s.loadBoolean(), + capacity: s.loadUintBig(128), + rate: s.loadUintBig(128), + } + }, + store(self: RateLimiter_Config, b: c.Builder): void { + b.storeBit(self.isEnabled); + b.storeUint(self.capacity, 128); + b.storeUint(self.rate, 128); + }, + toCell(self: RateLimiter_Config): c.Cell { + return makeCellFrom(self, RateLimiter_Config.store); + } +} + +/** + > struct RateLimiter_TokenBucket { + > tokens: uint128 + > lastUpdated: uint64 + > isEnabled: bool + > capacity: uint128 + > rate: uint128 + > } + */ +export interface RateLimiter_TokenBucket { + readonly $: 'RateLimiter_TokenBucket' + tokens: uint128 + lastUpdated: uint64 + isEnabled: boolean + capacity: uint128 + rate: uint128 +} + +export const RateLimiter_TokenBucket = { + create(args: { + tokens: uint128 + lastUpdated: uint64 + isEnabled: boolean + capacity: uint128 + rate: uint128 + }): RateLimiter_TokenBucket { + return { + $: 'RateLimiter_TokenBucket', + ...args + } + }, + fromSlice(s: c.Slice): RateLimiter_TokenBucket { + return { + $: 'RateLimiter_TokenBucket', + tokens: s.loadUintBig(128), + lastUpdated: s.loadUintBig(64), + isEnabled: s.loadBoolean(), + capacity: s.loadUintBig(128), + rate: s.loadUintBig(128), + } + }, + store(self: RateLimiter_TokenBucket, b: c.Builder): void { + b.storeUint(self.tokens, 128); + b.storeUint(self.lastUpdated, 64); + b.storeBit(self.isEnabled); + b.storeUint(self.capacity, 128); + b.storeUint(self.rate, 128); + }, + toCell(self: RateLimiter_TokenBucket): c.Cell { + return makeCellFrom(self, RateLimiter_TokenBucket.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 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('te6ccgEBGAEArgABFP8A9KQT9LzyyAsBAgFiAgMAFNAw+JHyQIQP8vACASAEBQIBIAYHAgEgEhMCASAICQIBIA4PAgEgCgsADbW1EIH+XhACAWoMDQANsFfhA/y8IAALpXUIH+XhAAunIwgf5eEADbSjsIH+XhACA3tgEBEAC6OuED/LwgALohoQP8vCAA24PthA/y8IAgFYFBUADbLgYQP8vCACAVgWFwAMqHGED/LwAAyqqIQP8vA='); + + 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 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 + 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, + 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 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 + transferInitiator: c.Address | null + forwardPayload: ForwardPayloadRemainder + }, extraOptions?: ExtraSendOptions) { + return provider.internal(via, { + value: msgValue, + body: TransferNotificationForRecipient.toCell(TransferNotificationForRecipient.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 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() + ); + } +} 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, + ) +}