From f032333eec33653983eea1cdcbfc0142107e8e1c Mon Sep 17 00:00:00 2001 From: pheuberger Date: Mon, 24 Mar 2025 22:57:29 +0200 Subject: [PATCH 1/3] refactor: rename generic method The name of the method was too specific since it's a fairly generic method. It will be used by the claim function that is going to be introduced in the next commit. --- src/client.ts | 2 +- src/safe/SafeTransactions.ts | 2 +- test/safe/transactions.test.ts | 16 ++++++++-------- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/client.ts b/src/client.ts index df4d36a..e70acb8 100644 --- a/src/client.ts +++ b/src/client.ts @@ -253,7 +253,7 @@ export class HypercertClient implements HypercertClientInterface { } const safeTransactions = new SafeTransactions(overrides.safeAddress, this._walletClient, this._getContract()); - return safeTransactions.mintHypercert(method, params, overrides); + return safeTransactions.sendTransaction(method, params, overrides); } const request = await this.simulateRequest(account, method, params, overrides); diff --git a/src/safe/SafeTransactions.ts b/src/safe/SafeTransactions.ts index eff6902..63e7d0b 100644 --- a/src/safe/SafeTransactions.ts +++ b/src/safe/SafeTransactions.ts @@ -30,7 +30,7 @@ export class SafeTransactions { }); } - public mintHypercert = ( + public sendTransaction = ( functionName: string, params: unknown[], overrides?: SupportedOverrides, diff --git a/test/safe/transactions.test.ts b/test/safe/transactions.test.ts index ee0e74e..996bad8 100644 --- a/test/safe/transactions.test.ts +++ b/test/safe/transactions.test.ts @@ -40,7 +40,7 @@ describe("SafeTransactions", () => { } as any); }); - describe("mintHypercert", () => { + describe("sendTransaction", () => { const validParams = [senderAddress, 1000n, "0xcid", 0]; it("correctly encodes function data for transaction", async () => { @@ -52,7 +52,7 @@ describe("SafeTransactions", () => { args: validParams, }); - await safeTransactions.mintHypercert(functionName, validParams, { + await safeTransactions.sendTransaction(functionName, validParams, { safeAddress, }); @@ -70,7 +70,7 @@ describe("SafeTransactions", () => { it("uses correct nonce from API", async () => { safeApiKitStub.getNextNonce.resolves("42"); - await safeTransactions.mintHypercert("mintClaim", validParams, { + await safeTransactions.sendTransaction("mintClaim", validParams, { safeAddress, }); @@ -95,7 +95,7 @@ describe("SafeTransactions", () => { ); try { - await safeTransactions.mintHypercert("mintClaim", validParams, { safeAddress }); + await safeTransactions.sendTransaction("mintClaim", validParams, { safeAddress }); expect.fail("Should throw ClientError"); } catch (e) { expect(e).to.be.instanceOf(ClientError); @@ -104,7 +104,7 @@ describe("SafeTransactions", () => { }); it("follows complete transaction flow", async () => { - const hash = await safeTransactions.mintHypercert("mintClaim", validParams, { + const hash = await safeTransactions.sendTransaction("mintClaim", validParams, { safeAddress, }); @@ -123,7 +123,7 @@ describe("SafeTransactions", () => { safeApiKitStub.proposeTransaction.rejects(new Error(errorMessage)); try { - await safeTransactions.mintHypercert("mintClaim", validParams, { safeAddress }); + await safeTransactions.sendTransaction("mintClaim", validParams, { safeAddress }); expect.fail("Should throw SafeTransactionError"); } catch (e) { expect(e).to.be.instanceOf(SafeTransactionError); @@ -142,7 +142,7 @@ describe("SafeTransactions", () => { connectedSafeStub.createTransaction.rejects(new Error(errorMessage)); try { - await safeTransactions.mintHypercert("mintClaim", [senderAddress, 1000n, "0xcid", 0], { safeAddress }); + await safeTransactions.sendTransaction("mintClaim", [senderAddress, 1000n, "0xcid", 0], { safeAddress }); expect.fail("Should throw SafeTransactionError"); } catch (e) { expect(e).to.be.instanceOf(SafeTransactionError); @@ -155,7 +155,7 @@ describe("SafeTransactions", () => { }); it("properly proposes transaction with correct parameters", async () => { - await safeTransactions.mintHypercert("mintClaim", [senderAddress, 1000n, "0xcid", 0], { safeAddress }); + await safeTransactions.sendTransaction("mintClaim", [senderAddress, 1000n, "0xcid", 0], { safeAddress }); const proposeCall = safeApiKitStub.proposeTransaction.getCall(0); expect(proposeCall.args[0]).to.deep.include({ From b04e78198f0330491c503dca803dda23d35919b3 Mon Sep 17 00:00:00 2001 From: pheuberger Date: Mon, 24 Mar 2025 22:58:59 +0200 Subject: [PATCH 2/3] feat: enable claiming from a Safe Akin to the mintHypercert method, enable the claimFractionFromAllowlist() method to follow the same pattern. --- src/client.ts | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/client.ts b/src/client.ts index e70acb8..3c40854 100644 --- a/src/client.ts +++ b/src/client.ts @@ -469,6 +469,8 @@ export class HypercertClient implements HypercertClientInterface { * This function handles the claiming of a fraction from an allowlist for the connected account. * It verifies the Merkle proof if a root is provided and then submits the minting request. * + * If you provide `overrides.safeAddress`, the transaction will be sent as a Safe transaction instead. + * * @param params - The parameters for the claim operation. * @param params.hypercertTokenId - The ID of the hypercert token to claim. * @param params.units - The number of units to claim. @@ -497,12 +499,20 @@ export class HypercertClient implements HypercertClientInterface { ); } - const request = await this.simulateRequest( - account, - "mintClaimFromAllowlist", - [account.address, proof, hypercertTokenId, units], - overrides, - ); + const accountAddress = overrides?.safeAddress ?? account.address; + const params = [accountAddress, proof, hypercertTokenId, units]; + + // If a safe address is provided, use the SafeTransactions class + if (overrides?.safeAddress) { + if (!this._walletClient) { + throw new ClientError("Safe address provided but no wallet client found"); + } + + const safeTransactions = new SafeTransactions(overrides.safeAddress, this._walletClient, this._getContract()); + return safeTransactions.sendTransaction("mintClaimFromAllowlist", params, overrides); + } + + const request = await this.simulateRequest(account, "mintClaimFromAllowlist", params, overrides); return this.submitRequest(request); }; From 17b89bfbb4b2376793f8434538133847ff8db7ed Mon Sep 17 00:00:00 2001 From: pheuberger Date: Tue, 25 Mar 2025 11:35:40 +0200 Subject: [PATCH 3/3] test: increase test coverage of SafeTransactions There were some uncovered lines in the constructor. --- test/safe/transactions.test.ts | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/test/safe/transactions.test.ts b/test/safe/transactions.test.ts index 996bad8..4322c74 100644 --- a/test/safe/transactions.test.ts +++ b/test/safe/transactions.test.ts @@ -171,6 +171,29 @@ describe("SafeTransactions", () => { }); }); }); + + describe("constructor", () => { + it("throws error when wallet client has no chain ID", () => { + chai.Assertion.expectAssertions(2); + + const invalidWalletClient = { ...walletClient, chain: undefined }; + + try { + new SafeTransactions( + safeAddress, + invalidWalletClient as any, + { + address: contractAddress, + abi: HypercertMinterAbi, + } as any, + ); + expect.fail("Should throw Error"); + } catch (e) { + expect(e).to.be.instanceOf(Error); + expect((e as Error).message).to.eq("No chain ID found in wallet client"); + } + }); + }); }); function createConnectedSafeStub(contractAddress: string, mockTxHash: `0x${string}`, mockSignature: `0x${string}`) {