From 7e346914c0517d1bc380fa8ed60bb27ca8848d27 Mon Sep 17 00:00:00 2001 From: Mark Spanbroek Date: Tue, 27 Jun 2023 15:59:31 +0200 Subject: [PATCH] Test contracts with polling --- testmodule/testContracts.nim | 286 ++++++++++++++++++----------------- testmodule/testErc20.nim | 120 +++++++-------- 2 files changed, 207 insertions(+), 199 deletions(-) diff --git a/testmodule/testContracts.nim b/testmodule/testContracts.nim index c27d53c..b406075 100644 --- a/testmodule/testContracts.nim +++ b/testmodule/testContracts.nim @@ -15,179 +15,185 @@ type method mint(token: TestToken, holder: Address, amount: UInt256): ?TransactionResponse {.base, contract.} method myBalance(token: TestToken): UInt256 {.contract, view.} -suite "Contracts": +for url in ["ws://localhost:8545", "http://localhost:8545"]: - var token: TestToken - var provider: JsonRpcProvider - var snapshot: JsonNode - var accounts: seq[Address] + suite "Contracts (" & url & ")": - setup: - provider = JsonRpcProvider.new("ws://localhost:8545") - snapshot = await provider.send("evm_snapshot") - accounts = await provider.listAccounts() - let deployment = readDeployment() - token = TestToken.new(!deployment.address(TestToken), provider) + var token: TestToken + var provider: JsonRpcProvider + var snapshot: JsonNode + var accounts: seq[Address] - teardown: - discard await provider.send("evm_revert", @[snapshot]) + setup: + provider = JsonRpcProvider.new(url, pollingInterval = 100.millis) + snapshot = await provider.send("evm_snapshot") + accounts = await provider.listAccounts() + let deployment = readDeployment() + token = TestToken.new(!deployment.address(TestToken), provider) - test "can call constant functions": - check (await token.name()) == "TestToken" - check (await token.totalSupply()) == 0.u256 - check (await token.balanceOf(accounts[0])) == 0.u256 - check (await token.allowance(accounts[0], accounts[1])) == 0.u256 + teardown: + discard await provider.send("evm_revert", @[snapshot]) - test "can call non-constant functions": - token = TestToken.new(token.address, provider.getSigner()) - discard await token.mint(accounts[1], 100.u256) - check (await token.totalSupply()) == 100.u256 - check (await token.balanceOf(accounts[1])) == 100.u256 + test "can call constant functions": + check (await token.name()) == "TestToken" + check (await token.totalSupply()) == 0.u256 + check (await token.balanceOf(accounts[0])) == 0.u256 + check (await token.allowance(accounts[0], accounts[1])) == 0.u256 - test "can call constant functions with a signer and the account is used for the call": - let signer0 = provider.getSigner(accounts[0]) - let signer1 = provider.getSigner(accounts[1]) - discard await token.connect(signer0).mint(accounts[1], 100.u256) - check (await token.connect(signer0).myBalance()) == 0.u256 - check (await token.connect(signer1).myBalance()) == 100.u256 + test "can call non-constant functions": + token = TestToken.new(token.address, provider.getSigner()) + discard await token.mint(accounts[1], 100.u256) + check (await token.totalSupply()) == 100.u256 + check (await token.balanceOf(accounts[1])) == 100.u256 - test "can call non-constant functions without a signer": - discard await token.mint(accounts[1], 100.u256) - check (await token.balanceOf(accounts[1])) == 0.u256 + test "can call constant functions with a signer and the account is used for the call": + let signer0 = provider.getSigner(accounts[0]) + let signer1 = provider.getSigner(accounts[1]) + discard await token.connect(signer0).mint(accounts[1], 100.u256) + check (await token.connect(signer0).myBalance()) == 0.u256 + check (await token.connect(signer1).myBalance()) == 100.u256 - test "can call constant functions without a return type": - token = TestToken.new(token.address, provider.getSigner()) - proc mint(token: TestToken, holder: Address, amount: UInt256) {.contract, view.} - await mint(token, accounts[1], 100.u256) - check (await balanceOf(token, accounts[1])) == 0.u256 + test "can call non-constant functions without a signer": + discard await token.mint(accounts[1], 100.u256) + check (await token.balanceOf(accounts[1])) == 0.u256 - test "can call non-constant functions without a return type": - token = TestToken.new(token.address, provider.getSigner()) - proc mint(token: TestToken, holder: Address, amount: UInt256) {.contract.} - await token.mint(accounts[1], 100.u256) - check (await balanceOf(token, accounts[1])) == 100.u256 + test "can call constant functions without a return type": + token = TestToken.new(token.address, provider.getSigner()) + proc mint(token: TestToken, holder: Address, amount: UInt256) {.contract, view.} + await mint(token, accounts[1], 100.u256) + check (await balanceOf(token, accounts[1])) == 0.u256 - test "can call non-constant functions with a ?TransactionResponse return type": - token = TestToken.new(token.address, provider.getSigner()) - proc mint(token: TestToken, - holder: Address, - amount: UInt256): ?TransactionResponse {.contract.} - let txResp = await token.mint(accounts[1], 100.u256) - check txResp is (?TransactionResponse) - check txResp.isSome + test "can call non-constant functions without a return type": + token = TestToken.new(token.address, provider.getSigner()) + proc mint(token: TestToken, holder: Address, amount: UInt256) {.contract.} + await token.mint(accounts[1], 100.u256) + check (await balanceOf(token, accounts[1])) == 100.u256 - test "can call non-constant functions with a Confirmable return type": + test "can call non-constant functions with a ?TransactionResponse return type": + token = TestToken.new(token.address, provider.getSigner()) + proc mint(token: TestToken, + holder: Address, + amount: UInt256): ?TransactionResponse {.contract.} + let txResp = await token.mint(accounts[1], 100.u256) + check txResp is (?TransactionResponse) + check txResp.isSome - token = TestToken.new(token.address, provider.getSigner()) - proc mint(token: TestToken, - holder: Address, - amount: UInt256): Confirmable {.contract.} - let txResp = await token.mint(accounts[1], 100.u256) - check txResp is Confirmable - check txResp.isSome + test "can call non-constant functions with a Confirmable return type": - test "fails to compile when function has an implementation": - let works = compiles: - proc foo(token: TestToken, bar: Address) {.contract.} = discard - check not works + token = TestToken.new(token.address, provider.getSigner()) + proc mint(token: TestToken, + holder: Address, + amount: UInt256): Confirmable {.contract.} + let txResp = await token.mint(accounts[1], 100.u256) + check txResp is Confirmable + check txResp.isSome - test "fails to compile when function has no parameters": - let works = compiles: - proc foo() {.contract.} - check not works + test "fails to compile when function has an implementation": + let works = compiles: + proc foo(token: TestToken, bar: Address) {.contract.} = discard + check not works - test "fails to compile when non-constant function has a return type": - let works = compiles: - proc foo(token: TestToken, bar: Address): UInt256 {.contract.} - check not works + test "fails to compile when function has no parameters": + let works = compiles: + proc foo() {.contract.} + check not works - test "can connect to different providers and signers": - let signer0 = provider.getSigner(accounts[0]) - let signer1 = provider.getSigner(accounts[1]) - discard await token.connect(signer0).mint(accounts[0], 100.u256) - await token.connect(signer0).transfer(accounts[1], 50.u256) - await token.connect(signer1).transfer(accounts[2], 25.u256) - check (await token.connect(provider).balanceOf(accounts[0])) == 50.u256 - check (await token.connect(provider).balanceOf(accounts[1])) == 25.u256 - check (await token.connect(provider).balanceOf(accounts[2])) == 25.u256 + test "fails to compile when non-constant function has a return type": + let works = compiles: + proc foo(token: TestToken, bar: Address): UInt256 {.contract.} + check not works - test "takes custom values for nonce, gasprice and gaslimit": - let overrides = TransactionOverrides( - nonce: some 100.u256, - gasPrice: some 200.u256, - gasLimit: some 300.u256 - ) - let signer = MockSigner.new(provider) - discard await token.connect(signer).mint(accounts[0], 42.u256, overrides) - check signer.transactions.len == 1 - check signer.transactions[0].nonce == overrides.nonce - check signer.transactions[0].gasPrice == overrides.gasPrice - check signer.transactions[0].gasLimit == overrides.gasLimit + test "can connect to different providers and signers": + let signer0 = provider.getSigner(accounts[0]) + let signer1 = provider.getSigner(accounts[1]) + discard await token.connect(signer0).mint(accounts[0], 100.u256) + await token.connect(signer0).transfer(accounts[1], 50.u256) + await token.connect(signer1).transfer(accounts[2], 25.u256) + check (await token.connect(provider).balanceOf(accounts[0])) == 50.u256 + check (await token.connect(provider).balanceOf(accounts[1])) == 25.u256 + check (await token.connect(provider).balanceOf(accounts[2])) == 25.u256 - test "can call functions for different block heights": - let block1 = await provider.getBlockNumber() - let signer = provider.getSigner(accounts[0]) - discard await token.connect(signer).mint(accounts[0], 100.u256) - let block2 = await provider.getBlockNumber() + test "takes custom values for nonce, gasprice and gaslimit": + let overrides = TransactionOverrides( + nonce: some 100.u256, + gasPrice: some 200.u256, + gasLimit: some 300.u256 + ) + let signer = MockSigner.new(provider) + discard await token.connect(signer).mint(accounts[0], 42.u256, overrides) + check signer.transactions.len == 1 + check signer.transactions[0].nonce == overrides.nonce + check signer.transactions[0].gasPrice == overrides.gasPrice + check signer.transactions[0].gasLimit == overrides.gasLimit - let beforeMint = CallOverrides(blockTag: some BlockTag.init(block1)) - let afterMint = CallOverrides(blockTag: some BlockTag.init(block2)) + test "can call functions for different block heights": + let block1 = await provider.getBlockNumber() + let signer = provider.getSigner(accounts[0]) + discard await token.connect(signer).mint(accounts[0], 100.u256) + let block2 = await provider.getBlockNumber() - check (await token.balanceOf(accounts[0], beforeMint)) == 0 - check (await token.balanceOf(accounts[0], afterMint)) == 100 + let beforeMint = CallOverrides(blockTag: some BlockTag.init(block1)) + let afterMint = CallOverrides(blockTag: some BlockTag.init(block2)) - test "receives events when subscribed": - var transfers: seq[Transfer] + check (await token.balanceOf(accounts[0], beforeMint)) == 0 + check (await token.balanceOf(accounts[0], afterMint)) == 100 - proc handleTransfer(transfer: Transfer) = - transfers.add(transfer) + test "receives events when subscribed": + var transfers: seq[Transfer] - let signer0 = provider.getSigner(accounts[0]) - let signer1 = provider.getSigner(accounts[1]) + proc handleTransfer(transfer: Transfer) = + transfers.add(transfer) - let subscription = await token.subscribe(Transfer, handleTransfer) - discard await token.connect(signer0).mint(accounts[0], 100.u256) - await token.connect(signer0).transfer(accounts[1], 50.u256) - await token.connect(signer1).transfer(accounts[2], 25.u256) - await subscription.unsubscribe() + let signer0 = provider.getSigner(accounts[0]) + let signer1 = provider.getSigner(accounts[1]) - check transfers == @[ - Transfer(receiver: accounts[0], value: 100.u256), - Transfer(sender: accounts[0], receiver: accounts[1], value: 50.u256), - Transfer(sender: accounts[1], receiver: accounts[2], value: 25.u256) - ] + let subscription = await token.subscribe(Transfer, handleTransfer) + discard await token.connect(signer0).mint(accounts[0], 100.u256) + await token.connect(signer0).transfer(accounts[1], 50.u256) + await token.connect(signer1).transfer(accounts[2], 25.u256) - test "stops receiving events when unsubscribed": - var transfers: seq[Transfer] + check eventually transfers == @[ + Transfer(receiver: accounts[0], value: 100.u256), + Transfer(sender: accounts[0], receiver: accounts[1], value: 50.u256), + Transfer(sender: accounts[1], receiver: accounts[2], value: 25.u256) + ] - proc handleTransfer(transfer: Transfer) = - transfers.add(transfer) + await subscription.unsubscribe() - let signer0 = provider.getSigner(accounts[0]) + test "stops receiving events when unsubscribed": + var transfers: seq[Transfer] - let subscription = await token.subscribe(Transfer, handleTransfer) - discard await token.connect(signer0).mint(accounts[0], 100.u256) - await subscription.unsubscribe() + proc handleTransfer(transfer: Transfer) = + transfers.add(transfer) - await token.connect(signer0).transfer(accounts[1], 50.u256) + let signer0 = provider.getSigner(accounts[0]) - check transfers == @[Transfer(receiver: accounts[0], value: 100.u256)] + let subscription = await token.subscribe(Transfer, handleTransfer) + discard await token.connect(signer0).mint(accounts[0], 100.u256) - test "can wait for contract interaction tx to be mined": - # must not be awaited so we can get newHeads inside of .wait - let futMined = provider.mineBlocks(10) + check eventually transfers.len == 1 + await subscription.unsubscribe() - let signer0 = provider.getSigner(accounts[0]) - let receipt = await token.connect(signer0) - .mint(accounts[1], 100.u256) - .confirm(3) # wait for 3 confirmations - let endBlock = await provider.getBlockNumber() + await token.connect(signer0).transfer(accounts[1], 50.u256) + await sleepAsync(100.millis) - check receipt.blockNumber.isSome # was eventually mined + check transfers.len == 1 - # >= 3 because more blocks may have been mined by the time the - # check in `.wait` was done. - # +1 for the block the tx was mined in - check (endBlock - !receipt.blockNumber) + 1 >= 3 + test "can wait for contract interaction tx to be mined": + # must not be awaited so we can get newHeads inside of .wait + let futMined = provider.mineBlocks(10) - await futMined + let signer0 = provider.getSigner(accounts[0]) + let receipt = await token.connect(signer0) + .mint(accounts[1], 100.u256) + .confirm(3) # wait for 3 confirmations + let endBlock = await provider.getBlockNumber() + + check receipt.blockNumber.isSome # was eventually mined + + # >= 3 because more blocks may have been mined by the time the + # check in `.wait` was done. + # +1 for the block the tx was mined in + check (endBlock - !receipt.blockNumber) + 1 >= 3 + + await futMined diff --git a/testmodule/testErc20.nim b/testmodule/testErc20.nim index d93bbc0..1e10690 100644 --- a/testmodule/testErc20.nim +++ b/testmodule/testErc20.nim @@ -13,84 +13,86 @@ type method mint(token: TestToken, holder: Address, amount: UInt256): ?TransactionResponse {.base, contract.} -suite "ERC20": +for url in ["ws://localhost:8545", "http://localhost:8545"]: - var token, token1: Erc20Token - var testToken: TestToken - var provider: JsonRpcProvider - var snapshot: JsonNode - var accounts: seq[Address] + suite "ERC20 (" & url & ")": - setup: - provider = JsonRpcProvider.new("ws://localhost:8545") - snapshot = await provider.send("evm_snapshot") - accounts = await provider.listAccounts() - let deployment = readDeployment() - testToken = TestToken.new(!deployment.address(TestToken), provider.getSigner()) - token = Erc20Token.new(!deployment.address(TestToken), provider.getSigner()) + var token, token1: Erc20Token + var testToken: TestToken + var provider: JsonRpcProvider + var snapshot: JsonNode + var accounts: seq[Address] - teardown: - discard await provider.send("evm_revert", @[snapshot]) + setup: + provider = JsonRpcProvider.new(url, pollingInterval = 100.millis) + snapshot = await provider.send("evm_snapshot") + accounts = await provider.listAccounts() + let deployment = readDeployment() + testToken = TestToken.new(!deployment.address(TestToken), provider.getSigner()) + token = Erc20Token.new(!deployment.address(TestToken), provider.getSigner()) - test "retrieves basic information": - check (await token.name()) == "TestToken" - check (await token.symbol()) == "TST" - check (await token.decimals()) == 12 - check (await token.totalSupply()) == 0.u256 - check (await token.balanceOf(accounts[0])) == 0.u256 - check (await token.allowance(accounts[0], accounts[1])) == 0.u256 + teardown: + discard await provider.send("evm_revert", @[snapshot]) - test "transfer tokens": - check (await token.balanceOf(accounts[0])) == 0.u256 - check (await token.allowance(accounts[0], accounts[1])) == 0.u256 + test "retrieves basic information": + check (await token.name()) == "TestToken" + check (await token.symbol()) == "TST" + check (await token.decimals()) == 12 + check (await token.totalSupply()) == 0.u256 + check (await token.balanceOf(accounts[0])) == 0.u256 + check (await token.allowance(accounts[0], accounts[1])) == 0.u256 - discard await testToken.mint(accounts[0], 100.u256) + test "transfer tokens": + check (await token.balanceOf(accounts[0])) == 0.u256 + check (await token.allowance(accounts[0], accounts[1])) == 0.u256 - check (await token.totalSupply()) == 100.u256 - check (await token.balanceOf(accounts[0])) == 100.u256 - check (await token.balanceOf(accounts[1])) == 0.u256 + discard await testToken.mint(accounts[0], 100.u256) - await token.transfer(accounts[1], 50.u256) + check (await token.totalSupply()) == 100.u256 + check (await token.balanceOf(accounts[0])) == 100.u256 + check (await token.balanceOf(accounts[1])) == 0.u256 - check (await token.balanceOf(accounts[0])) == 50.u256 - check (await token.balanceOf(accounts[1])) == 50.u256 + await token.transfer(accounts[1], 50.u256) - test "approve tokens": - discard await testToken.mint(accounts[0], 100.u256) + check (await token.balanceOf(accounts[0])) == 50.u256 + check (await token.balanceOf(accounts[1])) == 50.u256 - check (await token.allowance(accounts[0], accounts[1])) == 0.u256 - check (await token.balanceOf(accounts[0])) == 100.u256 - check (await token.balanceOf(accounts[1])) == 0.u256 + test "approve tokens": + discard await testToken.mint(accounts[0], 100.u256) - await token.approve(accounts[1], 50.u256) + check (await token.allowance(accounts[0], accounts[1])) == 0.u256 + check (await token.balanceOf(accounts[0])) == 100.u256 + check (await token.balanceOf(accounts[1])) == 0.u256 - check (await token.allowance(accounts[0], accounts[1])) == 50.u256 - check (await token.balanceOf(accounts[0])) == 100.u256 - check (await token.balanceOf(accounts[1])) == 0.u256 + await token.approve(accounts[1], 50.u256) - test "transferFrom tokens": - let senderAccount = accounts[0] - let receiverAccount = accounts[1] - let receiverAccountSigner = provider.getSigner(receiverAccount) + check (await token.allowance(accounts[0], accounts[1])) == 50.u256 + check (await token.balanceOf(accounts[0])) == 100.u256 + check (await token.balanceOf(accounts[1])) == 0.u256 - check (await token.balanceOf(senderAccount)) == 0.u256 - check (await token.allowance(senderAccount, receiverAccount)) == 0.u256 + test "transferFrom tokens": + let senderAccount = accounts[0] + let receiverAccount = accounts[1] + let receiverAccountSigner = provider.getSigner(receiverAccount) - discard await testToken.mint(senderAccount, 100.u256) + check (await token.balanceOf(senderAccount)) == 0.u256 + check (await token.allowance(senderAccount, receiverAccount)) == 0.u256 - check (await token.totalSupply()) == 100.u256 - check (await token.balanceOf(senderAccount)) == 100.u256 - check (await token.balanceOf(receiverAccount)) == 0.u256 + discard await testToken.mint(senderAccount, 100.u256) - await token.approve(receiverAccount, 50.u256) + check (await token.totalSupply()) == 100.u256 + check (await token.balanceOf(senderAccount)) == 100.u256 + check (await token.balanceOf(receiverAccount)) == 0.u256 - check (await token.allowance(senderAccount, receiverAccount)) == 50.u256 - check (await token.balanceOf(senderAccount)) == 100.u256 - check (await token.balanceOf(receiverAccount)) == 0.u256 + await token.approve(receiverAccount, 50.u256) - await token.connect(receiverAccountSigner).transferFrom(senderAccount, receiverAccount, 50.u256) + check (await token.allowance(senderAccount, receiverAccount)) == 50.u256 + check (await token.balanceOf(senderAccount)) == 100.u256 + check (await token.balanceOf(receiverAccount)) == 0.u256 - check (await token.balanceOf(senderAccount)) == 50.u256 - check (await token.balanceOf(receiverAccount)) == 50.u256 - check (await token.allowance(senderAccount, receiverAccount)) == 0.u256 + await token.connect(receiverAccountSigner).transferFrom(senderAccount, receiverAccount, 50.u256) + + check (await token.balanceOf(senderAccount)) == 50.u256 + check (await token.balanceOf(receiverAccount)) == 50.u256 + check (await token.allowance(senderAccount, receiverAccount)) == 0.u256