diff --git a/contracts/pingpong2.fc b/contracts/pingpong2.fc new file mode 100644 index 0000000..a45e63a --- /dev/null +++ b/contracts/pingpong2.fc @@ -0,0 +1,52 @@ +#include "imports/stdlib.fc"; + +int slice_hash(slice s) asm "HASHSU"; +int equal_slices(slice a, slice b) asm "SDEQ"; + +;; storage variables +global cell ctx_str; + +() load_data() impure { + var ds = get_data().begin_parse(); + ctx_str = ds~load_ref(); + ds.end_parse(); +} + +() save_data() impure { + set_data( + begin_cell() + .store_ref(ctx_str) + .end_cell() + ); +} + +() recv_internal(int my_balance, int msg_value, cell in_msg_full, slice in_msg_body) impure { + if (in_msg_body.slice_empty?()) { + return (); + } + slice cs = in_msg_full.begin_parse(); + cs~skip_bits(4); + slice sender_address = cs~load_msg_addr(); + ~dump(sender_address); + + load_data(); + slice current = ctx_str.begin_parse(); + slice ping = begin_cell().store_slice("ping").end_cell().begin_parse(); + + if (equal_slices(current,ping) == -1) { + cell c = begin_cell().store_slice("pong").end_cell(); + ctx_str = c; + save_data(); + return (); + } else { + cell c = begin_cell().store_slice("ping").end_cell(); + ctx_str = c; + save_data(); + return (); + } +} + +cell get_str() method_id { + load_data(); + return ctx_str; +} \ No newline at end of file diff --git a/tests/PingPong2.spec.ts b/tests/PingPong2.spec.ts new file mode 100644 index 0000000..33e562d --- /dev/null +++ b/tests/PingPong2.spec.ts @@ -0,0 +1,71 @@ +import { Blockchain, SandboxContract, TreasuryContract } from '@ton/sandbox'; +import { Cell, toNano, ContractProvider } from '@ton/core'; +import '@ton/test-utils'; +import { compile } from '@ton/blueprint'; + +import { PingPong2 } from '../wrappers/PingPong2'; + +describe('[PingPong2]', () => { + let code: Cell; + let blockchain: Blockchain; + let deployer: SandboxContract; + let pingPong2Contract: SandboxContract; + let user1: null | SandboxContract = null; + let provider: null | ContractProvider = null; + + beforeAll(async () => { + code = await compile('PingPong2'); + blockchain = await Blockchain.create(); + user1 = await blockchain.treasury('user1'); + pingPong2Contract = blockchain.openContract( + PingPong2.createFromConfig({}, code) + ); + provider = blockchain.provider(pingPong2Contract.address); + deployer = await blockchain.treasury('deployer'); + (provider as any).blockchain.openContract( + PingPong2.createFromConfig({}, code) + ); + }); + + it('[PingPong2] deploys', async () => { + const deployResult = await pingPong2Contract.sendDeploy( + deployer.getSender(), + toNano('0.05') + ); + expect(deployResult.transactions).toHaveTransaction({ + from: deployer.address, + to: pingPong2Contract.address, + deploy: true, + success: true, + }); + }); + + it('[PingPong2] toggle', async () => { + const str = await pingPong2Contract.getStr(); + const strOk = (str as any).toString().replace('x{', '').replace('}', ''); + const decoded = Buffer.from(strOk, 'hex').toString('utf8'); + expect(decoded).toBe('ping'); + + await pingPong2Contract.sendToggle( + (user1 as SandboxContract).getSender(), + { + value: toNano('0.05'), + } + ); + const str2 = await pingPong2Contract.getStr(); + const str2Ok = (str2 as any).toString().replace('x{', '').replace('}', ''); + const decoded2 = Buffer.from(str2Ok, 'hex').toString('utf8'); + expect(decoded2).toBe('pong'); + + await pingPong2Contract.sendToggle( + (user1 as SandboxContract).getSender(), + { + value: toNano('0.05'), + } + ); + const str3 = await pingPong2Contract.getStr(); + const str3Ok = (str3 as any).toString().replace('x{', '').replace('}', ''); + const decoded3 = Buffer.from(str3Ok, 'hex').toString('utf8'); + expect(decoded3).toBe('ping'); + }); +}); diff --git a/wrappers/PingPong2.compile.ts b/wrappers/PingPong2.compile.ts new file mode 100644 index 0000000..e1cf0cd --- /dev/null +++ b/wrappers/PingPong2.compile.ts @@ -0,0 +1,6 @@ +import { CompilerConfig } from '@ton/blueprint'; + +export const compile: CompilerConfig = { + lang: 'func', + targets: ['contracts/pingpong2.fc'], +}; diff --git a/wrappers/PingPong2.ts b/wrappers/PingPong2.ts new file mode 100644 index 0000000..d694593 --- /dev/null +++ b/wrappers/PingPong2.ts @@ -0,0 +1,60 @@ +import { + Address, + beginCell, + Cell, + Contract, + contractAddress, + ContractProvider, + Sender, + SendMode, +} from '@ton/core'; + +export function pingPong2ConfigToCell(): Cell { + const forwardPayload = beginCell().storeStringTail('ping').endCell(); + return beginCell().storeRef(forwardPayload).endCell(); +} + +export class PingPong2 implements Contract { + constructor( + readonly address: Address, + readonly init?: { code: Cell; data: Cell } + ) {} + + static createFromAddress(address: Address) { + return new PingPong2(address); + } + + static createFromConfig(config: object, code: Cell, workchain = 0) { + const data = pingPong2ConfigToCell(); + const init = { code, data }; + return new PingPong2(contractAddress(workchain, init), init); + } + + async sendDeploy(provider: ContractProvider, via: Sender, value: bigint) { + const a = await provider.internal(via, { + value, + sendMode: SendMode.PAY_GAS_SEPARATELY, + body: beginCell().endCell(), + }); + return a; + } + + async sendToggle( + provider: ContractProvider, + via: Sender, + opts: { + value: bigint; + } + ) { + await provider.internal(via, { + value: opts.value, + sendMode: SendMode.PAY_GAS_SEPARATELY, + body: beginCell().storeUint(10, 32).endCell(), + }); + } + + async getStr(provider: ContractProvider) { + const result = await provider.get('get_str', []); + return result.stack.readCell(); + } +}