-
Notifications
You must be signed in to change notification settings - Fork 56
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
tests for burnable zrc2 added, tests refactored
- Loading branch information
Showing
9 changed files
with
1,494 additions
and
1,370 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import { BN, Zilliqa, bytes, units } from "@zilliqa-js/zilliqa"; | ||
import Long from "long"; | ||
|
||
export const API = `http://localhost:${process.env["PORT"]}`; // Zilliqa Isolated Server | ||
export const CHAIN_ID = 222; | ||
export const MSG_VERSION = 1; | ||
export const VERSION = bytes.pack(CHAIN_ID, MSG_VERSION); | ||
|
||
export const JEST_WORKER_ID = Number(process.env["JEST_WORKER_ID"]); | ||
export const GENESIS_PRIVATE_KEY = global.GENESIS_PRIVATE_KEYS[JEST_WORKER_ID - 1]; | ||
|
||
export const zilliqa = new Zilliqa(API); | ||
zilliqa.wallet.addByPrivateKey(GENESIS_PRIVATE_KEY); | ||
|
||
export const GAS_PRICE = units.toQa("2000", units.Units.Li); | ||
|
||
export const FAUCET_PARAMS = { | ||
version: VERSION, | ||
amount: new BN(units.toQa("100000000", units.Units.Zil)), | ||
gasPrice: GAS_PRICE, | ||
gasLimit: Long.fromNumber(50), | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
import { scillaJSONParams } from "@zilliqa-js/scilla-json-utils"; | ||
import { getAddressFromPrivateKey, schnorr } from "@zilliqa-js/zilliqa"; | ||
import { FAUCET_PARAMS, zilliqa } from "./globalConfig"; | ||
|
||
export const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000"; | ||
|
||
export async function getAccounts(numberOfAccounts: number) { | ||
const accounts = Array.from({ length: numberOfAccounts }, schnorr.generatePrivateKey).map( | ||
(privateKey) => ({ | ||
privateKey, | ||
address: getAddressFromPrivateKey(privateKey), | ||
}) | ||
); | ||
|
||
for (const { privateKey, address } of accounts) { | ||
zilliqa.wallet.addByPrivateKey(privateKey); | ||
const tx = await zilliqa.blockchain.createTransaction( | ||
zilliqa.transactions.new( | ||
{ | ||
...FAUCET_PARAMS, | ||
toAddr: address, | ||
}, | ||
false | ||
) | ||
); | ||
if (!tx.getReceipt()?.success) { | ||
throw new Error(); | ||
} | ||
} | ||
|
||
return accounts; | ||
} | ||
|
||
export type ContractTestCaseDefinition = { | ||
name: string, | ||
transition: string, | ||
getSender: () => string, | ||
getParams: () => Record<string, Array<unknown>>, | ||
error: number | undefined, | ||
want: { | ||
expectState: (state: any) => void, | ||
events: Array<{ | ||
name: string, | ||
getParams: () => Record<string, Array<unknown>>, | ||
}>, | ||
transitions: Array<{ | ||
tag: string, | ||
getParams: () => Record<string, Array<unknown>>, | ||
}>, | ||
} | undefined, | ||
} | ||
|
||
export const expectEvents = (events, want) => { | ||
if (events === undefined) { | ||
expect(undefined).toBe(want); | ||
} | ||
|
||
for (const [index, event] of events.entries()) { | ||
expect(event._eventname).toBe(want[index].name); | ||
const wantParams = scillaJSONParams(want[index].getParams()); | ||
expect(JSON.stringify(event.params)).toBe(JSON.stringify(wantParams)); | ||
} | ||
}; | ||
|
||
export const expectTransitions = ( | ||
receiptTransitions: Array<{ msg: { params: any } }> | undefined, | ||
expectedTransitions: Array<{ | ||
tag: string, | ||
getParams: () => Record<string, Array<unknown>>, | ||
}> | ||
) => { | ||
if (!receiptTransitions && expectedTransitions.length > 0) { | ||
fail("Expected transitions but got none"); | ||
return; | ||
} | ||
|
||
expect(receiptTransitions!.length).toBe(expectedTransitions.length); | ||
|
||
for (const [index, transition] of receiptTransitions!.entries()) { | ||
const { msg } = transition; | ||
expect(expectedTransitions[index]!.tag).toBe(expectedTransitions[index]!.tag); | ||
const wantParams = scillaJSONParams(expectedTransitions[index]!.getParams()); | ||
expect(JSON.stringify(msg.params)).toBe(JSON.stringify(wantParams)); | ||
} | ||
}; | ||
|
||
export const getErrorMsg = (code) => | ||
`Exception thrown: (Message [(_exception : (String "Error")) ; (code : (Int32 ${code}))])`; | ||
|
||
export function runAllTestCases( | ||
testCases: Array<ContractTestCaseDefinition>, | ||
testedContractAddress: () => string, | ||
txParams: any | ||
) { | ||
for (const testCase of testCases) { | ||
it(`${testCase.transition}: ${testCase.name}`, async () => { | ||
zilliqa.wallet.setDefault(testCase.getSender()); | ||
const tx: any = await zilliqa.contracts | ||
.at(testedContractAddress()) | ||
.call( | ||
testCase.transition, | ||
scillaJSONParams(testCase.getParams()), | ||
txParams | ||
); | ||
|
||
if (testCase.want === undefined) { | ||
// Negative Cases | ||
expect(tx.receipt.success).toBe(false); | ||
expect(tx.receipt.exceptions[0].message).toBe( | ||
getErrorMsg(testCase.error) | ||
); | ||
} else { | ||
// Positive Cases | ||
expect(tx.receipt.success).toBe(true); | ||
expectEvents(tx.receipt.event_logs, testCase.want.events); | ||
expectTransitions(tx.receipt.transitions, testCase.want.transitions); | ||
|
||
const state = await zilliqa.contracts | ||
.at(testedContractAddress()) | ||
.getState(); | ||
|
||
testCase.want.expectState(state); | ||
} | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import fs from "fs"; | ||
import { Long, BN } from "@zilliqa-js/util"; | ||
import { GAS_PRICE, VERSION } from "../../globalConfig"; | ||
|
||
|
||
const CODE_PATH = "reference-contracts/FungibleToken-Burnable.scilla"; | ||
export const CODE = fs.readFileSync(CODE_PATH).toString(); | ||
|
||
export const FungibleBurnableToken_ERROR = { | ||
CodeIsSender: -1, | ||
CodeInsufficientFunds: -2, | ||
CodeInsufficientAllowance: -3, | ||
CodeNotOwner: -4 | ||
}; | ||
|
||
export const TOKEN_NAME = "TEST"; | ||
export const TOKEN_SYMBOL = "T"; | ||
export const TOKEN_DECIMALS = 6; | ||
export const TOKEN_INIT_SUPPLY = 1000000000; | ||
|
||
export const GAS_LIMIT = Long.fromNumber(100000); | ||
|
||
export const TX_PARAMS = { | ||
version: VERSION, | ||
amount: new BN(0), | ||
gasPrice: GAS_PRICE, | ||
gasLimit: GAS_LIMIT, | ||
}; |
201 changes: 201 additions & 0 deletions
201
tests/zrc2/fungible-token-burnable/fungibleBurnableToken.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,201 @@ | ||
import { expect } from "@jest/globals"; | ||
import { scillaJSONParams } from "@zilliqa-js/scilla-json-utils"; | ||
|
||
import { | ||
getAccounts, | ||
runAllTestCases, | ||
} from "../../testutils"; | ||
|
||
import { | ||
TX_PARAMS, | ||
CODE, | ||
FungibleBurnableToken_ERROR, | ||
TOKEN_NAME, | ||
TOKEN_SYMBOL, | ||
TOKEN_DECIMALS, | ||
TOKEN_INIT_SUPPLY, | ||
} from "./config"; | ||
import { GENESIS_PRIVATE_KEY, JEST_WORKER_ID, zilliqa } from "../../globalConfig"; | ||
|
||
let globalContractAddress: string | undefined; | ||
|
||
let globalTestAccounts: Array<{ | ||
privateKey: string; | ||
address: string; | ||
}> = []; | ||
const CONTRACT_OWNER = 0; | ||
const TOKEN_OWNER = 0; | ||
const STRANGER_1 = 1; | ||
const STRANGER_2 = 2; | ||
const STRANGER_1_INITIAL_TOKENS = 1000; | ||
const getTestAddr = (index) => globalTestAccounts[index]?.address as string; | ||
|
||
beforeAll(async () => { | ||
globalTestAccounts = await getAccounts(4); | ||
|
||
console.table({ | ||
JEST_WORKER_ID, | ||
GENESIS_PRIVATE_KEY, | ||
CONTRACT_OWNER: getTestAddr(CONTRACT_OWNER), | ||
TOKEN_OWNER: getTestAddr(TOKEN_OWNER), | ||
STRANGER_1: getTestAddr(STRANGER_1), | ||
STRANGER_2: getTestAddr(STRANGER_2), | ||
}); | ||
}); | ||
|
||
beforeEach(async () => { | ||
zilliqa.wallet.setDefault(getTestAddr(CONTRACT_OWNER)); | ||
const init = scillaJSONParams({ | ||
_scilla_version: ["Uint32", 0], | ||
contract_owner: ["ByStr20", getTestAddr(CONTRACT_OWNER)], | ||
name: ["String", TOKEN_NAME], | ||
symbol: ["String", TOKEN_SYMBOL], | ||
decimals: ["Uint32", TOKEN_DECIMALS], | ||
init_supply: ["Uint128", TOKEN_INIT_SUPPLY], | ||
}); | ||
const [contractDeploymentTransaction, contract] = await zilliqa.contracts | ||
.new(CODE, init) | ||
.deploy(TX_PARAMS, 33, 1000, true); | ||
globalContractAddress = contract.address; | ||
|
||
if (globalContractAddress === undefined) { | ||
throw new Error(JSON.stringify({ | ||
message: "Failed to deploy FungibleToken-Burnable contract", | ||
receipt: contractDeploymentTransaction.getReceipt() | ||
})); | ||
} | ||
|
||
let stranger1InitialTokenTransferTx: any = await zilliqa.contracts.at(globalContractAddress).call( | ||
"Transfer", | ||
scillaJSONParams({ | ||
to: ["ByStr20", getTestAddr(STRANGER_1)], | ||
amount: ["Uint128", STRANGER_1_INITIAL_TOKENS], | ||
}), | ||
TX_PARAMS | ||
); | ||
|
||
if (!stranger1InitialTokenTransferTx.receipt.success) { | ||
throw new Error("Initial transfer fund to STRANGER_1 failed"); | ||
} | ||
}); | ||
|
||
describe("Burn", () => { | ||
runAllTestCases( | ||
[ | ||
{ | ||
name: "throws CodeInsufficientFunds if not enough funds", | ||
transition: "Burn", | ||
getSender: () => getTestAddr(STRANGER_1), | ||
getParams: () => ({ | ||
amount: ["Uint128", STRANGER_1_INITIAL_TOKENS * 2], | ||
}), | ||
error: FungibleBurnableToken_ERROR.CodeInsufficientFunds, | ||
want: undefined, | ||
}, | ||
{ | ||
name: "successfuly burns tokens", | ||
transition: "Burn", | ||
getSender: () => getTestAddr(STRANGER_1), | ||
getParams: () => ({ | ||
amount: ["Uint128", STRANGER_1_INITIAL_TOKENS], | ||
}), | ||
error: undefined, | ||
want: { | ||
expectState: (state) => { | ||
expect( | ||
state.total_supply | ||
).toEqual(`${TOKEN_INIT_SUPPLY - STRANGER_1_INITIAL_TOKENS}`); | ||
}, | ||
events: [ | ||
{ | ||
name: "Burnt", | ||
getParams: () => ({ | ||
burner: ["ByStr20", getTestAddr(STRANGER_1)], | ||
burn_account: ["ByStr20", getTestAddr(STRANGER_1)], | ||
amount: ["Uint128", STRANGER_1_INITIAL_TOKENS], | ||
}), | ||
}, | ||
], | ||
transitions: [ | ||
{ | ||
tag: "BurnSuccessCallBack", | ||
getParams: () => ({ | ||
burner: ["ByStr20", getTestAddr(STRANGER_1)], | ||
amount: ["Uint128", STRANGER_1_INITIAL_TOKENS], | ||
}), | ||
}, | ||
], | ||
}, | ||
}, | ||
], | ||
() => globalContractAddress!, | ||
TX_PARAMS | ||
) | ||
}); | ||
|
||
describe("Transfer", () => { | ||
runAllTestCases( | ||
[ | ||
{ | ||
name: "throws CodeInsufficientFunds if not enough funds", | ||
transition: "Transfer", | ||
getSender: () => getTestAddr(STRANGER_1), | ||
getParams: () => ({ | ||
to: ["ByStr20", getTestAddr(STRANGER_2)], | ||
amount: ["Uint128", STRANGER_1_INITIAL_TOKENS * 2], | ||
}), | ||
error: FungibleBurnableToken_ERROR.CodeInsufficientFunds, | ||
want: undefined, | ||
}, | ||
{ | ||
name: "successfuly transfer tokens", | ||
transition: "Transfer", | ||
getSender: () => getTestAddr(STRANGER_1), | ||
getParams: () => ({ | ||
to: ["ByStr20", getTestAddr(STRANGER_2)], | ||
amount: ["Uint128", STRANGER_1_INITIAL_TOKENS], | ||
}), | ||
error: undefined, | ||
want: { | ||
expectState: (state) => { | ||
expect( | ||
state.total_supply | ||
).toEqual(`${TOKEN_INIT_SUPPLY}`); | ||
|
||
console.log("balanceeees", state.balances); | ||
}, | ||
events: [ | ||
{ | ||
name: "TransferSuccess", | ||
getParams: () => ({ | ||
sender: ["ByStr20", getTestAddr(STRANGER_1)], | ||
recipient: ["ByStr20", getTestAddr(STRANGER_2)], | ||
amount: ["Uint128", STRANGER_1_INITIAL_TOKENS], | ||
}), | ||
}, | ||
], | ||
transitions: [ | ||
{ | ||
tag: "RecipientAcceptTransfer", | ||
getParams: () => ({ | ||
sender: ["ByStr20", getTestAddr(STRANGER_1)], | ||
recipient: ["ByStr20", getTestAddr(STRANGER_2)], | ||
amount: ["Uint128", STRANGER_1_INITIAL_TOKENS], | ||
}), | ||
}, | ||
{ | ||
tag: "TransferSuccessCallBack", | ||
getParams: () => ({ | ||
sender: ["ByStr20", getTestAddr(STRANGER_1)], | ||
recipient: ["ByStr20", getTestAddr(STRANGER_2)], | ||
amount: ["Uint128", STRANGER_1_INITIAL_TOKENS], | ||
}), | ||
}, | ||
], | ||
}, | ||
}, | ||
], | ||
() => globalContractAddress!, | ||
TX_PARAMS | ||
) | ||
}); |
Oops, something went wrong.