Test contracts with polling

This commit is contained in:
Mark Spanbroek 2023-06-27 15:59:31 +02:00 committed by markspanbroek
parent 2481bda6e4
commit 7e346914c0
2 changed files with 207 additions and 199 deletions

View File

@ -15,179 +15,185 @@ type
method mint(token: TestToken, holder: Address, amount: UInt256): ?TransactionResponse {.base, contract.} method mint(token: TestToken, holder: Address, amount: UInt256): ?TransactionResponse {.base, contract.}
method myBalance(token: TestToken): UInt256 {.contract, view.} method myBalance(token: TestToken): UInt256 {.contract, view.}
suite "Contracts": for url in ["ws://localhost:8545", "http://localhost:8545"]:
var token: TestToken suite "Contracts (" & url & ")":
var provider: JsonRpcProvider
var snapshot: JsonNode
var accounts: seq[Address]
setup: var token: TestToken
provider = JsonRpcProvider.new("ws://localhost:8545") var provider: JsonRpcProvider
snapshot = await provider.send("evm_snapshot") var snapshot: JsonNode
accounts = await provider.listAccounts() var accounts: seq[Address]
let deployment = readDeployment()
token = TestToken.new(!deployment.address(TestToken), provider)
teardown: setup:
discard await provider.send("evm_revert", @[snapshot]) 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": teardown:
check (await token.name()) == "TestToken" discard await provider.send("evm_revert", @[snapshot])
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 non-constant functions": test "can call constant functions":
token = TestToken.new(token.address, provider.getSigner()) check (await token.name()) == "TestToken"
discard await token.mint(accounts[1], 100.u256) check (await token.totalSupply()) == 0.u256
check (await token.totalSupply()) == 100.u256 check (await token.balanceOf(accounts[0])) == 0.u256
check (await token.balanceOf(accounts[1])) == 100.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": test "can call non-constant functions":
let signer0 = provider.getSigner(accounts[0]) token = TestToken.new(token.address, provider.getSigner())
let signer1 = provider.getSigner(accounts[1]) discard await token.mint(accounts[1], 100.u256)
discard await token.connect(signer0).mint(accounts[1], 100.u256) check (await token.totalSupply()) == 100.u256
check (await token.connect(signer0).myBalance()) == 0.u256 check (await token.balanceOf(accounts[1])) == 100.u256
check (await token.connect(signer1).myBalance()) == 100.u256
test "can call non-constant functions without a signer": test "can call constant functions with a signer and the account is used for the call":
discard await token.mint(accounts[1], 100.u256) let signer0 = provider.getSigner(accounts[0])
check (await token.balanceOf(accounts[1])) == 0.u256 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": test "can call non-constant functions without a signer":
token = TestToken.new(token.address, provider.getSigner()) discard await token.mint(accounts[1], 100.u256)
proc mint(token: TestToken, holder: Address, amount: UInt256) {.contract, view.} check (await token.balanceOf(accounts[1])) == 0.u256
await mint(token, accounts[1], 100.u256)
check (await balanceOf(token, accounts[1])) == 0.u256
test "can call non-constant functions without a return type": test "can call constant functions without a return type":
token = TestToken.new(token.address, provider.getSigner()) token = TestToken.new(token.address, provider.getSigner())
proc mint(token: TestToken, holder: Address, amount: UInt256) {.contract.} proc mint(token: TestToken, holder: Address, amount: UInt256) {.contract, view.}
await token.mint(accounts[1], 100.u256) await mint(token, accounts[1], 100.u256)
check (await balanceOf(token, accounts[1])) == 100.u256 check (await balanceOf(token, accounts[1])) == 0.u256
test "can call non-constant functions with a ?TransactionResponse return type": test "can call non-constant functions without a return type":
token = TestToken.new(token.address, provider.getSigner()) token = TestToken.new(token.address, provider.getSigner())
proc mint(token: TestToken, proc mint(token: TestToken, holder: Address, amount: UInt256) {.contract.}
holder: Address, await token.mint(accounts[1], 100.u256)
amount: UInt256): ?TransactionResponse {.contract.} check (await balanceOf(token, accounts[1])) == 100.u256
let txResp = await token.mint(accounts[1], 100.u256)
check txResp is (?TransactionResponse)
check txResp.isSome
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()) test "can call non-constant functions with a Confirmable return type":
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 an implementation": token = TestToken.new(token.address, provider.getSigner())
let works = compiles: proc mint(token: TestToken,
proc foo(token: TestToken, bar: Address) {.contract.} = discard holder: Address,
check not works 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": test "fails to compile when function has an implementation":
let works = compiles: let works = compiles:
proc foo() {.contract.} proc foo(token: TestToken, bar: Address) {.contract.} = discard
check not works check not works
test "fails to compile when non-constant function has a return type": test "fails to compile when function has no parameters":
let works = compiles: let works = compiles:
proc foo(token: TestToken, bar: Address): UInt256 {.contract.} proc foo() {.contract.}
check not works check not works
test "can connect to different providers and signers": test "fails to compile when non-constant function has a return type":
let signer0 = provider.getSigner(accounts[0]) let works = compiles:
let signer1 = provider.getSigner(accounts[1]) proc foo(token: TestToken, bar: Address): UInt256 {.contract.}
discard await token.connect(signer0).mint(accounts[0], 100.u256) check not works
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 "takes custom values for nonce, gasprice and gaslimit": test "can connect to different providers and signers":
let overrides = TransactionOverrides( let signer0 = provider.getSigner(accounts[0])
nonce: some 100.u256, let signer1 = provider.getSigner(accounts[1])
gasPrice: some 200.u256, discard await token.connect(signer0).mint(accounts[0], 100.u256)
gasLimit: some 300.u256 await token.connect(signer0).transfer(accounts[1], 50.u256)
) await token.connect(signer1).transfer(accounts[2], 25.u256)
let signer = MockSigner.new(provider) check (await token.connect(provider).balanceOf(accounts[0])) == 50.u256
discard await token.connect(signer).mint(accounts[0], 42.u256, overrides) check (await token.connect(provider).balanceOf(accounts[1])) == 25.u256
check signer.transactions.len == 1 check (await token.connect(provider).balanceOf(accounts[2])) == 25.u256
check signer.transactions[0].nonce == overrides.nonce
check signer.transactions[0].gasPrice == overrides.gasPrice
check signer.transactions[0].gasLimit == overrides.gasLimit
test "can call functions for different block heights": test "takes custom values for nonce, gasprice and gaslimit":
let block1 = await provider.getBlockNumber() let overrides = TransactionOverrides(
let signer = provider.getSigner(accounts[0]) nonce: some 100.u256,
discard await token.connect(signer).mint(accounts[0], 100.u256) gasPrice: some 200.u256,
let block2 = await provider.getBlockNumber() 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)) test "can call functions for different block heights":
let afterMint = CallOverrides(blockTag: some BlockTag.init(block2)) 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 let beforeMint = CallOverrides(blockTag: some BlockTag.init(block1))
check (await token.balanceOf(accounts[0], afterMint)) == 100 let afterMint = CallOverrides(blockTag: some BlockTag.init(block2))
test "receives events when subscribed": check (await token.balanceOf(accounts[0], beforeMint)) == 0
var transfers: seq[Transfer] check (await token.balanceOf(accounts[0], afterMint)) == 100
proc handleTransfer(transfer: Transfer) = test "receives events when subscribed":
transfers.add(transfer) var transfers: seq[Transfer]
let signer0 = provider.getSigner(accounts[0]) proc handleTransfer(transfer: Transfer) =
let signer1 = provider.getSigner(accounts[1]) transfers.add(transfer)
let subscription = await token.subscribe(Transfer, handleTransfer) let signer0 = provider.getSigner(accounts[0])
discard await token.connect(signer0).mint(accounts[0], 100.u256) let signer1 = provider.getSigner(accounts[1])
await token.connect(signer0).transfer(accounts[1], 50.u256)
await token.connect(signer1).transfer(accounts[2], 25.u256)
await subscription.unsubscribe()
check transfers == @[ let subscription = await token.subscribe(Transfer, handleTransfer)
Transfer(receiver: accounts[0], value: 100.u256), discard await token.connect(signer0).mint(accounts[0], 100.u256)
Transfer(sender: accounts[0], receiver: accounts[1], value: 50.u256), await token.connect(signer0).transfer(accounts[1], 50.u256)
Transfer(sender: accounts[1], receiver: accounts[2], value: 25.u256) await token.connect(signer1).transfer(accounts[2], 25.u256)
]
test "stops receiving events when unsubscribed": check eventually transfers == @[
var transfers: seq[Transfer] 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) = await subscription.unsubscribe()
transfers.add(transfer)
let signer0 = provider.getSigner(accounts[0]) test "stops receiving events when unsubscribed":
var transfers: seq[Transfer]
let subscription = await token.subscribe(Transfer, handleTransfer) proc handleTransfer(transfer: Transfer) =
discard await token.connect(signer0).mint(accounts[0], 100.u256) transfers.add(transfer)
await subscription.unsubscribe()
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": check eventually transfers.len == 1
# must not be awaited so we can get newHeads inside of .wait await subscription.unsubscribe()
let futMined = provider.mineBlocks(10)
let signer0 = provider.getSigner(accounts[0]) await token.connect(signer0).transfer(accounts[1], 50.u256)
let receipt = await token.connect(signer0) await sleepAsync(100.millis)
.mint(accounts[1], 100.u256)
.confirm(3) # wait for 3 confirmations
let endBlock = await provider.getBlockNumber()
check receipt.blockNumber.isSome # was eventually mined check transfers.len == 1
# >= 3 because more blocks may have been mined by the time the test "can wait for contract interaction tx to be mined":
# check in `.wait` was done. # must not be awaited so we can get newHeads inside of .wait
# +1 for the block the tx was mined in let futMined = provider.mineBlocks(10)
check (endBlock - !receipt.blockNumber) + 1 >= 3
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

View File

@ -13,84 +13,86 @@ type
method mint(token: TestToken, holder: Address, amount: UInt256): ?TransactionResponse {.base, contract.} 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 suite "ERC20 (" & url & ")":
var testToken: TestToken
var provider: JsonRpcProvider
var snapshot: JsonNode
var accounts: seq[Address]
setup: var token, token1: Erc20Token
provider = JsonRpcProvider.new("ws://localhost:8545") var testToken: TestToken
snapshot = await provider.send("evm_snapshot") var provider: JsonRpcProvider
accounts = await provider.listAccounts() var snapshot: JsonNode
let deployment = readDeployment() var accounts: seq[Address]
testToken = TestToken.new(!deployment.address(TestToken), provider.getSigner())
token = Erc20Token.new(!deployment.address(TestToken), provider.getSigner())
teardown: setup:
discard await provider.send("evm_revert", @[snapshot]) 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": teardown:
check (await token.name()) == "TestToken" discard await provider.send("evm_revert", @[snapshot])
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
test "transfer tokens": test "retrieves basic information":
check (await token.balanceOf(accounts[0])) == 0.u256 check (await token.name()) == "TestToken"
check (await token.allowance(accounts[0], accounts[1])) == 0.u256 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 discard await testToken.mint(accounts[0], 100.u256)
check (await token.balanceOf(accounts[0])) == 100.u256
check (await token.balanceOf(accounts[1])) == 0.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 await token.transfer(accounts[1], 50.u256)
check (await token.balanceOf(accounts[1])) == 50.u256
test "approve tokens": check (await token.balanceOf(accounts[0])) == 50.u256
discard await testToken.mint(accounts[0], 100.u256) check (await token.balanceOf(accounts[1])) == 50.u256
check (await token.allowance(accounts[0], accounts[1])) == 0.u256 test "approve tokens":
check (await token.balanceOf(accounts[0])) == 100.u256 discard await testToken.mint(accounts[0], 100.u256)
check (await token.balanceOf(accounts[1])) == 0.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 await token.approve(accounts[1], 50.u256)
check (await token.balanceOf(accounts[0])) == 100.u256
check (await token.balanceOf(accounts[1])) == 0.u256
test "transferFrom tokens": check (await token.allowance(accounts[0], accounts[1])) == 50.u256
let senderAccount = accounts[0] check (await token.balanceOf(accounts[0])) == 100.u256
let receiverAccount = accounts[1] check (await token.balanceOf(accounts[1])) == 0.u256
let receiverAccountSigner = provider.getSigner(receiverAccount)
check (await token.balanceOf(senderAccount)) == 0.u256 test "transferFrom tokens":
check (await token.allowance(senderAccount, receiverAccount)) == 0.u256 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 discard await testToken.mint(senderAccount, 100.u256)
check (await token.balanceOf(senderAccount)) == 100.u256
check (await token.balanceOf(receiverAccount)) == 0.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 await token.approve(receiverAccount, 50.u256)
check (await token.balanceOf(senderAccount)) == 100.u256
check (await token.balanceOf(receiverAccount)) == 0.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 await token.connect(receiverAccountSigner).transferFrom(senderAccount, receiverAccount, 50.u256)
check (await token.balanceOf(receiverAccount)) == 50.u256
check (await token.allowance(senderAccount, 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