Skip to content

Commit

Permalink
improve ft example
Browse files Browse the repository at this point in the history
  • Loading branch information
idea404 committed Oct 4, 2022
1 parent 71f8b4f commit e895c58
Show file tree
Hide file tree
Showing 5 changed files with 8,813 additions and 2,252 deletions.
149 changes: 96 additions & 53 deletions examples/__tests__/test-fungible-token.ava.js
Original file line number Diff line number Diff line change
@@ -1,88 +1,131 @@
import { Worker } from "near-workspaces";
import { Worker, NEAR } from "near-workspaces";
import test from "ava";

test.beforeEach(async (t) => {
// Init the worker and start a Sandbox server
const worker = await Worker.init();

// Prepare sandbox for tests, create accounts, deploy contracts, etx.
const root = worker.rootAccount;
const totalSupply = 1000;
const yoctoAccountStorage = "324";

// Deploy the ft contract.
const ft = await root.devDeploy("./build/fungible-token.wasm");
const root = worker.rootAccount;
const xcc = await root.devDeploy("./build/fungible-token-helper.wasm");
const ft = await root.createSubAccount("ft");
await ft.deploy("./build/fungible-token.wasm");
await root.call(ft, "init", {
owner_id: root.accountId,
total_supply: totalSupply.toString(),
});
const alice = await root.createSubAccount("alice", { initialBalance: NEAR.parse("10 N").toJSON() });

// Init the contracts
await ft.call(ft, "init", { prefix: "a", totalSupply: "1000" });

// Create test accounts
const ali = await root.createSubAccount("ali");
const bob = await root.createSubAccount("bob");

// Save state for test runs, it is unique for each test
t.context.worker = worker;
t.context.accounts = { root, ft, ali, bob, xcc };
t.context.accounts = { root, ft, alice, xcc };
t.context.variables = { totalSupply, yoctoAccountStorage };
});

test.afterEach.always(async (t) => {
await t.context.worker.tearDown().catch((error) => {
console.log("Failed tear down the worker:", error);
console.log("Failed to tear down the worker:", error);
});
});

test("should register account and pay for storage", async (t) => {
const { ft, alice } = t.context.accounts;
const { yoctoAccountStorage } = t.context.variables;
const result = await alice.call(ft, "storage_deposit", { account_id: alice.accountId }, { attachedDeposit: NEAR.parse("1 N").toJSON() });
const aliceAfterBalance = await alice.balance();
const expected = {
message: `Account ${alice.accountId} registered with storage deposit of ${yoctoAccountStorage}`,
};
t.deepEqual(result, expected);
t.true(aliceAfterBalance.total > NEAR.parse("9 N").toJSON(), "alice should have received a refund");
});

test("should return message when account is already registered and not refund when no deposit is attached", async (t) => {
const { ft, alice } = t.context.accounts;
const { yoctoAccountStorage } = t.context.variables;
const result = await alice.call(ft, "storage_deposit", { account_id: alice.accountId }, { attachedDeposit: NEAR.parse("1 N").toJSON() });
const expected = {
message: `Account ${alice.accountId} registered with storage deposit of ${yoctoAccountStorage}`,
};
t.deepEqual(result, expected);
const result2 = await alice.call(ft, "storage_deposit", { account_id: alice.accountId }, { attachedDeposit: NEAR.parse("0 N").toJSON() });
t.is(result2.message, "Account is already registered");
});

test("should return message and refund predecessor caller when trying to pay for storage for an account that is already registered", async (t) => {
const { ft, alice } = t.context.accounts;
const { yoctoAccountStorage } = t.context.variables;
const result = await alice.call(ft, "storage_deposit", { account_id: alice.accountId }, { attachedDeposit: NEAR.parse("1 N").toJSON() });
const expected = {
message: `Account ${alice.accountId} registered with storage deposit of ${yoctoAccountStorage}`,
};
t.deepEqual(result, expected);
const result2 = await alice.call(ft, "storage_deposit", { account_id: alice.accountId }, { attachedDeposit: NEAR.parse("1 N").toJSON() });
t.is(result2.message, "Account is already registered, deposit refunded to predecessor");
const aliceBalance = await alice.balance();
t.is(aliceBalance.total > NEAR.parse("9 N"), true, "alice should have received a refund");
});

test("should return message when trying to pay for storage with less than the required amount and refund predecessor caller", async (t) => {
const { ft, alice } = t.context.accounts;
const { yoctoAccountStorage } = t.context.variables;
const result = await alice.call(ft, "storage_deposit", { account_id: alice.accountId }, { attachedDeposit: NEAR.from("100").toJSON() });
t.is(result.message, `Not enough attached deposit to cover storage cost. Required: ${yoctoAccountStorage}`);
});

test("should throw when trying to transfer for an unregistered account", async (t) => {
const { ft, alice, root } = t.context.accounts;
try {
await root.call(ft, "ft_transfer", { receiver_id: alice.accountId, amount: "1" }, { attachedDeposit: NEAR.from("1").toJSON() });
} catch (error) {
t.true(error.message.includes(`Account ${alice.accountId} is not registered`));
}
});

test("Owner has all balance in the beginning", async (t) => {
const { ft } = t.context.accounts;
const result = await ft.view("ftBalanceOf", { accountId: ft.accountId });
const { ft, root } = t.context.accounts;
const result = await ft.view("ft_balance_of", { account_id: root.accountId });
t.is(result, "1000");
});

test("Can transfer if balance is sufficient", async (t) => {
const { ali, ft } = t.context.accounts;

await ft.call(ft, "ftTransfer", { receiverId: ali.accountId, amount: "100" });
const aliBalance = await ft.view("ftBalanceOf", { accountId: ali.accountId });
const { alice, ft, root } = t.context.accounts;
await alice.call(ft, "storage_deposit", { account_id: alice.accountId }, { attachedDeposit: NEAR.parse("1 N").toJSON() });
await root.call(ft, "ft_transfer", { receiver_id: alice.accountId, amount: "100" }, { attachedDeposit: NEAR.from("1").toJSON() });
const aliBalance = await ft.view("ft_balance_of", { account_id: alice.accountId });
t.is(aliBalance, "100");
const ownerBalance = await ft.view("ftBalanceOf", {
accountId: ft.accountId,
const ownerBalance = await ft.view("ft_balance_of", {
account_id: root.accountId,
});
t.is(ownerBalance, "900");
});

test("Cannot transfer if balance is not sufficient", async (t) => {
const { ali, bob, ft } = t.context.accounts;
const { alice, root, ft } = t.context.accounts;
await alice.call(ft, "storage_deposit", { account_id: alice.accountId }, { attachedDeposit: NEAR.parse("1 N").toJSON() });
try {
await ali.call(ft, "ftTransfer", {
receiverId: bob.accountId,
amount: "100",
});
} catch (e) {
t.assert(
e
.toString()
.indexOf(
"Smart contract panicked: assertion failed: The account doesn't have enough balance"
) >= 0
await alice.call(
ft,
"ft_transfer",
{
receiverId: root.accountId,
amount: "100",
},
{ attachedDeposit: NEAR.from("1").toJSON() }
);
} catch (e) {
t.assert(e.toString().indexOf("Smart contract panicked: assertion failed: The account doesn't have enough balance") >= 0);
}
});

test("Cross contract transfer", async (t) => {
const { xcc, ft } = t.context.accounts;
await ft.call(
ft,
"ftTransferCall",
{ receiverId: xcc.accountId, amount: "900", memo: null, msg: "test msg" },
{ gas: 200000000000000 }
);
const aliBalance = await ft.view("ftBalanceOf", { accountId: xcc.accountId });
t.is(aliBalance, "900");
const aliSubContractData = await xcc.view("getContractData");
t.is(
aliSubContractData,
`[900 from ${ft.accountId} to ${xcc.accountId}] test msg `
);
const ownerBalance = await ft.view("ftBalanceOf", {
accountId: ft.accountId,
});
const { xcc, ft, root } = t.context.accounts;
await xcc.call(ft, "storage_deposit", { account_id: xcc.accountId }, { attachedDeposit: NEAR.parse("1 N").toJSON() });
await root.call(ft, "ft_transfer_call", { receiver_id: xcc.accountId, amount: "900", memo: null, msg: "test msg" }, { gas: 200000000000000, attachedDeposit: NEAR.from("1").toJSON() });
const xccBalance = await ft.view("ft_balance_of", { account_id: xcc.accountId });
t.is(xccBalance, "900");
const aliSubContractData = await xcc.view("get_contract_data");
t.is(aliSubContractData, `[900 from ${root.accountId} to ${xcc.accountId}] test msg `);
const ownerBalance = await ft.view("ft_balance_of", { account_id: root.accountId });
t.is(ownerBalance, "100");
});
Loading

0 comments on commit e895c58

Please sign in to comment.