From ad75174a3c397c76e5f2c258b3dd8dc5cd103531 Mon Sep 17 00:00:00 2001 From: Yvonne Zhang Date: Tue, 8 Aug 2023 07:48:28 -0700 Subject: [PATCH] Add unified interface for EOA and contract wallet signatures * Add unified interface for EOA and contract wallet signatures * Modify comment --- @types/AnyFiatTokenV2Instance.d.ts | 17 ++ contracts/v2/FiatTokenV2_2.sol | 99 ++++++++++ test/v2/FiatTokenV2.test.ts | 39 +++- test/v2/FiatTokenV2_2.test.ts | 128 +++++++++++- .../GasAbstraction/GasAbstraction.behavior.ts | 17 +- test/v2/GasAbstraction/helpers.ts | 60 +++++- .../GasAbstraction/testCancelAuthorization.ts | 91 +++++---- test/v2/GasAbstraction/testPermit.ts | 186 ++++++++++++------ .../testReceiveWithAuthorization.ts | 104 +++++----- .../testTransferWithAuthorization.ts | 98 +++++---- .../testTransferWithMultipleAuthorizations.ts | 22 +-- test/v2/safeAllowance.behavior.ts | 6 +- 12 files changed, 610 insertions(+), 257 deletions(-) create mode 100644 @types/AnyFiatTokenV2Instance.d.ts diff --git a/@types/AnyFiatTokenV2Instance.d.ts b/@types/AnyFiatTokenV2Instance.d.ts new file mode 100644 index 000000000..41ec93d13 --- /dev/null +++ b/@types/AnyFiatTokenV2Instance.d.ts @@ -0,0 +1,17 @@ +import { + FiatTokenV2Instance, + FiatTokenV21Instance, + FiatTokenV22Instance, +} from "./generated"; + +export interface FiatTokenV22InstanceExtended extends FiatTokenV22Instance { + permit?: typeof FiatTokenV2Instance.permit; + transferWithAuthorization?: typeof FiatTokenV2Instance.transferWithAuthorization; + receiveWithAuthorization?: typeof FiatTokenV2Instance.receiveWithAuthorization; + cancelAuthorization?: typeof FiatTokenV2Instance.cancelAuthorization; +} + +export type AnyFiatTokenV2Instance = + | FiatTokenV2Instance + | FiatTokenV21Instance + | FiatTokenV22InstanceExtended; diff --git a/contracts/v2/FiatTokenV2_2.sol b/contracts/v2/FiatTokenV2_2.sol index e738485ad..be7b5444a 100644 --- a/contracts/v2/FiatTokenV2_2.sol +++ b/contracts/v2/FiatTokenV2_2.sol @@ -57,4 +57,103 @@ contract FiatTokenV2_2 is FiatTokenV2_1 { function _domainSeparator() internal override view returns (bytes32) { return EIP712.makeDomainSeparator(name, "2", _chainId()); } + + /** + * @notice Update allowance with a signed permit + * @dev EOA wallet signatures should be packed in the order of r, s, v. + * @param owner Token owner's address (Authorizer) + * @param spender Spender's address + * @param value Amount of allowance + * @param deadline Expiration time, seconds since the epoch + * @param signature Signature bytes signed by an EOA wallet or a contract wallet + */ + function permit( + address owner, + address spender, + uint256 value, + uint256 deadline, + bytes memory signature + ) external whenNotPaused notBlacklisted(owner) notBlacklisted(spender) { + _permit(owner, spender, value, deadline, signature); + } + + /** + * @notice Execute a transfer with a signed authorization + * @dev EOA wallet signatures should be packed in the order of r, s, v. + * @param from Payer's address (Authorizer) + * @param to Payee's address + * @param value Amount to be transferred + * @param validAfter The time after which this is valid (unix time) + * @param validBefore The time before which this is valid (unix time) + * @param nonce Unique nonce + * @param signature Signature bytes signed by an EOA wallet or a contract wallet + */ + function transferWithAuthorization( + address from, + address to, + uint256 value, + uint256 validAfter, + uint256 validBefore, + bytes32 nonce, + bytes memory signature + ) external whenNotPaused notBlacklisted(from) notBlacklisted(to) { + _transferWithAuthorization( + from, + to, + value, + validAfter, + validBefore, + nonce, + signature + ); + } + + /** + * @notice Receive a transfer with a signed authorization from the payer + * @dev This has an additional check to ensure that the payee's address + * matches the caller of this function to prevent front-running attacks. + * EOA wallet signatures should be packed in the order of r, s, v. + * @param from Payer's address (Authorizer) + * @param to Payee's address + * @param value Amount to be transferred + * @param validAfter The time after which this is valid (unix time) + * @param validBefore The time before which this is valid (unix time) + * @param nonce Unique nonce + * @param signature Signature bytes signed by an EOA wallet or a contract wallet + */ + function receiveWithAuthorization( + address from, + address to, + uint256 value, + uint256 validAfter, + uint256 validBefore, + bytes32 nonce, + bytes memory signature + ) external whenNotPaused notBlacklisted(from) notBlacklisted(to) { + _receiveWithAuthorization( + from, + to, + value, + validAfter, + validBefore, + nonce, + signature + ); + } + + /** + * @notice Attempt to cancel an authorization + * @dev Works only if the authorization is not yet used. + * EOA wallet signatures should be packed in the order of r, s, v. + * @param authorizer Authorizer's address + * @param nonce Nonce of the authorization + * @param signature Signature bytes signed by an EOA wallet or a contract wallet + */ + function cancelAuthorization( + address authorizer, + bytes32 nonce, + bytes memory signature + ) external whenNotPaused { + _cancelAuthorization(authorizer, nonce, signature); + } } diff --git a/test/v2/FiatTokenV2.test.ts b/test/v2/FiatTokenV2.test.ts index 36ec77756..092851cc6 100644 --- a/test/v2/FiatTokenV2.test.ts +++ b/test/v2/FiatTokenV2.test.ts @@ -1,12 +1,24 @@ import { behavesLikeRescuable } from "../v1.1/Rescuable.behavior"; -import { FiatTokenV2Instance, RescuableInstance } from "../../@types/generated"; +import { + MockErc1271WalletInstance, + FiatTokenV2Instance, + RescuableInstance, +} from "../../@types/generated"; +import { AnyFiatTokenV2Instance } from "../../@types/AnyFiatTokenV2Instance"; import { usesOriginalStorageSlotPositions } from "../helpers/storageSlots.behavior"; import { hasSafeAllowance } from "./safeAllowance.behavior"; import { hasGasAbstraction } from "./GasAbstraction/GasAbstraction.behavior"; -import { makeDomainSeparator } from "./GasAbstraction/helpers"; +import { + SignatureBytesType, + TestParams, + WalletType, + makeDomainSeparator, +} from "./GasAbstraction/helpers"; import { expectRevert } from "../helpers"; +import { testTransferWithMultipleAuthorizations } from "./GasAbstraction/testTransferWithMultipleAuthorizations"; const FiatTokenV2 = artifacts.require("FiatTokenV2"); +const MockERC1271Wallet = artifacts.require("MockERC1271Wallet"); contract("FiatTokenV2", (accounts) => { const fiatTokenOwner = accounts[9]; @@ -32,7 +44,7 @@ contract("FiatTokenV2", (accounts) => { export function behavesLikeFiatTokenV2( accounts: Truffle.Accounts, - getFiatToken: () => FiatTokenV2Instance, + getFiatToken: () => AnyFiatTokenV2Instance, fiatTokenOwner: string ): void { let domainSeparator: string; @@ -60,12 +72,19 @@ export function behavesLikeFiatTokenV2( hasSafeAllowance(getFiatToken, fiatTokenOwner, accounts); - hasGasAbstraction( + const testParams: TestParams = { getFiatToken, - () => domainSeparator, + getDomainSeparator: () => domainSeparator, + getERC1271Wallet, fiatTokenOwner, - accounts - ); + accounts, + signerWalletType: WalletType.EOA, + signatureBytesType: SignatureBytesType.Unpacked, + }; + + hasGasAbstraction(testParams); + + testTransferWithMultipleAuthorizations(testParams); it("disallows calling initializeV2 twice", async () => { // It was called once in beforeEach. Try to call again. @@ -74,3 +93,9 @@ export function behavesLikeFiatTokenV2( ); }); } + +export async function getERC1271Wallet( + owner: string +): Promise { + return await MockERC1271Wallet.new(owner); +} diff --git a/test/v2/FiatTokenV2_2.test.ts b/test/v2/FiatTokenV2_2.test.ts index 7962d2310..428aaf805 100644 --- a/test/v2/FiatTokenV2_2.test.ts +++ b/test/v2/FiatTokenV2_2.test.ts @@ -1,24 +1,138 @@ -import { FiatTokenV22Instance } from "../../@types/generated"; +import { + AnyFiatTokenV2Instance, + FiatTokenV22InstanceExtended, +} from "../../@types/AnyFiatTokenV2Instance"; import { expectRevert, initializeToVersion } from "../helpers"; -import { behavesLikeFiatTokenV2 } from "./FiatTokenV2.test"; +import { behavesLikeFiatTokenV2, getERC1271Wallet } from "./FiatTokenV2.test"; +import { hasGasAbstraction } from "./GasAbstraction/GasAbstraction.behavior"; +import { + SignatureBytesType, + WalletType, + makeDomainSeparator, + permitSignature, + permitSignatureV22, + transferWithAuthorizationSignature, + transferWithAuthorizationSignatureV22, + cancelAuthorizationSignature, + cancelAuthorizationSignatureV22, + receiveWithAuthorizationSignature, + receiveWithAuthorizationSignatureV22, +} from "./GasAbstraction/helpers"; const FiatTokenV2_2 = artifacts.require("FiatTokenV2_2"); contract("FiatTokenV2_2", (accounts) => { const fiatTokenOwner = accounts[9]; - const [, , lostAndFound] = accounts; - let fiatToken: FiatTokenV22Instance; + let fiatToken: FiatTokenV22InstanceExtended; + + const getFiatToken = ( + signatureBytesType: SignatureBytesType + ): (() => AnyFiatTokenV2Instance) => { + return () => { + initializeOverloadedMethods(fiatToken, signatureBytesType); + return fiatToken; + }; + }; beforeEach(async () => { + const [, , lostAndFound] = accounts; + fiatToken = await FiatTokenV2_2.new(); await initializeToVersion(fiatToken, "2.2", fiatTokenOwner, lostAndFound); }); - behavesLikeFiatTokenV2(accounts, () => fiatToken, fiatTokenOwner); + behavesLikeFiatTokenV2( + accounts, + getFiatToken(SignatureBytesType.Unpacked), + fiatTokenOwner + ); + + behavesLikeFiatTokenV22( + accounts, + getFiatToken(SignatureBytesType.Packed), + fiatTokenOwner + ); +}); + +export function behavesLikeFiatTokenV22( + accounts: Truffle.Accounts, + getFiatToken: () => AnyFiatTokenV2Instance, + fiatTokenOwner: string +): void { + let domainSeparator: string; + + beforeEach(async () => { + domainSeparator = makeDomainSeparator( + "USD Coin", + "2", + 1, // hardcoded to 1 because of ganache bug: https://github.com/trufflesuite/ganache/issues/1643 + getFiatToken().address + ); + }); + + const v22TestParams = { + getFiatToken, + getDomainSeparator: () => domainSeparator, + getERC1271Wallet, + fiatTokenOwner, + accounts, + }; + + // Test gas abstraction funtionalities with both EOA and AA wallets + hasGasAbstraction({ + ...v22TestParams, + signerWalletType: WalletType.EOA, + signatureBytesType: SignatureBytesType.Packed, + }); + hasGasAbstraction({ + ...v22TestParams, + signerWalletType: WalletType.AA, + signatureBytesType: SignatureBytesType.Packed, + }); describe("initializeV2_2", () => { it("disallows calling initializeV2_2 twice", async () => { - await expectRevert(fiatToken.initializeV2_2()); + await expectRevert( + (getFiatToken() as FiatTokenV22InstanceExtended).initializeV2_2() + ); }); }); -}); +} + +/** + * With v2.2 we introduce overloaded functions for `permit`, + * `transferWithAuthorization`, `receiveWithAuthorization`, + * and `cancelAuthorization`. + * + * Since function overloading isn't supported by Javascript, + * the typechain library generates type interfaces for overloaded functions differently. + * For instance, we can no longer access the `permit` function with + * `fiattoken.permit`. Instead, we need to need to use the full function signature e.g. + * `fiattoken.methods["permit(address,address,uint256,uint256,uint8,bytes32,bytes32)"]` OR + * `fiattoken.methods["permit(address,address,uint256,uint256,bytes)"]` (v22 interface). + * + * To preserve type-coherence and reuse test suites written for v2 & v2.1 contracts, + * here we re-assign the overloaded method definition to the method name shorthand. + */ +export function initializeOverloadedMethods( + fiatToken: FiatTokenV22InstanceExtended, + signatureBytesType: SignatureBytesType +): void { + if (signatureBytesType == SignatureBytesType.Unpacked) { + fiatToken.permit = fiatToken.methods[permitSignature]; + fiatToken.transferWithAuthorization = + fiatToken.methods[transferWithAuthorizationSignature]; + fiatToken.receiveWithAuthorization = + fiatToken.methods[receiveWithAuthorizationSignature]; + fiatToken.cancelAuthorization = + fiatToken.methods[cancelAuthorizationSignature]; + } else { + fiatToken.permit = fiatToken.methods[permitSignatureV22]; + fiatToken.transferWithAuthorization = + fiatToken.methods[transferWithAuthorizationSignatureV22]; + fiatToken.receiveWithAuthorization = + fiatToken.methods[receiveWithAuthorizationSignatureV22]; + fiatToken.cancelAuthorization = + fiatToken.methods[cancelAuthorizationSignatureV22]; + } +} diff --git a/test/v2/GasAbstraction/GasAbstraction.behavior.ts b/test/v2/GasAbstraction/GasAbstraction.behavior.ts index bdb0ae363..c32d9c652 100644 --- a/test/v2/GasAbstraction/GasAbstraction.behavior.ts +++ b/test/v2/GasAbstraction/GasAbstraction.behavior.ts @@ -1,30 +1,15 @@ -import { FiatTokenV2Instance } from "../../../@types/generated"; import { TestParams } from "./helpers"; import { testTransferWithAuthorization } from "./testTransferWithAuthorization"; import { testCancelAuthorization } from "./testCancelAuthorization"; import { testPermit } from "./testPermit"; -import { testTransferWithMultipleAuthorizations } from "./testTransferWithMultipleAuthorizations"; import { testReceiveWithAuthorization } from "./testReceiveWithAuthorization"; -export function hasGasAbstraction( - getFiatToken: () => FiatTokenV2Instance, - getDomainSeparator: () => string, - fiatTokenOwner: string, - accounts: Truffle.Accounts -): void { +export function hasGasAbstraction(testParams: TestParams): void { describe("GasAbstraction", () => { - const testParams: TestParams = { - getFiatToken, - getDomainSeparator, - fiatTokenOwner, - accounts, - }; - describe("EIP-3009", () => { testTransferWithAuthorization(testParams); testReceiveWithAuthorization(testParams); testCancelAuthorization(testParams); - testTransferWithMultipleAuthorizations(testParams); }); describe("EIP-2612", () => { diff --git a/test/v2/GasAbstraction/helpers.ts b/test/v2/GasAbstraction/helpers.ts index 190fd0619..547ae1dd5 100644 --- a/test/v2/GasAbstraction/helpers.ts +++ b/test/v2/GasAbstraction/helpers.ts @@ -1,11 +1,26 @@ -import { FiatTokenV2Instance } from "../../../@types/generated"; +import { AnyFiatTokenV2Instance } from "../../../@types/AnyFiatTokenV2Instance"; +import { MockErc1271WalletInstance } from "../../../@types/generated"; import { Signature, ecSign, strip0x } from "../../helpers"; +import { packSignature } from "../../helpers"; + +export enum WalletType { + EOA = "EOA", + AA = "AA", +} + +export enum SignatureBytesType { + Packed = "Packed", // Signature provided in the format of a single byte array, packed in the order of r, s, v for EOA wallets + Unpacked = "Unpacked", // Signature values provided as separate inputs (v, r, s) +} export interface TestParams { - getFiatToken: () => FiatTokenV2Instance; + getFiatToken: () => AnyFiatTokenV2Instance; getDomainSeparator: () => string; fiatTokenOwner: string; accounts: Truffle.Accounts; + signerWalletType: WalletType; + signatureBytesType: SignatureBytesType; + getERC1271Wallet: (owner: string) => Promise; } export function makeDomainSeparator( @@ -30,6 +45,17 @@ export function makeDomainSeparator( ); } +export function prepareSignature( + signature: Signature, + signatureBytesType: SignatureBytesType +): Array { + if (signatureBytesType == SignatureBytesType.Unpacked) { + return [signature.v, signature.r, signature.s]; + } else { + return [packSignature(signature)]; + } +} + export const transferWithAuthorizationTypeHash = web3.utils.keccak256( "TransferWithAuthorization(address from,address to,uint256 value,uint256 validAfter,uint256 validBefore,bytes32 nonce)" ); @@ -46,6 +72,36 @@ export const permitTypeHash = web3.utils.keccak256( "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)" ); +/** + * Overloaded method signatures + */ +export const permitSignature = + "permit(address,address,uint256,uint256,uint8,bytes32,bytes32)"; + +export const permitSignatureV22 = + "permit(address,address,uint256,uint256,bytes)"; + +export const transferWithAuthorizationSignature = + "transferWithAuthorization(address,address,uint256,uint256,uint256,bytes32,uint8,bytes32,bytes32)"; + +export const transferWithAuthorizationSignatureV22 = + "transferWithAuthorization(address,address,uint256,uint256,uint256,bytes32,bytes)"; + +export const receiveWithAuthorizationSignature = + "receiveWithAuthorization(address,address,uint256,uint256,uint256,bytes32,uint8,bytes32,bytes32)"; + +export const receiveWithAuthorizationSignatureV22 = + "receiveWithAuthorization(address,address,uint256,uint256,uint256,bytes32,bytes)"; + +export const cancelAuthorizationSignature = + "cancelAuthorization(address,bytes32,uint8,bytes32,bytes32)"; + +export const cancelAuthorizationSignatureV22 = + "cancelAuthorization(address,bytes32,bytes)"; + +/** + * Signature generation helper functions + */ export function signTransferAuthorization( from: string, to: string, diff --git a/test/v2/GasAbstraction/testCancelAuthorization.ts b/test/v2/GasAbstraction/testCancelAuthorization.ts index 969d6b1a2..56bb45b40 100644 --- a/test/v2/GasAbstraction/testCancelAuthorization.ts +++ b/test/v2/GasAbstraction/testCancelAuthorization.ts @@ -1,5 +1,4 @@ import crypto from "crypto"; -import { FiatTokenV2Instance } from "../../../@types/generated"; import { ACCOUNTS_AND_KEYS, MAX_UINT256 } from "../../helpers/constants"; import { expectRevert, hexStringFromBuffer } from "../../helpers"; import { @@ -7,29 +6,50 @@ import { signTransferAuthorization, signCancelAuthorization, TestParams, + WalletType, + prepareSignature, } from "./helpers"; +import { AnyFiatTokenV2Instance } from "../../../@types/AnyFiatTokenV2Instance"; +import { MockErc1271WalletInstance } from "../../../@types/generated"; export function testCancelAuthorization({ getFiatToken, + getERC1271Wallet, getDomainSeparator, fiatTokenOwner, accounts, + signerWalletType, + signatureBytesType, }: TestParams): void { - describe("cancelAuthorization", () => { - let fiatToken: FiatTokenV2Instance; - let domainSeparator: string; + describe(`cancelAuthorization with ${signerWalletType} wallet, ${signatureBytesType} signature interface`, async () => { const [alice, bob] = ACCOUNTS_AND_KEYS; const charlie = accounts[1]; - let nonce: string; + const nonce = hexStringFromBuffer(crypto.randomBytes(32)); + + let fiatToken: AnyFiatTokenV2Instance; + let aliceWallet: MockErc1271WalletInstance; + let domainSeparator: string; + + let from: string; beforeEach(async () => { fiatToken = getFiatToken(); + aliceWallet = await getERC1271Wallet(alice.address); domainSeparator = getDomainSeparator(); - nonce = hexStringFromBuffer(crypto.randomBytes(32)); + + // Initialize `from` address either as Alice's EOA address or Alice's wallet address + if (signerWalletType == WalletType.AA) { + from = aliceWallet.address; + } else { + from = alice.address; + } + await fiatToken.configureMinter(fiatTokenOwner, 1000000e6, { from: fiatTokenOwner, }); - await fiatToken.mint(alice.address, 10e6, { from: fiatTokenOwner }); + await fiatToken.mint(from, 10e6, { + from: fiatTokenOwner, + }); }); it("has the expected type hash", async () => { @@ -39,7 +59,6 @@ export function testCancelAuthorization({ }); it("cancels unused transfer authorization if signature is valid", async () => { - const from = alice.address; const to = bob.address; const value = 7e6; const validAfter = 0; @@ -72,9 +91,7 @@ export function testCancelAuthorization({ await fiatToken.cancelAuthorization( from, nonce, - cancellation.v, - cancellation.r, - cancellation.s, + ...prepareSignature(cancellation, signatureBytesType), { from: charlie } ); @@ -90,9 +107,7 @@ export function testCancelAuthorization({ validAfter, validBefore, nonce, - authorization.v, - authorization.r, - authorization.s, + ...prepareSignature(authorization, signatureBytesType), { from: charlie } ), "authorization is used or canceled" @@ -100,7 +115,6 @@ export function testCancelAuthorization({ }); it("cannot be used to cancel someone else's authorization", async () => { - const from = alice.address; const to = bob.address; const value = 7e6; const validAfter = 0; @@ -134,9 +148,7 @@ export function testCancelAuthorization({ fiatToken.cancelAuthorization( from, nonce, - cancellation.v, - cancellation.r, - cancellation.s, + ...prepareSignature(cancellation, signatureBytesType), { from: charlie } ), "invalid signature" @@ -153,15 +165,12 @@ export function testCancelAuthorization({ validAfter, validBefore, nonce, - authorization.v, - authorization.r, - authorization.s, + ...prepareSignature(authorization, signatureBytesType), { from: charlie } ); }); it("reverts if the authorization has already been used", async () => { - const from = alice.address; const to = bob.address; const value = 7e6; const validAfter = 0; @@ -187,9 +196,7 @@ export function testCancelAuthorization({ validAfter, validBefore, nonce, - authorization.v, - authorization.r, - authorization.s, + ...prepareSignature(authorization, signatureBytesType), { from: charlie } ); @@ -206,9 +213,7 @@ export function testCancelAuthorization({ fiatToken.cancelAuthorization( from, nonce, - cancellation.v, - cancellation.r, - cancellation.s, + ...prepareSignature(cancellation, signatureBytesType), { from: charlie } ), "authorization is used or canceled" @@ -218,7 +223,7 @@ export function testCancelAuthorization({ it("reverts if the authorization has already been canceled", async () => { // create cancellation const cancellation = signCancelAuthorization( - alice.address, + from, nonce, domainSeparator, alice.key @@ -226,22 +231,18 @@ export function testCancelAuthorization({ // submit the cancellation await fiatToken.cancelAuthorization( - alice.address, + from, nonce, - cancellation.v, - cancellation.r, - cancellation.s, + ...prepareSignature(cancellation, signatureBytesType), { from: charlie } ); // try to submit the same cancellation again await expectRevert( fiatToken.cancelAuthorization( - alice.address, + from, nonce, - cancellation.v, - cancellation.r, - cancellation.s, + ...prepareSignature(cancellation, signatureBytesType), { from: charlie } ), "authorization is used or canceled" @@ -250,8 +251,8 @@ export function testCancelAuthorization({ it("reverts if the contract is paused", async () => { // create a cancellation - const { v, r, s } = signCancelAuthorization( - alice.address, + const cancellation = signCancelAuthorization( + from, nonce, domainSeparator, alice.key @@ -262,9 +263,15 @@ export function testCancelAuthorization({ // try to submit the cancellation await expectRevert( - fiatToken.cancelAuthorization(alice.address, nonce, v, r, s, { - from: charlie, - }), + fiatToken.cancelAuthorization( + from, + nonce, + ...prepareSignature(cancellation, signatureBytesType), + + { + from: charlie, + } + ), "paused" ); }); diff --git a/test/v2/GasAbstraction/testPermit.ts b/test/v2/GasAbstraction/testPermit.ts index 420b746ba..685d0f32f 100644 --- a/test/v2/GasAbstraction/testPermit.ts +++ b/test/v2/GasAbstraction/testPermit.ts @@ -1,5 +1,5 @@ import crypto from "crypto"; -import { FiatTokenV2Instance } from "../../../@types/generated"; +import { MockErc1271WalletInstance } from "../../../@types/generated"; import { Approval } from "../../../@types/generated/FiatTokenV2"; import { ACCOUNTS_AND_KEYS, @@ -12,32 +12,49 @@ import { TestParams, signTransferAuthorization, permitTypeHash, + WalletType, + prepareSignature, } from "./helpers"; +import { AnyFiatTokenV2Instance } from "../../../@types/AnyFiatTokenV2Instance"; export function testPermit({ getFiatToken, + getERC1271Wallet, getDomainSeparator, fiatTokenOwner, accounts, + signerWalletType, + signatureBytesType, }: TestParams): void { - describe("permit", () => { - let fiatToken: FiatTokenV2Instance; - let domainSeparator: string; + describe(`permit with ${signerWalletType} wallet, ${signatureBytesType} signature interface`, async () => { const [alice, bob] = ACCOUNTS_AND_KEYS; const charlie = accounts[1]; const initialBalance = 10e6; const permitParams = { - owner: alice.address, + owner: "", spender: bob.address, value: 7e6, nonce: 0, deadline: MAX_UINT256, }; + let fiatToken: AnyFiatTokenV2Instance; + let aliceWallet: MockErc1271WalletInstance; + let domainSeparator: string; + beforeEach(async () => { fiatToken = getFiatToken(); + aliceWallet = await getERC1271Wallet(alice.address); domainSeparator = getDomainSeparator(); + + // Initialize `owner` address either as Alice's EOA address or Alice's wallet address + if (signerWalletType == WalletType.AA) { + permitParams.owner = aliceWallet.address; + } else { + permitParams.owner = alice.address; + } + await fiatToken.configureMinter(fiatTokenOwner, 1000000e6, { from: fiatTokenOwner, }); @@ -56,7 +73,7 @@ export function testPermit({ // create a signed permit to grant Bob permission to spend Alice's funds // on behalf, and sign with Alice's key let nonce = 0; - let { v, r, s } = signPermit( + const signature1 = signPermit( owner, spender, value, @@ -79,9 +96,7 @@ export function testPermit({ spender, value, deadline, - v, - r, - s, + ...prepareSignature(signature1, signatureBytesType), { from: charlie } ); @@ -103,7 +118,7 @@ export function testPermit({ // increment nonce nonce = 1; value = 1e6; - ({ v, r, s } = signPermit( + const signature2 = signPermit( owner, spender, 1e6, @@ -111,7 +126,7 @@ export function testPermit({ deadline, domainSeparator, alice.key - )); + ); // submit the permit result = await fiatToken.permit( @@ -119,9 +134,7 @@ export function testPermit({ spender, value, deadline, - v, - r, - s, + ...prepareSignature(signature2, signatureBytesType), { from: charlie } ); @@ -141,7 +154,7 @@ export function testPermit({ it("reverts if the signature does not match given parameters", async () => { const { owner, spender, value, nonce, deadline } = permitParams; // create a signed permit - const { v, r, s } = signPermit( + const signature = signPermit( owner, spender, value, @@ -158,9 +171,7 @@ export function testPermit({ spender, value * 2, // pass incorrect value deadline, - v, - r, - s, + ...prepareSignature(signature, signatureBytesType), { from: charlie } ), "invalid signature" @@ -171,7 +182,7 @@ export function testPermit({ const { owner, spender, value, nonce, deadline } = permitParams; // create a signed permit to grant Bob permission to spend // Alice's funds on behalf, but sign with Bob's key instead of Alice's - const { v, r, s } = signPermit( + const signature = signPermit( owner, spender, value, @@ -184,9 +195,16 @@ export function testPermit({ // try to cheat by submitting the permit that is signed by a // wrong person await expectRevert( - fiatToken.permit(owner, spender, value, deadline, v, r, s, { - from: charlie, - }), + fiatToken.permit( + owner, + spender, + value, + deadline, + ...prepareSignature(signature, signatureBytesType), + { + from: charlie, + } + ), "invalid signature" ); }); @@ -196,7 +214,7 @@ export function testPermit({ // create a signed permit that won't be valid until 10 seconds // later const deadline = Math.floor(Date.now() / 1000) - 1; - const { v, r, s } = signPermit( + const signature = signPermit( owner, spender, value, @@ -208,9 +226,16 @@ export function testPermit({ // try to submit the permit that is expired await expectRevert( - fiatToken.permit(owner, spender, value, deadline, v, r, s, { - from: charlie, - }), + fiatToken.permit( + owner, + spender, + value, + deadline, + ...prepareSignature(signature, signatureBytesType), + { + from: charlie, + } + ), "permit is expired" ); }); @@ -219,7 +244,7 @@ export function testPermit({ const { owner, spender, value, deadline } = permitParams; const nonce = 1; // create a signed permit - const { v, r, s } = signPermit( + const signature = signPermit( owner, spender, value, @@ -233,9 +258,16 @@ export function testPermit({ // try to submit the permit await expectRevert( - fiatToken.permit(owner, spender, value, deadline, v, r, s, { - from: charlie, - }), + fiatToken.permit( + owner, + spender, + value, + deadline, + ...prepareSignature(signature, signatureBytesType), + { + from: charlie, + } + ), "invalid signature" ); }); @@ -243,7 +275,7 @@ export function testPermit({ it("reverts if the permit has already been used", async () => { const { owner, spender, value, nonce, deadline } = permitParams; // create a signed permit - const { v, r, s } = signPermit( + const signature = signPermit( owner, spender, value, @@ -254,15 +286,29 @@ export function testPermit({ ); // submit the permit - await fiatToken.permit(owner, spender, value, deadline, v, r, s, { - from: charlie, - }); + await fiatToken.permit( + owner, + spender, + value, + deadline, + ...prepareSignature(signature, signatureBytesType), + { + from: charlie, + } + ); // try to submit the permit again await expectRevert( - fiatToken.permit(owner, spender, value, deadline, v, r, s, { - from: charlie, - }), + fiatToken.permit( + owner, + spender, + value, + deadline, + ...prepareSignature(signature, signatureBytesType), + { + from: charlie, + } + ), "invalid signature" ); }); @@ -286,9 +332,7 @@ export function testPermit({ spender, value, deadline, - permit.v, - permit.r, - permit.s, + ...prepareSignature(permit, signatureBytesType), { from: charlie } ); @@ -311,9 +355,7 @@ export function testPermit({ spender, 1e6, deadline, - permit2.v, - permit2.r, - permit2.s, + ...prepareSignature(permit2, signatureBytesType), { from: charlie } ), "invalid signature" @@ -325,7 +367,7 @@ export function testPermit({ // create a signed permit that attempts to grant allowance to the // zero address const spender = ZERO_ADDRESS; - const { v, r, s } = signPermit( + const signature = signPermit( owner, spender, value, @@ -337,9 +379,16 @@ export function testPermit({ // try to submit the permit with invalid approval parameters await expectRevert( - fiatToken.permit(owner, spender, value, deadline, v, r, s, { - from: charlie, - }), + fiatToken.permit( + owner, + spender, + value, + deadline, + ...prepareSignature(signature, signatureBytesType), + { + from: charlie, + } + ), "approve to the zero address" ); }); @@ -354,7 +403,7 @@ export function testPermit({ // create a signed permit for a transfer const validAfter = 0; const nonce = hexStringFromBuffer(crypto.randomBytes(32)); - const { v, r, s } = signTransferAuthorization( + const signature = signTransferAuthorization( from, to, value, @@ -367,9 +416,16 @@ export function testPermit({ // try to submit the transfer permit await expectRevert( - fiatToken.permit(from, to, value, validBefore, v, r, s, { - from: charlie, - }), + fiatToken.permit( + from, + to, + value, + validBefore, + ...prepareSignature(signature, signatureBytesType), + { + from: charlie, + } + ), "invalid signature" ); }); @@ -377,7 +433,7 @@ export function testPermit({ it("reverts if the contract is paused", async () => { const { owner, spender, value, nonce, deadline } = permitParams; // create a signed permit - const { v, r, s } = signPermit( + const signature = signPermit( owner, spender, value, @@ -392,9 +448,14 @@ export function testPermit({ // try to submit the permit await expectRevert( - fiatToken.permit(owner, spender, value, deadline, v, r, s, { - from: charlie, - }), + fiatToken.permit( + owner, + spender, + value, + deadline, + ...prepareSignature(signature, signatureBytesType), + { from: charlie } + ), "paused" ); }); @@ -402,7 +463,7 @@ export function testPermit({ it("reverts if the owner or the spender is blacklisted", async () => { const { owner, spender, value, nonce, deadline } = permitParams; // create a signed permit - const { v, r, s } = signPermit( + const signature = signPermit( owner, spender, value, @@ -416,9 +477,16 @@ export function testPermit({ await fiatToken.blacklist(owner, { from: fiatTokenOwner }); const submitTx = () => - fiatToken.permit(owner, spender, value, deadline, v, r, s, { - from: charlie, - }); + fiatToken.permit( + owner, + spender, + value, + deadline, + ...prepareSignature(signature, signatureBytesType), + { + from: charlie, + } + ); // try to submit the permit await expectRevert(submitTx(), "account is blacklisted"); diff --git a/test/v2/GasAbstraction/testReceiveWithAuthorization.ts b/test/v2/GasAbstraction/testReceiveWithAuthorization.ts index 1dc01d646..538963ab7 100644 --- a/test/v2/GasAbstraction/testReceiveWithAuthorization.ts +++ b/test/v2/GasAbstraction/testReceiveWithAuthorization.ts @@ -1,5 +1,5 @@ import crypto from "crypto"; -import { FiatTokenV2Instance } from "../../../@types/generated"; +import { MockErc1271WalletInstance } from "../../../@types/generated"; import { AuthorizationUsed, Transfer, @@ -7,37 +7,53 @@ import { import { ACCOUNTS_AND_KEYS, MAX_UINT256 } from "../../helpers/constants"; import { expectRevert, hexStringFromBuffer } from "../../helpers"; import { + prepareSignature, receiveWithAuthorizationTypeHash, signReceiveAuthorization, TestParams, + WalletType, } from "./helpers"; +import { AnyFiatTokenV2Instance } from "../../../@types/AnyFiatTokenV2Instance"; export function testReceiveWithAuthorization({ getFiatToken, + getERC1271Wallet, getDomainSeparator, fiatTokenOwner, accounts, + signerWalletType, + signatureBytesType, }: TestParams): void { - describe("receiveWithAuthorization", () => { - let fiatToken: FiatTokenV2Instance; - let domainSeparator: string; + describe(`receiveWithAuthorization with ${signerWalletType} wallet, ${signatureBytesType} signature interface`, async () => { const [alice, charlie] = ACCOUNTS_AND_KEYS; const [, bob, david] = accounts; - let nonce: string; - + const nonce: string = hexStringFromBuffer(crypto.randomBytes(32)); const initialBalance = 10e6; const receiveParams = { - from: alice.address, + from: "", to: bob, value: 7e6, validAfter: 0, validBefore: MAX_UINT256, + nonce, }; + let fiatToken: AnyFiatTokenV2Instance; + let aliceWallet: MockErc1271WalletInstance; + let domainSeparator: string; + beforeEach(async () => { fiatToken = getFiatToken(); + aliceWallet = await getERC1271Wallet(alice.address); domainSeparator = getDomainSeparator(); - nonce = hexStringFromBuffer(crypto.randomBytes(32)); + + // Initialize `from` address either as Alice's EOA address or Alice's wallet address + if (signerWalletType == WalletType.AA) { + receiveParams.from = aliceWallet.address; + } else { + receiveParams.from = alice.address; + } + await fiatToken.configureMinter(fiatTokenOwner, 1000000e6, { from: fiatTokenOwner, }); @@ -56,7 +72,7 @@ export function testReceiveWithAuthorization({ const { from, to, value, validAfter, validBefore } = receiveParams; // create an authorization to transfer money from Alice to Bob and sign // with Alice's key - const { v, r, s } = signReceiveAuthorization( + const signature = signReceiveAuthorization( from, to, value, @@ -82,9 +98,7 @@ export function testReceiveWithAuthorization({ validAfter, validBefore, nonce, - v, - r, - s, + ...prepareSignature(signature, signatureBytesType), { from: bob } ); @@ -114,7 +128,7 @@ export function testReceiveWithAuthorization({ it("reverts if the caller is not the payee", async () => { const { from, to, value, validAfter, validBefore } = receiveParams; // create a signed authorization - const { v, r, s } = signReceiveAuthorization( + const signature = signReceiveAuthorization( from, to, value, @@ -134,9 +148,7 @@ export function testReceiveWithAuthorization({ validAfter, validBefore, nonce, - v, - r, - s, + ...prepareSignature(signature, signatureBytesType), { from: david } ), "caller must be the payee" @@ -146,7 +158,7 @@ export function testReceiveWithAuthorization({ it("reverts if the signature does not match given parameters", async () => { const { from, to, value, validAfter, validBefore } = receiveParams; // create a signed authorization - const { v, r, s } = signReceiveAuthorization( + const signature = signReceiveAuthorization( from, to, value, @@ -166,9 +178,7 @@ export function testReceiveWithAuthorization({ validAfter, validBefore, nonce, - v, - r, - s, + ...prepareSignature(signature, signatureBytesType), { from: bob } ), "invalid signature" @@ -179,7 +189,7 @@ export function testReceiveWithAuthorization({ const { from, to, value, validAfter, validBefore } = receiveParams; // create an authorization to transfer money from Alice to Bob, but // sign with Bob's key instead of Alice's - const { v, r, s } = signReceiveAuthorization( + const signature = signReceiveAuthorization( from, to, value, @@ -200,9 +210,7 @@ export function testReceiveWithAuthorization({ validAfter, validBefore, nonce, - v, - r, - s, + ...prepareSignature(signature, signatureBytesType), { from: bob } ), "invalid signature" @@ -214,7 +222,7 @@ export function testReceiveWithAuthorization({ // create a signed authorization that won't be valid until 10 seconds // later const validAfter = Math.floor(Date.now() / 1000) + 10; - const { v, r, s } = signReceiveAuthorization( + const signature = signReceiveAuthorization( from, to, value, @@ -234,9 +242,7 @@ export function testReceiveWithAuthorization({ validAfter, validBefore, nonce, - v, - r, - s, + ...prepareSignature(signature, signatureBytesType), { from: bob } ), "authorization is not yet valid" @@ -247,7 +253,7 @@ export function testReceiveWithAuthorization({ // create a signed authorization that expires immediately const { from, to, value, validAfter } = receiveParams; const validBefore = Math.floor(Date.now() / 1000); - const { v, r, s } = signReceiveAuthorization( + const signature = signReceiveAuthorization( from, to, value, @@ -267,9 +273,7 @@ export function testReceiveWithAuthorization({ validAfter, validBefore, nonce, - v, - r, - s, + ...prepareSignature(signature, signatureBytesType), { from: bob } ), "authorization is expired" @@ -280,7 +284,7 @@ export function testReceiveWithAuthorization({ const { from, to, validAfter, validBefore } = receiveParams; // create a signed authorization const value = 1e6; - const { v, r, s } = signReceiveAuthorization( + const signature = signReceiveAuthorization( from, to, value, @@ -299,9 +303,7 @@ export function testReceiveWithAuthorization({ validAfter, validBefore, nonce, - v, - r, - s, + ...prepareSignature(signature, signatureBytesType), { from: bob } ); @@ -314,9 +316,7 @@ export function testReceiveWithAuthorization({ validAfter, validBefore, nonce, - v, - r, - s, + ...prepareSignature(signature, signatureBytesType), { from: bob } ), "authorization is used or canceled" @@ -345,9 +345,7 @@ export function testReceiveWithAuthorization({ validAfter, validBefore, nonce, - authorization.v, - authorization.r, - authorization.s, + ...prepareSignature(authorization, signatureBytesType), { from: bob } ); @@ -373,9 +371,7 @@ export function testReceiveWithAuthorization({ validAfter, validBefore, nonce, - authorization2.v, - authorization2.r, - authorization2.s, + ...prepareSignature(authorization2, signatureBytesType), { from: bob } ), "authorization is used or canceled" @@ -387,7 +383,7 @@ export function testReceiveWithAuthorization({ // create a signed authorization that attempts to transfer an amount // that exceeds the sender's balance const value = initialBalance + 1; - const { v, r, s } = signReceiveAuthorization( + const signature = signReceiveAuthorization( from, to, value, @@ -407,9 +403,7 @@ export function testReceiveWithAuthorization({ validAfter, validBefore, nonce, - v, - r, - s, + ...prepareSignature(signature, signatureBytesType), { from: bob } ), "transfer amount exceeds balance" @@ -419,7 +413,7 @@ export function testReceiveWithAuthorization({ it("reverts if the contract is paused", async () => { const { from, to, value, validAfter, validBefore } = receiveParams; // create a signed authorization - const { v, r, s } = signReceiveAuthorization( + const signature = signReceiveAuthorization( from, to, value, @@ -442,9 +436,7 @@ export function testReceiveWithAuthorization({ validAfter, validBefore, nonce, - v, - r, - s, + ...prepareSignature(signature, signatureBytesType), { from: bob } ), "paused" @@ -454,7 +446,7 @@ export function testReceiveWithAuthorization({ it("reverts if the payer or the payee is blacklisted", async () => { const { from, to, value, validAfter, validBefore } = receiveParams; // create a signed authorization - const { v, r, s } = signReceiveAuthorization( + const signature = signReceiveAuthorization( from, to, value, @@ -476,9 +468,7 @@ export function testReceiveWithAuthorization({ validAfter, validBefore, nonce, - v, - r, - s, + ...prepareSignature(signature, signatureBytesType), { from: bob } ); diff --git a/test/v2/GasAbstraction/testTransferWithAuthorization.ts b/test/v2/GasAbstraction/testTransferWithAuthorization.ts index b7aa71f72..f5bc5f534 100644 --- a/test/v2/GasAbstraction/testTransferWithAuthorization.ts +++ b/test/v2/GasAbstraction/testTransferWithAuthorization.ts @@ -1,5 +1,5 @@ import crypto from "crypto"; -import { FiatTokenV2Instance } from "../../../@types/generated"; +import { MockErc1271WalletInstance } from "../../../@types/generated"; import { AuthorizationUsed, Transfer, @@ -10,34 +10,50 @@ import { transferWithAuthorizationTypeHash, signTransferAuthorization, TestParams, + WalletType, + prepareSignature, } from "./helpers"; +import { AnyFiatTokenV2Instance } from "../../../@types/AnyFiatTokenV2Instance"; export function testTransferWithAuthorization({ getFiatToken, + getERC1271Wallet, getDomainSeparator, fiatTokenOwner, accounts, + signerWalletType, + signatureBytesType, }: TestParams): void { - describe("transferWithAuthorization", () => { - let fiatToken: FiatTokenV2Instance; - let domainSeparator: string; + describe(`transferWithAuthorization with ${signerWalletType} wallet, ${signatureBytesType} signature interface`, async () => { const [alice, bob] = ACCOUNTS_AND_KEYS; const charlie = accounts[1]; - let nonce: string; - + const nonce: string = hexStringFromBuffer(crypto.randomBytes(32)); const initialBalance = 10e6; const transferParams = { - from: alice.address, + from: "", to: bob.address, value: 7e6, validAfter: 0, validBefore: MAX_UINT256, + nonce, }; + let fiatToken: AnyFiatTokenV2Instance; + let aliceWallet: MockErc1271WalletInstance; + let domainSeparator: string; + beforeEach(async () => { fiatToken = getFiatToken(); + aliceWallet = await getERC1271Wallet(alice.address); domainSeparator = getDomainSeparator(); - nonce = hexStringFromBuffer(crypto.randomBytes(32)); + + // Initialize `from` address either as Alice's EOA address or Alice's wallet address + if (signerWalletType == WalletType.AA) { + transferParams.from = aliceWallet.address; + } else { + transferParams.from = alice.address; + } + await fiatToken.configureMinter(fiatTokenOwner, 1000000e6, { from: fiatTokenOwner, }); @@ -56,7 +72,7 @@ export function testTransferWithAuthorization({ const { from, to, value, validAfter, validBefore } = transferParams; // create an authorization to transfer money from Alice to Bob and sign // with Alice's key - const { v, r, s } = signTransferAuthorization( + const signature = signTransferAuthorization( from, to, value, @@ -82,9 +98,7 @@ export function testTransferWithAuthorization({ validAfter, validBefore, nonce, - v, - r, - s, + ...prepareSignature(signature, signatureBytesType), { from: charlie } ); @@ -114,7 +128,7 @@ export function testTransferWithAuthorization({ it("reverts if the signature does not match given parameters", async () => { const { from, to, value, validAfter, validBefore } = transferParams; // create a signed authorization - const { v, r, s } = signTransferAuthorization( + const signature = signTransferAuthorization( from, to, value, @@ -134,9 +148,7 @@ export function testTransferWithAuthorization({ validAfter, validBefore, nonce, - v, - r, - s, + ...prepareSignature(signature, signatureBytesType), { from: charlie } ), "invalid signature" @@ -147,7 +159,7 @@ export function testTransferWithAuthorization({ const { from, to, value, validAfter, validBefore } = transferParams; // create an authorization to transfer money from Alice to Bob, but // sign with Bob's key instead of Alice's - const { v, r, s } = signTransferAuthorization( + const signature = signTransferAuthorization( from, to, value, @@ -168,9 +180,7 @@ export function testTransferWithAuthorization({ validAfter, validBefore, nonce, - v, - r, - s, + ...prepareSignature(signature, signatureBytesType), { from: charlie } ), "invalid signature" @@ -182,7 +192,7 @@ export function testTransferWithAuthorization({ // create a signed authorization that won't be valid until 10 seconds // later const validAfter = Math.floor(Date.now() / 1000) + 10; - const { v, r, s } = signTransferAuthorization( + const signature = signTransferAuthorization( from, to, value, @@ -202,9 +212,7 @@ export function testTransferWithAuthorization({ validAfter, validBefore, nonce, - v, - r, - s, + ...prepareSignature(signature, signatureBytesType), { from: charlie } ), "authorization is not yet valid" @@ -215,7 +223,7 @@ export function testTransferWithAuthorization({ // create a signed authorization that expires immediately const { from, to, value, validAfter } = transferParams; const validBefore = Math.floor(Date.now() / 1000); - const { v, r, s } = signTransferAuthorization( + const signature = signTransferAuthorization( from, to, value, @@ -235,9 +243,7 @@ export function testTransferWithAuthorization({ validAfter, validBefore, nonce, - v, - r, - s, + ...prepareSignature(signature, signatureBytesType), { from: charlie } ), "authorization is expired" @@ -248,7 +254,7 @@ export function testTransferWithAuthorization({ const { from, to, validAfter, validBefore } = transferParams; // create a signed authorization const value = 1e6; - const { v, r, s } = signTransferAuthorization( + const signature = signTransferAuthorization( from, to, value, @@ -267,9 +273,7 @@ export function testTransferWithAuthorization({ validAfter, validBefore, nonce, - v, - r, - s, + ...prepareSignature(signature, signatureBytesType), { from: charlie } ); @@ -282,9 +286,7 @@ export function testTransferWithAuthorization({ validAfter, validBefore, nonce, - v, - r, - s, + ...prepareSignature(signature, signatureBytesType), { from: charlie } ), "authorization is used or canceled" @@ -313,9 +315,7 @@ export function testTransferWithAuthorization({ validAfter, validBefore, nonce, - authorization.v, - authorization.r, - authorization.s, + ...prepareSignature(authorization, signatureBytesType), { from: charlie } ); @@ -341,9 +341,7 @@ export function testTransferWithAuthorization({ validAfter, validBefore, nonce, - authorization2.v, - authorization2.r, - authorization2.s, + ...prepareSignature(authorization2, signatureBytesType), { from: charlie } ), "authorization is used or canceled" @@ -355,7 +353,7 @@ export function testTransferWithAuthorization({ // create a signed authorization that attempts to transfer an amount // that exceeds the sender's balance const value = initialBalance + 1; - const { v, r, s } = signTransferAuthorization( + const signature = signTransferAuthorization( from, to, value, @@ -375,9 +373,7 @@ export function testTransferWithAuthorization({ validAfter, validBefore, nonce, - v, - r, - s, + ...prepareSignature(signature, signatureBytesType), { from: charlie } ), "transfer amount exceeds balance" @@ -387,7 +383,7 @@ export function testTransferWithAuthorization({ it("reverts if the contract is paused", async () => { const { from, to, value, validAfter, validBefore } = transferParams; // create a signed authorization - const { v, r, s } = signTransferAuthorization( + const signature = signTransferAuthorization( from, to, value, @@ -410,9 +406,7 @@ export function testTransferWithAuthorization({ validAfter, validBefore, nonce, - v, - r, - s, + ...prepareSignature(signature, signatureBytesType), { from: charlie } ), "paused" @@ -422,7 +416,7 @@ export function testTransferWithAuthorization({ it("reverts if the payer or the payee is blacklisted", async () => { const { from, to, value, validAfter, validBefore } = transferParams; // create a signed authorization - const { v, r, s } = signTransferAuthorization( + const signature = signTransferAuthorization( from, to, value, @@ -444,9 +438,7 @@ export function testTransferWithAuthorization({ validAfter, validBefore, nonce, - v, - r, - s, + ...prepareSignature(signature, signatureBytesType), { from: charlie } ); diff --git a/test/v2/GasAbstraction/testTransferWithMultipleAuthorizations.ts b/test/v2/GasAbstraction/testTransferWithMultipleAuthorizations.ts index de10459de..bc5bca635 100644 --- a/test/v2/GasAbstraction/testTransferWithMultipleAuthorizations.ts +++ b/test/v2/GasAbstraction/testTransferWithMultipleAuthorizations.ts @@ -1,8 +1,5 @@ import crypto from "crypto"; -import { - FiatTokenV2Instance, - FiatTokenUtilInstance, -} from "../../../@types/generated"; +import { FiatTokenUtilInstance } from "../../../@types/generated"; import { ACCOUNTS_AND_KEYS, MAX_UINT256 } from "../../helpers/constants"; import { expectRevert, @@ -13,6 +10,7 @@ import { } from "../../helpers"; import { signTransferAuthorization, TestParams } from "./helpers"; import { TransactionRawLog } from "../../../@types/TransactionRawLog"; +import { AnyFiatTokenV2Instance } from "../../../@types/AnyFiatTokenV2Instance"; const FiatTokenUtil = artifacts.require("FiatTokenUtil"); const ContractThatReverts = artifacts.require("ContractThatReverts"); @@ -22,15 +20,12 @@ export function testTransferWithMultipleAuthorizations({ getDomainSeparator, fiatTokenOwner, accounts, + signerWalletType, }: TestParams): void { - describe("transferWithMultipleAuthorizations", () => { - let fiatToken: FiatTokenV2Instance; - let fiatTokenUtil: FiatTokenUtilInstance; - let domainSeparator: string; + describe(`transferWithMultipleAuthorization with ${signerWalletType} wallet`, async () => { const [alice, bob] = ACCOUNTS_AND_KEYS; const charlie = accounts[1]; - let nonce: string; - + const nonce: string = hexStringFromBuffer(crypto.randomBytes(32)); const initialBalance = 10e6; const transferParams = { from: alice.address, @@ -38,13 +33,18 @@ export function testTransferWithMultipleAuthorizations({ value: 7e6, validAfter: 0, validBefore: MAX_UINT256, + nonce, }; + let fiatToken: AnyFiatTokenV2Instance; + let fiatTokenUtil: FiatTokenUtilInstance; + let domainSeparator: string; + beforeEach(async () => { fiatToken = getFiatToken(); fiatTokenUtil = await FiatTokenUtil.new(fiatToken.address); domainSeparator = getDomainSeparator(); - nonce = hexStringFromBuffer(crypto.randomBytes(32)); + await fiatToken.configureMinter(fiatTokenOwner, 1000000e6, { from: fiatTokenOwner, }); diff --git a/test/v2/safeAllowance.behavior.ts b/test/v2/safeAllowance.behavior.ts index 911c87c7d..2330562fd 100644 --- a/test/v2/safeAllowance.behavior.ts +++ b/test/v2/safeAllowance.behavior.ts @@ -1,15 +1,15 @@ -import { FiatTokenV2Instance } from "../../@types/generated"; +import { AnyFiatTokenV2Instance } from "../../@types/AnyFiatTokenV2Instance"; import { Approval } from "../../@types/generated/FiatTokenV2"; import { expectRevert } from "../helpers"; import { MAX_UINT256 } from "../helpers/constants"; export function hasSafeAllowance( - getFiatToken: () => FiatTokenV2Instance, + getFiatToken: () => AnyFiatTokenV2Instance, fiatTokenOwner: string, accounts: Truffle.Accounts ): void { describe("safe allowance", () => { - let fiatToken: FiatTokenV2Instance; + let fiatToken: AnyFiatTokenV2Instance; const [alice, bob] = accounts; beforeEach(() => {