From 691a6feb3dcf157858eec4a8bc6f1b2034d378d8 Mon Sep 17 00:00:00 2001 From: Patricio Tourne Passarino Date: Thu, 30 Jul 2026 16:42:01 -0300 Subject: [PATCH 1/2] ref: remove relay, use blockchain sender --- contracts/contracts/test/mock/relay.tolk | 24 --- contracts/tests/ccip/onramp/OnRamp.Setup.ts | 7 + .../ccip/onramp/OnRamp.executorExited.spec.ts | 12 +- .../onramp/OnRamp.generateMessageID.spec.ts | 12 +- contracts/wrappers/test/mock/Relay.ts | 148 ------------------ .../wrappers/tests.mock.Relay.compile.ts | 7 - 6 files changed, 15 insertions(+), 195 deletions(-) delete mode 100644 contracts/contracts/test/mock/relay.tolk delete mode 100644 contracts/wrappers/test/mock/Relay.ts delete mode 100644 contracts/wrappers/tests.mock.Relay.compile.ts diff --git a/contracts/contracts/test/mock/relay.tolk b/contracts/contracts/test/mock/relay.tolk deleted file mode 100644 index 6928be795c..0000000000 --- a/contracts/contracts/test/mock/relay.tolk +++ /dev/null @@ -1,24 +0,0 @@ -// SPDX-License-Identifier: MIT -tolk 1.4.1 - -struct (0x527146b1) Relay_Send { - bounce: bool, - value: coins, - to: address, - body: cell, - sendMode: uint8, -} - -fun onInternalMessage(in: InMessage) { - if (in.body.isEmpty()) { - return; - } - val msg = Relay_Send.fromSlice(in.body); - val relayMsg = createMessage({ - bounce: msg.bounce, - value: msg.value, - dest: msg.to, - body: msg.body, - }); - relayMsg.send(msg.sendMode); -} \ No newline at end of file diff --git a/contracts/tests/ccip/onramp/OnRamp.Setup.ts b/contracts/tests/ccip/onramp/OnRamp.Setup.ts index f8ea385a41..026cabc9f9 100644 --- a/contracts/tests/ccip/onramp/OnRamp.Setup.ts +++ b/contracts/tests/ccip/onramp/OnRamp.Setup.ts @@ -83,3 +83,10 @@ export async function setup(blockchain: Blockchain, overrides: OnRampOverrides = const { onramp, config } = await deployOnRampContract(blockchain, deployer, overrides) return { deployer, onramp, config } } +export async function getStorage(blockchain: Blockchain, addr: Address): Promise { + const contract = await blockchain.getContract(addr) + if (contract.accountState == undefined) throw new Error('Contract account state is undefined') + const state = contract.accountState + if (state.type !== 'active') throw new Error('Contract account state is not active') + return state.state.data! +} diff --git a/contracts/tests/ccip/onramp/OnRamp.executorExited.spec.ts b/contracts/tests/ccip/onramp/OnRamp.executorExited.spec.ts index 346476fb31..d4dce206de 100644 --- a/contracts/tests/ccip/onramp/OnRamp.executorExited.spec.ts +++ b/contracts/tests/ccip/onramp/OnRamp.executorExited.spec.ts @@ -7,8 +7,7 @@ import * as coverage from '../../coverage/coverage' import * as or from '../../../wrappers/gen/ccip/OnRamp' import * as ex from '../../../wrappers/gen/ccip/CCIPSendExecutor' import * as rt from '../../../wrappers/gen/ccip/Router' -import * as relay from '../../../wrappers/test/mock/Relay' -import { setup } from './OnRamp.Setup' +import { getStorage, setup } from './OnRamp.Setup' import { contractCode } from '../../../wrappers/codeLoader' import { ChainSelectors } from '../../utils/Selectors' import EVM_ADDRESS from '../../utils/evmAddress' @@ -60,7 +59,7 @@ describe('OnRamp - executor exit', () => { }, executor: { deployableCode: deployableCode, - executorCode: await relay.ContractClient.code(), + executorCode: Cell.EMPTY, }, })) @@ -114,12 +113,9 @@ describe('OnRamp - executor exit', () => { throw new Error('Executor address not found') } - const relayContract = blockchain.openContract( - relay.ContractClient.createFromAddress(executorAddress), - ) - executorSender = await relayContract.getSender(deployer.getSender()) + executorSender = blockchain.sender(executorAddress) - const executorStorageCell = await relayContract.getStorage() + const executorStorageCell = await getStorage(blockchain, executorAddress) const storage = ex.CCIPSendExecutor_InitialData.fromSlice(executorStorageCell.beginParse()) executorID = storage.id }) diff --git a/contracts/tests/ccip/onramp/OnRamp.generateMessageID.spec.ts b/contracts/tests/ccip/onramp/OnRamp.generateMessageID.spec.ts index 42ff3bd9b2..fadd28d195 100644 --- a/contracts/tests/ccip/onramp/OnRamp.generateMessageID.spec.ts +++ b/contracts/tests/ccip/onramp/OnRamp.generateMessageID.spec.ts @@ -6,8 +6,7 @@ import { WRAPPED_NATIVE } from '../../../src/utils' import * as or from '../../../wrappers/gen/ccip/OnRamp' import * as ex from '../../../wrappers/gen/ccip/CCIPSendExecutor' -import * as relay from '../../../wrappers/test/mock/Relay' -import { setup } from './OnRamp.Setup' +import { getStorage, setup } from './OnRamp.Setup' import { contractCode } from '../../../wrappers/codeLoader' import { ChainSelectors } from '../../utils/Selectors' import * as on from '../../../wrappers/gen/ccip/OnRamp' @@ -77,7 +76,7 @@ describe('OnRamp - generate message id', () => { }, executor: { deployableCode: deployableCode, - executorCode: await relay.ContractClient.code(), + executorCode: Cell.EMPTY, }, })) @@ -131,12 +130,9 @@ describe('OnRamp - generate message id', () => { throw new Error('Executor address not found') } - const relayContract = blockchain.openContract( - relay.ContractClient.createFromAddress(executorAddress), - ) - executorSender = await relayContract.getSender(deployer.getSender()) + executorSender = blockchain.sender(executorAddress) - const executorStorageCell = await relayContract.getStorage() + const executorStorageCell = await getStorage(blockchain, executorAddress) const storage = ex.CCIPSendExecutor_InitialData.fromSlice(executorStorageCell.beginParse()) executorID = storage.id }) diff --git a/contracts/wrappers/test/mock/Relay.ts b/contracts/wrappers/test/mock/Relay.ts deleted file mode 100644 index 6777b1ef52..0000000000 --- a/contracts/wrappers/test/mock/Relay.ts +++ /dev/null @@ -1,148 +0,0 @@ -import { - Address, - beginCell, - Builder, - Cell, - contractAddress, - ContractProvider, - Sender, - SenderArguments, - SendMode, - Slice, - toNano, -} from '@ton/core' -import { CellCodec } from '../../utils' -import { contractCode } from '../../codeLoader' -import { SandboxContractProvider } from '@ton/sandbox' - -export type Relay_Send = { - bounce: boolean - value: bigint - to: Address - body: Cell - sendMode: SendMode -} - -export enum OpCodes { - Relay_Send = 0x527146b1, -} - -export const builder = { - message: { - in: { - relay_Send: ((): CellCodec => { - return { - encode: (data: Relay_Send): Builder => { - return beginCell() - .storeUint(OpCodes.Relay_Send, 32) - .storeBit(data.bounce) - .storeCoins(data.value) - .storeAddress(data.to) - .storeRef(data.body) - .storeUint(data.sendMode, 8) - }, - load: (src: Slice): Relay_Send => { - src.skip(32) // opcode - return { - bounce: src.loadBit(), - value: src.loadCoins(), - to: src.loadAddress()!, - body: src.loadRef(), - sendMode: Number(src.loadUint(8)), - } - }, - } - })(), - }, - }, -} - -export class ContractClient { - constructor( - readonly address: Address, - readonly init?: { - code: Cell - }, - ) {} - - static createFromAddress(address: Address): ContractClient { - return new ContractClient(address) - } - - static createFromConfig(code: Cell, workchain = 0): ContractClient { - const init = { - code, - data: Cell.EMPTY, - } - return new ContractClient(contractAddress(workchain, init), init) - } - - async sendInternal(provider: ContractProvider, via: Sender, value: bigint, body: Cell) { - await provider.internal(via, { - value: value, - sendMode: SendMode.PAY_GAS_SEPARATELY, - body: body, - }) - } - - async sendRelay( - provider: ContractProvider, - via: Sender, - opts: { - value: bigint - body: Relay_Send - }, - ) { - return await provider.internal(via, { - value: opts.value, - sendMode: SendMode.PAY_GAS_SEPARATELY, - body: builder.message.in.relay_Send.encode(opts.body).asCell(), - }) - } - - static code(): Promise { - return contractCode.ccip.local('tests.mock.Relay') - } - - // Get a sender that routes messages via Relay contract - // This is not a contract getter but we use a get* name to use the injected - // provider when opened as a sandbox contract - async getSender(provider: SandboxContractProvider, via: Sender): Promise { - return new RelaySender(this, provider, via) - } - - async getStorage(provider: SandboxContractProvider): Promise { - const state = await provider.getState() - switch (state.state.type) { - case 'active': - return Cell.fromBoc(state.state.data!)[0] - default: - return Cell.EMPTY - } - } -} - -// A sender that routes messages via Relay contract -export class RelaySender implements Sender { - address?: Address | undefined - constructor( - readonly mock: ContractClient, - readonly provider: SandboxContractProvider, - readonly via: Sender, - ) { - this.address = mock.address - } - - send(args: SenderArguments): Promise { - return this.mock.sendRelay(this.provider, this.via, { - value: args.value + toNano('0.1'), - body: { - bounce: args.bounce ?? false, - value: args.value, - to: args.to, - body: args.body ?? Cell.EMPTY, - sendMode: args.sendMode ?? SendMode.PAY_GAS_SEPARATELY, - }, - }) - } -} diff --git a/contracts/wrappers/tests.mock.Relay.compile.ts b/contracts/wrappers/tests.mock.Relay.compile.ts deleted file mode 100644 index d5291eb0b0..0000000000 --- a/contracts/wrappers/tests.mock.Relay.compile.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { CompilerConfig } from '@ton/blueprint' - -export const compile: CompilerConfig = { - lang: 'tolk', - entrypoint: 'contracts/test/mock/relay.tolk', - withStackComments: true, -} From 45b7703f2952d021201fbbd2c1917a295b11d087 Mon Sep 17 00:00:00 2001 From: Patricio Tourne Passarino Date: Tue, 4 Aug 2026 09:55:55 -0300 Subject: [PATCH 2/2] ref: move to utils package --- contracts/tests/ccip/onramp/OnRamp.Setup.ts | 9 +-------- .../tests/ccip/onramp/OnRamp.executorExited.spec.ts | 3 ++- .../ccip/onramp/OnRamp.generateMessageID.spec.ts | 3 ++- contracts/wrappers/utils.ts | 11 ++++++++++- 4 files changed, 15 insertions(+), 11 deletions(-) diff --git a/contracts/tests/ccip/onramp/OnRamp.Setup.ts b/contracts/tests/ccip/onramp/OnRamp.Setup.ts index 026cabc9f9..6a2bee7e60 100644 --- a/contracts/tests/ccip/onramp/OnRamp.Setup.ts +++ b/contracts/tests/ccip/onramp/OnRamp.Setup.ts @@ -1,4 +1,4 @@ -import { Address, Cell, beginCell, toNano } from '@ton/core' +import { Cell, beginCell, toNano } from '@ton/core' import { Blockchain, SandboxContract, TreasuryContract } from '@ton/sandbox' import { generateRandomContractId } from '../../../src/utils' @@ -83,10 +83,3 @@ export async function setup(blockchain: Blockchain, overrides: OnRampOverrides = const { onramp, config } = await deployOnRampContract(blockchain, deployer, overrides) return { deployer, onramp, config } } -export async function getStorage(blockchain: Blockchain, addr: Address): Promise { - const contract = await blockchain.getContract(addr) - if (contract.accountState == undefined) throw new Error('Contract account state is undefined') - const state = contract.accountState - if (state.type !== 'active') throw new Error('Contract account state is not active') - return state.state.data! -} diff --git a/contracts/tests/ccip/onramp/OnRamp.executorExited.spec.ts b/contracts/tests/ccip/onramp/OnRamp.executorExited.spec.ts index d4dce206de..d31c179ec2 100644 --- a/contracts/tests/ccip/onramp/OnRamp.executorExited.spec.ts +++ b/contracts/tests/ccip/onramp/OnRamp.executorExited.spec.ts @@ -7,7 +7,8 @@ import * as coverage from '../../coverage/coverage' import * as or from '../../../wrappers/gen/ccip/OnRamp' import * as ex from '../../../wrappers/gen/ccip/CCIPSendExecutor' import * as rt from '../../../wrappers/gen/ccip/Router' -import { getStorage, setup } from './OnRamp.Setup' +import { setup } from './OnRamp.Setup' +import { getStorage } from '../../../wrappers/utils' import { contractCode } from '../../../wrappers/codeLoader' import { ChainSelectors } from '../../utils/Selectors' import EVM_ADDRESS from '../../utils/evmAddress' diff --git a/contracts/tests/ccip/onramp/OnRamp.generateMessageID.spec.ts b/contracts/tests/ccip/onramp/OnRamp.generateMessageID.spec.ts index fadd28d195..064bfca5da 100644 --- a/contracts/tests/ccip/onramp/OnRamp.generateMessageID.spec.ts +++ b/contracts/tests/ccip/onramp/OnRamp.generateMessageID.spec.ts @@ -6,7 +6,8 @@ import { WRAPPED_NATIVE } from '../../../src/utils' import * as or from '../../../wrappers/gen/ccip/OnRamp' import * as ex from '../../../wrappers/gen/ccip/CCIPSendExecutor' -import { getStorage, setup } from './OnRamp.Setup' +import { setup } from './OnRamp.Setup' +import { getStorage } from '../../../wrappers/utils' import { contractCode } from '../../../wrappers/codeLoader' import { ChainSelectors } from '../../utils/Selectors' import * as on from '../../../wrappers/gen/ccip/OnRamp' diff --git a/contracts/wrappers/utils.ts b/contracts/wrappers/utils.ts index bf89c14484..f01a806b35 100644 --- a/contracts/wrappers/utils.ts +++ b/contracts/wrappers/utils.ts @@ -1,4 +1,5 @@ -import { Builder, Slice, TupleItem } from '@ton/core' +import { Address, Builder, Cell, Slice, TupleItem } from '@ton/core' +import { Blockchain } from '@ton/sandbox' import { createHash } from 'crypto' /// Returns the facility ID for the given CRC16 key (e.g. stringCrc16("link.chain.ton.mcms.Timelock")). @@ -61,3 +62,11 @@ export const remainingBitsOrRefCodec = { } }, } + +export async function getStorage(blockchain: Blockchain, addr: Address): Promise { + const contract = await blockchain.getContract(addr) + if (contract.accountState == undefined) throw new Error('Contract account state is undefined') + const state = contract.accountState + if (state.type !== 'active') throw new Error('Contract account state is not active') + return state.state.data! +}