import { Blockchain, SandboxContract, TreasuryContract } from '@ton/sandbox'; import { Cell, toNano } from '@ton/core'; import { MainBalance } from '../wrappers/MainBalance'; import '@ton/test-utils'; import { compile } from '@ton/blueprint'; import { randomAddress } from '@ton/test-utils'; import { fromNano } from 'ton'; import { hex } from "../build/MainBalance.compiled.json"; import contractConfig, { servicePercent, tokenPercent } from '../config/contract.config'; import { calcPercent } from '../scripts/utils'; describe('MainBalance', () => { let code: Cell; beforeAll(async () => { // code = await compile('MainBalance'); code = Cell.fromBoc(Buffer.from(hex, "hex"))[0]; }); let blockchain: Blockchain; let owner: SandboxContract; let newOwner: SandboxContract; let user: SandboxContract; let anotherUser: SandboxContract; let mainBalance: SandboxContract; let serviceAddress: SandboxContract; let tokenAddress: SandboxContract; beforeEach(async () => { blockchain = await Blockchain.create(); owner = await blockchain.treasury('owner'); newOwner = await blockchain.treasury('newOwner'); user = await blockchain.treasury('user'); anotherUser = await blockchain.treasury('anotherUser'); serviceAddress = await blockchain.treasury('serviceAddress'); tokenAddress = await blockchain.treasury('tokenAddress'); mainBalance = blockchain.openContract(MainBalance.createFromConfig({ ownerAddress: owner.address.toString(), depositFunds: 0, serviceAddress: serviceAddress.address.toString(), tokenAddress: tokenAddress.address.toString() }, code)); const deployResult = await mainBalance.sendDeploy(owner.getSender(), toNano(0.05)); expect(deployResult.transactions).toHaveTransaction({ from: owner.address, to: mainBalance.address, deploy: true, success: true, }); }); it('should deploy', async () => { // the check is done inside beforeEach // blockchain and mainBalance are ready to use }); it("should deposit funds", async () => { const depositResult = await mainBalance.sendDeposit(user.getSender(), toNano('10')); expect(depositResult.transactions).toHaveTransaction({ from: user.address, to: mainBalance.address, success: true, }); expect(+fromNano(await mainBalance.getBalance())).toBeCloseTo(10, 0.05); expect(+fromNano(await mainBalance.getDepositFunds())).toBeCloseTo(calcPercent(10, contractConfig.totalFee), 0.05); }); it("should change owner address", async () => { await mainBalance.sendChangeOwnerAddress(owner.getSender(), newOwner.address); expect((await mainBalance.getOwnerAddress()).toString()).toBe(newOwner.address.toString()); }); it("shouldn't change owner address", async () => { await mainBalance.sendChangeOwnerAddress(user.getSender(), newOwner.address); expect((await mainBalance.getOwnerAddress()).toString()).not.toBe(newOwner.address.toString()); }); it("should change only service address", async () => { const changeResult = await mainBalance.sendChangeServiceAddress(owner.getSender(), newOwner.address, tokenAddress.address); const { serviceAddr } = await mainBalance.getServiceAddress(); expect(changeResult.transactions).toHaveTransaction({ from: owner.address, to: mainBalance.address, success: true, }); expect(serviceAddr.toString()).toBe(newOwner.address.toString()); }); it("should transfer service fee", async () => { await mainBalance.sendDeposit(user.getSender(), toNano(10)); await mainBalance.sendDeposit(user.getSender(), toNano(20)); await mainBalance.sendDeposit(anotherUser.getSender(), toNano(50)); let totalBalance = 10 + 20 + 50; // 80 const serviceFee = calcPercent(totalBalance, servicePercent); const tokenFee = calcPercent(totalBalance, tokenPercent); const tranferResult = await mainBalance.sendTransferServiceFee(owner.getSender(), toNano(serviceFee), toNano(tokenFee)); expect(tranferResult.transactions).toHaveTransaction({ from: owner.address, to: mainBalance.address, success: true, }); expect(+fromNano(await mainBalance.getDepositFunds())).toBe(0); expect(tranferResult.transactions).toHaveTransaction({ from: mainBalance.address, to: serviceAddress.address, success: true, }); expect(tranferResult.transactions).toHaveTransaction({ from: mainBalance.address, to: tokenAddress.address, success: true, }); }); it("shouldn't transfer service fee when funds exceeded", async () => { await mainBalance.sendDeposit(user.getSender(), toNano(10)); await mainBalance.sendDeposit(user.getSender(), toNano(20)); await mainBalance.sendDeposit(anotherUser.getSender(), toNano(50)); let totalBalance = 10 + 20 + 50; // 80 const serviceFee = calcPercent(totalBalance, servicePercent) + 10; const tokenFee = calcPercent(totalBalance, tokenPercent) + 10; const tranferResult = await mainBalance.sendTransferServiceFee(owner.getSender(), toNano(serviceFee), toNano(tokenFee)); expect(tranferResult.transactions).toHaveTransaction({ from: owner.address, to: mainBalance.address, success: false, exitCode: contractConfig.error.FUNDS_EXCEED }); }); it("should withdraw user coins", async () => { await mainBalance.sendDeposit(user.getSender(), toNano(20)); await mainBalance.sendDeposit(user.getSender(), toNano(40)); await mainBalance.sendDeposit(anotherUser.getSender(), toNano(90)); let totalBalance = 20 + 40 + 90; // 150 const serviceFee = calcPercent(totalBalance, servicePercent); const tokenFee = calcPercent(totalBalance, tokenPercent); await mainBalance.sendTransferServiceFee(owner.getSender(), toNano(serviceFee), toNano(tokenFee)); let userWithdrawAmount = toNano(60 - calcPercent(60, contractConfig.totalFee)); // data from backend, - 10% fee const withdrawResult = await mainBalance.sendWithdraw(owner.getSender(), user.address, userWithdrawAmount); expect(withdrawResult.transactions).toHaveTransaction({ from: mainBalance.address, to: user.address, value: userWithdrawAmount, success: true, }); expect(+fromNano(await mainBalance.getDepositFunds())).toBe(0); console.log("smc balance after transfer fee and withdraw", fromNano(await mainBalance.getBalance())); let anotherUserWithdrawAmount = toNano(90 - calcPercent(90, contractConfig.totalFee)); // data from backend, - 10% fee const secondWithdrawResult = await mainBalance.sendWithdraw(owner.getSender(), anotherUser.address, anotherUserWithdrawAmount); expect(secondWithdrawResult.transactions).toHaveTransaction({ from: mainBalance.address, to: anotherUser.address, value: anotherUserWithdrawAmount, success: true, }); console.log("smc balance after another withdraw", fromNano(await mainBalance.getBalance())); }); });