From 35439304322ed502f66da37ecb50e0e4954978b1 Mon Sep 17 00:00:00 2001 From: Alpay Aldemir Date: Sat, 3 Jun 2023 21:56:42 -0400 Subject: [PATCH] test: assert chained delegations can not be used to transfer more ERC20 tokens than the root delegation permits --- test/enforcers/ERC20AllowanceEnforcer.test.ts | 85 ++++++++++++++++++- test/utils.ts | 7 ++ 2 files changed, 91 insertions(+), 1 deletion(-) diff --git a/test/enforcers/ERC20AllowanceEnforcer.test.ts b/test/enforcers/ERC20AllowanceEnforcer.test.ts index 87687c7..9e2cbc6 100644 --- a/test/enforcers/ERC20AllowanceEnforcer.test.ts +++ b/test/enforcers/ERC20AllowanceEnforcer.test.ts @@ -6,7 +6,7 @@ import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers"; // @ts-ignore import { generateUtil } from "eth-delegatable-utils"; import { getPrivateKeys } from "../../utils/getPrivateKeys"; -import { generateDelegation } from "../utils"; +import { generateDelegation, prepend0x } from "../utils"; const { getSigners } = ethers; @@ -165,6 +165,89 @@ describe("ERC20AllowanceEnforcer", () => { ).to.be.revertedWith("ERC20AllowanceEnforcer:allowance-exceeded"); }); + it("should FAIL to transfer more than initial delegation permits", async () => { + expect(await ERC20Delegatable.balanceOf(wallet0.address)).to.eq( + ethers.utils.parseEther("1") + ); + + // root delegation (signer will be set to the message sender and therefore tokens will transfer from signer's account) + // root delegation provides allowance for 0.1 + const _delegation0 = generateDelegation( + CONTACT_NAME, + ERC20Delegatable, + PK0, + wallet1.address, + [ + { + enforcer: ERC20AllowanceEnforcer.address, + terms: ethers.utils.hexZeroPad( + utils.parseEther("0.1").toHexString(), + 32 + ), + }, + ] + ); + + const _delegationHash0 = + delegatableUtils.createSignedDelegationHash(_delegation0); + const _delegationHash0Hex = prepend0x(_delegationHash0.toString("hex")); + + // this delegation says allowance is 0.2 + const _delegation1 = generateDelegation( + CONTACT_NAME, + ERC20Delegatable, + PK1, + wallet2.address, + [ + { + enforcer: ERC20AllowanceEnforcer.address, + terms: ethers.utils.hexZeroPad( + utils.parseEther("0.2").toHexString(), + 32 + ), + }, + ], + _delegationHash0Hex + ); + + // invocation will try to transfer 0.2 + const INVOCATION_MESSAGE = { + replayProtection: { + nonce: "0x01", + queue: "0x00", + }, + batch: [ + { + authority: [_delegation0, _delegation1], + transaction: { + to: ERC20Delegatable.address, + gasLimit: "210000000000000000", + data: ( + await ERC20Delegatable.populateTransaction.transfer( + wallet1.address, + ethers.utils.parseEther("0.2") + ) + ).data, + }, + }, + ], + }; + const invocation = delegatableUtils.signInvocation(INVOCATION_MESSAGE, PK2); + + await expect( + ERC20Delegatable.invoke([ + { + signature: invocation.signature, + invocations: invocation.invocations, + }, + ]) + ).to.be.revertedWith("ERC20AllowanceEnforcer:allowance-exceeded"); + + expect(await ERC20Delegatable.balanceOf(wallet0.address)).to.eq( + ethers.utils.parseEther("1") + ); + }); + it("should FAIL to INVOKE invalid method", async () => { const PK = wallet0._signingKey().privateKey.substring(2); expect(await ERC20Delegatable.balanceOf(wallet0.address)).to.eq( diff --git a/test/utils.ts b/test/utils.ts index 5f538ff..d6c6fef 100644 --- a/test/utils.ts +++ b/test/utils.ts @@ -3,6 +3,13 @@ import { generateUtil } from "eth-delegatable-utils"; const BASE_AUTH = "0x0000000000000000000000000000000000000000000000000000000000000000"; +export function prepend0x(hex: string): string { + if (hex.toLowerCase().slice(0, 2) === "0x") { + return hex; + } + return "0x" + hex; +} + export function generateDelegation( name: any, contract: any,