From 8adbeed5bddd523ca69e40cabbea13033c46c85b Mon Sep 17 00:00:00 2001 From: stubbsta Date: Mon, 26 May 2025 09:30:23 +0200 Subject: [PATCH] Clean up code and error handling --- tests/waku_rln_relay/utils_onchain.nim | 112 ++++++++++++++----------- 1 file changed, 64 insertions(+), 48 deletions(-) diff --git a/tests/waku_rln_relay/utils_onchain.nim b/tests/waku_rln_relay/utils_onchain.nim index a433ad9d1..68c52b1c7 100644 --- a/tests/waku_rln_relay/utils_onchain.nim +++ b/tests/waku_rln_relay/utils_onchain.nim @@ -104,6 +104,14 @@ proc sendMintCall*( amountTokens: UInt256, recipientBalanceBeforeExpectedTokens: Option[UInt256] = none(UInt256), ): Future[TxHash] {.async.} = + let doBalanceAssert = recipientBalanceBeforeExpectedTokens.isSome() + + if doBalanceAssert: + let balanceBeforeMint = await getTokenBalance(web3, tokenAddress, recipientAddress) + let balanceBeforeExpectedTokens = recipientBalanceBeforeExpectedTokens.get() + assert balanceBeforeMint == balanceBeforeExpectedTokens, + fmt"Balance is {balanceBeforeMint} before minting but expected {balanceBeforeExpectedTokens}" + # Create mint transaction let mintSelector = "0x40c10f19" # Pad the address and amount to 32 bytes each let addressHex = recipientAddress.toHex() @@ -137,28 +145,16 @@ proc sendMintCall*( # Wait a bit for transaction to be mined await sleepAsync(500.milliseconds) - var balanceCallTx: TransactionArgs - balanceCallTx.to = Opt.some(tokenAddress) - balanceCallTx.data = Opt.some(byteutils.hexToSeqByte(balanceCallData)) - - # Make the call to get updated balance - let balanceResponse = await web3.provider.eth_call(balanceCallTx, "latest") - - let balanceHexStr = "0x" & byteutils.toHex(balanceResponse) - let balanceAfterTokens = stint.parse(balanceHexStr, UInt256, 16) - let balanceAfterExpectedTokens = - recipientBalanceBeforeExpectedTokens.get() + amountTokens - debug "token balance after minting", balanceAfterTokens = balanceAfterTokens - assert balanceAfterTokens == balanceAfterExpectedTokens, - fmt"Token balance is {balanceAfterTokens} but expected {balanceAfterExpectedTokens}" - - let balance3 = await web3.provider.eth_getBalance(recipientAddress, "latest") - debug "sendMintCall: after mint recipientAddress account balance: ", - recipientAddress = recipientAddress, balance = balance3 + if doBalanceAssert: + let balanceAfterMint = await getTokenBalance(web3, tokenAddress, recipientAddress) + let balanceAfterExpectedTokens = + recipientBalanceBeforeExpectedTokens.get() + amountTokens + assert balanceAfterMint == balanceAfterExpectedTokens, + fmt"Balance is {balanceAfterMint} after transfer but expected {balanceAfterExpectedTokens}" return txHash -proc checkApproval*( +proc checkAllowance*( web3: Web3, tokenAddress: Address, owner: Address, spender: Address ): Future[UInt256] {.async.} = let token = web3.contractSender(ERC20Token, tokenAddress) @@ -166,17 +162,26 @@ proc checkApproval*( debug "Current allowance", owner = owner, spender = spender, allowance = allowance return allowance -proc sendApproveCall*( +proc sendTokenApproveCall*( web3: Web3, accountFrom: Address, privateKey: keys.PrivateKey, tokenAddress: Address, spender: Address, amountWei: UInt256, + accountAllowanceBeforeExpectedTokens: Option[UInt256] = none(UInt256), ): Future[TxHash] {.async.} = # # ERC20 approve function signature: approve(address spender, uint256 amount) # # Create the contract call data # # Method ID for approve(address,uint256) is 0x095ea7b3 + let doBalanceAssert = accountAllowanceBeforeExpectedTokens.isSome() + + if doBalanceAssert: + let allowanceBeforeApproval = + await checkAllowance(web3, tokenAddress, accountFrom, spender) + let allowanceBeforeExpectedTokens = accountAllowanceBeforeExpectedTokens.get() + assert allowanceBeforeApproval == allowanceBeforeExpectedTokens, + fmt"Balance is {allowanceBeforeApproval} before minting but expected {allowanceBeforeExpectedTokens}" # Temporarily set the private key let oldPrivateKey = web3.privateKey @@ -189,11 +194,7 @@ proc sendApproveCall*( let addressHex = spender.toHex() # Already without 0x let paddedAddress = addressHex.align(64, '0') let amountHex = amountWei.toHex() - # let amountWithout0x = - # if amountHex.startsWith("0x"): - # amountHex[2 .. ^1] - # else: - # amountHex + let paddedAmount = amountHex.align(64, '0') let approveCallData = approveSelector & paddedAddress & paddedAmount @@ -215,6 +216,15 @@ proc sendApproveCall*( try: # Send will automatically sign because privateKey is set let txHash = await web3.send(tx) + + if doBalanceAssert: + let allowanceAfterApproval = + await checkAllowance(web3, tokenAddress, accountFrom, spender) + let allowanceAfterExpectedTokens = + accountAllowanceBeforeExpectedTokens.get() + amountWei + assert allowanceAfterApproval == allowanceAfterExpectedTokens, + fmt"Balance is {allowanceAfterApproval} before minting but expected {allowanceAfterExpectedTokens}" + return txHash except CatchableError as e: error "Failed to send approve transaction", error = e.msg @@ -225,7 +235,7 @@ proc sendApproveCall*( proc deployTestToken*( pk: keys.PrivateKey, acc: Address, web3: Web3 -): Future[Address] {.async.} = +): Future[Result[Address, string]] {.async.} = ## Executes a Foundry forge script that deploys the a token contract (ERC-20) used for testing. This is a prerequisite to enable the contract deployment and this token contract address needs to be minted and approved for the accounts that need to register membership with the contract ## submodulePath: path to the submodule containing contract deploy scripts @@ -240,25 +250,25 @@ proc deployTestToken*( execCmdEx(fmt"""cd {submodulePath} && {forgePath} clean""") trace "Executed forge clean command", output = forgeCleanOutput if forgeCleanExitCode != 0: - error "forge clean failed", output = forgeCleanOutput + return error("forge clean command failed") let (forgeInstallOutput, forgeInstallExitCode) = execCmdEx(fmt"""cd {submodulePath} && {forgePath} install""") trace "Executed forge install command", output = forgeInstallOutput if forgeInstallExitCode != 0: - error "forge install failed", output = forgeInstallOutput + return error("forge install command failed") let (pnpmInstallOutput, pnpmInstallExitCode) = execCmdEx(fmt"""cd {submodulePath} && pnpm install""") trace "Executed pnpm install command", output = pnpmInstallOutput if pnpmInstallExitCode != 0: - error "pnpm install failed", output = pnpmInstallOutput + return error("pnpm install command failed") let (forgeBuildOutput, forgeBuildExitCode) = execCmdEx(fmt"""cd {submodulePath} && {forgePath} build""") trace "Executed forge build command", output = forgeBuildOutput if forgeBuildExitCode != 0: - error "forge build failed", output = forgeBuildOutput + return error("forge build command failed") # Set the environment variable API keys to anything for testing putEnv("API_KEY_CARDONA", "123") @@ -272,19 +282,20 @@ proc deployTestToken*( trace "Executed forge command to deploy TestToken contract", output = outputDeployTestToken if exitCodeDeployTestToken != 0: - # error "Forge command to deploy TestToken contract failed", output = outputDeployTestToken - raise newException( - CatchableError, - "Forge command to deploy TestToken contract failed, output=" & - outputDeployTestToken, - ) + return error("Forge command to deploy TestToken contract failed") + # raise newException( + # CatchableError, + # "Forge command to deploy TestToken contract failed, output=" & + # outputDeployTestToken, + # ) # Parse the output to find contract address let testTokenAddressRes = getContractAddressFromDeployScriptOutput(outputDeployTestToken) if testTokenAddressRes.isErr(): - error "Failed to get TestToken contract address from deploy script output" - ##TODO: raise exception here? + error "Failed to get TestToken contract address from deploy script output", + error = testTokenAddressRes.error + return err("Failed to get TestToken contract address from deploy script output") let testTokenAddress = testTokenAddressRes.get() debug "Address of the TestToken contract", testTokenAddress debug "TestToken contract deployer account details", account = acc, pk = pk @@ -292,9 +303,9 @@ proc deployTestToken*( let testTokenAddressBytes = hexToByteArray[20](testTokenAddress) let testTokenAddressAddress = Address(testTokenAddressBytes) - return testTokenAddressAddress + return ok(testTokenAddressAddress) -proc approveAndVerify*( +proc approveTokenAllowanceAndVerify*( web3: Web3, accountFrom: Address, privateKey: keys.PrivateKey, @@ -309,8 +320,8 @@ proc approveAndVerify*( amount = amountWei # Send approval - let txHash = await sendApproveCall( - web3, accountFrom, privateKey, tokenAddress, spender, amountWei + let txHash = await sendTokenApproveCall( + web3, accountFrom, privateKey, tokenAddress, spender, amountWei, some(0.u256) ) debug "Approval transaction sent", txHash = txHash @@ -328,7 +339,7 @@ proc approveAndVerify*( await sleepAsync(100.milliseconds) # Check allowance after mining - let allowanceAfter = await checkApproval(web3, tokenAddress, accountFrom, spender) + let allowanceAfter = await checkAllowance(web3, tokenAddress, accountFrom, spender) debug "Allowance after approval", amount = allowanceAfter return allowanceAfter >= amountWei @@ -423,7 +434,7 @@ proc executeForgeContractDeployScripts*(): Future[Address] {.async.} = error "Forge command to deploy Proxy failed" raise newException( CatchableError, - "Forge command to deploy proxy contract failed, exitCodeDeployProxy=", + "Forge command to deploy proxy contract failed, output=" & outputDeployProxy, ) let proxyAddress = getContractAddressFromDeployScriptOutput(outputDeployProxy) @@ -520,7 +531,7 @@ proc sendEthTransfer*( let txHash = await web3.send(tx) # Wait a bit for transaction to be mined - await sleepAsync(2000.milliseconds) + await sleepAsync(1000.milliseconds) if doBalanceAssert: let balanceAfterWei = await web3.provider.eth_getBalance(accountTo, "latest") @@ -645,18 +656,23 @@ proc setupOnchainGroupManager*( # we just need to fund the default account # the send procedure returns a tx hash that we don't use, hence discard discard await sendEthTransfer( - web3, web3.defaultAccount, acc, ethToWei(5000.u256), some(0.u256) + web3, web3.defaultAccount, acc, ethToWei(1000.u256), some(0.u256) ) - let testTokenAddress = await deployTestToken(privateKey, acc, web3) + let testTokenAddressRes = await deployTestToken(privateKey, acc, web3) + if testTokenAddressRes.isErr(): + error "Failed to deploy test token contract", error = testTokenAddressRes.error + raise newException(CatchableError, "Failed to deploy test token contract") + let testTokenAddress = testTokenAddressRes.get() putEnv("TOKEN_ADDRESS", testTokenAddress.toHex()) + # mint the token from the generated account discard await sendMintCall( web3, web3.defaultAccount, testTokenAddress, acc, ethToWei(1000.u256), some(0.u256) ) let contractAddress = await executeForgeContractDeployScripts() - let approvalSuccess = await approveAndVerify( + let approvalSuccess = await approveTokenAllowanceAndVerify( web3, acc, # owner privateKey,