From 22354d225acda0812c649a1ebd725ebf023be859 Mon Sep 17 00:00:00 2001 From: Tim Schwarz <4171783+tmjssz@users.noreply.github.com> Date: Wed, 26 Jun 2024 15:04:18 +0200 Subject: [PATCH 01/85] relay-kit: Add viem dependency --- packages/relay-kit/package.json | 3 ++- yarn.lock | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/packages/relay-kit/package.json b/packages/relay-kit/package.json index da9e56721..8ff3ae872 100644 --- a/packages/relay-kit/package.json +++ b/packages/relay-kit/package.json @@ -42,6 +42,7 @@ "@safe-global/protocol-kit": "^4.0.2", "@safe-global/safe-core-sdk-types": "^5.0.2", "@safe-global/safe-modules-deployments": "^2.1.1", - "ethers": "^6.13.1" + "ethers": "^6.13.1", + "viem": "^2.16.1" } } diff --git a/yarn.lock b/yarn.lock index 346026551..5ab385e95 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2641,6 +2641,11 @@ abitype@1.0.0: resolved "https://registry.yarnpkg.com/abitype/-/abitype-1.0.0.tgz#237176dace81d90d018bebf3a45cb42f2a2d9e97" integrity sha512-NMeMah//6bJ56H5XRj8QCV4AwuW6hB6zqz2LnhhLdcWVQOsXki6/Pn3APeqxCma62nXIcmZWdu1DlHWS74umVQ== +abitype@1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/abitype/-/abitype-1.0.4.tgz#a817ff44860e8a84e9a37ed22aa9b738dbb51dba" + integrity sha512-UivtYZOGJGE8rsrM/N5vdRkUpqEZVmuTumfTuolm7m/6O09wprd958rx8kUBwVAAAhQDveGAgD0GJdBuR8s6tw== + abitype@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/abitype/-/abitype-1.0.2.tgz#183c28f2f3b4278810ed1543941b555bb73f301d" @@ -9513,6 +9518,20 @@ viem@^2.15.1: isows "1.0.4" ws "8.17.1" +viem@^2.16.1: + version "2.16.1" + resolved "https://registry.yarnpkg.com/viem/-/viem-2.16.1.tgz#6be85ab69e2948d878d7b42f5d0e22333a8f6b33" + integrity sha512-rmgXcxif740m2ARqPFoiXRHkljXhsruCZgRXf6XuS6n+Lymy7X2ma5vuzBw3mDKiA2BmxjbyJC4Wxi7kaIwHhw== + dependencies: + "@adraffy/ens-normalize" "1.10.0" + "@noble/curves" "1.2.0" + "@noble/hashes" "1.3.2" + "@scure/bip32" "1.3.2" + "@scure/bip39" "1.2.1" + abitype "1.0.4" + isows "1.0.4" + ws "8.17.1" + w3c-xmlserializer@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz" From 26661714f2d8b9bbf785a70e7cca8e2ef0424f2c Mon Sep 17 00:00:00 2001 From: Tim Schwarz <4171783+tmjssz@users.noreply.github.com> Date: Wed, 26 Jun 2024 15:07:29 +0200 Subject: [PATCH 02/85] relay-kit: Migrate 4337 related components to viem --- .../src/utils/transactions/utils.ts | 5 +- .../src/packs/safe-4337/Safe4337Pack.test.ts | 155 +++++++++++------- .../src/packs/safe-4337/Safe4337Pack.ts | 63 ++++--- .../src/packs/safe-4337/SafeOperation.test.ts | 6 +- .../src/packs/safe-4337/SafeOperation.ts | 10 +- .../src/packs/safe-4337/constants.ts | 4 +- .../packs/safe-4337/testing-utils/helpers.ts | 13 +- .../relay-kit/src/packs/safe-4337/types.ts | 7 +- .../relay-kit/src/packs/safe-4337/utils.ts | 71 +++++--- 9 files changed, 214 insertions(+), 120 deletions(-) diff --git a/packages/protocol-kit/src/utils/transactions/utils.ts b/packages/protocol-kit/src/utils/transactions/utils.ts index 583752527..4ea1477e0 100644 --- a/packages/protocol-kit/src/utils/transactions/utils.ts +++ b/packages/protocol-kit/src/utils/transactions/utils.ts @@ -1,3 +1,4 @@ +import { Hash } from 'viem' import { ethers, Interface, getBytes, solidityPacked as solidityPack } from 'ethers' import SafeProvider from '@safe-global/protocol-kit/SafeProvider' import { DEFAULT_SAFE_VERSION } from '@safe-global/protocol-kit/contracts/config' @@ -116,8 +117,8 @@ function encodeMetaTransaction(tx: MetaTransactionData): string { return encoded.slice(2) } -export function encodeMultiSendData(txs: MetaTransactionData[]): string { - return '0x' + txs.map((tx) => encodeMetaTransaction(tx)).join('') +export function encodeMultiSendData(txs: MetaTransactionData[]): Hash { + return `0x${txs.map((tx) => encodeMetaTransaction(tx)).join('')}` } export function decodeMultiSendData(encodedData: string): MetaTransactionData[] { diff --git a/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.test.ts b/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.test.ts index e24a5c761..0db857e03 100644 --- a/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.test.ts +++ b/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.test.ts @@ -1,5 +1,5 @@ import dotenv from 'dotenv' -import { ethers } from 'ethers' +import * as viem from 'viem' import Safe, * as protocolKit from '@safe-global/protocol-kit' import { getAddModulesLibDeployment, @@ -12,6 +12,7 @@ import * as constants from './constants' import * as fixtures from './testing-utils/fixtures' import { createSafe4337Pack, generateTransferCallData } from './testing-utils/helpers' import * as utils from './utils' +import { toBeHex } from 'ethers' dotenv.config() @@ -34,7 +35,7 @@ jest.mock('./utils', () => ({ getEip4337BundlerProvider: jest.fn(() => ({ send: sendMock })) })) -let safe4337ModuleAddress: string +let safe4337ModuleAddress: viem.Hash let addModulesLibAddress: string describe('Safe4337Pack', () => { @@ -44,7 +45,7 @@ describe('Safe4337Pack', () => { released: true, version: '0.2.0', network - })?.networkAddresses[network] as string + })?.networkAddresses[network] as viem.Hash addModulesLibAddress = getAddModulesLibDeployment({ released: true, version: '0.2.0', @@ -219,7 +220,7 @@ describe('Safe4337Pack', () => { }) it('should encode the enableModules transaction as deployment data', async () => { - const encodeFunctionDataSpy = jest.spyOn(constants.INTERFACES, 'encodeFunctionData') + const encodeFunctionDataSpy = jest.spyOn(viem, 'encodeFunctionData') const safeCreateSpy = jest.spyOn(Safe, 'init') const safe4337Pack = await createSafe4337Pack({ @@ -229,7 +230,11 @@ describe('Safe4337Pack', () => { } }) - expect(encodeFunctionDataSpy).toHaveBeenCalledWith('enableModules', [[safe4337ModuleAddress]]) + expect(encodeFunctionDataSpy).toHaveBeenCalledWith({ + abi: constants.ABI, + functionName: 'enableModules', + args: [[safe4337ModuleAddress]] + }) expect(safeCreateSpy).toHaveBeenCalledWith({ provider: safe4337Pack.protocolKit.getSafeProvider().provider, signer: safe4337Pack.protocolKit.getSafeProvider().signer, @@ -242,20 +247,22 @@ describe('Safe4337Pack', () => { owners: [fixtures.OWNER_1, fixtures.OWNER_2], threshold: 1, to: addModulesLibAddress, - data: constants.INTERFACES.encodeFunctionData('enableModules', [ - [safe4337ModuleAddress] - ]), + data: viem.encodeFunctionData({ + abi: constants.ABI, + functionName: 'enableModules', + args: [[safe4337ModuleAddress]] + }), fallbackHandler: safe4337ModuleAddress, - paymentToken: ethers.ZeroAddress, + paymentToken: viem.zeroAddress, payment: 0, - paymentReceiver: ethers.ZeroAddress + paymentReceiver: viem.zeroAddress } } }) }) it('should encode the enablesModule transaction together with a specific token approval in a multiSend call when trying to use a paymaster', async () => { - const encodeFunctionDataSpy = jest.spyOn(constants.INTERFACES, 'encodeFunctionData') + const encodeFunctionDataSpy = jest.spyOn(viem, 'encodeFunctionData') const safeCreateSpy = jest.spyOn(Safe, 'init') const safe4337Pack = await createSafe4337Pack({ @@ -269,13 +276,19 @@ describe('Safe4337Pack', () => { } }) - const enableModulesData = constants.INTERFACES.encodeFunctionData('enableModules', [ - [safe4337ModuleAddress] - ]) - const approveData = constants.INTERFACES.encodeFunctionData('approve', [ - fixtures.PAYMASTER_ADDRESS, - 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffn - ]) + const enableModulesData = viem.encodeFunctionData({ + abi: constants.ABI, + functionName: 'enableModules', + args: [[safe4337ModuleAddress]] + }) + const approveData = viem.encodeFunctionData({ + abi: constants.ABI, + functionName: 'approve', + args: [ + fixtures.PAYMASTER_ADDRESS, + 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffn + ] + }) const enable4337ModuleTransaction = { to: addModulesLibAddress, @@ -296,7 +309,11 @@ describe('Safe4337Pack', () => { approveToPaymasterTransaction ]) - expect(encodeFunctionDataSpy).toHaveBeenNthCalledWith(4, 'multiSend', [multiSendData]) + expect(encodeFunctionDataSpy).toHaveBeenNthCalledWith(4, { + abi: constants.ABI, + functionName: 'multiSend', + args: [multiSendData] + }) expect(safeCreateSpy).toHaveBeenCalledWith({ provider: safe4337Pack.protocolKit.getSafeProvider().provider, signer: safe4337Pack.protocolKit.getSafeProvider().signer, @@ -309,11 +326,15 @@ describe('Safe4337Pack', () => { owners: [fixtures.OWNER_1], threshold: 1, to: await safe4337Pack.protocolKit.getMultiSendAddress(), - data: constants.INTERFACES.encodeFunctionData('multiSend', [multiSendData]), + data: viem.encodeFunctionData({ + abi: constants.ABI, + functionName: 'multiSend', + args: [multiSendData] + }), fallbackHandler: safe4337ModuleAddress, - paymentToken: ethers.ZeroAddress, + paymentToken: viem.zeroAddress, payment: 0, - paymentReceiver: ethers.ZeroAddress + paymentReceiver: viem.zeroAddress } } }) @@ -352,14 +373,20 @@ describe('Safe4337Pack', () => { entryPoint: '0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789', initCode: '0x', paymasterAndData: '0x', - callData: constants.INTERFACES.encodeFunctionData('executeUserOp', [ - await safe4337Pack.protocolKit.getMultiSendAddress(), - '0', - constants.INTERFACES.encodeFunctionData('multiSend', [ - protocolKit.encodeMultiSendData(transactions) - ]), - OperationType.DelegateCall - ]), + callData: viem.encodeFunctionData({ + abi: constants.ABI, + functionName: 'executeUserOp', + args: [ + (await safe4337Pack.protocolKit.getMultiSendAddress()) as viem.Hash, + 0n, + viem.encodeFunctionData({ + abi: constants.ABI, + functionName: 'multiSend', + args: [protocolKit.encodeMultiSendData(transactions)] + }), + OperationType.DelegateCall + ] + }), nonce: 1n, callGasLimit: 150000n, validAfter: 0, @@ -382,12 +409,16 @@ describe('Safe4337Pack', () => { entryPoint: '0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789', initCode: '0x', paymasterAndData: '0x', - callData: constants.INTERFACES.encodeFunctionData('executeUserOp', [ - transferUSDC.to, - transferUSDC.value, - transferUSDC.data, - OperationType.Call - ]), + callData: viem.encodeFunctionData({ + abi: constants.ABI, + functionName: 'executeUserOp', + args: [ + transferUSDC.to as viem.Hash, + BigInt(transferUSDC.value), + transferUSDC.data as viem.Hash, + OperationType.Call + ] + }), nonce: 1n, callGasLimit: 150000n, validAfter: 0, @@ -441,12 +472,16 @@ describe('Safe4337Pack', () => { entryPoint: '0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789', initCode: '0x', paymasterAndData: '0x0000000000325602a77416A16136FDafd04b299f', - callData: constants.INTERFACES.encodeFunctionData('executeUserOp', [ - transferUSDC.to, - transferUSDC.value, - transferUSDC.data, - OperationType.Call - ]), + callData: viem.encodeFunctionData({ + abi: constants.ABI, + functionName: 'executeUserOp', + args: [ + transferUSDC.to as viem.Hash, + BigInt(transferUSDC.value), + transferUSDC.data as viem.Hash, + OperationType.Call + ] + }), nonce: 1n, callGasLimit: 150000n, validAfter: 0, @@ -498,10 +533,11 @@ describe('Safe4337Pack', () => { const approveTransaction = { to: fixtures.PAYMASTER_TOKEN_ADDRESS, - data: constants.INTERFACES.encodeFunctionData('approve', [ - fixtures.PAYMASTER_ADDRESS, - amountToApprove - ]), + data: viem.encodeFunctionData({ + abi: constants.ABI, + functionName: 'approve', + args: [fixtures.PAYMASTER_ADDRESS, amountToApprove] + }), value: '0', operation: OperationType.Call // Call for approve } @@ -514,14 +550,20 @@ describe('Safe4337Pack', () => { entryPoint: '0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789', initCode: '0x', paymasterAndData: '0x0000000000325602a77416A16136FDafd04b299f', - callData: constants.INTERFACES.encodeFunctionData('executeUserOp', [ - await safe4337Pack.protocolKit.getMultiSendAddress(), - '0', - constants.INTERFACES.encodeFunctionData('multiSend', [ - protocolKit.encodeMultiSendData(batch) - ]), - OperationType.DelegateCall - ]), + callData: viem.encodeFunctionData({ + abi: constants.ABI, + functionName: 'executeUserOp', + args: [ + (await safe4337Pack.protocolKit.getMultiSendAddress()) as viem.Hash, + 0n, + viem.encodeFunctionData({ + abi: constants.ABI, + functionName: 'multiSend', + args: [protocolKit.encodeMultiSendData(batch)] + }), + OperationType.DelegateCall + ] + }), nonce: 1n, callGasLimit: 150000n, validAfter: 0, @@ -619,13 +661,16 @@ describe('Safe4337Pack', () => { ]) }) - it('should allow to send a UserOperation to the bundler using a SafeOperationResponse object from the api', async () => { + it.only('should allow to send a UserOperation to the bundler using a SafeOperationResponse object from the api', async () => { const safe4337Pack = await createSafe4337Pack({ options: { safeAddress: fixtures.SAFE_ADDRESS_v1_4_1 } }) + console.log('ethers', toBeHex('3')) + console.log('viem', viem.toHex('3')) + await safe4337Pack.executeTransaction({ executable: fixtures.SAFE_OPERATION_RESPONSE }) expect(sendMock).toHaveBeenCalledWith(constants.RPC_4337_CALLS.SEND_USER_OPERATION, [ diff --git a/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.ts b/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.ts index 106830bdb..449a1f102 100644 --- a/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.ts +++ b/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.ts @@ -1,4 +1,5 @@ import { ethers } from 'ethers' +import { Hash, encodeFunctionData, zeroAddress } from 'viem' import semverSatisfies from 'semver/functions/satisfies' import Safe, { EthSafeSignature, @@ -33,9 +34,9 @@ import { PaymasterOptions } from './types' import { + ABI, DEFAULT_SAFE_VERSION, DEFAULT_SAFE_MODULES_VERSION, - INTERFACES, RPC_4337_CALLS } from './constants' import { @@ -73,7 +74,7 @@ export class Safe4337Pack extends RelayKitBasePack<{ #BUNDLER_URL: string #ENTRYPOINT_ADDRESS: string - #SAFE_4337_MODULE_ADDRESS: string = '0x' + #SAFE_4337_MODULE_ADDRESS: Hash = '0x' #bundlerClient: ethers.JsonRpcProvider @@ -148,7 +149,9 @@ export class Safe4337Pack extends RelayKitBasePack<{ version: safeModulesVersion, network }) - safe4337ModuleAddress = safe4337ModuleDeployment?.networkAddresses[network] + safe4337ModuleAddress = safe4337ModuleDeployment?.networkAddresses[network] as + | Hash + | undefined } if (!addModulesLibAddress || !safe4337ModuleAddress) { @@ -198,7 +201,11 @@ export class Safe4337Pack extends RelayKitBasePack<{ } let deploymentTo = addModulesLibAddress - let deploymentData = INTERFACES.encodeFunctionData('enableModules', [[safe4337ModuleAddress]]) + let deploymentData = encodeFunctionData({ + abi: ABI, + functionName: 'enableModules', + args: [[safe4337ModuleAddress]] + }) const { isSponsored, paymasterTokenAddress } = paymasterOptions || {} @@ -211,22 +218,32 @@ export class Safe4337Pack extends RelayKitBasePack<{ const enable4337ModulesTransaction = { to: addModulesLibAddress, value: '0', - data: INTERFACES.encodeFunctionData('enableModules', [[safe4337ModuleAddress]]), + data: encodeFunctionData({ + abi: ABI, + functionName: 'enableModules', + args: [[safe4337ModuleAddress]] + }), operation: OperationType.DelegateCall // DelegateCall required for enabling the 4337 module } const approveToPaymasterTransaction = { to: paymasterTokenAddress, - data: INTERFACES.encodeFunctionData('approve', [paymasterAddress, amountToApprove]), + data: encodeFunctionData({ + abi: ABI, + functionName: 'approve', + args: [paymasterAddress, amountToApprove] + }), value: '0', operation: OperationType.Call // Call for approve } const setupBatch = [enable4337ModulesTransaction, approveToPaymasterTransaction] - const batchData = INTERFACES.encodeFunctionData('multiSend', [ - encodeMultiSendData(setupBatch) - ]) + const batchData = encodeFunctionData({ + abi: ABI, + functionName: 'multiSend', + args: [encodeMultiSendData(setupBatch)] + }) const multiSendContract = await getMultiSendContract({ safeProvider: new SafeProvider({ provider, signer }), @@ -251,9 +268,9 @@ export class Safe4337Pack extends RelayKitBasePack<{ to: deploymentTo, data: deploymentData, fallbackHandler: safe4337ModuleAddress, - paymentToken: ethers.ZeroAddress, + paymentToken: zeroAddress, payment: 0, - paymentReceiver: ethers.ZeroAddress + paymentReceiver: zeroAddress } } }) @@ -402,7 +419,11 @@ export class Safe4337Pack extends RelayKitBasePack<{ const approveToPaymasterTransaction = { to: paymasterTokenAddress, - data: INTERFACES.encodeFunctionData('approve', [paymasterAddress, amountToApprove]), + data: encodeFunctionData({ + abi: ABI, + functionName: 'approve', + args: [paymasterAddress, amountToApprove] + }), value: '0', operation: OperationType.Call // Call for approve } @@ -670,12 +691,16 @@ export class Safe4337Pack extends RelayKitBasePack<{ * @param {MetaTransactionData} transaction - The transaction data to encode. * @return {string} The encoded call data string. */ - #encodeExecuteUserOpCallData(transaction: MetaTransactionData): string { - return INTERFACES.encodeFunctionData('executeUserOp', [ - transaction.to, - transaction.value, - transaction.data, - transaction.operation || OperationType.Call - ]) + #encodeExecuteUserOpCallData(transaction: MetaTransactionData): Hash { + return encodeFunctionData({ + abi: ABI, + functionName: 'executeUserOp', + args: [ + transaction.to as Hash, + BigInt(transaction.value), + transaction.data as Hash, + transaction.operation || OperationType.Call + ] + }) } } diff --git a/packages/relay-kit/src/packs/safe-4337/SafeOperation.test.ts b/packages/relay-kit/src/packs/safe-4337/SafeOperation.test.ts index f46a9ff2d..ebd4354fc 100644 --- a/packages/relay-kit/src/packs/safe-4337/SafeOperation.test.ts +++ b/packages/relay-kit/src/packs/safe-4337/SafeOperation.test.ts @@ -1,4 +1,4 @@ -import { ethers } from 'ethers' +import { encodePacked } from 'viem' import { EthSafeSignature } from '@safe-global/protocol-kit' import EthSafeOperation from './SafeOperation' import * as fixtures from './testing-utils/fixtures' @@ -106,7 +106,7 @@ describe('SafeOperation', () => { expect(safeOperation.toUserOperation()).toMatchObject({ sender: safeOperation.data.safe, - nonce: ethers.toBeHex(fixtures.USER_OPERATION.nonce), + nonce: fixtures.USER_OPERATION.nonce, initCode: safeOperation.data.initCode, callData: safeOperation.data.callData, callGasLimit: safeOperation.data.callGasLimit, @@ -115,7 +115,7 @@ describe('SafeOperation', () => { maxFeePerGas: safeOperation.data.maxFeePerGas, maxPriorityFeePerGas: safeOperation.data.maxPriorityFeePerGas, paymasterAndData: safeOperation.data.paymasterAndData, - signature: ethers.solidityPacked( + signature: encodePacked( ['uint48', 'uint48', 'bytes'], [ safeOperation.data.validAfter, diff --git a/packages/relay-kit/src/packs/safe-4337/SafeOperation.ts b/packages/relay-kit/src/packs/safe-4337/SafeOperation.ts index 00b991c67..dc96da223 100644 --- a/packages/relay-kit/src/packs/safe-4337/SafeOperation.ts +++ b/packages/relay-kit/src/packs/safe-4337/SafeOperation.ts @@ -1,4 +1,4 @@ -import { ethers } from 'ethers' +import { Hex, encodePacked, toHex } from 'viem' import { EstimateGasData, SafeOperation, @@ -54,8 +54,8 @@ class EthSafeOperation implements SafeOperation { this.signatures.set(signature.signer.toLowerCase(), signature) } - encodedSignatures(): string { - return buildSignatureBytes(Array.from(this.signatures.values())) + encodedSignatures(): Hex { + return buildSignatureBytes(Array.from(this.signatures.values())) as Hex } addEstimations(estimations: EstimateGasData): void { @@ -75,7 +75,7 @@ class EthSafeOperation implements SafeOperation { toUserOperation(): UserOperation { return { sender: this.data.safe, - nonce: ethers.toBeHex(this.data.nonce), + nonce: toHex(this.data.nonce), initCode: this.data.initCode, callData: this.data.callData, callGasLimit: this.data.callGasLimit, @@ -84,7 +84,7 @@ class EthSafeOperation implements SafeOperation { maxFeePerGas: this.data.maxFeePerGas, maxPriorityFeePerGas: this.data.maxPriorityFeePerGas, paymasterAndData: this.data.paymasterAndData, - signature: ethers.solidityPacked( + signature: encodePacked( ['uint48', 'uint48', 'bytes'], [this.data.validAfter, this.data.validUntil, this.encodedSignatures()] ) diff --git a/packages/relay-kit/src/packs/safe-4337/constants.ts b/packages/relay-kit/src/packs/safe-4337/constants.ts index 04e66c1ef..e267e13c1 100644 --- a/packages/relay-kit/src/packs/safe-4337/constants.ts +++ b/packages/relay-kit/src/packs/safe-4337/constants.ts @@ -1,4 +1,4 @@ -import { ethers } from 'ethers' +import { parseAbi } from 'viem' export const DEFAULT_SAFE_VERSION = '1.4.1' export const DEFAULT_SAFE_MODULES_VERSION = '0.2.0' @@ -21,7 +21,7 @@ export const EIP712_SAFE_OPERATION_TYPE = { ] } -export const INTERFACES = new ethers.Interface([ +export const ABI = parseAbi([ 'function enableModules(address[])', 'function multiSend(bytes memory transactions) public payable', 'function executeUserOp(address to, uint256 value, bytes data, uint8 operation)', diff --git a/packages/relay-kit/src/packs/safe-4337/testing-utils/helpers.ts b/packages/relay-kit/src/packs/safe-4337/testing-utils/helpers.ts index 66a6fb270..bfac57106 100644 --- a/packages/relay-kit/src/packs/safe-4337/testing-utils/helpers.ts +++ b/packages/relay-kit/src/packs/safe-4337/testing-utils/helpers.ts @@ -1,13 +1,16 @@ -import { ethers } from 'ethers' +import { Hash, encodeFunctionData, parseAbi } from 'viem' import { Safe4337InitOptions } from '../types' import { Safe4337Pack } from '../Safe4337Pack' import * as fixtures from './fixtures' -export const generateTransferCallData = (to: string, value: bigint) => { - const functionAbi = 'function transfer(address _to, uint256 _value) returns (bool)' - const iface = new ethers.Interface([functionAbi]) +export const generateTransferCallData = (to: Hash, value: bigint) => { + const functionAbi = parseAbi(['function transfer(address _to, uint256 _value) returns (bool)']) - return iface.encodeFunctionData('transfer', [to, value]) + return encodeFunctionData({ + abi: functionAbi, + functionName: 'transfer', + args: [to, value] + }) } const safe4337PackCache = new Map() diff --git a/packages/relay-kit/src/packs/safe-4337/types.ts b/packages/relay-kit/src/packs/safe-4337/types.ts index 349a31be2..2f13a595f 100644 --- a/packages/relay-kit/src/packs/safe-4337/types.ts +++ b/packages/relay-kit/src/packs/safe-4337/types.ts @@ -1,3 +1,4 @@ +import { Hash } from 'viem' import Safe, { SafeProviderConfig } from '@safe-global/protocol-kit' import { EstimateGasData, @@ -24,7 +25,7 @@ export type PaymasterOptions = { paymasterUrl?: string isSponsored?: boolean sponsorshipPolicyId?: string - paymasterAddress: string + paymasterAddress: Hash paymasterTokenAddress?: string amountToApprove?: bigint } @@ -36,7 +37,7 @@ export type Safe4337InitOptions = { safeModulesVersion?: string customContracts?: { entryPointAddress?: string - safe4337ModuleAddress?: string + safe4337ModuleAddress?: Hash addModulesLibAddress?: string } options: ExistingSafeOptions | PredictedSafeOptions @@ -50,7 +51,7 @@ export type Safe4337Options = { paymasterOptions?: PaymasterOptions bundlerClient: ethers.JsonRpcProvider entryPointAddress: string - safe4337ModuleAddress: string + safe4337ModuleAddress: Hash } export type Safe4337CreateTransactionProps = { diff --git a/packages/relay-kit/src/packs/safe-4337/utils.ts b/packages/relay-kit/src/packs/safe-4337/utils.ts index ec6b58f3a..01a384a30 100644 --- a/packages/relay-kit/src/packs/safe-4337/utils.ts +++ b/packages/relay-kit/src/packs/safe-4337/utils.ts @@ -1,3 +1,4 @@ +import { Hash, encodeFunctionData, encodePacked, hashTypedData, toHex } from 'viem' import { SafeUserOperation, OperationType, @@ -12,7 +13,7 @@ import { buildSignatureBytes } from '@safe-global/protocol-kit' import { ethers } from 'ethers' -import { EIP712_SAFE_OPERATION_TYPE, INTERFACES } from './constants' +import { ABI, EIP712_SAFE_OPERATION_TYPE } from './constants' /** * Gets the EIP-4337 bundler provider. @@ -33,13 +34,13 @@ export function getEip4337BundlerProvider(bundlerUrl: string): ethers.JsonRpcPro * * @param {SafeUserOperation} safeUserOperation - Safe user operation to sign. * @param {SafeProvider} safeProvider - Safe provider. - * @param {string} safe4337ModuleAddress - Safe 4337 module address. + * @param {Hash} safe4337ModuleAddress - Safe 4337 module address. * @return {Promise} The SafeSignature object containing the data and the signatures. */ export async function signSafeOp( safeUserOperation: SafeUserOperation, safeProvider: SafeProvider, - safe4337ModuleAddress: string + safe4337ModuleAddress: Hash ): Promise { const signer = (await safeProvider.getExternalSigner()) as ethers.Signer const chainId = await safeProvider.getChainId() @@ -52,11 +53,11 @@ export async function signSafeOp( EIP712_SAFE_OPERATION_TYPE, { ...safeUserOperation, - nonce: ethers.toBeHex(safeUserOperation.nonce), - validAfter: ethers.toBeHex(safeUserOperation.validAfter), - validUntil: ethers.toBeHex(safeUserOperation.validUntil), - maxFeePerGas: ethers.toBeHex(safeUserOperation.maxFeePerGas), - maxPriorityFeePerGas: ethers.toBeHex(safeUserOperation.maxPriorityFeePerGas) + nonce: toHex(safeUserOperation.nonce), + validAfter: toHex(safeUserOperation.validAfter), + validUntil: toHex(safeUserOperation.validUntil), + maxFeePerGas: toHex(safeUserOperation.maxFeePerGas), + maxPriorityFeePerGas: toHex(safeUserOperation.maxPriorityFeePerGas) } ) @@ -67,14 +68,18 @@ export async function signSafeOp( * Encodes multi-send data from transactions batch. * * @param {MetaTransactionData[]} transactions - an array of transaction to to be encoded. - * @return {string} The encoded data string. + * @return {Hash} The encoded data string. */ -export function encodeMultiSendCallData(transactions: MetaTransactionData[]): string { - return INTERFACES.encodeFunctionData('multiSend', [ - encodeMultiSendData( - transactions.map((tx) => ({ ...tx, operation: tx.operation ?? OperationType.Call })) - ) - ]) +export function encodeMultiSendCallData(transactions: MetaTransactionData[]): Hash { + return encodeFunctionData({ + abi: ABI, + functionName: 'multiSend', + args: [ + encodeMultiSendData( + transactions.map((tx) => ({ ...tx, operation: tx.operation ?? OperationType.Call })) + ) + ] + }) } /** @@ -82,22 +87,23 @@ export function encodeMultiSendCallData(transactions: MetaTransactionData[]): st * * @param {SafeUserOperation} safeUserOperation - The SafeUserOperation. * @param {bigint} chainId - The chain id. - * @param {string} safe4337ModuleAddress - The Safe 4337 module address. + * @param {Hash} safe4337ModuleAddress - The Safe 4337 module address. * @return {string} The hash of the safe operation. */ export function calculateSafeUserOperationHash( safeUserOperation: SafeUserOperation, chainId: bigint, - safe4337ModuleAddress: string -): string { - return ethers.TypedDataEncoder.hash( - { - chainId, + safe4337ModuleAddress: Hash +): Hash { + return hashTypedData({ + domain: { + chainId: Number(chainId), verifyingContract: safe4337ModuleAddress }, - EIP712_SAFE_OPERATION_TYPE, - safeUserOperation - ) + types: EIP712_SAFE_OPERATION_TYPE, + primaryType: 'SafeOp', + message: safeUserOperation + }) } /** @@ -108,6 +114,16 @@ export function calculateSafeUserOperationHash( */ export function userOperationToHexValues(userOperation: UserOperation) { const userOperationWithHexValues = { + ...userOperation, + nonce: toHex(userOperation.nonce), + callGasLimit: toHex(userOperation.callGasLimit), + verificationGasLimit: toHex(userOperation.verificationGasLimit), + preVerificationGas: toHex(userOperation.preVerificationGas), + maxFeePerGas: toHex(userOperation.maxFeePerGas), + maxPriorityFeePerGas: toHex(userOperation.maxPriorityFeePerGas) + } + + const userOperationWithHexValuesEthers = { ...userOperation, nonce: ethers.toBeHex(userOperation.nonce), callGasLimit: ethers.toBeHex(userOperation.callGasLimit), @@ -117,6 +133,9 @@ export function userOperationToHexValues(userOperation: UserOperation) { maxPriorityFeePerGas: ethers.toBeHex(userOperation.maxPriorityFeePerGas) } + console.log(userOperationWithHexValues) + console.log(userOperationWithHexValuesEthers) + return userOperationWithHexValues } @@ -140,9 +159,9 @@ export function addDummySignature( return { ...userOperation, - signature: ethers.solidityPacked( + signature: encodePacked( ['uint48', 'uint48', 'bytes'], - [0, 0, buildSignatureBytes(signatures)] + [0, 0, buildSignatureBytes(signatures) as Hash] ) } } From b3d329e0e07a4ac1bc9d99b08e670d2913b39457 Mon Sep 17 00:00:00 2001 From: Tim Schwarz <4171783+tmjssz@users.noreply.github.com> Date: Wed, 26 Jun 2024 15:08:40 +0200 Subject: [PATCH 03/85] playground: Use `generateTransferCallData` function from relay-kit instead of re-implementing it --- .../relay-kit/usdc-transfer-4337-counterfactual.ts | 8 ++++++-- .../usdc-transfer-4337-erc20-counterfactual.ts | 3 ++- playground/relay-kit/usdc-transfer-4337-erc20.ts | 3 ++- .../usdc-transfer-4337-sponsored-counterfactual.ts | 3 ++- playground/relay-kit/usdc-transfer-4337-sponsored.ts | 3 ++- playground/relay-kit/usdc-transfer-4337.ts | 3 ++- playground/safe-kit/deploy-and-execute-transaction.ts | 6 ++++-- playground/utils.ts | 11 +++-------- 8 files changed, 23 insertions(+), 17 deletions(-) diff --git a/playground/relay-kit/usdc-transfer-4337-counterfactual.ts b/playground/relay-kit/usdc-transfer-4337-counterfactual.ts index 7b3e91d88..0386217bb 100644 --- a/playground/relay-kit/usdc-transfer-4337-counterfactual.ts +++ b/playground/relay-kit/usdc-transfer-4337-counterfactual.ts @@ -1,6 +1,8 @@ +import { Hash } from 'viem' import { ethers } from 'ethers' import { Safe4337Pack } from '@safe-global/relay-kit' -import { waitForOperationToFinish, transfer, generateTransferCallData } from '../utils' +import { generateTransferCallData } from '@safe-global/relay-kit/src/packs/safe-4337/testing-utils/helpers' +import { waitForOperationToFinish, transfer } from '../utils' // Safe owner PK const PRIVATE_KEY = '' @@ -61,7 +63,9 @@ async function main() { console.log(`sending ${nativeTokenAmount} ETH...`) const ethersSigner = await safe4337Pack.protocolKit.getSafeProvider().getExternalSigner() - const signerAddress = await safe4337Pack.protocolKit.getSafeProvider().getSignerAddress() + const signerAddress = (await safe4337Pack.protocolKit.getSafeProvider().getSignerAddress()) as + | Hash + | undefined const ethersProvider = safe4337Pack.protocolKit.getSafeProvider().getExternalProvider() if (!ethersSigner || !signerAddress) { diff --git a/playground/relay-kit/usdc-transfer-4337-erc20-counterfactual.ts b/playground/relay-kit/usdc-transfer-4337-erc20-counterfactual.ts index f80a23db9..5c3ee5a7f 100644 --- a/playground/relay-kit/usdc-transfer-4337-erc20-counterfactual.ts +++ b/playground/relay-kit/usdc-transfer-4337-erc20-counterfactual.ts @@ -1,5 +1,6 @@ import { Safe4337Pack } from '@safe-global/relay-kit' -import { waitForOperationToFinish, transfer, generateTransferCallData } from '../utils' +import { generateTransferCallData } from '@safe-global/relay-kit/src/packs/safe-4337/testing-utils/helpers' +import { waitForOperationToFinish, transfer } from '../utils' // Safe owner PK const PRIVATE_KEY = '' diff --git a/playground/relay-kit/usdc-transfer-4337-erc20.ts b/playground/relay-kit/usdc-transfer-4337-erc20.ts index 3dd524274..8b8146d51 100644 --- a/playground/relay-kit/usdc-transfer-4337-erc20.ts +++ b/playground/relay-kit/usdc-transfer-4337-erc20.ts @@ -1,5 +1,6 @@ import { Safe4337Pack } from '@safe-global/relay-kit' -import { waitForOperationToFinish, transfer, generateTransferCallData } from '../utils' +import { generateTransferCallData } from '@safe-global/relay-kit/src/packs/safe-4337/testing-utils/helpers' +import { waitForOperationToFinish, transfer } from '../utils' // Safe owner PK const PRIVATE_KEY = '' diff --git a/playground/relay-kit/usdc-transfer-4337-sponsored-counterfactual.ts b/playground/relay-kit/usdc-transfer-4337-sponsored-counterfactual.ts index 2e89c7b5a..699c9cfe5 100644 --- a/playground/relay-kit/usdc-transfer-4337-sponsored-counterfactual.ts +++ b/playground/relay-kit/usdc-transfer-4337-sponsored-counterfactual.ts @@ -1,5 +1,6 @@ import { Safe4337Pack } from '@safe-global/relay-kit' -import { waitForOperationToFinish, transfer, generateTransferCallData } from '../utils' +import { generateTransferCallData } from '@safe-global/relay-kit/src/packs/safe-4337/testing-utils/helpers' +import { waitForOperationToFinish, transfer } from '../utils' // Safe owner PK const PRIVATE_KEY = '' diff --git a/playground/relay-kit/usdc-transfer-4337-sponsored.ts b/playground/relay-kit/usdc-transfer-4337-sponsored.ts index 7751c0c91..c6a972994 100644 --- a/playground/relay-kit/usdc-transfer-4337-sponsored.ts +++ b/playground/relay-kit/usdc-transfer-4337-sponsored.ts @@ -1,5 +1,6 @@ import { Safe4337Pack } from '@safe-global/relay-kit' -import { waitForOperationToFinish, generateTransferCallData } from '../utils' +import { generateTransferCallData } from '@safe-global/relay-kit/src/packs/safe-4337/testing-utils/helpers' +import { waitForOperationToFinish } from '../utils' // Safe owner PK const PRIVATE_KEY = '' diff --git a/playground/relay-kit/usdc-transfer-4337.ts b/playground/relay-kit/usdc-transfer-4337.ts index b58105444..6fbe7cc4a 100644 --- a/playground/relay-kit/usdc-transfer-4337.ts +++ b/playground/relay-kit/usdc-transfer-4337.ts @@ -1,5 +1,6 @@ import { Safe4337Pack } from '@safe-global/relay-kit' -import { waitForOperationToFinish, generateTransferCallData } from 'playground/utils' +import { generateTransferCallData } from '@safe-global/relay-kit/src/packs/safe-4337/testing-utils/helpers' +import { waitForOperationToFinish } from 'playground/utils' // Safe owner PK const PRIVATE_KEY = '' diff --git a/playground/safe-kit/deploy-and-execute-transaction.ts b/playground/safe-kit/deploy-and-execute-transaction.ts index 6850a8b3e..190db3ae3 100644 --- a/playground/safe-kit/deploy-and-execute-transaction.ts +++ b/playground/safe-kit/deploy-and-execute-transaction.ts @@ -1,5 +1,6 @@ +import { Hash } from 'viem' import { createSafeClient } from '@safe-global/safe-kit' -import { generateTransferCallData } from '../utils' +import { generateTransferCallData } from '@safe-global/relay-kit/src/packs/safe-4337/testing-utils/helpers' const OWNER_1_PRIVATE_KEY = '' const OWNER_1_ADDRESS = '' @@ -19,7 +20,8 @@ async function main() { } }) - const signerAddress = (await safeClient.protocolKit.getSafeProvider().getSignerAddress()) || '0x' + const signerAddress = ((await safeClient.protocolKit.getSafeProvider().getSignerAddress()) || + '0x') as Hash console.log( '-Safe Address:', diff --git a/playground/utils.ts b/playground/utils.ts index 19634fcf2..d80ea62c8 100644 --- a/playground/utils.ts +++ b/playground/utils.ts @@ -1,5 +1,7 @@ import { ethers } from 'ethers' +import { Hash } from 'viem' import { Safe4337Pack } from '@safe-global/relay-kit' +import { generateTransferCallData } from '@safe-global/relay-kit/src/packs/safe-4337/testing-utils/helpers' import { GetSafeOperationListResponse } from '@safe-global/api-kit' export async function waitForOperationToFinish( @@ -24,17 +26,10 @@ export async function waitForOperationToFinish( console.groupEnd() } -export function generateTransferCallData(to: string, value: bigint) { - const functionAbi = 'function transfer(address _to, uint256 _value) returns (bool)' - const iface = new ethers.Interface([functionAbi]) - - return iface.encodeFunctionData('transfer', [to, value]) -} - export async function transfer( signer: ethers.AbstractSigner, tokenAddress: string, - to: string, + to: Hash, amount: bigint ) { const transferEC20 = { From e2be4ea282fff39cb32c23dc55a0175731a779dd Mon Sep 17 00:00:00 2001 From: Tim Schwarz <4171783+tmjssz@users.noreply.github.com> Date: Wed, 26 Jun 2024 15:49:34 +0200 Subject: [PATCH 04/85] relay-kit: Fix hex string conversion for nonce --- .../src/packs/safe-4337/Safe4337Pack.test.ts | 6 +----- packages/relay-kit/src/packs/safe-4337/utils.ts | 15 +-------------- 2 files changed, 2 insertions(+), 19 deletions(-) diff --git a/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.test.ts b/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.test.ts index 0db857e03..c9f67d7f5 100644 --- a/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.test.ts +++ b/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.test.ts @@ -12,7 +12,6 @@ import * as constants from './constants' import * as fixtures from './testing-utils/fixtures' import { createSafe4337Pack, generateTransferCallData } from './testing-utils/helpers' import * as utils from './utils' -import { toBeHex } from 'ethers' dotenv.config() @@ -661,16 +660,13 @@ describe('Safe4337Pack', () => { ]) }) - it.only('should allow to send a UserOperation to the bundler using a SafeOperationResponse object from the api', async () => { + it('should allow to send a UserOperation to the bundler using a SafeOperationResponse object from the api', async () => { const safe4337Pack = await createSafe4337Pack({ options: { safeAddress: fixtures.SAFE_ADDRESS_v1_4_1 } }) - console.log('ethers', toBeHex('3')) - console.log('viem', viem.toHex('3')) - await safe4337Pack.executeTransaction({ executable: fixtures.SAFE_OPERATION_RESPONSE }) expect(sendMock).toHaveBeenCalledWith(constants.RPC_4337_CALLS.SEND_USER_OPERATION, [ diff --git a/packages/relay-kit/src/packs/safe-4337/utils.ts b/packages/relay-kit/src/packs/safe-4337/utils.ts index 01a384a30..9f7111377 100644 --- a/packages/relay-kit/src/packs/safe-4337/utils.ts +++ b/packages/relay-kit/src/packs/safe-4337/utils.ts @@ -115,7 +115,7 @@ export function calculateSafeUserOperationHash( export function userOperationToHexValues(userOperation: UserOperation) { const userOperationWithHexValues = { ...userOperation, - nonce: toHex(userOperation.nonce), + nonce: toHex(BigInt(userOperation.nonce)), callGasLimit: toHex(userOperation.callGasLimit), verificationGasLimit: toHex(userOperation.verificationGasLimit), preVerificationGas: toHex(userOperation.preVerificationGas), @@ -123,19 +123,6 @@ export function userOperationToHexValues(userOperation: UserOperation) { maxPriorityFeePerGas: toHex(userOperation.maxPriorityFeePerGas) } - const userOperationWithHexValuesEthers = { - ...userOperation, - nonce: ethers.toBeHex(userOperation.nonce), - callGasLimit: ethers.toBeHex(userOperation.callGasLimit), - verificationGasLimit: ethers.toBeHex(userOperation.verificationGasLimit), - preVerificationGas: ethers.toBeHex(userOperation.preVerificationGas), - maxFeePerGas: ethers.toBeHex(userOperation.maxFeePerGas), - maxPriorityFeePerGas: ethers.toBeHex(userOperation.maxPriorityFeePerGas) - } - - console.log(userOperationWithHexValues) - console.log(userOperationWithHexValuesEthers) - return userOperationWithHexValues } From 6a5278c91a7aab0e323f19a7149d05e79474b0dd Mon Sep 17 00:00:00 2001 From: Tim Schwarz <4171783+tmjssz@users.noreply.github.com> Date: Thu, 27 Jun 2024 15:01:05 +0200 Subject: [PATCH 05/85] relay-kit: Migrate 4337 bundler client to viem Use viem's `PublicClient` instead of ether's `JsonRpcProvider` --- .../src/packs/safe-4337/Safe4337Pack.test.ts | 77 ++++++++----- .../src/packs/safe-4337/Safe4337Pack.ts | 108 +++++++++--------- .../src/packs/safe-4337/constants.ts | 29 +++-- .../estimators/PimlicoFeeEstimator.test.ts | 22 ++-- .../estimators/PimlicoFeeEstimator.ts | 34 ++++-- .../packs/safe-4337/testing-utils/fixtures.ts | 10 +- .../relay-kit/src/packs/safe-4337/types.ts | 91 +++++++++++++-- .../relay-kit/src/packs/safe-4337/utils.ts | 30 +++-- .../src/packs/safe-4337/utils/entrypoint.ts | 5 +- playground/utils.ts | 2 +- 10 files changed, 272 insertions(+), 136 deletions(-) diff --git a/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.test.ts b/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.test.ts index c9f67d7f5..e55be36cb 100644 --- a/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.test.ts +++ b/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.test.ts @@ -22,16 +22,22 @@ const requestResponseMap = { [constants.RPC_4337_CALLS.ESTIMATE_USER_OPERATION_GAS]: fixtures.GAS_ESTIMATION, [constants.RPC_4337_CALLS.GET_USER_OPERATION_BY_HASH]: fixtures.USER_OPERATION_BY_HASH, [constants.RPC_4337_CALLS.GET_USER_OPERATION_RECEIPT]: fixtures.USER_OPERATION_RECEIPT, + [constants.RPC_4337_CALLS.SPONSOR_USER_OPERATION]: fixtures.SPONSORED_GAS_ESTIMATION, ['pimlico_getUserOperationGasPrice']: fixtures.USER_OPERATION_GAS_PRICE } -const sendMock = jest.fn(async (method: string) => { +const requestMock = jest.fn(async ({ method }: { method: keyof typeof requestResponseMap }) => { return requestResponseMap[method] }) +const readContractMock = jest.fn().mockResolvedValue(1n) + jest.mock('./utils', () => ({ ...jest.requireActual('./utils'), - getEip4337BundlerProvider: jest.fn(() => ({ send: sendMock })) + getEip4337BundlerProvider: jest.fn(() => ({ + request: requestMock, + readContract: readContractMock + })) })) let safe4337ModuleAddress: viem.Hash @@ -115,7 +121,9 @@ describe('Safe4337Pack', () => { const mockedUtils = jest.requireMock('./utils') mockedUtils.getEip4337BundlerProvider.mockImplementationOnce(() => ({ - send: jest.fn(async (method: string) => overridenMap[method]) + request: jest.fn( + async ({ method }: { method: keyof typeof overridenMap }) => overridenMap[method] + ) })) await expect( @@ -470,7 +478,7 @@ describe('Safe4337Pack', () => { safe: fixtures.SAFE_ADDRESS_v1_4_1, entryPoint: '0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789', initCode: '0x', - paymasterAndData: '0x0000000000325602a77416A16136FDafd04b299f', + paymasterAndData: '0x1405B3659a11a16459fc27Fa1925b60388C38Ce1', callData: viem.encodeFunctionData({ abi: constants.ABI, functionName: 'executeUserOp', @@ -482,12 +490,12 @@ describe('Safe4337Pack', () => { ] }), nonce: 1n, - callGasLimit: 150000n, + callGasLimit: 100000n, validAfter: 0, validUntil: 0, maxFeePerGas: 100000n, maxPriorityFeePerGas: 200000n, - verificationGasLimit: 150000n, + verificationGasLimit: 100000n, preVerificationGas: 100000n }) }) @@ -650,14 +658,24 @@ describe('Safe4337Pack', () => { let safeOperation = await safe4337Pack.createTransaction({ transactions: [transferUSDC] }) + expect(readContractMock).toHaveBeenCalledWith({ + address: constants.ENTRYPOINT_ADDRESS_V06, + abi: constants.ENTRYPOINT_ABI, + functionName: 'getNonce', + args: [fixtures.SAFE_ADDRESS_v1_4_1, 0n] + }) + safeOperation = await safe4337Pack.signSafeOperation(safeOperation) await safe4337Pack.executeTransaction({ executable: safeOperation }) - expect(sendMock).toHaveBeenCalledWith(constants.RPC_4337_CALLS.SEND_USER_OPERATION, [ - utils.userOperationToHexValues(safeOperation.toUserOperation()), - fixtures.ENTRYPOINTS[0] - ]) + expect(requestMock).toHaveBeenCalledWith({ + method: constants.RPC_4337_CALLS.SEND_USER_OPERATION, + params: [ + utils.userOperationToHexValues(safeOperation.toUserOperation()), + fixtures.ENTRYPOINTS[0] + ] + }) }) it('should allow to send a UserOperation to the bundler using a SafeOperationResponse object from the api', async () => { @@ -669,24 +687,27 @@ describe('Safe4337Pack', () => { await safe4337Pack.executeTransaction({ executable: fixtures.SAFE_OPERATION_RESPONSE }) - expect(sendMock).toHaveBeenCalledWith(constants.RPC_4337_CALLS.SEND_USER_OPERATION, [ - utils.userOperationToHexValues({ - sender: '0xE322e721bCe76cE7FCf3A475f139A9314571ad3D', - nonce: '3', - initCode: '0x', - callData: - '0x7bb37428000000000000000000000000e322e721bce76ce7fcf3a475f139a9314571ad3d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', - callGasLimit: 122497n, - verificationGasLimit: 123498n, - preVerificationGas: 50705n, - maxFeePerGas: 105183831060n, - maxPriorityFeePerGas: 1380000000n, - paymasterAndData: '0x', - signature: - '0x000000000000000000000000cb28e74375889e400a4d8aca46b8c59e1cf8825e373c26fa99c2fd7c078080e64fe30eaf1125257bdfe0b358b5caef68aa0420478145f52decc8e74c979d43ab1d' - }), - fixtures.ENTRYPOINTS[0] - ]) + expect(requestMock).toHaveBeenCalledWith({ + method: constants.RPC_4337_CALLS.SEND_USER_OPERATION, + params: [ + utils.userOperationToHexValues({ + sender: '0xE322e721bCe76cE7FCf3A475f139A9314571ad3D', + nonce: '3', + initCode: '0x', + callData: + '0x7bb37428000000000000000000000000e322e721bce76ce7fcf3a475f139a9314571ad3d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + callGasLimit: 122497n, + verificationGasLimit: 123498n, + preVerificationGas: 50705n, + maxFeePerGas: 105183831060n, + maxPriorityFeePerGas: 1380000000n, + paymasterAndData: '0x', + signature: + '0x000000000000000000000000cb28e74375889e400a4d8aca46b8c59e1cf8825e373c26fa99c2fd7c078080e64fe30eaf1125257bdfe0b358b5caef68aa0420478145f52decc8e74c979d43ab1d' + }), + fixtures.ENTRYPOINTS[0] + ] + }) }) it('should return a UserOperation based on a userOpHash', async () => { diff --git a/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.ts b/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.ts index 449a1f102..314206360 100644 --- a/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.ts +++ b/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.ts @@ -1,5 +1,4 @@ -import { ethers } from 'ethers' -import { Hash, encodeFunctionData, zeroAddress } from 'viem' +import { Address, Hash, encodeFunctionData, zeroAddress } from 'viem' import semverSatisfies from 'semver/functions/satisfies' import Safe, { EthSafeSignature, @@ -31,13 +30,15 @@ import { Safe4337Options, UserOperationReceipt, UserOperationWithPayload, - PaymasterOptions + PaymasterOptions, + BundlerClient } from './types' import { ABI, DEFAULT_SAFE_VERSION, DEFAULT_SAFE_MODULES_VERSION, - RPC_4337_CALLS + RPC_4337_CALLS, + ENTRYPOINT_ABI } from './constants' import { addDummySignature, @@ -73,10 +74,10 @@ export class Safe4337Pack extends RelayKitBasePack<{ }> { #BUNDLER_URL: string - #ENTRYPOINT_ADDRESS: string - #SAFE_4337_MODULE_ADDRESS: Hash = '0x' + #ENTRYPOINT_ADDRESS: Address + #SAFE_4337_MODULE_ADDRESS: Address = '0x' - #bundlerClient: ethers.JsonRpcProvider + #bundlerClient: BundlerClient #chainId: bigint @@ -120,7 +121,7 @@ export class Safe4337Pack extends RelayKitBasePack<{ const { provider, signer, options, bundlerUrl, customContracts, paymasterOptions } = initOptions let protocolKit: Safe const bundlerClient = getEip4337BundlerProvider(bundlerUrl) - const chainId = await bundlerClient.send(RPC_4337_CALLS.CHAIN_ID, []) + const chainId = await bundlerClient.request({ method: RPC_4337_CALLS.CHAIN_ID }) let addModulesLibAddress = customContracts?.addModulesLibAddress const network = parseInt(chainId, 16).toString() @@ -139,7 +140,7 @@ export class Safe4337Pack extends RelayKitBasePack<{ version: safeModulesVersion, network }) - addModulesLibAddress = addModulesDeployment?.networkAddresses[network] + addModulesLibAddress = addModulesDeployment?.networkAddresses[network] as Address | undefined } let safe4337ModuleAddress = customContracts?.safe4337ModuleAddress @@ -250,7 +251,7 @@ export class Safe4337Pack extends RelayKitBasePack<{ safeVersion: options.safeVersion || DEFAULT_SAFE_VERSION }) - deploymentTo = await multiSendContract.getAddress() + deploymentTo = (await multiSendContract.getAddress()) as Address deploymentData = batchData } @@ -276,7 +277,7 @@ export class Safe4337Pack extends RelayKitBasePack<{ }) } - let selectedEntryPoint + let selectedEntryPoint: Address | undefined if (customContracts?.entryPointAddress) { const requiredSafeModulesVersion = entryPointToSafeModules(customContracts?.entryPointAddress) @@ -287,16 +288,15 @@ export class Safe4337Pack extends RelayKitBasePack<{ selectedEntryPoint = customContracts?.entryPointAddress } else { - const supportedEntryPoints = await bundlerClient.send( - RPC_4337_CALLS.SUPPORTED_ENTRY_POINTS, - [] - ) + const supportedEntryPoints = await bundlerClient.request({ + method: RPC_4337_CALLS.SUPPORTED_ENTRY_POINTS + }) if (!supportedEntryPoints.length) { throw new Error('No entrypoint provided or available through the bundler') } - selectedEntryPoint = supportedEntryPoints.find((entryPoint: string) => { + selectedEntryPoint = supportedEntryPoints.find((entryPoint) => { const requiredSafeModulesVersion = entryPointToSafeModules(entryPoint) return semverSatisfies(safeModulesVersion, requiredSafeModulesVersion) }) @@ -342,15 +342,15 @@ export class Safe4337Pack extends RelayKitBasePack<{ safeOperation.addEstimations(setupEstimationData) } - const estimateUserOperationGas = await this.#bundlerClient.send( - RPC_4337_CALLS.ESTIMATE_USER_OPERATION_GAS, - [ + const estimateUserOperationGas = await this.#bundlerClient.request({ + method: RPC_4337_CALLS.ESTIMATE_USER_OPERATION_GAS, + params: [ userOperationToHexValues( addDummySignature(safeOperation.toUserOperation(), await this.protocolKit.getOwners()) ), this.#ENTRYPOINT_ADDRESS ] - ) + }) if (estimateUserOperationGas) { safeOperation.addEstimations({ @@ -404,7 +404,7 @@ export class Safe4337Pack extends RelayKitBasePack<{ transactions, options = {} }: Safe4337CreateTransactionProps): Promise { - const safeAddress = await this.protocolKit.getAddress() + const safeAddress = (await this.protocolKit.getAddress()) as Address const nonce = await this.#getSafeNonceFromEntrypoint(safeAddress) const { amountToApprove, validUntil, validAfter, feeEstimator } = options @@ -596,9 +596,9 @@ export class Safe4337Pack extends RelayKitBasePack<{ * @param {EthSafeOperation | SafeOperationResponse} props.executable - The SafeOperation to execute. It can be: * - A response from the API (Tx Service) * - An instance of EthSafeOperation - * @return {Promise} The user operation hash. + * @return {Promise} The user operation hash. */ - async executeTransaction({ executable }: Safe4337ExecutableProps): Promise { + async executeTransaction({ executable }: Safe4337ExecutableProps): Promise { let safeOperation: EthSafeOperation if (isSafeOperationResponse(executable)) { @@ -609,30 +609,36 @@ export class Safe4337Pack extends RelayKitBasePack<{ const userOperation = safeOperation.toUserOperation() - return this.#bundlerClient.send(RPC_4337_CALLS.SEND_USER_OPERATION, [ - userOperationToHexValues(userOperation), - this.#ENTRYPOINT_ADDRESS - ]) + return this.#bundlerClient.request({ + method: RPC_4337_CALLS.SEND_USER_OPERATION, + params: [userOperationToHexValues(userOperation), this.#ENTRYPOINT_ADDRESS] + }) } /** * Return a UserOperation based on a hash (userOpHash) returned by eth_sendUserOperation * - * @param {string} userOpHash - The hash of the user operation to fetch. Returned from the #sendUserOperation method + * @param {Hash} userOpHash - The hash of the user operation to fetch. Returned from the #sendUserOperation method * @returns {UserOperation} - null in case the UserOperation is not yet included in a block, or a full UserOperation, with the addition of entryPoint, blockNumber, blockHash and transactionHash */ - async getUserOperationByHash(userOpHash: string): Promise { - return this.#bundlerClient.send(RPC_4337_CALLS.GET_USER_OPERATION_BY_HASH, [userOpHash]) + async getUserOperationByHash(userOpHash: Hash): Promise { + return this.#bundlerClient.request({ + method: RPC_4337_CALLS.GET_USER_OPERATION_BY_HASH, + params: [userOpHash] + }) } /** * Return a UserOperation receipt based on a hash (userOpHash) returned by eth_sendUserOperation * - * @param {string} userOpHash - The hash of the user operation to fetch. Returned from the #sendUserOperation method + * @param {Hash} userOpHash - The hash of the user operation to fetch. Returned from the #sendUserOperation method * @returns {UserOperationReceipt} - null in case the UserOperation is not yet included in a block, or UserOperationReceipt object */ - async getUserOperationReceipt(userOpHash: string): Promise { - return this.#bundlerClient.send(RPC_4337_CALLS.GET_USER_OPERATION_RECEIPT, [userOpHash]) + async getUserOperationReceipt(userOpHash: Hash): Promise { + return this.#bundlerClient.request({ + method: RPC_4337_CALLS.GET_USER_OPERATION_RECEIPT, + params: [userOpHash] + }) } /** @@ -642,7 +648,9 @@ export class Safe4337Pack extends RelayKitBasePack<{ * @returns {string[]} - The supported entry points. */ async getSupportedEntryPoints(): Promise { - return this.#bundlerClient.send(RPC_4337_CALLS.SUPPORTED_ENTRY_POINTS, []) + return this.#bundlerClient.request({ + method: RPC_4337_CALLS.SUPPORTED_ENTRY_POINTS + }) } /** @@ -651,36 +659,22 @@ export class Safe4337Pack extends RelayKitBasePack<{ * @returns {string} - The chain id. */ async getChainId(): Promise { - return this.#bundlerClient.send(RPC_4337_CALLS.CHAIN_ID, []) + return this.#bundlerClient.request({ method: RPC_4337_CALLS.CHAIN_ID }) } /** * Gets account nonce from the bundler. * - * @param {string} safeAddress - Account address for which the nonce is to be fetched. + * @param {Address} safeAddress - Account address for which the nonce is to be fetched. * @returns {Promise} The Promise object will resolve to the account nonce. */ - async #getSafeNonceFromEntrypoint(safeAddress: string): Promise { - const abi = [ - { - inputs: [ - { name: 'sender', type: 'address' }, - { name: 'key', type: 'uint192' } - ], - name: 'getNonce', - outputs: [{ name: 'nonce', type: 'uint256' }], - stateMutability: 'view', - type: 'function' - } - ] - - const contract = new ethers.Contract( - this.#ENTRYPOINT_ADDRESS || '0x', - abi, - this.protocolKit.getSafeProvider().getExternalProvider() - ) - - const newNonce = await contract.getNonce(safeAddress, BigInt(0)) + async #getSafeNonceFromEntrypoint(safeAddress: Address): Promise { + const newNonce = await this.#bundlerClient.readContract({ + address: this.#ENTRYPOINT_ADDRESS || '0x', + abi: ENTRYPOINT_ABI, + functionName: 'getNonce', + args: [safeAddress, BigInt(0)] + }) return newNonce.toString() } diff --git a/packages/relay-kit/src/packs/safe-4337/constants.ts b/packages/relay-kit/src/packs/safe-4337/constants.ts index e267e13c1..07458e3f4 100644 --- a/packages/relay-kit/src/packs/safe-4337/constants.ts +++ b/packages/relay-kit/src/packs/safe-4337/constants.ts @@ -28,15 +28,28 @@ export const ABI = parseAbi([ 'function approve(address _spender, uint256 _value)' ]) +export const ENTRYPOINT_ABI = [ + { + inputs: [ + { name: 'sender', type: 'address' }, + { name: 'key', type: 'uint192' } + ], + name: 'getNonce', + outputs: [{ name: 'nonce', type: 'uint256' }], + stateMutability: 'view', + type: 'function' + } +] as const + export const ENTRYPOINT_ADDRESS_V06 = '0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789' export const ENTRYPOINT_ADDRESS_V07 = '0x0000000071727De22E5E9d8BAf0edAc6f37da032' -export const RPC_4337_CALLS = { - ESTIMATE_USER_OPERATION_GAS: 'eth_estimateUserOperationGas', - SEND_USER_OPERATION: 'eth_sendUserOperation', - GET_USER_OPERATION_BY_HASH: 'eth_getUserOperationByHash', - GET_USER_OPERATION_RECEIPT: 'eth_getUserOperationReceipt', - SUPPORTED_ENTRY_POINTS: 'eth_supportedEntryPoints', - CHAIN_ID: 'eth_chainId', - SPONSOR_USER_OPERATION: 'pm_sponsorUserOperation' +export enum RPC_4337_CALLS { + ESTIMATE_USER_OPERATION_GAS = 'eth_estimateUserOperationGas', + SEND_USER_OPERATION = 'eth_sendUserOperation', + GET_USER_OPERATION_BY_HASH = 'eth_getUserOperationByHash', + GET_USER_OPERATION_RECEIPT = 'eth_getUserOperationReceipt', + SUPPORTED_ENTRY_POINTS = 'eth_supportedEntryPoints', + CHAIN_ID = 'eth_chainId', + SPONSOR_USER_OPERATION = 'pm_sponsorUserOperation' } diff --git a/packages/relay-kit/src/packs/safe-4337/estimators/PimlicoFeeEstimator.test.ts b/packages/relay-kit/src/packs/safe-4337/estimators/PimlicoFeeEstimator.test.ts index 3d0dcf4f7..5335b86dd 100644 --- a/packages/relay-kit/src/packs/safe-4337/estimators/PimlicoFeeEstimator.test.ts +++ b/packages/relay-kit/src/packs/safe-4337/estimators/PimlicoFeeEstimator.test.ts @@ -5,7 +5,7 @@ import * as constants from '../constants' jest.mock('../utils', () => ({ ...jest.requireActual('../utils'), getEip4337BundlerProvider: () => ({ - send: async (method: string) => { + request: async ({ method }: { method: string }) => { switch (method) { case constants.RPC_4337_CALLS.SPONSOR_USER_OPERATION: return fixtures.SPONSORED_GAS_ESTIMATION @@ -35,16 +35,18 @@ describe('PimlicoFeeEstimator', () => { expect(sponsoredGasEstimation).toEqual(fixtures.USER_OPERATION_GAS_PRICE.fast) }) - // TODO: This tests breaks because of the BigInt serialization and requires further investigation - // it('should enable to adjust the gas estimation', async () => { - // const sponsoredGasEstimation = await estimator.adjustEstimation({ - // bundlerUrl: fixtures.BUNDLER_URL, - // userOperation: fixtures.USER_OPERATION, - // entryPoint: fixtures.ENTRYPOINTS[0] - // }) + it('should enable to adjust the gas estimation', async () => { + const sponsoredGasEstimation = await estimator.adjustEstimation({ + bundlerUrl: fixtures.BUNDLER_URL, + userOperation: fixtures.USER_OPERATION, + entryPoint: fixtures.ENTRYPOINTS[0] + }) - // expect(sponsoredGasEstimation).toEqual({ verificationGasLimit: 41_528n }) - // }) + expect(sponsoredGasEstimation).toEqual({ + verificationGasLimit: 124_584n, + callGasLimit: 181_176n + }) + }) it('should get the paymaster estimation', async () => { const paymasterGasEstimation = await estimator.getPaymasterEstimation({ diff --git a/packages/relay-kit/src/packs/safe-4337/estimators/PimlicoFeeEstimator.ts b/packages/relay-kit/src/packs/safe-4337/estimators/PimlicoFeeEstimator.ts index f00932f43..15255a049 100644 --- a/packages/relay-kit/src/packs/safe-4337/estimators/PimlicoFeeEstimator.ts +++ b/packages/relay-kit/src/packs/safe-4337/estimators/PimlicoFeeEstimator.ts @@ -1,6 +1,6 @@ -import { ethers } from 'ethers' import { EstimateGasData } from '@safe-global/safe-core-sdk-types' import { + BundlerClient, EstimateFeeFunctionProps, EstimateSponsoredFeeFunctionProps, EstimateSponsoredGasData, @@ -34,20 +34,34 @@ export class PimlicoFeeEstimator implements IFeeEstimator { }: EstimateSponsoredFeeFunctionProps): Promise { const paymasterClient = getEip4337BundlerProvider(paymasterUrl) - const params = sponsorshipPolicyId - ? [userOperationToHexValues(userOperation), entryPoint, { sponsorshipPolicyId }] - : [userOperationToHexValues(userOperation), entryPoint] + const { paymasterAndData, callGasLimit, verificationGasLimit, preVerificationGas } = + await paymasterClient.request({ + method: RPC_4337_CALLS.SPONSOR_USER_OPERATION, + params: sponsorshipPolicyId + ? [userOperationToHexValues(userOperation), entryPoint, { sponsorshipPolicyId }] + : [userOperationToHexValues(userOperation), entryPoint] + }) - const gasEstimate = await paymasterClient.send(RPC_4337_CALLS.SPONSOR_USER_OPERATION, params) - - return gasEstimate + return { + paymasterAndData, + callGasLimit: BigInt(callGasLimit), + verificationGasLimit: BigInt(verificationGasLimit), + preVerificationGas: BigInt(preVerificationGas) + } } async #getFeeData( - bundlerClient: ethers.JsonRpcProvider + bundlerClient: BundlerClient ): Promise> { - const { fast } = await bundlerClient.send('pimlico_getUserOperationGasPrice', []) + const { + fast: { maxFeePerGas, maxPriorityFeePerGas } + } = await bundlerClient.request({ + method: 'pimlico_getUserOperationGasPrice' + }) - return fast + return { + maxFeePerGas: BigInt(maxFeePerGas), + maxPriorityFeePerGas: BigInt(maxPriorityFeePerGas) + } } } diff --git a/packages/relay-kit/src/packs/safe-4337/testing-utils/fixtures.ts b/packages/relay-kit/src/packs/safe-4337/testing-utils/fixtures.ts index 9b9f3c016..ba63f9d53 100644 --- a/packages/relay-kit/src/packs/safe-4337/testing-utils/fixtures.ts +++ b/packages/relay-kit/src/packs/safe-4337/testing-utils/fixtures.ts @@ -20,7 +20,7 @@ export const PAYMASTER_URL = 'https://paymaster.url' export const USER_OPERATION_HASH = '0x3cb881d1969036174f38d636d22108d1d032145518b53104fc0b1e1296d2cc9c' -export const ENTRYPOINTS = [ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07] +export const ENTRYPOINTS = [ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07] as const export const USER_OPERATION_RECEIPT = { userOpHash: '0x3cb881d1969036174f38d636d22108d1d032145518b53104fc0b1e1296d2cc9c', @@ -89,9 +89,9 @@ export const USER_OPERATION_BY_HASH = { } export const GAS_ESTIMATION = { - verificationGasLimit: '0x186A0', - preVerificationGas: '0x186A0', - callGasLimit: '0x186A0' + verificationGasLimit: 100000n, + preVerificationGas: 100000n, + callGasLimit: 100000n } export const SAFE_OPERATION_RESPONSE = { @@ -140,5 +140,5 @@ export const SPONSORED_GAS_ESTIMATION = { } export const USER_OPERATION_GAS_PRICE = { - fast: { maxFeePerGas: '0x186A0', maxPriorityFeePerGas: '0x30D40' } + fast: { maxFeePerGas: 100000n, maxPriorityFeePerGas: 200000n } } diff --git a/packages/relay-kit/src/packs/safe-4337/types.ts b/packages/relay-kit/src/packs/safe-4337/types.ts index 2f13a595f..e1702c4de 100644 --- a/packages/relay-kit/src/packs/safe-4337/types.ts +++ b/packages/relay-kit/src/packs/safe-4337/types.ts @@ -1,4 +1,4 @@ -import { Hash } from 'viem' +import { Account, Address, Chain, Hash, Hex, PublicClient, PublicRpcSchema, Transport } from 'viem' import Safe, { SafeProviderConfig } from '@safe-global/protocol-kit' import { EstimateGasData, @@ -7,8 +7,8 @@ import { SafeVersion, UserOperation } from '@safe-global/safe-core-sdk-types' -import { ethers } from 'ethers' import EthSafeOperation from './SafeOperation' +import { RPC_4337_CALLS } from './constants' type ExistingSafeOptions = { safeAddress: string @@ -36,9 +36,9 @@ export type Safe4337InitOptions = { bundlerUrl: string safeModulesVersion?: string customContracts?: { - entryPointAddress?: string - safe4337ModuleAddress?: Hash - addModulesLibAddress?: string + entryPointAddress?: Address + safe4337ModuleAddress?: Address + addModulesLibAddress?: Address } options: ExistingSafeOptions | PredictedSafeOptions paymasterOptions?: PaymasterOptions @@ -49,9 +49,9 @@ export type Safe4337Options = { protocolKit: Safe bundlerUrl: string paymasterOptions?: PaymasterOptions - bundlerClient: ethers.JsonRpcProvider - entryPointAddress: string - safe4337ModuleAddress: Hash + bundlerClient: BundlerClient + entryPointAddress: Address + safe4337ModuleAddress: Address } export type Safe4337CreateTransactionProps = { @@ -153,3 +153,78 @@ export type EstimateFeeProps = { safeOperation: EthSafeOperation feeEstimator?: IFeeEstimator } + +type UserOperationStringValues = Omit< + UserOperation, + | 'callGasLimit' + | 'verificationGasLimit' + | 'preVerificationGas' + | 'maxFeePerGas' + | 'maxPriorityFeePerGas' +> & { + callGasLimit: string + verificationGasLimit: string + preVerificationGas: string + maxFeePerGas: string + maxPriorityFeePerGas: string +} + +export type PimlicoCustomRpcSchema = [ + { + Method: 'pimlico_getUserOperationGasPrice' + Parameters: never + ReturnType: { + slow: { maxFeePerGas: string; maxPriorityFeePerGas: string } + standard: { maxFeePerGas: string; maxPriorityFeePerGas: string } + fast: { maxFeePerGas: string; maxPriorityFeePerGas: string } + } + }, + { + Method: 'pm_sponsorUserOperation' + Parameters: [UserOperationStringValues, string, { sponsorshipPolicyId?: string }?] + ReturnType: { + paymasterAndData: string + callGasLimit: string + verificationGasLimit: string + preVerificationGas: string + } + }, + { + Method: RPC_4337_CALLS.SUPPORTED_ENTRY_POINTS + Parameters: never + ReturnType: Hex[] + }, + { + Method: RPC_4337_CALLS.ESTIMATE_USER_OPERATION_GAS + Parameters: [UserOperationStringValues, string] + ReturnType: { callGasLimit: string; verificationGasLimit: string; preVerificationGas: string } + }, + { + Method: RPC_4337_CALLS.SEND_USER_OPERATION + Parameters: [UserOperationStringValues, string] + ReturnType: Hex + }, + { + Method: RPC_4337_CALLS.GET_USER_OPERATION_BY_HASH + Parameters: [Hash] + ReturnType: { + userOperation: UserOperation + entryPoint: Address + transactionHash: Hash + blockHash: Hash + blockNumber: string + } + }, + { + Method: RPC_4337_CALLS.GET_USER_OPERATION_RECEIPT + Parameters: [Hash] + ReturnType: UserOperationReceipt + } +] + +export type BundlerClient = PublicClient< + Transport, + Chain | undefined, + Account | undefined, + [...PimlicoCustomRpcSchema, ...PublicRpcSchema] +> diff --git a/packages/relay-kit/src/packs/safe-4337/utils.ts b/packages/relay-kit/src/packs/safe-4337/utils.ts index 9f7111377..106463c6e 100644 --- a/packages/relay-kit/src/packs/safe-4337/utils.ts +++ b/packages/relay-kit/src/packs/safe-4337/utils.ts @@ -1,4 +1,14 @@ -import { Hash, encodeFunctionData, encodePacked, hashTypedData, toHex } from 'viem' +import { + Hash, + PublicRpcSchema, + createPublicClient, + encodeFunctionData, + encodePacked, + hashTypedData, + http, + rpcSchema, + toHex +} from 'viem' import { SafeUserOperation, OperationType, @@ -12,18 +22,19 @@ import { encodeMultiSendData, buildSignatureBytes } from '@safe-global/protocol-kit' -import { ethers } from 'ethers' import { ABI, EIP712_SAFE_OPERATION_TYPE } from './constants' +import { BundlerClient, PimlicoCustomRpcSchema } from './types' /** * Gets the EIP-4337 bundler provider. * * @param {string} bundlerUrl The EIP-4337 bundler URL. - * @return {Provider} The EIP-4337 bundler provider. + * @return {BundlerClient} The EIP-4337 bundler provider. */ -export function getEip4337BundlerProvider(bundlerUrl: string): ethers.JsonRpcProvider { - const provider = new ethers.JsonRpcProvider(bundlerUrl, undefined, { - batchMaxCount: 1 +export function getEip4337BundlerProvider(bundlerUrl: string): BundlerClient { + const provider = createPublicClient({ + transport: http(bundlerUrl), + rpcSchema: rpcSchema<[...PimlicoCustomRpcSchema, ...PublicRpcSchema]>() }) return provider @@ -42,7 +53,12 @@ export async function signSafeOp( safeProvider: SafeProvider, safe4337ModuleAddress: Hash ): Promise { - const signer = (await safeProvider.getExternalSigner()) as ethers.Signer + const signer = await safeProvider.getExternalSigner() + + if (!signer) { + throw new Error('No signer found') + } + const chainId = await safeProvider.getChainId() const signerAddress = await signer.getAddress() const signature = await signer.signTypedData( diff --git a/packages/relay-kit/src/packs/safe-4337/utils/entrypoint.ts b/packages/relay-kit/src/packs/safe-4337/utils/entrypoint.ts index a61a48e30..e3d472504 100644 --- a/packages/relay-kit/src/packs/safe-4337/utils/entrypoint.ts +++ b/packages/relay-kit/src/packs/safe-4337/utils/entrypoint.ts @@ -1,3 +1,4 @@ +import { Address } from 'viem' import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from '../constants' const EQ_0_2_0 = '0.2.0' @@ -8,8 +9,8 @@ export function sameString(str1: string, str2: string): boolean { return str1.toLowerCase() === str2.toLowerCase() } -export function entryPointToSafeModules(entryPoint: string): string { - const moduleVersionToEntryPoint: Record = { +export function entryPointToSafeModules(entryPoint: Address) { + const moduleVersionToEntryPoint: Record = { [ENTRYPOINT_ADDRESS_V06]: EQ_0_2_0, [ENTRYPOINT_ADDRESS_V07]: EQ_OR_GT_0_3_0 } diff --git a/playground/utils.ts b/playground/utils.ts index d80ea62c8..2d7dfb166 100644 --- a/playground/utils.ts +++ b/playground/utils.ts @@ -5,7 +5,7 @@ import { generateTransferCallData } from '@safe-global/relay-kit/src/packs/safe- import { GetSafeOperationListResponse } from '@safe-global/api-kit' export async function waitForOperationToFinish( - userOperationHash: string, + userOperationHash: Hash, chainName: string, safe4337Pack: Safe4337Pack ) { From c0403177de5c76f8772d9ce745808aaf50f35031 Mon Sep 17 00:00:00 2001 From: Tim Schwarz <4171783+tmjssz@users.noreply.github.com> Date: Thu, 27 Jun 2024 15:01:28 +0200 Subject: [PATCH 06/85] relay-kit: Remove `ethers` dependency --- packages/relay-kit/package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/relay-kit/package.json b/packages/relay-kit/package.json index 8ff3ae872..4f857ce6e 100644 --- a/packages/relay-kit/package.json +++ b/packages/relay-kit/package.json @@ -42,7 +42,6 @@ "@safe-global/protocol-kit": "^4.0.2", "@safe-global/safe-core-sdk-types": "^5.0.2", "@safe-global/safe-modules-deployments": "^2.1.1", - "ethers": "^6.13.1", "viem": "^2.16.1" } } From 7e0bd8e6dde23a88e936183695842fae386283f7 Mon Sep 17 00:00:00 2001 From: Tim Schwarz <4171783+tmjssz@users.noreply.github.com> Date: Tue, 2 Jul 2024 13:35:32 +0200 Subject: [PATCH 07/85] fix(api-kit): Adjust e1e tests to 4337 bundler client changes --- .../tests/e2e/addSafeOperation.test.ts | 60 ++++++++++++------- .../src/packs/safe-4337/SafeOperation.ts | 4 +- 2 files changed, 40 insertions(+), 24 deletions(-) diff --git a/packages/api-kit/tests/e2e/addSafeOperation.test.ts b/packages/api-kit/tests/e2e/addSafeOperation.test.ts index 420c21e76..d617e1f84 100644 --- a/packages/api-kit/tests/e2e/addSafeOperation.test.ts +++ b/packages/api-kit/tests/e2e/addSafeOperation.test.ts @@ -1,15 +1,19 @@ import chai from 'chai' import chaiAsPromised from 'chai-as-promised' -import { ethers } from 'ethers' import sinon from 'sinon' import sinonChai from 'sinon-chai' import Safe from '@safe-global/protocol-kit' import SafeApiKit from '@safe-global/api-kit/index' +import { getAddSafeOperationProps } from '@safe-global/api-kit/utils/safeOperation' import { Safe4337Pack } from '@safe-global/relay-kit' +import * as viem from '@safe-global/relay-kit/node_modules/viem' import { generateTransferCallData } from '@safe-global/relay-kit/packs/safe-4337/testing-utils/helpers' -import { RPC_4337_CALLS } from '@safe-global/relay-kit/packs/safe-4337/constants' +import { + ENTRYPOINT_ABI, + ENTRYPOINT_ADDRESS_V06, + RPC_4337_CALLS +} from '@safe-global/relay-kit/packs/safe-4337/constants' import { getKits } from '../utils/setupKits' -import { getAddSafeOperationProps } from '@safe-global/api-kit/utils/safeOperation' chai.use(chaiAsPromised) chai.use(sinonChai) @@ -34,27 +38,24 @@ describe('addSafeOperation', () => { } // Setup mocks for the bundler client - const providerStub = sinon.stub(ethers.JsonRpcProvider.prototype, 'send') - - providerStub.withArgs(RPC_4337_CALLS.CHAIN_ID, []).returns(Promise.resolve('0xaa36a7')) - providerStub - .withArgs(RPC_4337_CALLS.SUPPORTED_ENTRY_POINTS, []) - .returns(Promise.resolve(['0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789'])) - providerStub - .withArgs('pimlico_getUserOperationGasPrice', []) - .returns( - Promise.resolve({ fast: { maxFeePerGas: '0x3b9aca00', maxPriorityFeePerGas: '0x3b9aca00' } }) - ) - providerStub.withArgs(RPC_4337_CALLS.ESTIMATE_USER_OPERATION_GAS, sinon.match.any).returns( - Promise.resolve({ - preVerificationGas: BigInt(Date.now()), - callGasLimit: BigInt(Date.now()), - verificationGasLimit: BigInt(Date.now()) - }) + const requestStub = sinon.stub() + + sinon.stub(viem, 'createPublicClient').get( + () => () => + ({ + request: requestStub, + readContract: sinon + .stub() + .withArgs({ + address: ENTRYPOINT_ADDRESS_V06, + abi: ENTRYPOINT_ABI, + functionName: 'getNonce', + args: [SAFE_ADDRESS, BigInt(0)] + }) + .resolves(123n) + }) as unknown as viem.PublicClient ) - providerStub.callThrough() - before(async () => { ;({ safeApiKit, protocolKit } = await getKits({ safeAddress: SAFE_ADDRESS, @@ -62,6 +63,21 @@ describe('addSafeOperation', () => { txServiceUrl: TX_SERVICE_URL })) + requestStub.withArgs({ method: RPC_4337_CALLS.CHAIN_ID }).resolves('0xaa36a7') + requestStub + .withArgs({ method: RPC_4337_CALLS.SUPPORTED_ENTRY_POINTS }) + .resolves([ENTRYPOINT_ADDRESS_V06]) + requestStub + .withArgs({ method: 'pimlico_getUserOperationGasPrice' }) + .resolves({ fast: { maxFeePerGas: '0x3b9aca00', maxPriorityFeePerGas: '0x3b9aca00' } }) + requestStub + .withArgs({ method: RPC_4337_CALLS.ESTIMATE_USER_OPERATION_GAS, params: sinon.match.any }) + .resolves({ + preVerificationGas: BigInt(Date.now()), + callGasLimit: BigInt(Date.now()), + verificationGasLimit: BigInt(Date.now()) + }) + safe4337Pack = await Safe4337Pack.init({ provider: protocolKit.getSafeProvider().provider, signer: protocolKit.getSafeProvider().signer, diff --git a/packages/relay-kit/src/packs/safe-4337/SafeOperation.ts b/packages/relay-kit/src/packs/safe-4337/SafeOperation.ts index dc96da223..d98d656d2 100644 --- a/packages/relay-kit/src/packs/safe-4337/SafeOperation.ts +++ b/packages/relay-kit/src/packs/safe-4337/SafeOperation.ts @@ -1,4 +1,4 @@ -import { Hex, encodePacked, toHex } from 'viem' +import { Hash, Hex, encodePacked, toHex } from 'viem' import { EstimateGasData, SafeOperation, @@ -92,7 +92,7 @@ class EthSafeOperation implements SafeOperation { } getHash(): string { - return calculateSafeUserOperationHash(this.data, this.chainId, this.moduleAddress) + return calculateSafeUserOperationHash(this.data, this.chainId, this.moduleAddress as Hash) } } From e693167f9ca7368518ea729ed2f6600fa1620438 Mon Sep 17 00:00:00 2001 From: Tim Schwarz <4171783+tmjssz@users.noreply.github.com> Date: Tue, 2 Jul 2024 14:35:44 +0200 Subject: [PATCH 08/85] fix(api-kit): e2e test --- packages/api-kit/tests/e2e/getSafeOperationsByAddress.test.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/api-kit/tests/e2e/getSafeOperationsByAddress.test.ts b/packages/api-kit/tests/e2e/getSafeOperationsByAddress.test.ts index 71768425f..63d479d69 100644 --- a/packages/api-kit/tests/e2e/getSafeOperationsByAddress.test.ts +++ b/packages/api-kit/tests/e2e/getSafeOperationsByAddress.test.ts @@ -80,9 +80,7 @@ describe('getSafeOperationsByAddress', () => { chai.expect(response).to.have.property('count').greaterThan(1) chai.expect(response).to.have.property('results').to.be.an('array') chai.expect(response.results.length).to.be.lessThanOrEqual(3) - chai - .expect(response.results[0].safeOperationHash) - .to.be.eq('0xfbc38024f74946d9ec31e0c8658dd65e335c6e57c14575250787ec5fb270c08a') + chai.expect(response.results).to.be.deep.equal(safeOperations.slice(0, 3)) }) it('should get all SafeOperations excluding the first one with offset = 1', async () => { From 92a62b79cbb98cc13003f45d2916dd5a1f5e81fd Mon Sep 17 00:00:00 2001 From: Tim Schwarz <4171783+tmjssz@users.noreply.github.com> Date: Tue, 2 Jul 2024 15:40:59 +0200 Subject: [PATCH 09/85] Revert uses of `Hash`, `Hex` + `Address` types from viem in interfaces To avoid breaking changes we keep regular `string` types for now and do type casting whenever necessary for calling viem's functions. --- .../src/utils/transactions/utils.ts | 3 +- .../src/packs/safe-4337/Safe4337Pack.test.ts | 6 +-- .../src/packs/safe-4337/Safe4337Pack.ts | 50 +++++++++---------- .../src/packs/safe-4337/SafeOperation.test.ts | 4 +- .../src/packs/safe-4337/SafeOperation.ts | 10 ++-- .../packs/safe-4337/testing-utils/helpers.ts | 6 +-- .../relay-kit/src/packs/safe-4337/types.ts | 12 ++--- .../relay-kit/src/packs/safe-4337/utils.ts | 19 +++---- .../usdc-transfer-4337-counterfactual.ts | 5 +- .../deploy-and-execute-transaction.ts | 4 +- playground/utils.ts | 5 +- 11 files changed, 59 insertions(+), 65 deletions(-) diff --git a/packages/protocol-kit/src/utils/transactions/utils.ts b/packages/protocol-kit/src/utils/transactions/utils.ts index 4ea1477e0..e5657a4d5 100644 --- a/packages/protocol-kit/src/utils/transactions/utils.ts +++ b/packages/protocol-kit/src/utils/transactions/utils.ts @@ -1,4 +1,3 @@ -import { Hash } from 'viem' import { ethers, Interface, getBytes, solidityPacked as solidityPack } from 'ethers' import SafeProvider from '@safe-global/protocol-kit/SafeProvider' import { DEFAULT_SAFE_VERSION } from '@safe-global/protocol-kit/contracts/config' @@ -117,7 +116,7 @@ function encodeMetaTransaction(tx: MetaTransactionData): string { return encoded.slice(2) } -export function encodeMultiSendData(txs: MetaTransactionData[]): Hash { +export function encodeMultiSendData(txs: MetaTransactionData[]): string { return `0x${txs.map((tx) => encodeMetaTransaction(tx)).join('')}` } diff --git a/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.test.ts b/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.test.ts index e55be36cb..1d93bab48 100644 --- a/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.test.ts +++ b/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.test.ts @@ -314,7 +314,7 @@ describe('Safe4337Pack', () => { const multiSendData = protocolKit.encodeMultiSendData([ enable4337ModuleTransaction, approveToPaymasterTransaction - ]) + ]) as viem.Hash expect(encodeFunctionDataSpy).toHaveBeenNthCalledWith(4, { abi: constants.ABI, @@ -389,7 +389,7 @@ describe('Safe4337Pack', () => { viem.encodeFunctionData({ abi: constants.ABI, functionName: 'multiSend', - args: [protocolKit.encodeMultiSendData(transactions)] + args: [protocolKit.encodeMultiSendData(transactions) as viem.Hash] }), OperationType.DelegateCall ] @@ -566,7 +566,7 @@ describe('Safe4337Pack', () => { viem.encodeFunctionData({ abi: constants.ABI, functionName: 'multiSend', - args: [protocolKit.encodeMultiSendData(batch)] + args: [protocolKit.encodeMultiSendData(batch) as viem.Hash] }), OperationType.DelegateCall ] diff --git a/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.ts b/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.ts index 314206360..5ea87f5bb 100644 --- a/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.ts +++ b/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.ts @@ -74,8 +74,8 @@ export class Safe4337Pack extends RelayKitBasePack<{ }> { #BUNDLER_URL: string - #ENTRYPOINT_ADDRESS: Address - #SAFE_4337_MODULE_ADDRESS: Address = '0x' + #ENTRYPOINT_ADDRESS: string + #SAFE_4337_MODULE_ADDRESS: string = '0x' #bundlerClient: BundlerClient @@ -150,9 +150,7 @@ export class Safe4337Pack extends RelayKitBasePack<{ version: safeModulesVersion, network }) - safe4337ModuleAddress = safe4337ModuleDeployment?.networkAddresses[network] as - | Hash - | undefined + safe4337ModuleAddress = safe4337ModuleDeployment?.networkAddresses[network] } if (!addModulesLibAddress || !safe4337ModuleAddress) { @@ -205,7 +203,7 @@ export class Safe4337Pack extends RelayKitBasePack<{ let deploymentData = encodeFunctionData({ abi: ABI, functionName: 'enableModules', - args: [[safe4337ModuleAddress]] + args: [[safe4337ModuleAddress as Address]] }) const { isSponsored, paymasterTokenAddress } = paymasterOptions || {} @@ -222,7 +220,7 @@ export class Safe4337Pack extends RelayKitBasePack<{ data: encodeFunctionData({ abi: ABI, functionName: 'enableModules', - args: [[safe4337ModuleAddress]] + args: [[safe4337ModuleAddress as Address]] }), operation: OperationType.DelegateCall // DelegateCall required for enabling the 4337 module } @@ -232,7 +230,7 @@ export class Safe4337Pack extends RelayKitBasePack<{ data: encodeFunctionData({ abi: ABI, functionName: 'approve', - args: [paymasterAddress, amountToApprove] + args: [paymasterAddress as Address, amountToApprove] }), value: '0', operation: OperationType.Call // Call for approve @@ -243,7 +241,7 @@ export class Safe4337Pack extends RelayKitBasePack<{ const batchData = encodeFunctionData({ abi: ABI, functionName: 'multiSend', - args: [encodeMultiSendData(setupBatch)] + args: [encodeMultiSendData(setupBatch) as Hash] }) const multiSendContract = await getMultiSendContract({ @@ -277,10 +275,12 @@ export class Safe4337Pack extends RelayKitBasePack<{ }) } - let selectedEntryPoint: Address | undefined + let selectedEntryPoint if (customContracts?.entryPointAddress) { - const requiredSafeModulesVersion = entryPointToSafeModules(customContracts?.entryPointAddress) + const requiredSafeModulesVersion = entryPointToSafeModules( + customContracts?.entryPointAddress as Address + ) if (!semverSatisfies(safeModulesVersion, requiredSafeModulesVersion)) throw new Error( `The selected entrypoint ${customContracts?.entryPointAddress} is not compatible with version ${safeModulesVersion} of Safe modules` @@ -422,7 +422,7 @@ export class Safe4337Pack extends RelayKitBasePack<{ data: encodeFunctionData({ abi: ABI, functionName: 'approve', - args: [paymasterAddress, amountToApprove] + args: [paymasterAddress as Address, amountToApprove] }), value: '0', operation: OperationType.Call // Call for approve @@ -596,9 +596,9 @@ export class Safe4337Pack extends RelayKitBasePack<{ * @param {EthSafeOperation | SafeOperationResponse} props.executable - The SafeOperation to execute. It can be: * - A response from the API (Tx Service) * - An instance of EthSafeOperation - * @return {Promise} The user operation hash. + * @return {Promise} The user operation hash. */ - async executeTransaction({ executable }: Safe4337ExecutableProps): Promise { + async executeTransaction({ executable }: Safe4337ExecutableProps): Promise { let safeOperation: EthSafeOperation if (isSafeOperationResponse(executable)) { @@ -618,26 +618,26 @@ export class Safe4337Pack extends RelayKitBasePack<{ /** * Return a UserOperation based on a hash (userOpHash) returned by eth_sendUserOperation * - * @param {Hash} userOpHash - The hash of the user operation to fetch. Returned from the #sendUserOperation method + * @param {string} userOpHash - The hash of the user operation to fetch. Returned from the #sendUserOperation method * @returns {UserOperation} - null in case the UserOperation is not yet included in a block, or a full UserOperation, with the addition of entryPoint, blockNumber, blockHash and transactionHash */ - async getUserOperationByHash(userOpHash: Hash): Promise { + async getUserOperationByHash(userOpHash: string): Promise { return this.#bundlerClient.request({ method: RPC_4337_CALLS.GET_USER_OPERATION_BY_HASH, - params: [userOpHash] + params: [userOpHash as Hash] }) } /** * Return a UserOperation receipt based on a hash (userOpHash) returned by eth_sendUserOperation * - * @param {Hash} userOpHash - The hash of the user operation to fetch. Returned from the #sendUserOperation method + * @param {string} userOpHash - The hash of the user operation to fetch. Returned from the #sendUserOperation method * @returns {UserOperationReceipt} - null in case the UserOperation is not yet included in a block, or UserOperationReceipt object */ - async getUserOperationReceipt(userOpHash: Hash): Promise { + async getUserOperationReceipt(userOpHash: string): Promise { return this.#bundlerClient.request({ method: RPC_4337_CALLS.GET_USER_OPERATION_RECEIPT, - params: [userOpHash] + params: [userOpHash as Hash] }) } @@ -665,15 +665,15 @@ export class Safe4337Pack extends RelayKitBasePack<{ /** * Gets account nonce from the bundler. * - * @param {Address} safeAddress - Account address for which the nonce is to be fetched. + * @param {string} safeAddress - Account address for which the nonce is to be fetched. * @returns {Promise} The Promise object will resolve to the account nonce. */ - async #getSafeNonceFromEntrypoint(safeAddress: Address): Promise { + async #getSafeNonceFromEntrypoint(safeAddress: string): Promise { const newNonce = await this.#bundlerClient.readContract({ - address: this.#ENTRYPOINT_ADDRESS || '0x', + address: (this.#ENTRYPOINT_ADDRESS as Address) || '0x', abi: ENTRYPOINT_ABI, functionName: 'getNonce', - args: [safeAddress, BigInt(0)] + args: [safeAddress as Address, BigInt(0)] }) return newNonce.toString() @@ -685,7 +685,7 @@ export class Safe4337Pack extends RelayKitBasePack<{ * @param {MetaTransactionData} transaction - The transaction data to encode. * @return {string} The encoded call data string. */ - #encodeExecuteUserOpCallData(transaction: MetaTransactionData): Hash { + #encodeExecuteUserOpCallData(transaction: MetaTransactionData): string { return encodeFunctionData({ abi: ABI, functionName: 'executeUserOp', diff --git a/packages/relay-kit/src/packs/safe-4337/SafeOperation.test.ts b/packages/relay-kit/src/packs/safe-4337/SafeOperation.test.ts index ebd4354fc..9ea2645dd 100644 --- a/packages/relay-kit/src/packs/safe-4337/SafeOperation.test.ts +++ b/packages/relay-kit/src/packs/safe-4337/SafeOperation.test.ts @@ -1,4 +1,4 @@ -import { encodePacked } from 'viem' +import { Hex, encodePacked } from 'viem' import { EthSafeSignature } from '@safe-global/protocol-kit' import EthSafeOperation from './SafeOperation' import * as fixtures from './testing-utils/fixtures' @@ -120,7 +120,7 @@ describe('SafeOperation', () => { [ safeOperation.data.validAfter, safeOperation.data.validUntil, - safeOperation.encodedSignatures() + safeOperation.encodedSignatures() as Hex ] ) }) diff --git a/packages/relay-kit/src/packs/safe-4337/SafeOperation.ts b/packages/relay-kit/src/packs/safe-4337/SafeOperation.ts index d98d656d2..eaec3b908 100644 --- a/packages/relay-kit/src/packs/safe-4337/SafeOperation.ts +++ b/packages/relay-kit/src/packs/safe-4337/SafeOperation.ts @@ -1,4 +1,4 @@ -import { Hash, Hex, encodePacked, toHex } from 'viem' +import { Address, Hex, encodePacked, toHex } from 'viem' import { EstimateGasData, SafeOperation, @@ -54,8 +54,8 @@ class EthSafeOperation implements SafeOperation { this.signatures.set(signature.signer.toLowerCase(), signature) } - encodedSignatures(): Hex { - return buildSignatureBytes(Array.from(this.signatures.values())) as Hex + encodedSignatures(): string { + return buildSignatureBytes(Array.from(this.signatures.values())) } addEstimations(estimations: EstimateGasData): void { @@ -86,13 +86,13 @@ class EthSafeOperation implements SafeOperation { paymasterAndData: this.data.paymasterAndData, signature: encodePacked( ['uint48', 'uint48', 'bytes'], - [this.data.validAfter, this.data.validUntil, this.encodedSignatures()] + [this.data.validAfter, this.data.validUntil, this.encodedSignatures() as Hex] ) } } getHash(): string { - return calculateSafeUserOperationHash(this.data, this.chainId, this.moduleAddress as Hash) + return calculateSafeUserOperationHash(this.data, this.chainId, this.moduleAddress as Address) } } diff --git a/packages/relay-kit/src/packs/safe-4337/testing-utils/helpers.ts b/packages/relay-kit/src/packs/safe-4337/testing-utils/helpers.ts index bfac57106..e44addd04 100644 --- a/packages/relay-kit/src/packs/safe-4337/testing-utils/helpers.ts +++ b/packages/relay-kit/src/packs/safe-4337/testing-utils/helpers.ts @@ -1,15 +1,15 @@ -import { Hash, encodeFunctionData, parseAbi } from 'viem' +import { Address, encodeFunctionData, parseAbi } from 'viem' import { Safe4337InitOptions } from '../types' import { Safe4337Pack } from '../Safe4337Pack' import * as fixtures from './fixtures' -export const generateTransferCallData = (to: Hash, value: bigint) => { +export const generateTransferCallData = (to: string, value: bigint) => { const functionAbi = parseAbi(['function transfer(address _to, uint256 _value) returns (bool)']) return encodeFunctionData({ abi: functionAbi, functionName: 'transfer', - args: [to, value] + args: [to as Address, value] }) } diff --git a/packages/relay-kit/src/packs/safe-4337/types.ts b/packages/relay-kit/src/packs/safe-4337/types.ts index e1702c4de..a1059f202 100644 --- a/packages/relay-kit/src/packs/safe-4337/types.ts +++ b/packages/relay-kit/src/packs/safe-4337/types.ts @@ -25,7 +25,7 @@ export type PaymasterOptions = { paymasterUrl?: string isSponsored?: boolean sponsorshipPolicyId?: string - paymasterAddress: Hash + paymasterAddress: string paymasterTokenAddress?: string amountToApprove?: bigint } @@ -36,9 +36,9 @@ export type Safe4337InitOptions = { bundlerUrl: string safeModulesVersion?: string customContracts?: { - entryPointAddress?: Address - safe4337ModuleAddress?: Address - addModulesLibAddress?: Address + entryPointAddress?: string + safe4337ModuleAddress?: string + addModulesLibAddress?: string } options: ExistingSafeOptions | PredictedSafeOptions paymasterOptions?: PaymasterOptions @@ -50,8 +50,8 @@ export type Safe4337Options = { bundlerUrl: string paymasterOptions?: PaymasterOptions bundlerClient: BundlerClient - entryPointAddress: Address - safe4337ModuleAddress: Address + entryPointAddress: string + safe4337ModuleAddress: string } export type Safe4337CreateTransactionProps = { diff --git a/packages/relay-kit/src/packs/safe-4337/utils.ts b/packages/relay-kit/src/packs/safe-4337/utils.ts index 106463c6e..54b164211 100644 --- a/packages/relay-kit/src/packs/safe-4337/utils.ts +++ b/packages/relay-kit/src/packs/safe-4337/utils.ts @@ -1,4 +1,5 @@ import { + Address, Hash, PublicRpcSchema, createPublicClient, @@ -45,13 +46,13 @@ export function getEip4337BundlerProvider(bundlerUrl: string): BundlerClient { * * @param {SafeUserOperation} safeUserOperation - Safe user operation to sign. * @param {SafeProvider} safeProvider - Safe provider. - * @param {Hash} safe4337ModuleAddress - Safe 4337 module address. + * @param {string} safe4337ModuleAddress - Safe 4337 module address. * @return {Promise} The SafeSignature object containing the data and the signatures. */ export async function signSafeOp( safeUserOperation: SafeUserOperation, safeProvider: SafeProvider, - safe4337ModuleAddress: Hash + safe4337ModuleAddress: string ): Promise { const signer = await safeProvider.getExternalSigner() @@ -84,16 +85,16 @@ export async function signSafeOp( * Encodes multi-send data from transactions batch. * * @param {MetaTransactionData[]} transactions - an array of transaction to to be encoded. - * @return {Hash} The encoded data string. + * @return {string} The encoded data string. */ -export function encodeMultiSendCallData(transactions: MetaTransactionData[]): Hash { +export function encodeMultiSendCallData(transactions: MetaTransactionData[]): string { return encodeFunctionData({ abi: ABI, functionName: 'multiSend', args: [ encodeMultiSendData( transactions.map((tx) => ({ ...tx, operation: tx.operation ?? OperationType.Call })) - ) + ) as Hash ] }) } @@ -103,18 +104,18 @@ export function encodeMultiSendCallData(transactions: MetaTransactionData[]): Ha * * @param {SafeUserOperation} safeUserOperation - The SafeUserOperation. * @param {bigint} chainId - The chain id. - * @param {Hash} safe4337ModuleAddress - The Safe 4337 module address. + * @param {string} safe4337ModuleAddress - The Safe 4337 module address. * @return {string} The hash of the safe operation. */ export function calculateSafeUserOperationHash( safeUserOperation: SafeUserOperation, chainId: bigint, - safe4337ModuleAddress: Hash -): Hash { + safe4337ModuleAddress: string +): string { return hashTypedData({ domain: { chainId: Number(chainId), - verifyingContract: safe4337ModuleAddress + verifyingContract: safe4337ModuleAddress as Address }, types: EIP712_SAFE_OPERATION_TYPE, primaryType: 'SafeOp', diff --git a/playground/relay-kit/usdc-transfer-4337-counterfactual.ts b/playground/relay-kit/usdc-transfer-4337-counterfactual.ts index 0386217bb..edaf237f5 100644 --- a/playground/relay-kit/usdc-transfer-4337-counterfactual.ts +++ b/playground/relay-kit/usdc-transfer-4337-counterfactual.ts @@ -1,4 +1,3 @@ -import { Hash } from 'viem' import { ethers } from 'ethers' import { Safe4337Pack } from '@safe-global/relay-kit' import { generateTransferCallData } from '@safe-global/relay-kit/src/packs/safe-4337/testing-utils/helpers' @@ -63,9 +62,7 @@ async function main() { console.log(`sending ${nativeTokenAmount} ETH...`) const ethersSigner = await safe4337Pack.protocolKit.getSafeProvider().getExternalSigner() - const signerAddress = (await safe4337Pack.protocolKit.getSafeProvider().getSignerAddress()) as - | Hash - | undefined + const signerAddress = await safe4337Pack.protocolKit.getSafeProvider().getSignerAddress() const ethersProvider = safe4337Pack.protocolKit.getSafeProvider().getExternalProvider() if (!ethersSigner || !signerAddress) { diff --git a/playground/safe-kit/deploy-and-execute-transaction.ts b/playground/safe-kit/deploy-and-execute-transaction.ts index 190db3ae3..b263f29d9 100644 --- a/playground/safe-kit/deploy-and-execute-transaction.ts +++ b/playground/safe-kit/deploy-and-execute-transaction.ts @@ -1,4 +1,3 @@ -import { Hash } from 'viem' import { createSafeClient } from '@safe-global/safe-kit' import { generateTransferCallData } from '@safe-global/relay-kit/src/packs/safe-4337/testing-utils/helpers' @@ -20,8 +19,7 @@ async function main() { } }) - const signerAddress = ((await safeClient.protocolKit.getSafeProvider().getSignerAddress()) || - '0x') as Hash + const signerAddress = (await safeClient.protocolKit.getSafeProvider().getSignerAddress()) || '0x' console.log( '-Safe Address:', diff --git a/playground/utils.ts b/playground/utils.ts index 2d7dfb166..069bf4daa 100644 --- a/playground/utils.ts +++ b/playground/utils.ts @@ -1,11 +1,10 @@ import { ethers } from 'ethers' -import { Hash } from 'viem' import { Safe4337Pack } from '@safe-global/relay-kit' import { generateTransferCallData } from '@safe-global/relay-kit/src/packs/safe-4337/testing-utils/helpers' import { GetSafeOperationListResponse } from '@safe-global/api-kit' export async function waitForOperationToFinish( - userOperationHash: Hash, + userOperationHash: string, chainName: string, safe4337Pack: Safe4337Pack ) { @@ -29,7 +28,7 @@ export async function waitForOperationToFinish( export async function transfer( signer: ethers.AbstractSigner, tokenAddress: string, - to: Hash, + to: string, amount: bigint ) { const transferEC20 = { From f554a93d4f3a3c6a105031877be99ce5e2c96903 Mon Sep 17 00:00:00 2001 From: Tim Schwarz <4171783+tmjssz@users.noreply.github.com> Date: Wed, 3 Jul 2024 17:06:00 +0200 Subject: [PATCH 10/85] api-kit: Migrate `signDelegate` to viem --- .../src/types/safeTransactionServiceTypes.ts | 8 ++++---- packages/api-kit/src/utils/signDelegate.ts | 18 ++++++++++++++---- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/packages/api-kit/src/types/safeTransactionServiceTypes.ts b/packages/api-kit/src/types/safeTransactionServiceTypes.ts index 5b2c5e604..3d3c67088 100644 --- a/packages/api-kit/src/types/safeTransactionServiceTypes.ts +++ b/packages/api-kit/src/types/safeTransactionServiceTypes.ts @@ -1,4 +1,4 @@ -import { Signer, TypedDataDomain, TypedDataField } from 'ethers' +import { TypedDataDomain, TypedDataParameter, WalletClient } from 'viem' import { SafeMultisigTransactionResponse, SafeTransactionData, @@ -77,14 +77,14 @@ export type AddSafeDelegateProps = { safeAddress?: string delegateAddress: string delegatorAddress: string - signer: Signer + signer: WalletClient label: string } export type DeleteSafeDelegateProps = { delegateAddress: string delegatorAddress: string - signer: Signer + signer: WalletClient } export type SafeDelegateResponse = { @@ -255,7 +255,7 @@ export type GetSafeMessageListProps = { export type EIP712TypedData = { domain: TypedDataDomain - types: TypedDataField + types: TypedDataParameter message: Record } diff --git a/packages/api-kit/src/utils/signDelegate.ts b/packages/api-kit/src/utils/signDelegate.ts index be75ca1e3..8c9b13613 100644 --- a/packages/api-kit/src/utils/signDelegate.ts +++ b/packages/api-kit/src/utils/signDelegate.ts @@ -1,10 +1,14 @@ -import { Signer } from 'ethers' +import { WalletClient } from 'viem' -export async function signDelegate(signer: Signer, delegateAddress: string, chainId: bigint) { +export async function signDelegate( + walletClient: WalletClient, + delegateAddress: string, + chainId: bigint +) { const domain = { name: 'Safe Transaction Service', version: '1.0', - chainId: chainId + chainId: Number(chainId) } const types = { @@ -16,5 +20,11 @@ export async function signDelegate(signer: Signer, delegateAddress: string, chai const totp = Math.floor(Date.now() / 1000 / 3600) - return signer.signTypedData(domain, types, { delegateAddress, totp }) + return walletClient.signTypedData({ + account: walletClient.account!.address, + domain, + types, + primaryType: 'Delegate', + message: { delegateAddress, totp } + }) } From d008d4fd0bb442bef3048afc6745bf7f4f01a903 Mon Sep 17 00:00:00 2001 From: Tim Schwarz <4171783+tmjssz@users.noreply.github.com> Date: Wed, 3 Jul 2024 17:22:58 +0200 Subject: [PATCH 11/85] auth-kit: Migrate to viem --- packages/auth-kit/jest.config.js | 3 ++- packages/auth-kit/package.json | 2 +- packages/auth-kit/setup.jest.ts | 3 +++ packages/auth-kit/src/AuthKitBasePack.ts | 16 +++++++--------- .../auth-kit/src/packs/safe-auth/SafeAuthPack.ts | 15 +++++++-------- packages/auth-kit/src/types.ts | 4 ++-- 6 files changed, 22 insertions(+), 21 deletions(-) create mode 100644 packages/auth-kit/setup.jest.ts diff --git a/packages/auth-kit/jest.config.js b/packages/auth-kit/jest.config.js index e96123e0d..b99ff1d06 100644 --- a/packages/auth-kit/jest.config.js +++ b/packages/auth-kit/jest.config.js @@ -8,7 +8,8 @@ const config = { moduleNameMapper: { '^@safe-global/protocol-kit/(.*)$': '/../protocol-kit/src/$1', '^@safe-global/auth-kit/(.*)$': '/src/$1' - } + }, + setupFiles: ['/setup.jest.ts'] } module.exports = config diff --git a/packages/auth-kit/package.json b/packages/auth-kit/package.json index 614408682..2551ab964 100644 --- a/packages/auth-kit/package.json +++ b/packages/auth-kit/package.json @@ -42,6 +42,6 @@ "@safe-global/api-kit": "^2.4.2", "@safe-global/protocol-kit": "^4.0.2", "@web3auth/safeauth-embed": "^0.0.0", - "ethers": "^6.13.1" + "viem": "^2.17.0" } } diff --git a/packages/auth-kit/setup.jest.ts b/packages/auth-kit/setup.jest.ts new file mode 100644 index 000000000..db3cb4975 --- /dev/null +++ b/packages/auth-kit/setup.jest.ts @@ -0,0 +1,3 @@ +import { TextEncoder, TextDecoder } from 'util' + +Object.assign(global, { TextDecoder, TextEncoder }) diff --git a/packages/auth-kit/src/AuthKitBasePack.ts b/packages/auth-kit/src/AuthKitBasePack.ts index 09a2641f3..5fcb2cdca 100644 --- a/packages/auth-kit/src/AuthKitBasePack.ts +++ b/packages/auth-kit/src/AuthKitBasePack.ts @@ -1,4 +1,4 @@ -import { ethers } from 'ethers' +import { createWalletClient, custom } from 'viem' import SafeApiKit from '@safe-global/api-kit' import type { AuthKitEthereumProvider, AuthKitSignInData } from './types' @@ -85,11 +85,10 @@ export abstract class AuthKitBasePack { throw new Error('Provider is not defined') } - const ethersProvider = new ethers.BrowserProvider(authKitProvider) + const client = createWalletClient({ transport: custom(authKitProvider) }) + const [address] = await client.getAddresses() - const signer = await ethersProvider.getSigner() - - return signer.getAddress() + return address } async getChainId(): Promise { @@ -99,11 +98,10 @@ export abstract class AuthKitBasePack { throw new Error('Provider is not defined') } - const ethersProvider = new ethers.BrowserProvider(authKitProvider) - - const networkDetails = await ethersProvider.getNetwork() + const client = createWalletClient({ transport: custom(authKitProvider) }) + const chainId = await client.getChainId() - return networkDetails.chainId + return BigInt(chainId) } /** diff --git a/packages/auth-kit/src/packs/safe-auth/SafeAuthPack.ts b/packages/auth-kit/src/packs/safe-auth/SafeAuthPack.ts index e524226d5..ca4a22108 100644 --- a/packages/auth-kit/src/packs/safe-auth/SafeAuthPack.ts +++ b/packages/auth-kit/src/packs/safe-auth/SafeAuthPack.ts @@ -1,4 +1,3 @@ -import { Eip1193Provider } from 'ethers' import SafeAuthEmbed from '@web3auth/safeauth-embed' import { TorusInPageProvider, WsEmbedParams } from '@web3auth/ws-embed' import { getErrorMessage } from '@safe-global/auth-kit/lib/errors' @@ -13,7 +12,7 @@ import { SafeAuthUserInfo } from './types' -import type { AuthKitSignInData } from '@safe-global/auth-kit/types' +import type { AuthKitEthereumProvider, AuthKitSignInData } from '@safe-global/auth-kit/types' import { CHAIN_CONFIG } from './constants' const SAFE_WALLET_SERVICES_URL = 'https://safe.web3auth.com' @@ -25,7 +24,7 @@ const WS_EMBED_NOT_INITIALIZED = 'SafeEmbed SDK is not initialized' */ export class SafeAuthPack extends AuthKitBasePack { safeAuthEmbed!: SafeAuthEmbed - #provider: Eip1193Provider | null + #provider: AuthKitEthereumProvider | null #config?: SafeAuthConfig /** @@ -72,7 +71,7 @@ export class SafeAuthPack extends AuthKitBasePack { } }) - this.#provider = this.safeAuthEmbed.provider + this.#provider = this.safeAuthEmbed.provider as AuthKitEthereumProvider } catch (e) { throw new Error(getErrorMessage(e)) } @@ -91,7 +90,7 @@ export class SafeAuthPack extends AuthKitBasePack { await this.safeAuthEmbed.login(options) - this.#provider = this.safeAuthEmbed.provider + this.#provider = this.safeAuthEmbed.provider as AuthKitEthereumProvider const eoa = await this.getAddress() const safes = await this.getSafes(this.#config?.txServiceUrl) @@ -101,10 +100,10 @@ export class SafeAuthPack extends AuthKitBasePack { /** * Get the provider returned by the Web3Auth WsEmbed - * @returns A EIP-1193 compatible provider. Can be wrapped with ethers or web3 + * @returns A EIP-1193 compatible provider. Can be wrapped with viem, ethers or web3 */ - getProvider(): Eip1193Provider | null { - return this.#provider as Eip1193Provider + getProvider(): AuthKitEthereumProvider | null { + return this.#provider } /** diff --git a/packages/auth-kit/src/types.ts b/packages/auth-kit/src/types.ts index 7f26b40b3..e9dfd568b 100644 --- a/packages/auth-kit/src/types.ts +++ b/packages/auth-kit/src/types.ts @@ -1,8 +1,8 @@ -import { Eip1193Provider } from 'ethers' +import { EIP1193Provider } from 'viem' // We want to use a specific auth-kit type and avoid to return external library types in the abstract base pack class // If we decide to change the external library, we will only need to change the type in this file -export type AuthKitEthereumProvider = Eip1193Provider +export type AuthKitEthereumProvider = EIP1193Provider export type AuthKitSignInData = { eoa: string From 56b294c39f75ca882d9961e9efd33591ed848eba Mon Sep 17 00:00:00 2001 From: Tim Schwarz <4171783+tmjssz@users.noreply.github.com> Date: Wed, 3 Jul 2024 17:24:47 +0200 Subject: [PATCH 12/85] auth-kit: Rename file to `jest.setup.ts` --- packages/auth-kit/jest.config.js | 2 +- packages/auth-kit/{setup.jest.ts => jest.setup.ts} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename packages/auth-kit/{setup.jest.ts => jest.setup.ts} (100%) diff --git a/packages/auth-kit/jest.config.js b/packages/auth-kit/jest.config.js index b99ff1d06..14ef1f454 100644 --- a/packages/auth-kit/jest.config.js +++ b/packages/auth-kit/jest.config.js @@ -9,7 +9,7 @@ const config = { '^@safe-global/protocol-kit/(.*)$': '/../protocol-kit/src/$1', '^@safe-global/auth-kit/(.*)$': '/src/$1' }, - setupFiles: ['/setup.jest.ts'] + setupFiles: ['/jest.setup.ts'] } module.exports = config diff --git a/packages/auth-kit/setup.jest.ts b/packages/auth-kit/jest.setup.ts similarity index 100% rename from packages/auth-kit/setup.jest.ts rename to packages/auth-kit/jest.setup.ts From da2b0967ed78be0f5193124ae95439b73c515226 Mon Sep 17 00:00:00 2001 From: Tim Schwarz <4171783+tmjssz@users.noreply.github.com> Date: Wed, 3 Jul 2024 17:31:36 +0200 Subject: [PATCH 13/85] onramp-kit: Migrate to viem --- packages/onramp-kit/jest.config.js | 3 +- packages/onramp-kit/jest.setup.ts | 3 ++ packages/onramp-kit/package.json | 3 +- .../packs/monerium/SafeMoneriumClient.test.ts | 3 +- .../src/packs/monerium/SafeMoneriumClient.ts | 47 +++++++------------ .../src/packs/monerium/signatures.ts | 8 ++-- 6 files changed, 30 insertions(+), 37 deletions(-) create mode 100644 packages/onramp-kit/jest.setup.ts diff --git a/packages/onramp-kit/jest.config.js b/packages/onramp-kit/jest.config.js index 919893179..bde683c7e 100644 --- a/packages/onramp-kit/jest.config.js +++ b/packages/onramp-kit/jest.config.js @@ -9,7 +9,8 @@ const config = { moduleNameMapper: { '^@safe-global/protocol-kit/(.*)$': '/../protocol-kit/src/$1', '^@safe-global/onramp-kit/(.*)$': '/src/$1' - } + }, + setupFiles: ['/jest.setup.ts'] } module.exports = config diff --git a/packages/onramp-kit/jest.setup.ts b/packages/onramp-kit/jest.setup.ts new file mode 100644 index 000000000..db3cb4975 --- /dev/null +++ b/packages/onramp-kit/jest.setup.ts @@ -0,0 +1,3 @@ +import { TextEncoder, TextDecoder } from 'util' + +Object.assign(global, { TextDecoder, TextEncoder }) diff --git a/packages/onramp-kit/package.json b/packages/onramp-kit/package.json index 893e32fc1..4cf20fb91 100644 --- a/packages/onramp-kit/package.json +++ b/packages/onramp-kit/package.json @@ -41,7 +41,8 @@ "@safe-global/safe-core-sdk-types": "^5.0.2", "@stripe/crypto": "^0.0.4", "@stripe/stripe-js": "^1.54.2", - "ethers": "^6.13.1" + "ethers": "^6.13.1", + "viem": "^2.17.0" }, "devDependencies": { "events": "^3.3.0", diff --git a/packages/onramp-kit/src/packs/monerium/SafeMoneriumClient.test.ts b/packages/onramp-kit/src/packs/monerium/SafeMoneriumClient.test.ts index cb7e7e2fb..061a86841 100644 --- a/packages/onramp-kit/src/packs/monerium/SafeMoneriumClient.test.ts +++ b/packages/onramp-kit/src/packs/monerium/SafeMoneriumClient.test.ts @@ -1,4 +1,5 @@ -import { Contract, hashMessage } from 'ethers' +import { Contract } from 'ethers' +import { hashMessage } from 'viem' import { PaymentStandard } from '@monerium/sdk' import Safe, * as protocolKitPackage from '@safe-global/protocol-kit' import { diff --git a/packages/onramp-kit/src/packs/monerium/SafeMoneriumClient.ts b/packages/onramp-kit/src/packs/monerium/SafeMoneriumClient.ts index a9b891bf9..905f932d5 100644 --- a/packages/onramp-kit/src/packs/monerium/SafeMoneriumClient.ts +++ b/packages/onramp-kit/src/packs/monerium/SafeMoneriumClient.ts @@ -1,4 +1,4 @@ -import { hashMessage, getBytes } from 'ethers' +import { Hash, encodeFunctionData, hashMessage } from 'viem' import { getChain as getMoneriumChain, getNetwork as getMoneriumNetwork, @@ -19,12 +19,7 @@ import { } from '@safe-global/onramp-kit/lib/errors' import { OperationType, SafeMultisigTransactionResponse } from '@safe-global/safe-core-sdk-types' -import { - EIP_1271_BYTES_INTERFACE, - EIP_1271_INTERFACE, - MAGIC_VALUE, - MAGIC_VALUE_BYTES -} from './signatures' +import { EIP_1271_ABI, EIP_1271_BYTES_ABI, MAGIC_VALUE, MAGIC_VALUE_BYTES } from './signatures' import { SafeMoneriumOrder } from './types' export class SafeMoneriumClient extends MoneriumClient { @@ -195,31 +190,23 @@ export class SafeMoneriumClient extends MoneriumClient { */ async #isValidSignature(safeAddress: string, messageHash: string): Promise { try { - const eip1271data = EIP_1271_INTERFACE.encodeFunctionData('isValidSignature', [ - messageHash, - '0x' - ]) - const msgBytes = getBytes(messageHash) - - const eip1271BytesData = EIP_1271_BYTES_INTERFACE.encodeFunctionData('isValidSignature', [ - msgBytes, - '0x' - ]) - - const checks = [ - this.#safeProvider.call({ - from: safeAddress, - to: safeAddress, - data: eip1271data - }), - this.#safeProvider.call({ - from: safeAddress, - to: safeAddress, - data: eip1271BytesData + const [eip1271data, eip1271BytesData] = [EIP_1271_ABI, EIP_1271_BYTES_ABI].map((abi) => + encodeFunctionData({ + abi, + functionName: 'isValidSignature', + args: [messageHash as Hash, '0x'] }) - ] + ) - const responses = await Promise.allSettled(checks) + const responses = await Promise.allSettled( + [eip1271data, eip1271BytesData].map((data) => + this.#safeProvider.call({ + from: safeAddress, + to: safeAddress, + data + }) + ) + ) return responses.reduce((prev, response) => { if (response.status === 'fulfilled') { diff --git a/packages/onramp-kit/src/packs/monerium/signatures.ts b/packages/onramp-kit/src/packs/monerium/signatures.ts index b089c4616..5f8392445 100644 --- a/packages/onramp-kit/src/packs/monerium/signatures.ts +++ b/packages/onramp-kit/src/packs/monerium/signatures.ts @@ -1,4 +1,4 @@ -import { Interface } from 'ethers' +import { parseAbi } from 'viem' // EIP-1271 magic values (https://eips.ethereum.org/EIPS/eip-1271) // The four-byte code is defined as follows: @@ -10,11 +10,11 @@ import { Interface } from 'ethers' const MAGIC_VALUE = '0x1626ba7e' const MAGIC_VALUE_BYTES = '0x20c13b0b' -const EIP_1271_INTERFACE = new Interface([ +const EIP_1271_ABI = parseAbi([ 'function isValidSignature(bytes32 _dataHash, bytes calldata _signature) external view' ]) -const EIP_1271_BYTES_INTERFACE = new Interface([ +const EIP_1271_BYTES_ABI = parseAbi([ 'function isValidSignature(bytes calldata _data, bytes calldata _signature) public view' ]) -export { EIP_1271_BYTES_INTERFACE, EIP_1271_INTERFACE, MAGIC_VALUE, MAGIC_VALUE_BYTES } +export { EIP_1271_BYTES_ABI, EIP_1271_ABI, MAGIC_VALUE, MAGIC_VALUE_BYTES } From 77041213e605300cc1d985a0a3c9a6b0c21788e8 Mon Sep 17 00:00:00 2001 From: Tim Schwarz <4171783+tmjssz@users.noreply.github.com> Date: Thu, 4 Jul 2024 12:10:32 +0200 Subject: [PATCH 14/85] api-kit: Use WalletClient type with local account for `signDelegate` function Fix tests for refactored signDelegate function --- .../src/types/safeTransactionServiceTypes.ts | 13 ++++-- packages/api-kit/src/utils/signDelegate.ts | 5 +-- .../api-kit/tests/e2e/addSafeDelegate.test.ts | 38 ++++++++++------- .../tests/e2e/getSafeDelegates.test.ts | 28 ++++++++----- .../tests/e2e/removeSafeDelegate.test.ts | 24 +++++++---- packages/api-kit/tests/endpoint/index.test.ts | 42 +++++++++++-------- 6 files changed, 92 insertions(+), 58 deletions(-) diff --git a/packages/api-kit/src/types/safeTransactionServiceTypes.ts b/packages/api-kit/src/types/safeTransactionServiceTypes.ts index 3d3c67088..7468a0f4b 100644 --- a/packages/api-kit/src/types/safeTransactionServiceTypes.ts +++ b/packages/api-kit/src/types/safeTransactionServiceTypes.ts @@ -1,4 +1,11 @@ -import { TypedDataDomain, TypedDataParameter, WalletClient } from 'viem' +import { + Chain, + LocalAccount, + Transport, + TypedDataDomain, + TypedDataParameter, + WalletClient +} from 'viem' import { SafeMultisigTransactionResponse, SafeTransactionData, @@ -77,14 +84,14 @@ export type AddSafeDelegateProps = { safeAddress?: string delegateAddress: string delegatorAddress: string - signer: WalletClient + signer: WalletClient label: string } export type DeleteSafeDelegateProps = { delegateAddress: string delegatorAddress: string - signer: WalletClient + signer: WalletClient } export type SafeDelegateResponse = { diff --git a/packages/api-kit/src/utils/signDelegate.ts b/packages/api-kit/src/utils/signDelegate.ts index 8c9b13613..96d26ad1c 100644 --- a/packages/api-kit/src/utils/signDelegate.ts +++ b/packages/api-kit/src/utils/signDelegate.ts @@ -1,7 +1,7 @@ -import { WalletClient } from 'viem' +import { Chain, LocalAccount, Transport, WalletClient } from 'viem' export async function signDelegate( - walletClient: WalletClient, + walletClient: WalletClient, delegateAddress: string, chainId: bigint ) { @@ -21,7 +21,6 @@ export async function signDelegate( const totp = Math.floor(Date.now() / 1000 / 3600) return walletClient.signTypedData({ - account: walletClient.account!.address, domain, types, primaryType: 'Delegate', diff --git a/packages/api-kit/tests/e2e/addSafeDelegate.test.ts b/packages/api-kit/tests/e2e/addSafeDelegate.test.ts index f791c14fd..ec9873c5c 100644 --- a/packages/api-kit/tests/e2e/addSafeDelegate.test.ts +++ b/packages/api-kit/tests/e2e/addSafeDelegate.test.ts @@ -1,4 +1,6 @@ -import { ethers, Signer } from 'ethers' +import { createWalletClient, http } from 'viem' +import { privateKeyToAccount } from 'viem/accounts' +import { sepolia } from 'viem/chains' import SafeApiKit, { AddSafeDelegateProps } from '@safe-global/api-kit/index' import chai from 'chai' import chaiAsPromised from 'chai-as-promised' @@ -11,17 +13,21 @@ const PRIVATE_KEY_1 = '0x83a415ca62e11f5fa5567e98450d0f82ae19ff36ef876c10a8d448c const PRIVATE_KEY_2 = '0xb0057716d5917badaf911b193b12b910811c1497b5bada8d7711f758981c3773' let safeApiKit: SafeApiKit -let signer: Signer +let signer: AddSafeDelegateProps['signer'] describe('addSafeDelegate', () => { before(async () => { safeApiKit = getApiKit('https://safe-transaction-sepolia.staging.5afe.dev/api') - signer = new ethers.Wallet(PRIVATE_KEY_1) + signer = createWalletClient({ + chain: sepolia, + transport: http(), + account: privateKeyToAccount(PRIVATE_KEY_1) + }) }) it('should fail if Label is empty', async () => { const delegateAddress = '0x9cCBDE03eDd71074ea9c49e413FA9CDfF16D263B' - const delegatorAddress = await signer.getAddress() + const delegatorAddress = signer.account!.address const delegateConfig: AddSafeDelegateProps = { delegateAddress, delegatorAddress, @@ -35,7 +41,7 @@ describe('addSafeDelegate', () => { it('should fail if Safe delegate address is empty', async () => { const delegateAddress = '' - const delegatorAddress = await signer.getAddress() + const delegatorAddress = signer.account!.address const delegateConfig: AddSafeDelegateProps = { delegateAddress, delegatorAddress, @@ -64,7 +70,7 @@ describe('addSafeDelegate', () => { it('should fail if Safe address is not checksummed', async () => { const safeAddress = '0xF8ef84392f7542576F6b9d1b140334144930Ac78'.toLowerCase() const delegateAddress = '0x9cCBDE03eDd71074ea9c49e413FA9CDfF16D263B' - const delegatorAddress = await signer.getAddress() + const delegatorAddress = signer.account!.address const delegateConfig: AddSafeDelegateProps = { safeAddress, delegateAddress, @@ -80,7 +86,7 @@ describe('addSafeDelegate', () => { it('should fail if Safe delegate address is not checksummed', async () => { const safeAddress = '0xF8ef84392f7542576F6b9d1b140334144930Ac78' const delegateAddress = '0x9cCBDE03eDd71074ea9c49e413FA9CDfF16D263B'.toLowerCase() - const delegatorAddress = await signer.getAddress() + const delegatorAddress = signer.account!.address const delegateConfig: AddSafeDelegateProps = { safeAddress, delegateAddress, @@ -96,7 +102,7 @@ describe('addSafeDelegate', () => { it('should fail if Safe delegator address is not checksummed', async () => { const safeAddress = '0xF8ef84392f7542576F6b9d1b140334144930Ac78' const delegateAddress = '0x9cCBDE03eDd71074ea9c49e413FA9CDfF16D263B' - const delegatorAddress = (await signer.getAddress()).toLowerCase() + const delegatorAddress = signer.account!.address.toLocaleLowerCase() const delegateConfig: AddSafeDelegateProps = { safeAddress, delegateAddress, @@ -112,7 +118,7 @@ describe('addSafeDelegate', () => { it('should fail if Safe does not exist', async () => { const safeAddress = '0x1dF62f291b2E969fB0849d99D9Ce41e2F137006e' const delegateAddress = '0x9cCBDE03eDd71074ea9c49e413FA9CDfF16D263B' - const delegatorAddress = await signer.getAddress() + const delegatorAddress = signer.account!.address const delegateConfig: AddSafeDelegateProps = { safeAddress, delegateAddress, @@ -128,8 +134,12 @@ describe('addSafeDelegate', () => { it('should fail if the signer is not an owner of the Safe', async () => { const safeAddress = '0xF8ef84392f7542576F6b9d1b140334144930Ac78' const delegateAddress = '0x9cCBDE03eDd71074ea9c49e413FA9CDfF16D263B' - const nonOwnerSigner = new ethers.Wallet(PRIVATE_KEY_2) - const delegatorAddress = await nonOwnerSigner.getAddress() + const nonOwnerSigner = createWalletClient({ + chain: sepolia, + transport: http(), + account: privateKeyToAccount(PRIVATE_KEY_2) + }) + const delegatorAddress = nonOwnerSigner.account!.address const delegateConfig: AddSafeDelegateProps = { safeAddress, delegateAddress, @@ -147,7 +157,7 @@ describe('addSafeDelegate', () => { it('should add a new delegate', async () => { const safeAddress = '0xF8ef84392f7542576F6b9d1b140334144930Ac78' const delegateAddress = '0x9cCBDE03eDd71074ea9c49e413FA9CDfF16D263B' - const delegatorAddress = await signer.getAddress() + const delegatorAddress = signer.account!.address const delegateConfig: AddSafeDelegateProps = { safeAddress, delegateAddress, @@ -170,7 +180,7 @@ describe('addSafeDelegate', () => { it('should add a new delegate without specifying a Safe', async () => { const delegateAddress = '0x9cCBDE03eDd71074ea9c49e413FA9CDfF16D263B' - const delegatorAddress = await signer.getAddress() + const delegatorAddress = signer.account!.address const delegateConfig: AddSafeDelegateProps = { delegateAddress, delegatorAddress, @@ -200,7 +210,7 @@ describe('addSafeDelegate', () => { const eip3770SafeAddress = `${config.EIP_3770_PREFIX}:${safeAddress}` const delegateAddress = '0x9cCBDE03eDd71074ea9c49e413FA9CDfF16D263B' const eip3770DelegateAddress = `${config.EIP_3770_PREFIX}:${delegateAddress}` - const delegatorAddress = await signer.getAddress() + const delegatorAddress = signer.account!.address const eip3770DelegatorAddress = `${config.EIP_3770_PREFIX}:${delegatorAddress}` const delegateConfig: AddSafeDelegateProps = { safeAddress: eip3770SafeAddress, diff --git a/packages/api-kit/tests/e2e/getSafeDelegates.test.ts b/packages/api-kit/tests/e2e/getSafeDelegates.test.ts index 6d1b7cbd0..c72508e16 100644 --- a/packages/api-kit/tests/e2e/getSafeDelegates.test.ts +++ b/packages/api-kit/tests/e2e/getSafeDelegates.test.ts @@ -1,4 +1,6 @@ -import { ethers, Signer } from 'ethers' +import { createWalletClient, http } from 'viem' +import { sepolia } from 'viem/chains' +import { privateKeyToAccount } from 'viem/accounts' import SafeApiKit, { DeleteSafeDelegateProps } from '@safe-global/api-kit/index' import chai from 'chai' import chaiAsPromised from 'chai-as-promised' @@ -10,14 +12,18 @@ chai.use(chaiAsPromised) const PRIVATE_KEY = '0x83a415ca62e11f5fa5567e98450d0f82ae19ff36ef876c10a8d448c788a53676' let safeApiKit: SafeApiKit -let signer: Signer +let signer: DeleteSafeDelegateProps['signer'] describe('getSafeDelegates', () => { const safeAddress = '0xF8ef84392f7542576F6b9d1b140334144930Ac78' before(async () => { safeApiKit = getApiKit('https://safe-transaction-sepolia.staging.5afe.dev/api') - signer = new ethers.Wallet(PRIVATE_KEY) + signer = createWalletClient({ + chain: sepolia, + transport: http(), + account: privateKeyToAccount(PRIVATE_KEY) + }) }) it('should fail if Safe address is empty', async () => { @@ -46,7 +52,7 @@ describe('getSafeDelegates', () => { let delegateConfig2: DeleteSafeDelegateProps before(async () => { - delegatorAddress = await signer.getAddress() + delegatorAddress = signer.account!.address delegateConfig1 = { delegateAddress: '0x9cCBDE03eDd71074ea9c49e413FA9CDfF16D263B', delegatorAddress, @@ -90,11 +96,11 @@ describe('getSafeDelegates', () => { chai.expect(sortedResults.length).to.be.eq(2) chai.expect(sortedResults[0].safe).to.be.eq(safeAddress) chai.expect(sortedResults[0].delegate).to.be.eq(delegateConfig1.delegateAddress) - chai.expect(sortedResults[0].delegator).to.be.eq(await delegateConfig1.signer.getAddress()) + chai.expect(sortedResults[0].delegator).to.be.eq(delegateConfig1.signer.account!.address) chai.expect(sortedResults[0].label).to.be.eq('Label1') chai.expect(sortedResults[1].safe).to.be.eq(safeAddress) chai.expect(sortedResults[1].delegate).to.be.eq(delegateConfig2.delegateAddress) - chai.expect(sortedResults[1].delegator).to.be.eq(await delegateConfig2.signer.getAddress()) + chai.expect(sortedResults[1].delegator).to.be.eq(delegateConfig2.signer.account!.address) chai.expect(sortedResults[1].label).to.be.eq('Label2') }) @@ -104,7 +110,7 @@ describe('getSafeDelegates', () => { chai.expect(results.length).to.be.eq(1) chai.expect(results[0].safe).to.be.eq(safeAddress) chai.expect(results[0].delegate).to.be.eq(delegateConfig1.delegateAddress) - chai.expect(results[0].delegator).to.be.eq(await delegateConfig1.signer.getAddress()) + chai.expect(results[0].delegator).to.be.eq(delegateConfig1.signer.account!.address) chai.expect(results[0].label).to.be.eq('Label1') }) @@ -114,7 +120,7 @@ describe('getSafeDelegates', () => { chai.expect(results.length).to.be.eq(1) chai.expect(results[0].safe).to.be.eq(safeAddress) chai.expect(results[0].delegate).to.be.eq(delegateConfig2.delegateAddress) - chai.expect(results[0].delegator).to.be.eq(await delegateConfig2.signer.getAddress()) + chai.expect(results[0].delegator).to.be.eq(delegateConfig2.signer.account!.address) chai.expect(results[0].label).to.be.eq('Label2') }) }) @@ -122,7 +128,7 @@ describe('getSafeDelegates', () => { it('should return an array of delegates EIP-3770', async () => { const safeAddress = '0xF8ef84392f7542576F6b9d1b140334144930Ac78' const eip3770SafeAddress = `${config.EIP_3770_PREFIX}:${safeAddress}` - const delegatorAddress = await signer.getAddress() + const delegatorAddress = signer.account!.address const delegateConfig1: DeleteSafeDelegateProps = { delegateAddress: `${config.EIP_3770_PREFIX}:0x9cCBDE03eDd71074ea9c49e413FA9CDfF16D263B`, delegatorAddress, @@ -150,10 +156,10 @@ describe('getSafeDelegates', () => { const sortedResults = results.sort((a, b) => (a.delegate > b.delegate ? -1 : 1)) chai.expect(sortedResults.length).to.be.eq(2) chai.expect(sortedResults[0].delegate).to.be.eq('0x9cCBDE03eDd71074ea9c49e413FA9CDfF16D263B') - chai.expect(sortedResults[0].delegator).to.be.eq(await delegateConfig1.signer.getAddress()) + chai.expect(sortedResults[0].delegator).to.be.eq(delegateConfig1.signer.account!.address) chai.expect(sortedResults[0].label).to.be.eq('Label1') chai.expect(sortedResults[1].delegate).to.be.eq('0x22d491Bde2303f2f43325b2108D26f1eAbA1e32b') - chai.expect(sortedResults[1].delegator).to.be.eq(await delegateConfig2.signer.getAddress()) + chai.expect(sortedResults[1].delegator).to.be.eq(delegateConfig2.signer.account!.address) chai.expect(sortedResults[1].label).to.be.eq('Label2') await safeApiKit.removeSafeDelegate({ delegateAddress: delegateConfig1.delegateAddress, diff --git a/packages/api-kit/tests/e2e/removeSafeDelegate.test.ts b/packages/api-kit/tests/e2e/removeSafeDelegate.test.ts index cb04880b2..29af873ae 100644 --- a/packages/api-kit/tests/e2e/removeSafeDelegate.test.ts +++ b/packages/api-kit/tests/e2e/removeSafeDelegate.test.ts @@ -1,4 +1,6 @@ -import { ethers, Signer } from 'ethers' +import { createWalletClient, http } from 'viem' +import { sepolia } from 'viem/chains' +import { privateKeyToAccount } from 'viem/accounts' import SafeApiKit, { DeleteSafeDelegateProps } from '@safe-global/api-kit/index' import chai from 'chai' import chaiAsPromised from 'chai-as-promised' @@ -10,17 +12,21 @@ chai.use(chaiAsPromised) const PRIVATE_KEY = '0x83a415ca62e11f5fa5567e98450d0f82ae19ff36ef876c10a8d448c788a53676' let safeApiKit: SafeApiKit -let signer: Signer +let signer: DeleteSafeDelegateProps['signer'] describe('removeSafeDelegate', () => { before(async () => { safeApiKit = getApiKit('https://safe-transaction-sepolia.staging.5afe.dev/api') - signer = new ethers.Wallet(PRIVATE_KEY) + signer = createWalletClient({ + chain: sepolia, + transport: http(), + account: privateKeyToAccount(PRIVATE_KEY) + }) }) it('should fail if Safe delegate address is empty', async () => { const delegateAddress = '' - const delegatorAddress = await signer.getAddress() + const delegatorAddress = signer.account!.address const delegateConfig: DeleteSafeDelegateProps = { delegateAddress, delegatorAddress, @@ -46,7 +52,7 @@ describe('removeSafeDelegate', () => { it('should fail if Safe delegate address is not checksummed', async () => { const delegateAddress = '0x9cCBDE03eDd71074ea9c49e413FA9CDfF16D263B'.toLowerCase() - const delegatorAddress = await signer.getAddress() + const delegatorAddress = signer.account!.address const delegateConfig: DeleteSafeDelegateProps = { delegateAddress, delegatorAddress, @@ -59,7 +65,7 @@ describe('removeSafeDelegate', () => { it('should fail if Safe delegator address is not checksummed', async () => { const delegateAddress = '0x9cCBDE03eDd71074ea9c49e413FA9CDfF16D263B' - const delegatorAddress = (await signer.getAddress()).toLowerCase() + const delegatorAddress = signer.account!.address.toLowerCase() const delegateConfig: DeleteSafeDelegateProps = { delegateAddress, delegatorAddress, @@ -72,7 +78,7 @@ describe('removeSafeDelegate', () => { it('should fail if the delegate to remove is not a delegate', async () => { const delegateAddress = '0x1dF62f291b2E969fB0849d99D9Ce41e2F137006e' - const delegatorAddress = await signer.getAddress() + const delegatorAddress = signer.account!.address const delegateConfig: DeleteSafeDelegateProps = { delegateAddress, delegatorAddress, @@ -83,7 +89,7 @@ describe('removeSafeDelegate', () => { it('should remove a delegate', async () => { const delegateAddress = '0x9cCBDE03eDd71074ea9c49e413FA9CDfF16D263B' - const delegatorAddress = await signer.getAddress() + const delegatorAddress = signer.account!.address const delegateConfig: DeleteSafeDelegateProps = { delegateAddress, delegatorAddress, @@ -106,7 +112,7 @@ describe('removeSafeDelegate', () => { it('should remove a delegate EIP-3770', async () => { const delegateAddress = '0x9cCBDE03eDd71074ea9c49e413FA9CDfF16D263B' const eip3770DelegateAddress = `${config.EIP_3770_PREFIX}:${delegateAddress}` - const delegatorAddress = await signer.getAddress() + const delegatorAddress = signer.account!.address const eip3770DelegatorAddress = `${config.EIP_3770_PREFIX}:${delegatorAddress}` const delegateConfig: DeleteSafeDelegateProps = { delegateAddress: eip3770DelegateAddress, diff --git a/packages/api-kit/tests/endpoint/index.test.ts b/packages/api-kit/tests/endpoint/index.test.ts index 68f96c9a3..d21c4bbb0 100644 --- a/packages/api-kit/tests/endpoint/index.test.ts +++ b/packages/api-kit/tests/endpoint/index.test.ts @@ -1,4 +1,10 @@ -import { getDefaultProvider, Wallet } from 'ethers' +import chai from 'chai' +import chaiAsPromised from 'chai-as-promised' +import sinon from 'sinon' +import sinonChai from 'sinon-chai' +import { privateKeyToAccount } from 'viem/accounts' +import { sepolia } from 'viem/chains' +import { createWalletClient, http } from 'viem' import SafeApiKit, { AddMessageProps, AddSafeDelegateProps, @@ -8,13 +14,9 @@ import SafeApiKit, { import * as httpRequests from '@safe-global/api-kit/utils/httpRequests' import Safe from '@safe-global/protocol-kit' import { UserOperation } from '@safe-global/safe-core-sdk-types' -import chai from 'chai' -import chaiAsPromised from 'chai-as-promised' -import sinon from 'sinon' -import sinonChai from 'sinon-chai' +import { signDelegate } from '@safe-global/api-kit/utils/signDelegate' import config from '../utils/config' import { getApiKit, getKits } from '../utils/setupKits' -import { signDelegate } from '@safe-global/api-kit/utils/signDelegate' chai.use(chaiAsPromised) chai.use(sinonChai) @@ -33,8 +35,12 @@ const eip3770TokenAddress = `${config.EIP_3770_PREFIX}:${tokenAddress}` const safeTxHash = '0x317834aea988fd3cfa54fd8b2be2c96b4fd70a14d8c9470a7110576b01e6480a' const safeOpHash = '0x8b1840745ec0a6288e868c6e285dadcfebd49e846d307610a9ccd97f445ace93' const txServiceBaseUrl = 'https://safe-transaction-sepolia.safe.global/api' -const defaultProvider = getDefaultProvider(config.JSON_RPC) -const signer = new Wallet(PRIVATE_KEY_1, defaultProvider) + +const walletClient = createWalletClient({ + transport: http(), + chain: sepolia, + account: privateKeyToAccount(PRIVATE_KEY_1) +}) let protocolKit: Safe let safeApiKit: SafeApiKit @@ -205,11 +211,11 @@ describe('Endpoint tests', () => { const delegateConfig: AddSafeDelegateProps = { delegateAddress, delegatorAddress, - signer, + signer: walletClient, label: 'label' } - const signature = await signDelegate(signer, delegateAddress, chainId) + const signature = await signDelegate(walletClient, delegateAddress, chainId) await chai .expect(safeApiKit.addSafeDelegate(delegateConfig)) .to.be.eventually.deep.equals({ data: { success: true } }) @@ -230,11 +236,11 @@ describe('Endpoint tests', () => { const delegateConfig: AddSafeDelegateProps = { delegateAddress: eip3770DelegateAddress, delegatorAddress: eip3770DelegatorAddress, - signer, + signer: walletClient, label: 'label' } - const signature = await signDelegate(signer, delegateAddress, chainId) + const signature = await signDelegate(walletClient, delegateAddress, chainId) await chai .expect(safeApiKit.addSafeDelegate(delegateConfig)) .to.be.eventually.deep.equals({ data: { success: true } }) @@ -255,10 +261,10 @@ describe('Endpoint tests', () => { const delegateConfig: DeleteSafeDelegateProps = { delegateAddress, delegatorAddress, - signer + signer: walletClient } - const signature = await signDelegate(signer, delegateAddress, chainId) + const signature = await signDelegate(walletClient, delegateAddress, chainId) await chai .expect(safeApiKit.removeSafeDelegate(delegateConfig)) .to.be.eventually.deep.equals({ data: { success: true } }) @@ -276,10 +282,10 @@ describe('Endpoint tests', () => { const delegateConfig: DeleteSafeDelegateProps = { delegateAddress: eip3770DelegateAddress, delegatorAddress, - signer + signer: walletClient } - const signature = await signDelegate(signer, delegateAddress, chainId) + const signature = await signDelegate(walletClient, delegateAddress, chainId) await chai .expect(safeApiKit.removeSafeDelegate(delegateConfig)) .to.be.eventually.deep.equals({ data: { success: true } }) @@ -363,7 +369,7 @@ describe('Endpoint tests', () => { nonce: 1 } const origin = 'Safe Core SDK: Safe API Kit' - const signerAddress = await signer.getAddress() + const signerAddress = await walletClient.account.address const safeTransaction = await protocolKit.createTransaction({ transactions: [safeTransactionData], options @@ -411,7 +417,7 @@ describe('Endpoint tests', () => { nonce: 1 } const origin = 'Safe Core SDK: Safe API Kit' - const signerAddress = await signer.getAddress() + const signerAddress = await walletClient.account.address const safeTransaction = await protocolKit.createTransaction({ transactions: [safeTransactionData], options From bc494f53e723c041d7f5bd3e6245cc3e65c7cd8b Mon Sep 17 00:00:00 2001 From: Tim Schwarz <4171783+tmjssz@users.noreply.github.com> Date: Fri, 5 Jul 2024 11:16:33 +0200 Subject: [PATCH 15/85] api-kit: Improve Safe Delegates response types --- packages/api-kit/src/SafeApiKit.ts | 4 ++-- .../api-kit/src/types/safeTransactionServiceTypes.ts | 10 ++++------ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/packages/api-kit/src/SafeApiKit.ts b/packages/api-kit/src/SafeApiKit.ts index 47dc05472..0623228c8 100644 --- a/packages/api-kit/src/SafeApiKit.ts +++ b/packages/api-kit/src/SafeApiKit.ts @@ -15,7 +15,6 @@ import { ProposeTransactionProps, SafeCreationInfoResponse, SafeDelegateListResponse, - SafeDelegateResponse, SafeInfoResponse, SafeMessage, SafeMessageListResponse, @@ -26,6 +25,7 @@ import { SafeServiceInfoResponse, SafeSingletonResponse, SignatureResponse, + SignedSafeDelegateResponse, TokenInfoListResponse, TokenInfoResponse, TransferListResponse @@ -316,7 +316,7 @@ class SafeApiKit { delegatorAddress, label, signer - }: AddSafeDelegateProps): Promise { + }: AddSafeDelegateProps): Promise { if (delegateAddress === '') { throw new Error('Invalid Safe delegate address') } diff --git a/packages/api-kit/src/types/safeTransactionServiceTypes.ts b/packages/api-kit/src/types/safeTransactionServiceTypes.ts index 7468a0f4b..713791d53 100644 --- a/packages/api-kit/src/types/safeTransactionServiceTypes.ts +++ b/packages/api-kit/src/types/safeTransactionServiceTypes.ts @@ -99,15 +99,13 @@ export type SafeDelegateResponse = { readonly delegate: string readonly delegator: string readonly label: string +} + +export type SignedSafeDelegateResponse = SafeDelegateResponse & { readonly signature: string } -export type SafeDelegateListResponse = ListResponse<{ - readonly safe: string - readonly delegate: string - readonly delegator: string - readonly label: string -}> +export type SafeDelegateListResponse = ListResponse export type SafeMultisigTransactionEstimate = { readonly to: string From 563cccec93632ca718755e7d5c8488e1445d8eca Mon Sep 17 00:00:00 2001 From: Tim Schwarz <4171783+tmjssz@users.noreply.github.com> Date: Fri, 5 Jul 2024 11:17:31 +0200 Subject: [PATCH 16/85] api-kit: Fix `getSafeDelegates` e2e tests --- .../api-kit/tests/e2e/getSafeDelegates.test.ts | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/packages/api-kit/tests/e2e/getSafeDelegates.test.ts b/packages/api-kit/tests/e2e/getSafeDelegates.test.ts index c72508e16..a260afb6c 100644 --- a/packages/api-kit/tests/e2e/getSafeDelegates.test.ts +++ b/packages/api-kit/tests/e2e/getSafeDelegates.test.ts @@ -1,7 +1,10 @@ import { createWalletClient, http } from 'viem' import { sepolia } from 'viem/chains' import { privateKeyToAccount } from 'viem/accounts' -import SafeApiKit, { DeleteSafeDelegateProps } from '@safe-global/api-kit/index' +import SafeApiKit, { + DeleteSafeDelegateProps, + SafeDelegateResponse +} from '@safe-global/api-kit/index' import chai from 'chai' import chaiAsPromised from 'chai-as-promised' import config from '../utils/config' @@ -50,6 +53,7 @@ describe('getSafeDelegates', () => { let delegatorAddress: string let delegateConfig1: DeleteSafeDelegateProps let delegateConfig2: DeleteSafeDelegateProps + let delegatesResponse: SafeDelegateResponse[] before(async () => { delegatorAddress = signer.account!.address @@ -91,6 +95,7 @@ describe('getSafeDelegates', () => { it('should return an array of delegates', async () => { const { results, count } = await safeApiKit.getSafeDelegates({ safeAddress }) + delegatesResponse = results const sortedResults = results.sort((a, b) => (a.delegate > b.delegate ? -1 : 1)) chai.expect(count).to.be.eq(2) chai.expect(sortedResults.length).to.be.eq(2) @@ -108,20 +113,14 @@ describe('getSafeDelegates', () => { const { results, count } = await safeApiKit.getSafeDelegates({ safeAddress, limit: 1 }) chai.expect(count).to.be.eq(2) chai.expect(results.length).to.be.eq(1) - chai.expect(results[0].safe).to.be.eq(safeAddress) - chai.expect(results[0].delegate).to.be.eq(delegateConfig1.delegateAddress) - chai.expect(results[0].delegator).to.be.eq(delegateConfig1.signer.account!.address) - chai.expect(results[0].label).to.be.eq('Label1') + chai.expect(results).to.be.deep.eq(delegatesResponse.slice(0, 1)) }) it('should return only the second delegate with offset = 1', async () => { const { results, count } = await safeApiKit.getSafeDelegates({ safeAddress, offset: 1 }) chai.expect(count).to.be.eq(2) chai.expect(results.length).to.be.eq(1) - chai.expect(results[0].safe).to.be.eq(safeAddress) - chai.expect(results[0].delegate).to.be.eq(delegateConfig2.delegateAddress) - chai.expect(results[0].delegator).to.be.eq(delegateConfig2.signer.account!.address) - chai.expect(results[0].label).to.be.eq('Label2') + chai.expect(results).to.be.deep.eq(delegatesResponse.slice(1)) }) }) From 5129709098f383d42fff7e81e644ecbe516374c9 Mon Sep 17 00:00:00 2001 From: leonardotc Date: Tue, 9 Jul 2024 13:33:07 +0200 Subject: [PATCH 17/85] PR fixes --- .../tests/e2e/addSafeOperation.test.ts | 2 +- packages/api-kit/tests/endpoint/index.test.ts | 22 +++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/api-kit/tests/e2e/addSafeOperation.test.ts b/packages/api-kit/tests/e2e/addSafeOperation.test.ts index d617e1f84..7c373b591 100644 --- a/packages/api-kit/tests/e2e/addSafeOperation.test.ts +++ b/packages/api-kit/tests/e2e/addSafeOperation.test.ts @@ -6,7 +6,7 @@ import Safe from '@safe-global/protocol-kit' import SafeApiKit from '@safe-global/api-kit/index' import { getAddSafeOperationProps } from '@safe-global/api-kit/utils/safeOperation' import { Safe4337Pack } from '@safe-global/relay-kit' -import * as viem from '@safe-global/relay-kit/node_modules/viem' +import viem from 'viem' import { generateTransferCallData } from '@safe-global/relay-kit/packs/safe-4337/testing-utils/helpers' import { ENTRYPOINT_ABI, diff --git a/packages/api-kit/tests/endpoint/index.test.ts b/packages/api-kit/tests/endpoint/index.test.ts index d21c4bbb0..2beadd40b 100644 --- a/packages/api-kit/tests/endpoint/index.test.ts +++ b/packages/api-kit/tests/endpoint/index.test.ts @@ -36,7 +36,7 @@ const safeTxHash = '0x317834aea988fd3cfa54fd8b2be2c96b4fd70a14d8c9470a7110576b01 const safeOpHash = '0x8b1840745ec0a6288e868c6e285dadcfebd49e846d307610a9ccd97f445ace93' const txServiceBaseUrl = 'https://safe-transaction-sepolia.safe.global/api' -const walletClient = createWalletClient({ +const signer = createWalletClient({ transport: http(), chain: sepolia, account: privateKeyToAccount(PRIVATE_KEY_1) @@ -211,11 +211,11 @@ describe('Endpoint tests', () => { const delegateConfig: AddSafeDelegateProps = { delegateAddress, delegatorAddress, - signer: walletClient, + signer, label: 'label' } - const signature = await signDelegate(walletClient, delegateAddress, chainId) + const signature = await signDelegate(signer, delegateAddress, chainId) await chai .expect(safeApiKit.addSafeDelegate(delegateConfig)) .to.be.eventually.deep.equals({ data: { success: true } }) @@ -236,11 +236,11 @@ describe('Endpoint tests', () => { const delegateConfig: AddSafeDelegateProps = { delegateAddress: eip3770DelegateAddress, delegatorAddress: eip3770DelegatorAddress, - signer: walletClient, + signer, label: 'label' } - const signature = await signDelegate(walletClient, delegateAddress, chainId) + const signature = await signDelegate(signer, delegateAddress, chainId) await chai .expect(safeApiKit.addSafeDelegate(delegateConfig)) .to.be.eventually.deep.equals({ data: { success: true } }) @@ -261,10 +261,10 @@ describe('Endpoint tests', () => { const delegateConfig: DeleteSafeDelegateProps = { delegateAddress, delegatorAddress, - signer: walletClient + signer } - const signature = await signDelegate(walletClient, delegateAddress, chainId) + const signature = await signDelegate(signer, delegateAddress, chainId) await chai .expect(safeApiKit.removeSafeDelegate(delegateConfig)) .to.be.eventually.deep.equals({ data: { success: true } }) @@ -282,10 +282,10 @@ describe('Endpoint tests', () => { const delegateConfig: DeleteSafeDelegateProps = { delegateAddress: eip3770DelegateAddress, delegatorAddress, - signer: walletClient + signer } - const signature = await signDelegate(walletClient, delegateAddress, chainId) + const signature = await signDelegate(signer, delegateAddress, chainId) await chai .expect(safeApiKit.removeSafeDelegate(delegateConfig)) .to.be.eventually.deep.equals({ data: { success: true } }) @@ -369,7 +369,7 @@ describe('Endpoint tests', () => { nonce: 1 } const origin = 'Safe Core SDK: Safe API Kit' - const signerAddress = await walletClient.account.address + const signerAddress = signer.account.address const safeTransaction = await protocolKit.createTransaction({ transactions: [safeTransactionData], options @@ -417,7 +417,7 @@ describe('Endpoint tests', () => { nonce: 1 } const origin = 'Safe Core SDK: Safe API Kit' - const signerAddress = await walletClient.account.address + const signerAddress = signer.account.address const safeTransaction = await protocolKit.createTransaction({ transactions: [safeTransactionData], options From 2d56a2aaa126b8c6c2cad632cf720ece3db8869e Mon Sep 17 00:00:00 2001 From: Tim Schwarz <4171783+tmjssz@users.noreply.github.com> Date: Wed, 10 Jul 2024 16:54:14 +0200 Subject: [PATCH 18/85] Add comment for TextEncoder polyfill Also remove unnecessary TextDecoder polyfill --- packages/auth-kit/jest.setup.ts | 5 +++-- packages/onramp-kit/jest.setup.ts | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/auth-kit/jest.setup.ts b/packages/auth-kit/jest.setup.ts index db3cb4975..3c03d4839 100644 --- a/packages/auth-kit/jest.setup.ts +++ b/packages/auth-kit/jest.setup.ts @@ -1,3 +1,4 @@ -import { TextEncoder, TextDecoder } from 'util' +import { TextEncoder } from 'util' -Object.assign(global, { TextDecoder, TextEncoder }) +// TextEncoder is used by viem but not bundled with it. Therefore we need to polyfill it for the tests. +Object.assign(global, { TextEncoder }) diff --git a/packages/onramp-kit/jest.setup.ts b/packages/onramp-kit/jest.setup.ts index db3cb4975..3c03d4839 100644 --- a/packages/onramp-kit/jest.setup.ts +++ b/packages/onramp-kit/jest.setup.ts @@ -1,3 +1,4 @@ -import { TextEncoder, TextDecoder } from 'util' +import { TextEncoder } from 'util' -Object.assign(global, { TextDecoder, TextEncoder }) +// TextEncoder is used by viem but not bundled with it. Therefore we need to polyfill it for the tests. +Object.assign(global, { TextEncoder }) From 8af26ef99fdfedbde403b4743a3aa253c5b15e23 Mon Sep 17 00:00:00 2001 From: leonardotc Date: Thu, 11 Jul 2024 15:35:01 +0200 Subject: [PATCH 19/85] Feat/viem migration tests (#894) * relay-kit: Add viem dependency * relay-kit: Migrate 4337 related components to viem * playground: Use `generateTransferCallData` function from relay-kit instead of re-implementing it * Update contracts tests * relay-kit: Fix hex string conversion for nonce * Initial draft setup contracts * Solved some compilations errors * Minor type corrections * Resolved conflict and changed some more types * Wip * Change txResult function * Update contracts * Multiple contract fixes * Change bytes contract type * Multiple minor fixes * Fix multiple contract structures * Fix general transaction simulation * Fix build * Remove ethers * Removed typed data usage * Fix build * Change provider test * Remove the least ethers from protocol-kit * Fix some tests * Fix types * Fix more types * Multiple fixes * Fix build * Fix protocol kit unit tests * Enable e2e tests * Fix protocol-kit tests setup * Fix external signer function * Fix encoder types mismatch * Fix modules manager getAddress * Fix multiple getAddress tests * Fix erc20 tests * Fix chain id issue in the contracts * Fix general encoding for signature verification * Fix storage test * Multiple fixes * Fix provider isContract function * Fix safe contract calls * Fix encoding * Fix decode multisend data * Fix safetxerrorresponse * Fix gaslimit test * Fix legacy transaction options * Fix signer conversion * Fix checksummed address * Fix provider tests v1.2.0 * Fix gas estimation for 1.2.0 * Fix call parameters * Multiple fixes --------- Co-authored-by: Tim Schwarz <4171783+tmjssz@users.noreply.github.com> --- packages/api-kit/hardhat.config.ts | 2 +- packages/api-kit/package.json | 2 +- packages/protocol-kit/hardhat.config.ts | 3 +- packages/protocol-kit/package.json | 5 +- packages/protocol-kit/src/Safe.ts | 37 +-- packages/protocol-kit/src/SafeProvider.ts | 196 +++++++++++----- .../src/contracts/BaseContract.ts | 91 ++++++-- ...ompatibilityFallbackHandlerBaseContract.ts | 6 +- .../CreateCall/CreateCallBaseContract.ts | 6 +- .../v1.3.0/CreateCallContract_v1_3_0.ts | 14 +- .../v1.4.1/CreateCallContract_v1_4_1.ts | 14 +- .../MultiSend/MultiSendBaseContract.ts | 3 +- .../MultiSendCallOnlyBaseContract.ts | 3 +- .../src/contracts/Safe/SafeBaseContract.ts | 3 +- .../Safe/v1.0.0/SafeContract_v1_0_0.ts | 131 ++++++----- .../Safe/v1.1.1/SafeContract_v1_1_1.ts | 117 +++++----- .../Safe/v1.2.0/SafeContract_v1_2_0.ts | 122 +++++----- .../Safe/v1.3.0/SafeContract_v1_3_0.ts | 122 +++++----- .../Safe/v1.4.1/SafeContract_v1_4_1.ts | 121 +++++----- .../SafeProxyFactoryBaseContract.ts | 6 +- .../v1.0.0/SafeProxyFactoryContract_v1_0_0.ts | 37 +-- .../v1.1.1/SafeProxyFactoryContract_v1_1_1.ts | 50 ++-- .../v1.3.0/SafeProxyFactoryContract_v1_3_0.ts | 50 ++-- .../v1.4.1/SafeProxyFactoryContract_v1_4_1.ts | 48 ++-- .../SignMessageLibBaseContract.ts | 3 +- .../v1.3.0/SignMessageLibContract_v1_3_0.ts | 9 +- .../v1.4.1/SignMessageLibContract_v1_4_1.ts | 9 +- .../SimulateTxAccessorBaseContract.ts | 6 +- .../SimulateTxAccessorContract_v1_3_0.ts | 10 +- .../SimulateTxAccessorContract_v1_4_1.ts | 9 +- .../protocol-kit/src/contracts/constants.ts | 7 +- .../src/contracts/contractInstances.ts | 20 +- .../src/contracts/safeDeploymentContracts.ts | 5 +- packages/protocol-kit/src/contracts/utils.ts | 114 ++++++--- .../src/managers/fallbackHandlerManager.ts | 3 +- .../protocol-kit/src/managers/guardManager.ts | 3 +- .../src/managers/moduleManager.ts | 8 +- .../protocol-kit/src/managers/ownerManager.ts | 3 +- packages/protocol-kit/src/types/contracts.ts | 38 ++- .../protocol-kit/src/types/safeProvider.ts | 2 +- packages/protocol-kit/src/utils/address.ts | 4 +- packages/protocol-kit/src/utils/constants.ts | 8 +- .../protocol-kit/src/utils/eip-3770/index.ts | 5 +- .../protocol-kit/src/utils/eip-712/encode.ts | 211 +++++++++++++++++ .../protocol-kit/src/utils/eip-712/index.ts | 12 +- .../protocol-kit/src/utils/erc-20/index.ts | 18 +- .../src/utils/signatures/utils.ts | 42 ++-- .../src/utils/transactions/gas.ts | 66 ++---- .../src/utils/transactions/utils.ts | 107 +++++++-- packages/protocol-kit/src/utils/types.ts | 17 ++ .../tests/e2e/contractManager.test.ts | 6 +- packages/protocol-kit/tests/e2e/core.test.ts | 107 +++++---- .../createSafeDeploymentTransaction.test.ts | 23 +- .../tests/e2e/createTransaction.test.ts | 73 +++--- .../tests/e2e/createTransactionBatch.test.ts | 16 +- .../e2e/eip1271-contract-signatures.test.ts | 6 +- .../protocol-kit/tests/e2e/eip1271.test.ts | 19 +- .../protocol-kit/tests/e2e/erc-20.test.ts | 12 +- .../protocol-kit/tests/e2e/execution.test.ts | 87 +++---- .../tests/e2e/fallbackHandlerManager.test.ts | 76 +++--- .../tests/e2e/getEncodedTransaction.test.ts | 6 +- .../tests/e2e/guardManager.test.ts | 55 +++-- .../tests/e2e/moduleManager.test.ts | 111 +++++---- .../tests/e2e/offChainSignatures.test.ts | 24 +- .../tests/e2e/onChainSignatures.test.ts | 16 +- .../tests/e2e/ownerManager.test.ts | 66 +++--- .../tests/e2e/safeFactory.test.ts | 18 +- .../tests/e2e/safeProvider.test.ts | 30 +-- .../protocol-kit/tests/e2e/threshold.test.ts | 10 +- .../tests/e2e/transactionUtils.test.ts | 1 - .../tests/e2e/utils/setupContractNetworks.ts | 16 +- .../tests/e2e/utils/setupContracts.ts | 220 ++++++++++-------- .../tests/e2e/utils/setupProvider.ts | 13 +- .../tests/e2e/utils/setupTestNetwork.ts | 10 +- .../tests/e2e/utils/transactions.ts | 19 +- ...SafeTransactionIntoDeploymentBatch.test.ts | 8 +- .../protocol-kit/tests/unit/eip-712.test.ts | 13 +- packages/safe-core-sdk-types/src/index.ts | 16 -- packages/safe-core-sdk-types/src/types.ts | 10 +- yarn.lock | 115 +++++---- 80 files changed, 1883 insertions(+), 1247 deletions(-) create mode 100644 packages/protocol-kit/src/utils/eip-712/encode.ts diff --git a/packages/api-kit/hardhat.config.ts b/packages/api-kit/hardhat.config.ts index 6525853ab..c5c5e2710 100644 --- a/packages/api-kit/hardhat.config.ts +++ b/packages/api-kit/hardhat.config.ts @@ -1,4 +1,4 @@ -import '@nomicfoundation/hardhat-ethers' +import '@nomicfoundation/hardhat-viem' import dotenv from 'dotenv' import { HardhatUserConfig, HttpNetworkUserConfig } from 'hardhat/types' import yargs from 'yargs' diff --git a/packages/api-kit/package.json b/packages/api-kit/package.json index 7448d0875..070aeb608 100644 --- a/packages/api-kit/package.json +++ b/packages/api-kit/package.json @@ -39,7 +39,7 @@ ], "homepage": "https://github.com/safe-global/safe-core-sdk#readme", "devDependencies": { - "@nomicfoundation/hardhat-ethers": "^3.0.6", + "@nomicfoundation/hardhat-viem": "^2.0.2", "@types/chai": "^4.3.16", "@types/chai-as-promised": "^7.1.8", "@types/mocha": "^10.0.6", diff --git a/packages/protocol-kit/hardhat.config.ts b/packages/protocol-kit/hardhat.config.ts index 1d0aa7a5e..3db6266f9 100644 --- a/packages/protocol-kit/hardhat.config.ts +++ b/packages/protocol-kit/hardhat.config.ts @@ -1,6 +1,5 @@ -import '@nomicfoundation/hardhat-ethers' +import '@nomicfoundation/hardhat-viem' import 'hardhat-deploy' -import 'hardhat-deploy-ethers' import 'tsconfig-paths/register' import dotenv from 'dotenv' import { HardhatUserConfig, HttpNetworkUserConfig } from 'hardhat/types' diff --git a/packages/protocol-kit/package.json b/packages/protocol-kit/package.json index c183317cb..241c4ba0c 100644 --- a/packages/protocol-kit/package.json +++ b/packages/protocol-kit/package.json @@ -33,7 +33,7 @@ "format:check": "prettier --check \"*/**/*.{js,json,md,ts}\"", "format": "prettier --write \"*/**/*.{js,json,md,ts}\"", "unbuild": "rimraf dist artifacts deployments cache .nyc_output *.tsbuildinfo", - "build": "yarn unbuild && hardhat compile && yarn safe-deployments && tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json" + "build": "yarn unbuild && hardhat compile && yarn safe-deployments && NODE_OPTIONS=--max-old-space-size=8192 tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json" }, "repository": { "type": "git", @@ -50,7 +50,7 @@ "homepage": "https://github.com/safe-global/safe-core-sdk#readme", "devDependencies": { "@gnosis.pm/safe-contracts-v1.3.0": "npm:@gnosis.pm/safe-contracts@1.3.0", - "@nomicfoundation/hardhat-ethers": "^3.0.6", + "@nomicfoundation/hardhat-viem": "^2.0.2", "@openzeppelin/contracts": "^2.5.1", "@safe-global/safe-contracts-v1.4.1": "npm:@safe-global/safe-contracts@1.4.1", "@types/chai": "^4.3.16", @@ -63,7 +63,6 @@ "dotenv": "^16.4.5", "hardhat": "^2.19.3", "hardhat-deploy": "^0.11.45", - "hardhat-deploy-ethers": "^0.4.2", "mocha": "^10.2.0", "nyc": "^15.1.0", "tsconfig-paths": "^4.2.0", diff --git a/packages/protocol-kit/src/Safe.ts b/packages/protocol-kit/src/Safe.ts index 52fe2d961..db1edc14b 100644 --- a/packages/protocol-kit/src/Safe.ts +++ b/packages/protocol-kit/src/Safe.ts @@ -72,6 +72,8 @@ import { import SafeMessage from './utils/messages/SafeMessage' import semverSatisfies from 'semver/functions/satisfies' import SafeProvider from './SafeProvider' +import { asAddress, asHash, asHex } from './utils/types' +import { Hash, Hex } from 'viem' const EQ_OR_GT_1_4_1 = '>=1.4.1' const EQ_OR_GT_1_3_0 = '>=1.3.0' @@ -482,7 +484,7 @@ class Safe { ...options, to: await multiSendContract.getAddress(), value: '0', - data: multiSendContract.encode('multiSend', [multiSendData]), + data: multiSendContract.encode('multiSend', [asHex(multiSendData)]), operation: OperationType.DelegateCall } newTransaction = multiSendTransaction @@ -839,7 +841,10 @@ class Safe { const owners = await this.getOwners() const ownersWhoApproved: string[] = [] for (const owner of owners) { - const [approved] = await this.#contractManager.safeContract.approvedHashes([owner, txHash]) + const [approved] = await this.#contractManager.safeContract.approvedHashes([ + asAddress(owner), + asHash(txHash) + ]) if (approved > 0) { ownersWhoApproved.push(owner) } @@ -1400,8 +1405,8 @@ class Safe { value: '0', // we use the createProxyWithNonce method to create the Safe in a deterministic address, see: https://github.com/safe-global/safe-contracts/blob/main/contracts/proxies/SafeProxyFactory.sol#L52 data: safeProxyFactoryContract.encode('createProxyWithNonce', [ - await safeSingletonContract.getAddress(), - initializer, // call to the setup method to set the threshold & owners of the new Safe + asAddress(await safeSingletonContract.getAddress()), + asHex(initializer), // call to the setup method to set the threshold & owners of the new Safe BigInt(saltNonce) ]) } @@ -1435,7 +1440,7 @@ class Safe { // multiSend method with the transactions encoded const batchData = multiSendCallOnlyContract.encode('multiSend', [ - encodeMultiSendData(transactions) // encoded transactions + asHex(encodeMultiSendData(transactions)) // encoded transactions ]) const transactionBatch = { @@ -1507,17 +1512,17 @@ class Safe { const signatureToCheck = signature && Array.isArray(signature) ? buildSignatureBytes(signature) : signature - // @ts-expect-error Argument of type isValidSignature(bytes32,bytes) is not assignable to parameter of type isValidSignature - const data = fallbackHandler.encode('isValidSignature(bytes32,bytes)', [ - messageHash, - signatureToCheck - ]) - - // @ts-expect-error Argument of type isValidSignature(bytes32,bytes) is not assignable to parameter of type isValidSignature - const bytesData = fallbackHandler.encode('isValidSignature(bytes,bytes)', [ - messageHash, - signatureToCheck - ]) + const bytes32Tuple: [_dataHash: Hash, _signature: Hex] = [ + asHash(messageHash), + asHex(signatureToCheck) + ] + const data = fallbackHandler.encode('isValidSignature', bytes32Tuple) + + const bytesTuple: [_data: Hash, _signature: Hex] = [ + asHash(messageHash), + asHex(signatureToCheck) + ] + const bytesData = fallbackHandler.encode('isValidSignature', bytesTuple) try { const isValidSignatureResponse = await Promise.all([ diff --git a/packages/protocol-kit/src/SafeProvider.ts b/packages/protocol-kit/src/SafeProvider.ts index 7b79fde1d..4de47381d 100644 --- a/packages/protocol-kit/src/SafeProvider.ts +++ b/packages/protocol-kit/src/SafeProvider.ts @@ -1,15 +1,5 @@ -import { - ethers, - TransactionResponse, - AbstractSigner, - Provider, - BrowserProvider, - JsonRpcProvider -} from 'ethers' import { generateTypedData, validateEip3770Address } from '@safe-global/protocol-kit/utils' import { isTypedDataSigner } from '@safe-global/protocol-kit/contracts/utils' -import { EMPTY_DATA } from '@safe-global/protocol-kit/utils/constants' - import { EIP712TypedDataMessage, EIP712TypedDataTx, @@ -34,47 +24,109 @@ import { HttpTransport, SocketTransport } from '@safe-global/protocol-kit/types' +import { asAddress, asHash, asHex } from './utils/types' +import { + createPublicClient, + createWalletClient, + WalletClient, + PublicClient, + custom, + http, + getAddress, + isAddress, + Transaction, + decodeAbiParameters, + encodeAbiParameters, + parseAbiParameters, + toBytes, + BlockTag, + Transport, + Chain +} from 'viem' +import { privateKeyToAccount, Account } from 'viem/accounts' +import { toEstimateGasParameters, toCallGasParameters } from '@safe-global/protocol-kit/utils' + +function asBlockId(blockId: number | string | undefined) { + return typeof blockId === 'number' ? blockNumber(blockId) : blockTag(blockId) +} + +function blockNumber(blockNumber: any) { + return { blockNumber: blockNumber.toNumber() } +} + +function blockTag(blockTag: any) { + return { blockTag: blockTag as BlockTag } +} class SafeProvider { - #externalProvider: BrowserProvider | JsonRpcProvider + #externalProvider: PublicClient signer?: string provider: Eip1193Provider | HttpTransport | SocketTransport constructor({ provider, signer }: SafeProviderConfig) { if (typeof provider === 'string') { - this.#externalProvider = new JsonRpcProvider(provider) + this.#externalProvider = createPublicClient({ + transport: http(provider) + }) } else { - this.#externalProvider = new BrowserProvider(provider) + const client = createPublicClient({ + transport: custom(provider) + }) + this.#externalProvider = client } this.provider = provider - this.signer = signer + this.signer = signer ? asHex(signer) : signer } - getExternalProvider(): Provider { + getExternalProvider(): PublicClient { return this.#externalProvider } - async getExternalSigner(): Promise { + async getExternalSigner(): Promise< + WalletClient | undefined + > { // If the signer is not an Ethereum address, it should be a private key - if (this.signer && !ethers.isAddress(this.signer)) { - const privateKeySigner = new ethers.Wallet(this.signer, this.#externalProvider) - return privateKeySigner + const { transport, chain } = this.getExternalProvider() + if (this.signer && !this.isAddress(this.signer)) { + const account = privateKeyToAccount(asHex(this.signer)) + return createWalletClient({ + account, + chain, + transport: custom(transport) + }) } + // If we have a signer and its not a pk, it might be a delegate on the rpc levels and this should work with eth_requestAcc if (this.signer) { - return this.#externalProvider.getSigner(this.signer) + return createWalletClient({ + account: asAddress(this.signer), + chain, + transport: custom(transport) + }) } - if (this.#externalProvider instanceof BrowserProvider) { - return this.#externalProvider.getSigner() + if (transport?.type === 'custom') { + // This behavior is a reproduction of JsonRpcApiProvider#getSigner (which is super of BrowserProvider). + // it dispatches and eth_accounts and picks the index 0. https://github.com/ethers-io/ethers.js/blob/a4b1d1f43fca14f2e826e3c60e0d45f5b6ef3ec4/src.ts/providers/provider-jsonrpc.ts#L1119C24-L1119C37 + const wallet = createWalletClient({ + chain, + transport: custom(transport) + }) + + const [address] = await wallet.getAddresses() + return createWalletClient({ + account: address, + transport: custom(transport), + chain: wallet.chain + }) } return undefined } isAddress(address: string): boolean { - return ethers.isAddress(address) + return isAddress(address) } async getEip3770Address(fullAddress: string): Promise { @@ -83,19 +135,26 @@ class SafeProvider { } async getBalance(address: string, blockTag?: string | number): Promise { - return this.#externalProvider.getBalance(address, blockTag) + return this.#externalProvider.getBalance({ + address: asAddress(address), + ...asBlockId(blockTag) + }) } async getNonce(address: string, blockTag?: string | number): Promise { - return this.#externalProvider.getTransactionCount(address, blockTag) + return this.#externalProvider.getTransactionCount({ + address: asAddress(address), + ...asBlockId(blockTag) + }) } async getChainId(): Promise { - return (await this.#externalProvider.getNetwork()).chainId + const res = await this.#externalProvider.getChainId() + return BigInt(res) } getChecksummedAddress(address: string): string { - return ethers.getAddress(address) + return getAddress(asHex(address)) } async getSafeContract({ @@ -118,7 +177,7 @@ class SafeProvider { customContractAddress, customContractAbi }: GetContractProps) { - const signerOrProvider = (await this.getExternalSigner()) || this.#externalProvider + const signerOrProvider = this.#externalProvider return getSafeProxyFactoryContractInstance( safeVersion, this, @@ -202,39 +261,54 @@ class SafeProvider { } async getContractCode(address: string, blockTag?: string | number): Promise { - return this.#externalProvider.getCode(address, blockTag) + const res = this.#externalProvider.getCode({ + address: asAddress(address), + ...asBlockId(blockTag) + }) + return res?.toString() } async isContractDeployed(address: string, blockTag?: string | number): Promise { - const contractCode = await this.#externalProvider.getCode(address, blockTag) - return contractCode !== EMPTY_DATA + const contractCode = await this.#externalProvider.getCode({ + address: asAddress(address), + ...asBlockId(blockTag) + }) + // https://github.com/wevm/viem/blob/963877cd43083260a4399d6f0bbf142ccede53b4/src/actions/public/getCode.ts#L71 + return !!contractCode } async getStorageAt(address: string, position: string): Promise { - const content = await this.#externalProvider.getStorage(address, position) - const decodedContent = this.decodeParameters(['address'], content) + const content = await this.#externalProvider.getStorageAt({ + address: asAddress(address), + slot: asHex(position) + }) + const decodedContent = this.decodeParameters('address', asHex(content)) return decodedContent[0] } - async getTransaction(transactionHash: string): Promise { - return this.#externalProvider.getTransaction(transactionHash) as Promise + async getTransaction(transactionHash: string): Promise { + return this.#externalProvider.getTransaction({ + hash: asHash(transactionHash) + }) as Promise } async getSignerAddress(): Promise { - const signer = await this.getExternalSigner() - - return signer?.getAddress() + const externalSigner = await this.getExternalSigner() + return externalSigner ? getAddress(externalSigner.account.address) : undefined } async signMessage(message: string): Promise { const signer = await this.getExternalSigner() + const account = await this.getSignerAddress() - if (!signer) { + if (!signer || !account) { throw new Error('SafeProvider must be initialized with a signer to use this method') } - const messageArray = ethers.getBytes(message) - return signer.signMessage(messageArray) + return (await signer?.signMessage!({ + account: asHex(account), + message: { raw: toBytes(message) } + })) as string } async signTypedData(safeEIP712Args: SafeEIP712Args): Promise { @@ -246,13 +320,19 @@ class SafeProvider { if (isTypedDataSigner(signer)) { const typedData = generateTypedData(safeEIP712Args) - const signature = await signer.signTypedData( - typedData.domain, - typedData.primaryType === 'SafeMessage' - ? { SafeMessage: (typedData as EIP712TypedDataMessage).types.SafeMessage } - : { SafeTx: (typedData as EIP712TypedDataTx).types.SafeTx }, - typedData.message - ) + const { chainId, verifyingContract } = typedData.domain + const chain = chainId ? Number(chainId) : undefined // ensure empty string becomes undefined + const domain = { verifyingContract: asAddress(verifyingContract), chainId: chain } + + const signature = await signer.signTypedData({ + domain, + types: + typedData.primaryType === 'SafeMessage' + ? { SafeMessage: (typedData as EIP712TypedDataMessage).types.SafeMessage } + : { SafeTx: (typedData as EIP712TypedDataTx).types.SafeTx }, + primaryType: typedData.primaryType, + message: typedData.message + }) return signature } @@ -260,20 +340,26 @@ class SafeProvider { } async estimateGas(transaction: SafeProviderTransaction): Promise { - return (await this.#externalProvider.estimateGas(transaction)).toString() + const converted = toEstimateGasParameters(transaction) + return (await this.#externalProvider.estimateGas(converted)).toString() } - call(transaction: SafeProviderTransaction, blockTag?: string | number): Promise { - return this.#externalProvider.call({ ...transaction, blockTag }) + async call(transaction: SafeProviderTransaction, blockTag?: string | number): Promise { + const converted = toCallGasParameters(transaction) + const { data } = await this.#externalProvider.call({ + ...converted, + ...asBlockId(blockTag) + }) + return data ?? '0x' } // TODO: fix anys - encodeParameters(types: string[], values: any[]): string { - return new ethers.AbiCoder().encode(types, values) + encodeParameters(types: string, values: any[]): string { + return encodeAbiParameters(parseAbiParameters(types), values) } - decodeParameters(types: string[], values: string): { [key: string]: any } { - return new ethers.AbiCoder().decode(types, values) + decodeParameters(types: string, values: string): { [key: string]: any } { + return decodeAbiParameters(parseAbiParameters(types), asHex(values)) } } diff --git a/packages/protocol-kit/src/contracts/BaseContract.ts b/packages/protocol-kit/src/contracts/BaseContract.ts index 3041893a1..10c42910b 100644 --- a/packages/protocol-kit/src/contracts/BaseContract.ts +++ b/packages/protocol-kit/src/contracts/BaseContract.ts @@ -1,14 +1,27 @@ import { Abi } from 'abitype' -import { Contract, ContractRunner, InterfaceAbi } from 'ethers' - +import { + PublicClient, + Address, + getContract, + encodeFunctionData, + GetContractReturnType, + WalletClient, + Hash, + Chain +} from 'viem' import { contractName, getContractDeployment } from '@safe-global/protocol-kit/contracts/config' import SafeProvider from '@safe-global/protocol-kit/SafeProvider' +import * as allChains from 'viem/chains' import { EncodeFunction, EstimateGasFunction, GetAddressFunction, - SafeVersion + SafeVersion, + TransactionOptions } from '@safe-global/safe-core-sdk-types' +import { asAddress } from '../utils/types' +import { ContractTransactionOptions, ContractLegacyTransactionOptions } from '../types/contracts' +import { isLegacyTransaction, createTxOptions, createLegacyTxOptions } from './utils' /** * Abstract class BaseContract @@ -25,14 +38,15 @@ import { * - CreateCallBaseContract extends BaseContract * - SafeProxyFactoryBaseContract extends BaseContract */ -class BaseContract { +class BaseContract { contractAbi: ContractAbiType contractAddress: string contractName: contractName safeVersion: SafeVersion safeProvider: SafeProvider - contract!: Contract - runner?: ContractRunner | null + chainId: bigint + contract!: GetContractReturnType + runner: PublicClient | null /** * @constructor @@ -54,7 +68,7 @@ class BaseContract { safeVersion: SafeVersion, customContractAddress?: string, customContractAbi?: ContractAbiType, - runner?: ContractRunner | null + runner?: PublicClient | null ) { const deployment = getContractDeployment(safeVersion, chainId, contractName) @@ -67,6 +81,7 @@ class BaseContract { throw new Error(`Invalid ${contractName.replace('Version', '')} contract address`) } + this.chainId = chainId this.contractName = contractName this.safeVersion = safeVersion this.contractAddress = contractAddress @@ -80,24 +95,66 @@ class BaseContract { } async init() { - this.contract = new Contract( - this.contractAddress, - this.contractAbi, - (await this.safeProvider.getExternalSigner()) || this.runner - ) + const client = this.runner || (await this.safeProvider.getExternalSigner()) + this.contract = getContract({ + address: this.contractAddress as Address, + abi: this.contractAbi, + client: client! + }) + } + + async getTransactionReceipt(hash: Hash) { + const client = this.runner + return client?.getTransactionReceipt({ hash }) + } + + async convertOptions( + options?: TransactionOptions + ): Promise { + const chain = this.getChain() + if (!chain) throw new Error('Invalid chainId') + const signerAddress = await this.safeProvider.getSignerAddress() + const account = asAddress(signerAddress!) + const txOptions = isLegacyTransaction(options) + ? createLegacyTxOptions(options) + : createTxOptions(options) + return { chain, account, ...txOptions } // Needs to be in this order to override the `account` if necessary + } + + getChain(): Chain | undefined { + return Object.values(allChains).find((chain) => chain.id === Number(this.chainId)) } getAddress: GetAddressFunction = () => { - return this.contract.getAddress() + return Promise.resolve(this.contract.address) } encode: EncodeFunction = (functionToEncode, args) => { - return this.contract.interface.encodeFunctionData(functionToEncode, args as ReadonlyArray<[]>) + const abi = this.contractAbi as Abi + const functionName = functionToEncode as string + const params = args as unknown[] + return encodeFunctionData({ + abi, + functionName, + args: params + }) } - estimateGas: EstimateGasFunction = (functionToEstimate, args, options = {}) => { - const contractMethodToEstimate = this.contract.getFunction(functionToEstimate) - return contractMethodToEstimate.estimateGas(...(args as ReadonlyArray<[]>), options) + estimateGas: EstimateGasFunction = async ( + functionToEstimate, + args, + options = {} + ) => { + const contractOptions = await this.convertOptions(options) + const abi = this.contractAbi as Abi + const params = args as unknown[] + return this.runner!.estimateContractGas({ + abi, + functionName: functionToEstimate, + address: this.contract.address, + args: params, + ...contractOptions + }) } } diff --git a/packages/protocol-kit/src/contracts/CompatibilityFallbackHandler/CompatibilityFallbackHandlerBaseContract.ts b/packages/protocol-kit/src/contracts/CompatibilityFallbackHandler/CompatibilityFallbackHandlerBaseContract.ts index 2583b1b10..fde1eb24a 100644 --- a/packages/protocol-kit/src/contracts/CompatibilityFallbackHandler/CompatibilityFallbackHandlerBaseContract.ts +++ b/packages/protocol-kit/src/contracts/CompatibilityFallbackHandler/CompatibilityFallbackHandlerBaseContract.ts @@ -1,5 +1,5 @@ import { Abi } from 'abitype' -import { ContractRunner, InterfaceAbi } from 'ethers' +import { PublicClient } from 'viem' import SafeProvider from '@safe-global/protocol-kit/SafeProvider' import BaseContract from '@safe-global/protocol-kit/contracts/BaseContract' @@ -20,7 +20,7 @@ import { contractName } from '@safe-global/protocol-kit/contracts/config' * - CompatibilityFallbackHandlerContract_v1_3_0 extends CompatibilityFallbackHandlerBaseContract */ abstract class CompatibilityFallbackHandlerBaseContract< - CompatibilityFallbackHandlerContractAbiType extends InterfaceAbi & Abi + CompatibilityFallbackHandlerContractAbiType extends Abi > extends BaseContract { contractName: contractName @@ -42,7 +42,7 @@ abstract class CompatibilityFallbackHandlerBaseContract< safeVersion: SafeVersion, customContractAddress?: string, customContractAbi?: CompatibilityFallbackHandlerContractAbiType, - runner?: ContractRunner | null + runner?: PublicClient | null ) { const contractName = 'compatibilityFallbackHandler' diff --git a/packages/protocol-kit/src/contracts/CreateCall/CreateCallBaseContract.ts b/packages/protocol-kit/src/contracts/CreateCall/CreateCallBaseContract.ts index 9dc3ae51d..f4518daab 100644 --- a/packages/protocol-kit/src/contracts/CreateCall/CreateCallBaseContract.ts +++ b/packages/protocol-kit/src/contracts/CreateCall/CreateCallBaseContract.ts @@ -1,5 +1,5 @@ import { Abi } from 'abitype' -import { ContractRunner, InterfaceAbi } from 'ethers' +import { PublicClient } from 'viem' import SafeProvider from '@safe-global/protocol-kit/SafeProvider' import BaseContract from '@safe-global/protocol-kit/contracts/BaseContract' @@ -20,7 +20,7 @@ import { contractName } from '@safe-global/protocol-kit/contracts/config' * - CreateCallContract_v1_3_0 extends CreateCallBaseContract */ abstract class CreateCallBaseContract< - CreateCallContractAbiType extends InterfaceAbi & Abi + CreateCallContractAbiType extends Abi > extends BaseContract { contractName: contractName @@ -42,7 +42,7 @@ abstract class CreateCallBaseContract< safeVersion: SafeVersion, customContractAddress?: string, customContractAbi?: CreateCallContractAbiType, - runner?: ContractRunner | null + runner?: PublicClient | null ) { const contractName = 'createCallVersion' diff --git a/packages/protocol-kit/src/contracts/CreateCall/v1.3.0/CreateCallContract_v1_3_0.ts b/packages/protocol-kit/src/contracts/CreateCall/v1.3.0/CreateCallContract_v1_3_0.ts index 9d44b93c7..43d97521e 100644 --- a/packages/protocol-kit/src/contracts/CreateCall/v1.3.0/CreateCallContract_v1_3_0.ts +++ b/packages/protocol-kit/src/contracts/CreateCall/v1.3.0/CreateCallContract_v1_3_0.ts @@ -59,8 +59,11 @@ class CreateCallContract_v1_3_0 await this.estimateGas('performCreate', [...args], { ...options }) ).toString() } - const txResponse = await this.contract.performCreate(...args, { ...options }) - return toTxResult(txResponse, options) + const txResponse = await this.contract.write.performCreate( + args, + await this.convertOptions(options) + ) + return toTxResult(this.runner!, txResponse, options) } /** @@ -75,8 +78,11 @@ class CreateCallContract_v1_3_0 if (options && !options.gasLimit) { options.gasLimit = (await this.estimateGas('performCreate2', args, options)).toString() } - const txResponse = await this.contract.performCreate2(...args) - return toTxResult(txResponse, options) + const txResponse = await this.contract.write.performCreate2( + args, + await this.convertOptions(options) + ) + return toTxResult(this.runner!, txResponse, options) } } diff --git a/packages/protocol-kit/src/contracts/CreateCall/v1.4.1/CreateCallContract_v1_4_1.ts b/packages/protocol-kit/src/contracts/CreateCall/v1.4.1/CreateCallContract_v1_4_1.ts index f9f1e0094..50a194917 100644 --- a/packages/protocol-kit/src/contracts/CreateCall/v1.4.1/CreateCallContract_v1_4_1.ts +++ b/packages/protocol-kit/src/contracts/CreateCall/v1.4.1/CreateCallContract_v1_4_1.ts @@ -57,8 +57,11 @@ class CreateCallContract_v1_4_1 if (options && !options.gasLimit) { options.gasLimit = (await this.estimateGas('performCreate', args, options)).toString() } - const txResponse = await this.contract.performCreate(...args, options) - return toTxResult(txResponse, options) + const txResponse = await this.contract.write.performCreate( + args, + await this.convertOptions(options) + ) + return toTxResult(this.runner!, txResponse, options) } /** @@ -75,8 +78,11 @@ class CreateCallContract_v1_4_1 await this.estimateGas('performCreate2', [...args], { ...options }) ).toString() } - const txResponse = await this.contract.performCreate2(...args) - return toTxResult(txResponse, options) + const txResponse = await this.contract.write.performCreate2( + args, + await this.convertOptions(options) + ) + return toTxResult(this.runner!, txResponse, options) } } diff --git a/packages/protocol-kit/src/contracts/MultiSend/MultiSendBaseContract.ts b/packages/protocol-kit/src/contracts/MultiSend/MultiSendBaseContract.ts index 835be1b2f..a3f285fda 100644 --- a/packages/protocol-kit/src/contracts/MultiSend/MultiSendBaseContract.ts +++ b/packages/protocol-kit/src/contracts/MultiSend/MultiSendBaseContract.ts @@ -1,5 +1,4 @@ import { Abi } from 'abitype' -import { InterfaceAbi } from 'ethers' import SafeProvider from '@safe-global/protocol-kit/SafeProvider' import { SafeVersion } from '@safe-global/safe-core-sdk-types' @@ -20,7 +19,7 @@ import { contractName } from '@safe-global/protocol-kit/contracts/config' * - MultiSendContract_v1_3_0 extends MultiSendBaseContract */ abstract class MultiSendBaseContract< - MultiSendContractAbiType extends InterfaceAbi & Abi + MultiSendContractAbiType extends Abi > extends BaseContract { contractName: contractName diff --git a/packages/protocol-kit/src/contracts/MultiSend/MultiSendCallOnlyBaseContract.ts b/packages/protocol-kit/src/contracts/MultiSend/MultiSendCallOnlyBaseContract.ts index bd69961e1..1397adeb8 100644 --- a/packages/protocol-kit/src/contracts/MultiSend/MultiSendCallOnlyBaseContract.ts +++ b/packages/protocol-kit/src/contracts/MultiSend/MultiSendCallOnlyBaseContract.ts @@ -1,5 +1,4 @@ import { Abi } from 'abitype' -import { InterfaceAbi } from 'ethers' import SafeProvider from '@safe-global/protocol-kit/SafeProvider' import { SafeVersion } from '@safe-global/safe-core-sdk-types' @@ -20,7 +19,7 @@ import { contractName } from '@safe-global/protocol-kit/contracts/config' * - MultiSendCallOnlyContract_v1_3_0 extends MultiSendCallOnlyBaseContract */ abstract class MultiSendCallOnlyBaseContract< - MultiSendCallOnlyContractAbiType extends InterfaceAbi & Abi + MultiSendCallOnlyContractAbiType extends Abi > extends BaseContract { contractName: contractName diff --git a/packages/protocol-kit/src/contracts/Safe/SafeBaseContract.ts b/packages/protocol-kit/src/contracts/Safe/SafeBaseContract.ts index 04eac3d53..6ab5aa848 100644 --- a/packages/protocol-kit/src/contracts/Safe/SafeBaseContract.ts +++ b/packages/protocol-kit/src/contracts/Safe/SafeBaseContract.ts @@ -1,5 +1,4 @@ import { Abi } from 'abitype' -import { InterfaceAbi } from 'ethers' import SafeProvider from '@safe-global/protocol-kit/SafeProvider' import { SafeVersion } from '@safe-global/safe-core-sdk-types' @@ -24,7 +23,7 @@ import { SAFE_FEATURES, hasSafeFeature } from '@safe-global/protocol-kit/utils' * - SafeContract_v1_0_0 extends SafeBaseContract */ abstract class SafeBaseContract< - SafeContractAbiType extends InterfaceAbi & Abi + SafeContractAbiType extends Abi > extends BaseContract { contractName: contractName diff --git a/packages/protocol-kit/src/contracts/Safe/v1.0.0/SafeContract_v1_0_0.ts b/packages/protocol-kit/src/contracts/Safe/v1.0.0/SafeContract_v1_0_0.ts index c969d0446..0635625bf 100644 --- a/packages/protocol-kit/src/contracts/Safe/v1.0.0/SafeContract_v1_0_0.ts +++ b/packages/protocol-kit/src/contracts/Safe/v1.0.0/SafeContract_v1_0_0.ts @@ -13,6 +13,8 @@ import { TransactionResult } from '@safe-global/safe-core-sdk-types' import { SENTINEL_ADDRESS } from '@safe-global/protocol-kit/utils/constants' +import { asAddress, asHash, asHex } from '@safe-global/protocol-kit/utils/types' +import { Address } from 'viem' /** * SafeContract_v1_0_0 is the implementation specific to the Safe contract version 1.0.0. @@ -63,23 +65,23 @@ class SafeContract_v1_0_0 /* ----- Specific v1.0.0 properties ----- */ DOMAIN_SEPARATOR_TYPEHASH: SafeContract_v1_0_0_Function<'DOMAIN_SEPARATOR_TYPEHASH'> = async () => { - return [await this.contract.DOMAIN_SEPARATOR_TYPEHASH()] + return [await this.contract.read.DOMAIN_SEPARATOR_TYPEHASH()] } SENTINEL_MODULES: SafeContract_v1_0_0_Function<'SENTINEL_MODULES'> = async () => { - return [await this.contract.SENTINEL_MODULES()] + return [await this.contract.read.SENTINEL_MODULES()] } SENTINEL_OWNERS: SafeContract_v1_0_0_Function<'SENTINEL_OWNERS'> = async () => { - return [await this.contract.SENTINEL_OWNERS()] + return [await this.contract.read.SENTINEL_OWNERS()] } SAFE_MSG_TYPEHASH: SafeContract_v1_0_0_Function<'SAFE_MSG_TYPEHASH'> = async () => { - return [await this.contract.SAFE_MSG_TYPEHASH()] + return [await this.contract.read.SAFE_MSG_TYPEHASH()] } SAFE_TX_TYPEHASH: SafeContract_v1_0_0_Function<'SAFE_TX_TYPEHASH'> = async () => { - return [await this.contract.SAFE_TX_TYPEHASH()] + return [await this.contract.read.SAFE_TX_TYPEHASH()] } /* ----- End of specific v1.0.0 properties ----- */ @@ -87,14 +89,14 @@ class SafeContract_v1_0_0 * @returns Array[contractName] */ NAME: SafeContract_v1_0_0_Function<'NAME'> = async () => { - return [await this.contract.NAME()] + return [await this.contract.read.NAME()] } /** * @returns Array[safeContractVersion] */ VERSION: SafeContract_v1_0_0_Function<'VERSION'> = async () => { - return [await this.contract.VERSION()] + return [await this.contract.read.VERSION()] } /** @@ -102,14 +104,14 @@ class SafeContract_v1_0_0 * @returns Array[approvedHashes] */ approvedHashes: SafeContract_v1_0_0_Function<'approvedHashes'> = async (args) => { - return [await this.contract.approvedHashes(...args)] + return [await this.contract.read.approvedHashes(args)] } /** * @returns Array[domainSeparator] */ domainSeparator: SafeContract_v1_0_0_Function<'domainSeparator'> = async () => { - return [await this.contract.domainSeparator()] + return [await this.contract.read.domainSeparator()] } /** @@ -117,7 +119,7 @@ class SafeContract_v1_0_0 * @returns Array[Array[modules]] */ getModules: SafeContract_v1_0_0_Function<'getModules'> = async () => { - return [await this.contract.getModules()] + return [await this.contract.read.getModules()] } /** @@ -125,7 +127,7 @@ class SafeContract_v1_0_0 * @returns Array[Array[owners]] */ getOwners: SafeContract_v1_0_0_Function<'getOwners'> = async () => { - return [await this.contract.getOwners()] + return [await this.contract.read.getOwners()] } /** @@ -133,7 +135,7 @@ class SafeContract_v1_0_0 * @returns Array[threshold] */ getThreshold: SafeContract_v1_0_0_Function<'getThreshold'> = async () => { - return [await this.contract.getThreshold()] + return [await this.contract.read.getThreshold()] } /** @@ -142,7 +144,7 @@ class SafeContract_v1_0_0 * @returns Array[isOwner] */ isOwner: SafeContract_v1_0_0_Function<'isOwner'> = async (args) => { - return [await this.contract.isOwner(...args)] + return [await this.contract.read.isOwner(args)] } /** @@ -150,7 +152,7 @@ class SafeContract_v1_0_0 * @returns Array[nonce] */ nonce: SafeContract_v1_0_0_Function<'nonce'> = async () => { - return [await this.contract.nonce()] + return [await this.contract.read.nonce()] } /** @@ -158,7 +160,7 @@ class SafeContract_v1_0_0 * @returns Array[signedMessages] */ signedMessages: SafeContract_v1_0_0_Function<'signedMessages'> = async (args) => { - return [await this.contract.signedMessages(...args)] + return [await this.contract.read.signedMessages(args)] } /** @@ -167,7 +169,7 @@ class SafeContract_v1_0_0 * @returns Array[messageHash] */ getMessageHash: SafeContract_v1_0_0_Function<'getMessageHash'> = async (args) => { - return [await this.contract.getMessageHash(...args)] + return [await this.contract.read.getMessageHash(args)] } /** @@ -176,7 +178,7 @@ class SafeContract_v1_0_0 * @returns Array[encodedData] */ encodeTransactionData: SafeContract_v1_0_0_Function<'encodeTransactionData'> = async (args) => { - return [await this.contract.encodeTransactionData(...args)] + return [await this.contract.read.encodeTransactionData(args)] } /** @@ -185,7 +187,7 @@ class SafeContract_v1_0_0 * @returns Array[transactionHash] */ getTransactionHash: SafeContract_v1_0_0_Function<'getTransactionHash'> = async (args) => { - return [await this.contract.getTransactionHash(...args)] + return [await this.contract.read.getTransactionHash(args)] } /** @@ -195,10 +197,17 @@ class SafeContract_v1_0_0 * @returns Transaction result. */ async approveHash(hash: string, options?: TransactionOptions): Promise { - const gasLimit = options?.gasLimit || (await this.estimateGas('approveHash', [hash], options)) - const txResponse = await this.contract.approveHash(hash, { ...options, gasLimit }) + const gasLimit = + options?.gasLimit || (await this.estimateGas('approveHash', [asHash(hash)], options)) + const txResponse = await this.contract.write.approveHash( + [asHash(hash)], + await this.convertOptions({ + ...options, + gasLimit + }) + ) - return toTxResult(txResponse, options) + return toTxResult(this.runner!, txResponse, options) } /** @@ -216,38 +225,40 @@ class SafeContract_v1_0_0 (await this.estimateGas( 'execTransaction', [ - safeTransaction.data.to, + asAddress(safeTransaction.data.to), BigInt(safeTransaction.data.value), - safeTransaction.data.data, + asHex(safeTransaction.data.data), safeTransaction.data.operation, BigInt(safeTransaction.data.safeTxGas), BigInt(safeTransaction.data.baseGas), BigInt(safeTransaction.data.gasPrice), - safeTransaction.data.gasToken, - safeTransaction.data.refundReceiver, - safeTransaction.encodedSignatures() + asAddress(safeTransaction.data.gasToken), + asAddress(safeTransaction.data.refundReceiver), + asHex(safeTransaction.encodedSignatures()) ], options )) - const txResponse = await this.contract.execTransaction( - safeTransaction.data.to, - safeTransaction.data.value, - safeTransaction.data.data, - safeTransaction.data.operation, - safeTransaction.data.safeTxGas, - safeTransaction.data.baseGas, - safeTransaction.data.gasPrice, - safeTransaction.data.gasToken, - safeTransaction.data.refundReceiver, - safeTransaction.encodedSignatures(), - { ...options, gasLimit } + const txResponse = await this.contract.write.execTransaction( + [ + asAddress(safeTransaction.data.to), + BigInt(safeTransaction.data.value), + asHex(safeTransaction.data.data), + safeTransaction.data.operation, + BigInt(safeTransaction.data.safeTxGas), + BigInt(safeTransaction.data.baseGas), + BigInt(safeTransaction.data.gasPrice), + asAddress(safeTransaction.data.gasToken), + asAddress(safeTransaction.data.refundReceiver), + asHex(safeTransaction.encodedSignatures()) + ], + await this.convertOptions({ ...options, gasLimit }) ) - return toTxResult(txResponse, options) + return toTxResult(this.runner!, txResponse, options) } - async getModulesPaginated([start, pageSize]: [string, bigint]): Promise<[string[], string]> { + async getModulesPaginated([start, pageSize]: [Address, bigint]): Promise<[string[], string]> { if (pageSize <= 0) throw new Error('Invalid page size for fetching paginated modules') const size = Number(pageSize) @@ -274,7 +285,7 @@ class SafeContract_v1_0_0 * @param moduleAddress - The module address to check. * @returns True, if the module with the given address is enabled. */ - async isModuleEnabled([moduleAddress]: [string]): Promise<[boolean]> { + async isModuleEnabled([moduleAddress]: [Address]): Promise<[boolean]> { const [modules] = await this.getModules() const isModuleEnabled = modules.some((enabledModuleAddress) => sameString(enabledModuleAddress, moduleAddress) @@ -298,33 +309,37 @@ class SafeContract_v1_0_0 (await this.estimateGas( 'execTransaction', [ - safeTransaction.data.to, + asAddress(safeTransaction.data.to), BigInt(safeTransaction.data.value), - safeTransaction.data.data, + asHex(safeTransaction.data.data), safeTransaction.data.operation, BigInt(safeTransaction.data.safeTxGas), BigInt(safeTransaction.data.baseGas), BigInt(safeTransaction.data.gasPrice), - safeTransaction.data.gasToken, - safeTransaction.data.refundReceiver, - safeTransaction.encodedSignatures() + asAddress(safeTransaction.data.gasToken), + asAddress(safeTransaction.data.refundReceiver), + asHex(safeTransaction.encodedSignatures()) ], options )) - return await this.contract.execTransaction.staticCall( - safeTransaction.data.to, - BigInt(safeTransaction.data.value), - safeTransaction.data.data, - safeTransaction.data.operation, - BigInt(safeTransaction.data.safeTxGas), - BigInt(safeTransaction.data.baseGas), - BigInt(safeTransaction.data.gasPrice), - safeTransaction.data.gasToken, - safeTransaction.data.refundReceiver, - safeTransaction.encodedSignatures(), - { ...options, gasLimit } + const txResult = await this.contract.simulate.execTransaction( + [ + asAddress(safeTransaction.data.to), + BigInt(safeTransaction.data.value), + asHex(safeTransaction.data.data), + safeTransaction.data.operation, + BigInt(safeTransaction.data.safeTxGas), + BigInt(safeTransaction.data.baseGas), + BigInt(safeTransaction.data.gasPrice), + asAddress(safeTransaction.data.gasToken), + asAddress(safeTransaction.data.refundReceiver), + asHex(safeTransaction.encodedSignatures()) + ], + await this.convertOptions({ ...options, gasLimit }) ) + + return txResult.result } catch (error) { return false } diff --git a/packages/protocol-kit/src/contracts/Safe/v1.1.1/SafeContract_v1_1_1.ts b/packages/protocol-kit/src/contracts/Safe/v1.1.1/SafeContract_v1_1_1.ts index 970eb6b5a..53175a7ef 100644 --- a/packages/protocol-kit/src/contracts/Safe/v1.1.1/SafeContract_v1_1_1.ts +++ b/packages/protocol-kit/src/contracts/Safe/v1.1.1/SafeContract_v1_1_1.ts @@ -12,6 +12,7 @@ import { TransactionOptions, TransactionResult } from '@safe-global/safe-core-sdk-types' +import { asAddress, asHash, asHex } from '@safe-global/protocol-kit/utils/types' /** * SafeContract_v1_1_1 is the implementation specific to the Safe contract version 1.1.1. @@ -63,14 +64,14 @@ class SafeContract_v1_1_1 * @returns Array[contractName] */ NAME: SafeContract_v1_1_1_Function<'NAME'> = async () => { - return [await this.contract.NAME()] + return [await this.contract.read.NAME()] } /** * @returns Array[safeContractVersion] */ VERSION: SafeContract_v1_1_1_Function<'VERSION'> = async () => { - return [await this.contract.VERSION()] + return [await this.contract.read.VERSION()] } /** @@ -78,14 +79,14 @@ class SafeContract_v1_1_1 * @returns Array[approvedHashes] */ approvedHashes: SafeContract_v1_1_1_Function<'approvedHashes'> = async (args) => { - return [await this.contract.approvedHashes(...args)] + return [await this.contract.read.approvedHashes(args)] } /** * @returns Array[domainSeparator] */ domainSeparator: SafeContract_v1_1_1_Function<'domainSeparator'> = async () => { - return [await this.contract.domainSeparator()] + return [await this.contract.read.domainSeparator()] } /** @@ -93,7 +94,7 @@ class SafeContract_v1_1_1 * @returns Array[Array[modules]] */ getModules: SafeContract_v1_1_1_Function<'getModules'> = async () => { - return [await this.contract.getModules()] + return [await this.contract.read.getModules()] } /** @@ -102,8 +103,8 @@ class SafeContract_v1_1_1 * @returns Array[Array[modules], next] */ getModulesPaginated: SafeContract_v1_1_1_Function<'getModulesPaginated'> = async (args) => { - const res = await this.contract.getModulesPaginated(...args) - return [res.array, res.next] + const [array, next] = await this.contract.read.getModulesPaginated(args) + return [array, next] } /** @@ -111,7 +112,7 @@ class SafeContract_v1_1_1 * @returns Array[Array[owners]] */ getOwners: SafeContract_v1_1_1_Function<'getOwners'> = async () => { - return [await this.contract.getOwners()] + return [await this.contract.read.getOwners()] } /** @@ -119,7 +120,7 @@ class SafeContract_v1_1_1 * @returns Array[threshold] */ getThreshold: SafeContract_v1_1_1_Function<'getThreshold'> = async () => { - return [await this.contract.getThreshold()] + return [await this.contract.read.getThreshold()] } /** @@ -128,7 +129,7 @@ class SafeContract_v1_1_1 * @returns Array[isOwner] */ isOwner: SafeContract_v1_1_1_Function<'isOwner'> = async (args) => { - return [await this.contract.isOwner(...args)] + return [await this.contract.read.isOwner(args)] } /** @@ -136,7 +137,7 @@ class SafeContract_v1_1_1 * @returns Array[nonce] */ nonce: SafeContract_v1_1_1_Function<'nonce'> = async () => { - return [await this.contract.nonce()] + return [await this.contract.read.nonce()] } /** @@ -144,7 +145,7 @@ class SafeContract_v1_1_1 * @returns Array[signedMessages] */ signedMessages: SafeContract_v1_1_1_Function<'signedMessages'> = async (args) => { - return [await this.contract.signedMessages(...args)] + return [await this.contract.read.signedMessages(args)] } /** @@ -153,7 +154,7 @@ class SafeContract_v1_1_1 * @returns Array[messageHash] */ getMessageHash: SafeContract_v1_1_1_Function<'getMessageHash'> = async (args) => { - return [await this.contract.getMessageHash(...args)] + return [await this.contract.read.getMessageHash(args)] } /** @@ -162,7 +163,7 @@ class SafeContract_v1_1_1 * @returns Array[encodedData] */ encodeTransactionData: SafeContract_v1_1_1_Function<'encodeTransactionData'> = async (args) => { - return [await this.contract.encodeTransactionData(...args)] + return [await this.contract.read.encodeTransactionData(args)] } /** @@ -171,7 +172,7 @@ class SafeContract_v1_1_1 * @returns Array[transactionHash] */ getTransactionHash: SafeContract_v1_1_1_Function<'getTransactionHash'> = async (args) => { - return [await this.contract.getTransactionHash(...args)] + return [await this.contract.read.getTransactionHash(args)] } /** @@ -181,10 +182,14 @@ class SafeContract_v1_1_1 * @returns Transaction result. */ async approveHash(hash: string, options?: TransactionOptions): Promise { - const gasLimit = options?.gasLimit || (await this.estimateGas('approveHash', [hash], options)) - const txResponse = await this.contract.approveHash(hash, { ...options, gasLimit }) + const gasLimit = + options?.gasLimit || (await this.estimateGas('approveHash', [asHash(hash)], options)) + const txResponse = await this.contract.write.approveHash( + [asHash(hash)], + await this.convertOptions({ ...options, gasLimit }) + ) - return toTxResult(txResponse, options) + return toTxResult(this.runner!, txResponse, options) } /** @@ -202,35 +207,37 @@ class SafeContract_v1_1_1 (await this.estimateGas( 'execTransaction', [ - safeTransaction.data.to, + asAddress(safeTransaction.data.to), BigInt(safeTransaction.data.value), - safeTransaction.data.data, + asHex(safeTransaction.data.data), safeTransaction.data.operation, BigInt(safeTransaction.data.safeTxGas), BigInt(safeTransaction.data.baseGas), BigInt(safeTransaction.data.gasPrice), - safeTransaction.data.gasToken, - safeTransaction.data.refundReceiver, - safeTransaction.encodedSignatures() + asAddress(safeTransaction.data.gasToken), + asAddress(safeTransaction.data.refundReceiver), + asHex(safeTransaction.encodedSignatures()) ], options )) - const txResponse = await this.contract.execTransaction( - safeTransaction.data.to, - safeTransaction.data.value, - safeTransaction.data.data, - safeTransaction.data.operation, - safeTransaction.data.safeTxGas, - safeTransaction.data.baseGas, - safeTransaction.data.gasPrice, - safeTransaction.data.gasToken, - safeTransaction.data.refundReceiver, - safeTransaction.encodedSignatures(), - { ...options, gasLimit } + const txResponse = await this.contract.write.execTransaction( + [ + asAddress(safeTransaction.data.to), + BigInt(safeTransaction.data.value), + asHex(safeTransaction.data.data), + safeTransaction.data.operation, + BigInt(safeTransaction.data.safeTxGas), + BigInt(safeTransaction.data.baseGas), + BigInt(safeTransaction.data.gasPrice), + asAddress(safeTransaction.data.gasToken), + asAddress(safeTransaction.data.refundReceiver), + asHex(safeTransaction.encodedSignatures()) + ], + await this.convertOptions({ ...options, gasLimit }) ) - return toTxResult(txResponse, options) + return toTxResult(this.runner!, txResponse, options) } /** @@ -262,33 +269,37 @@ class SafeContract_v1_1_1 (await this.estimateGas( 'execTransaction', [ - safeTransaction.data.to, + asAddress(safeTransaction.data.to), BigInt(safeTransaction.data.value), - safeTransaction.data.data, + asHex(safeTransaction.data.data), safeTransaction.data.operation, BigInt(safeTransaction.data.safeTxGas), BigInt(safeTransaction.data.baseGas), BigInt(safeTransaction.data.gasPrice), - safeTransaction.data.gasToken, - safeTransaction.data.refundReceiver, - safeTransaction.encodedSignatures() + asAddress(safeTransaction.data.gasToken), + asAddress(safeTransaction.data.refundReceiver), + asHex(safeTransaction.encodedSignatures()) ], options )) - return await this.contract.execTransaction.staticCall( - safeTransaction.data.to, - BigInt(safeTransaction.data.value), - safeTransaction.data.data, - safeTransaction.data.operation, - BigInt(safeTransaction.data.safeTxGas), - BigInt(safeTransaction.data.baseGas), - BigInt(safeTransaction.data.gasPrice), - safeTransaction.data.gasToken, - safeTransaction.data.refundReceiver, - safeTransaction.encodedSignatures(), - { ...options, gasLimit } + const transactionResult = await this.contract.simulate.execTransaction( + [ + asAddress(safeTransaction.data.to), + BigInt(safeTransaction.data.value), + asHex(safeTransaction.data.data), + safeTransaction.data.operation, + BigInt(safeTransaction.data.safeTxGas), + BigInt(safeTransaction.data.baseGas), + BigInt(safeTransaction.data.gasPrice), + asAddress(safeTransaction.data.gasToken), + asAddress(safeTransaction.data.refundReceiver), + asHex(safeTransaction.encodedSignatures()) + ], + await this.convertOptions({ ...options, gasLimit }) ) + + return transactionResult.result } catch (error) { return false } diff --git a/packages/protocol-kit/src/contracts/Safe/v1.2.0/SafeContract_v1_2_0.ts b/packages/protocol-kit/src/contracts/Safe/v1.2.0/SafeContract_v1_2_0.ts index e6f130ad6..3764e0a20 100644 --- a/packages/protocol-kit/src/contracts/Safe/v1.2.0/SafeContract_v1_2_0.ts +++ b/packages/protocol-kit/src/contracts/Safe/v1.2.0/SafeContract_v1_2_0.ts @@ -11,6 +11,7 @@ import { TransactionOptions, TransactionResult } from '@safe-global/safe-core-sdk-types' +import { asAddress, asHash, asHex } from '@safe-global/protocol-kit/utils/types' /** * SafeContract_v1_2_0 is the implementation specific to the Safe contract version 1.2.0. @@ -62,14 +63,14 @@ class SafeContract_v1_2_0 * @returns Array[contractName] */ NAME: SafeContract_v1_2_0_Function<'NAME'> = async () => { - return [await this.contract.NAME()] + return [await this.contract.read.NAME()] } /** * @returns Array[safeContractVersion] */ VERSION: SafeContract_v1_2_0_Function<'VERSION'> = async () => { - return [await this.contract.VERSION()] + return [await this.contract.read.VERSION()] } /** @@ -77,14 +78,14 @@ class SafeContract_v1_2_0 * @returns Array[approvedHashes] */ approvedHashes: SafeContract_v1_2_0_Function<'approvedHashes'> = async (args) => { - return [await this.contract.approvedHashes(...args)] + return [await this.contract.read.approvedHashes(args)] } /** * @returns Array[domainSeparator] */ domainSeparator: SafeContract_v1_2_0_Function<'domainSeparator'> = async () => { - return [await this.contract.domainSeparator()] + return [await this.contract.read.domainSeparator()] } /** @@ -92,7 +93,7 @@ class SafeContract_v1_2_0 * @returns Array[Array[modules]] */ getModules: SafeContract_v1_2_0_Function<'getModules'> = async () => { - return [await this.contract.getModules()] + return [await this.contract.read.getModules()] } /** @@ -101,8 +102,8 @@ class SafeContract_v1_2_0 * @returns Array[Array[modules], next] */ getModulesPaginated: SafeContract_v1_2_0_Function<'getModulesPaginated'> = async (args) => { - const res = await this.contract.getModulesPaginated(...args) - return [res.array, res.next] + const [array, next] = await this.contract.read.getModulesPaginated(args) + return [array, next] } /** @@ -110,7 +111,7 @@ class SafeContract_v1_2_0 * @returns Array[Array[owners]] */ getOwners: SafeContract_v1_2_0_Function<'getOwners'> = async () => { - return [await this.contract.getOwners()] + return [await this.contract.read.getOwners()] } /** @@ -118,7 +119,7 @@ class SafeContract_v1_2_0 * @returns Array[threshold] */ getThreshold: SafeContract_v1_2_0_Function<'getThreshold'> = async () => { - return [await this.contract.getThreshold()] + return [await this.contract.read.getThreshold()] } /** @@ -127,7 +128,7 @@ class SafeContract_v1_2_0 * @returns Array[isEnabled] */ isModuleEnabled: SafeContract_v1_2_0_Function<'isModuleEnabled'> = async (args) => { - return [await this.contract.isModuleEnabled(...args)] + return [await this.contract.read.isModuleEnabled(args)] } /** @@ -136,7 +137,7 @@ class SafeContract_v1_2_0 * @returns Array[isOwner] */ isOwner: SafeContract_v1_2_0_Function<'isOwner'> = async (args) => { - return [await this.contract.isOwner(...args)] + return [await this.contract.read.isOwner(args)] } /** @@ -144,7 +145,7 @@ class SafeContract_v1_2_0 * @returns Array[nonce] */ nonce: SafeContract_v1_2_0_Function<'nonce'> = async () => { - return [await this.contract.nonce()] + return [await this.contract.read.nonce()] } /** @@ -152,7 +153,7 @@ class SafeContract_v1_2_0 * @returns Array[signedMessages] */ signedMessages: SafeContract_v1_2_0_Function<'signedMessages'> = async (args) => { - return [await this.contract.signedMessages(...args)] + return [await this.contract.read.signedMessages(args)] } /** @@ -160,7 +161,7 @@ class SafeContract_v1_2_0 * @returns Array[messageHash] */ getMessageHash: SafeContract_v1_2_0_Function<'getMessageHash'> = async (args) => { - return [await this.contract.getMessageHash(...args)] + return [await this.contract.read.getMessageHash(args)] } /** @@ -170,7 +171,7 @@ class SafeContract_v1_2_0 * @returns Array[encodedData] */ encodeTransactionData: SafeContract_v1_2_0_Function<'encodeTransactionData'> = async (args) => { - return [await this.contract.encodeTransactionData(...args)] + return [await this.contract.read.encodeTransactionData(args)] } /** @@ -180,7 +181,7 @@ class SafeContract_v1_2_0 * @returns Array[transactionHash] */ getTransactionHash: SafeContract_v1_2_0_Function<'getTransactionHash'> = async (args) => { - return [await this.contract.getTransactionHash(...args)] + return [await this.contract.read.getTransactionHash(args)] } /** @@ -190,10 +191,14 @@ class SafeContract_v1_2_0 * @returns Transaction result. */ async approveHash(hash: string, options?: TransactionOptions): Promise { - const gasLimit = options?.gasLimit || (await this.estimateGas('approveHash', [hash], options)) - const txResponse = await this.contract.approveHash(hash, { ...options, gasLimit }) + const gasLimit = + options?.gasLimit || (await this.estimateGas('approveHash', [asHash(hash)], options)) + const txResponse = await this.contract.write.approveHash( + [asHash(hash)], + await this.convertOptions({ ...options, gasLimit }) + ) - return toTxResult(txResponse, options) + return toTxResult(this.runner!, txResponse, options) } /** @@ -211,35 +216,37 @@ class SafeContract_v1_2_0 (await this.estimateGas( 'execTransaction', [ - safeTransaction.data.to, + asAddress(safeTransaction.data.to), BigInt(safeTransaction.data.value), - safeTransaction.data.data, + asHex(safeTransaction.data.data), safeTransaction.data.operation, BigInt(safeTransaction.data.safeTxGas), BigInt(safeTransaction.data.baseGas), BigInt(safeTransaction.data.gasPrice), - safeTransaction.data.gasToken, - safeTransaction.data.refundReceiver, - safeTransaction.encodedSignatures() + asAddress(safeTransaction.data.gasToken), + asAddress(safeTransaction.data.refundReceiver), + asHex(safeTransaction.encodedSignatures()) ], options )) - const txResponse = await this.contract.execTransaction( - safeTransaction.data.to, - safeTransaction.data.value, - safeTransaction.data.data, - safeTransaction.data.operation, - safeTransaction.data.safeTxGas, - safeTransaction.data.baseGas, - safeTransaction.data.gasPrice, - safeTransaction.data.gasToken, - safeTransaction.data.refundReceiver, - safeTransaction.encodedSignatures(), - { ...options, gasLimit } + const txResponse = await this.contract.write.execTransaction( + [ + asAddress(safeTransaction.data.to), + BigInt(safeTransaction.data.value), + asHex(safeTransaction.data.data), + safeTransaction.data.operation, + BigInt(safeTransaction.data.safeTxGas), + BigInt(safeTransaction.data.baseGas), + BigInt(safeTransaction.data.gasPrice), + asAddress(safeTransaction.data.gasToken), + asAddress(safeTransaction.data.refundReceiver), + asHex(safeTransaction.encodedSignatures()) + ], + await this.convertOptions({ ...options, gasLimit }) ) - return toTxResult(txResponse, options) + return toTxResult(this.runner!, txResponse, options) } /** @@ -247,7 +254,8 @@ class SafeContract_v1_2_0 * @returns Array[chainId] */ async getChainId(): Promise<[bigint]> { - return [await this.contract.getChainId()] + const chainId = await this.runner!.getChainId() + return [BigInt(chainId)] } /** @@ -263,33 +271,37 @@ class SafeContract_v1_2_0 (await this.estimateGas( 'execTransaction', [ - safeTransaction.data.to, + asAddress(safeTransaction.data.to), BigInt(safeTransaction.data.value), - safeTransaction.data.data, + asHex(safeTransaction.data.data), safeTransaction.data.operation, BigInt(safeTransaction.data.safeTxGas), BigInt(safeTransaction.data.baseGas), BigInt(safeTransaction.data.gasPrice), - safeTransaction.data.gasToken, - safeTransaction.data.refundReceiver, - safeTransaction.encodedSignatures() + asAddress(safeTransaction.data.gasToken), + asAddress(safeTransaction.data.refundReceiver), + asHex(safeTransaction.encodedSignatures()) ], options )) - return await this.contract.execTransaction.staticCall( - safeTransaction.data.to, - BigInt(safeTransaction.data.value), - safeTransaction.data.data, - safeTransaction.data.operation, - BigInt(safeTransaction.data.safeTxGas), - BigInt(safeTransaction.data.baseGas), - BigInt(safeTransaction.data.gasPrice), - safeTransaction.data.gasToken, - safeTransaction.data.refundReceiver, - safeTransaction.encodedSignatures(), - { ...options, gasLimit } + const transactionResult = await this.contract.simulate.execTransaction( + [ + asAddress(safeTransaction.data.to), + BigInt(safeTransaction.data.value), + asHex(safeTransaction.data.data), + safeTransaction.data.operation, + BigInt(safeTransaction.data.safeTxGas), + BigInt(safeTransaction.data.baseGas), + BigInt(safeTransaction.data.gasPrice), + asAddress(safeTransaction.data.gasToken), + asAddress(safeTransaction.data.refundReceiver), + asHex(safeTransaction.encodedSignatures()) + ], + await this.convertOptions({ ...options, gasLimit }) ) + + return transactionResult.result } catch (error) { return false } diff --git a/packages/protocol-kit/src/contracts/Safe/v1.3.0/SafeContract_v1_3_0.ts b/packages/protocol-kit/src/contracts/Safe/v1.3.0/SafeContract_v1_3_0.ts index 66d48071e..8dd50ac8f 100644 --- a/packages/protocol-kit/src/contracts/Safe/v1.3.0/SafeContract_v1_3_0.ts +++ b/packages/protocol-kit/src/contracts/Safe/v1.3.0/SafeContract_v1_3_0.ts @@ -12,6 +12,8 @@ import { TransactionOptions, TransactionResult } from '@safe-global/safe-core-sdk-types' +import { asAddress, asHash, asHex } from '@safe-global/protocol-kit/utils/types' + /** * SafeContract_v1_3_0 is the implementation specific to the Safe contract version 1.3.0. * @@ -62,7 +64,7 @@ class SafeContract_v1_3_0 * @returns Array[safeContractVersion] */ VERSION: SafeContract_v1_3_0_Function<'VERSION'> = async () => { - return [await this.contract.VERSION()] + return [await this.contract.read.VERSION()] } /** @@ -70,7 +72,7 @@ class SafeContract_v1_3_0 * @returns Array[approvedHashes] */ approvedHashes: SafeContract_v1_3_0_Function<'approvedHashes'> = async (args) => { - return [await this.contract.approvedHashes(...args)] + return [await this.contract.read.approvedHashes(args)] } /** @@ -80,7 +82,7 @@ class SafeContract_v1_3_0 * @returns Empty array */ checkNSignatures: SafeContract_v1_3_0_Function<'checkNSignatures'> = async (args) => { - await this.contract.checkNSignatures(...args) + await this.contract.read.checkNSignatures(args) return [] } @@ -90,7 +92,7 @@ class SafeContract_v1_3_0 * @returns Empty array */ checkSignatures: SafeContract_v1_3_0_Function<'checkSignatures'> = async (args) => { - await this.contract.checkSignatures(...args) + await this.contract.read.checkSignatures(args) return [] } @@ -98,7 +100,7 @@ class SafeContract_v1_3_0 * @returns Array[domainSeparator] */ domainSeparator: SafeContract_v1_3_0_Function<'domainSeparator'> = async () => { - return [await this.contract.domainSeparator()] + return [await this.contract.read.domainSeparator()] } /** @@ -107,7 +109,7 @@ class SafeContract_v1_3_0 * @returns Array[encodedData] */ encodeTransactionData: SafeContract_v1_3_0_Function<'encodeTransactionData'> = async (args) => { - return [await this.contract.encodeTransactionData(...args)] + return [await this.contract.read.encodeTransactionData(args)] } /** @@ -116,8 +118,8 @@ class SafeContract_v1_3_0 * @returns Array[Array[modules], next] */ getModulesPaginated: SafeContract_v1_3_0_Function<'getModulesPaginated'> = async (args) => { - const res = await this.contract.getModulesPaginated(...args) - return [res.array, res.next] + const [array, next] = await this.contract.read.getModulesPaginated(args) + return [array, next] } /** @@ -125,7 +127,7 @@ class SafeContract_v1_3_0 * @returns Array[Array[owners]] */ getOwners: SafeContract_v1_3_0_Function<'getOwners'> = async () => { - return [await this.contract.getOwners()] + return [await this.contract.read.getOwners()] } /** @@ -134,7 +136,7 @@ class SafeContract_v1_3_0 * @returns Array[storage] */ getStorageAt: SafeContract_v1_3_0_Function<'getStorageAt'> = async (args) => { - return [await this.contract.getStorageAt(...args)] + return [await this.contract.read.getStorageAt(args)] } /** @@ -142,7 +144,7 @@ class SafeContract_v1_3_0 * @returns Array[threshold] */ getThreshold: SafeContract_v1_3_0_Function<'getThreshold'> = async () => { - return [await this.contract.getThreshold()] + return [await this.contract.read.getThreshold()] } /** @@ -151,7 +153,7 @@ class SafeContract_v1_3_0 * @returns Array[transactionHash] */ getTransactionHash: SafeContract_v1_3_0_Function<'getTransactionHash'> = async (args) => { - return [await this.contract.getTransactionHash(...args)] + return [await this.contract.read.getTransactionHash(args)] } /** @@ -160,7 +162,7 @@ class SafeContract_v1_3_0 * @returns Array[isEnabled] */ isModuleEnabled: SafeContract_v1_3_0_Function<'isModuleEnabled'> = async (args) => { - return [await this.contract.isModuleEnabled(...args)] + return [await this.contract.read.isModuleEnabled(args)] } /** @@ -169,7 +171,7 @@ class SafeContract_v1_3_0 * @returns Array[isOwner] */ isOwner: SafeContract_v1_3_0_Function<'isOwner'> = async (args) => { - return [await this.contract.isOwner(...args)] + return [await this.contract.read.isOwner(args)] } /** @@ -177,7 +179,7 @@ class SafeContract_v1_3_0 * @returns Array[nonce] */ nonce: SafeContract_v1_3_0_Function<'nonce'> = async () => { - return [await this.contract.nonce()] + return [await this.contract.read.nonce()] } /** @@ -185,7 +187,7 @@ class SafeContract_v1_3_0 * @returns Array[signedMessages] */ signedMessages: SafeContract_v1_3_0_Function<'signedMessages'> = async (args) => { - return [await this.contract.signedMessages(...args)] + return [await this.contract.read.signedMessages(args)] } /** @@ -201,33 +203,37 @@ class SafeContract_v1_3_0 (await this.estimateGas( 'execTransaction', [ - safeTransaction.data.to, + asAddress(safeTransaction.data.to), BigInt(safeTransaction.data.value), - safeTransaction.data.data, + asHex(safeTransaction.data.data), safeTransaction.data.operation, BigInt(safeTransaction.data.safeTxGas), BigInt(safeTransaction.data.baseGas), BigInt(safeTransaction.data.gasPrice), - safeTransaction.data.gasToken, - safeTransaction.data.refundReceiver, - safeTransaction.encodedSignatures() + asAddress(safeTransaction.data.gasToken), + asAddress(safeTransaction.data.refundReceiver), + asHex(safeTransaction.encodedSignatures()) ], options )) - return await this.contract.execTransaction.staticCall( - safeTransaction.data.to, - BigInt(safeTransaction.data.value), - safeTransaction.data.data, - safeTransaction.data.operation, - BigInt(safeTransaction.data.safeTxGas), - BigInt(safeTransaction.data.baseGas), - BigInt(safeTransaction.data.gasPrice), - safeTransaction.data.gasToken, - safeTransaction.data.refundReceiver, - safeTransaction.encodedSignatures(), - { ...options, gasLimit } + const txResult = await this.contract.simulate.execTransaction( + [ + asAddress(safeTransaction.data.to), + BigInt(safeTransaction.data.value), + asHex(safeTransaction.data.data), + safeTransaction.data.operation, + BigInt(safeTransaction.data.safeTxGas), + BigInt(safeTransaction.data.baseGas), + BigInt(safeTransaction.data.gasPrice), + asAddress(safeTransaction.data.gasToken), + asAddress(safeTransaction.data.refundReceiver), + asHex(safeTransaction.encodedSignatures()) + ], + await this.convertOptions({ ...options, gasLimit }) ) + + return txResult.result } catch (error) { return false } @@ -248,35 +254,37 @@ class SafeContract_v1_3_0 (await this.estimateGas( 'execTransaction', [ - safeTransaction.data.to, + asAddress(safeTransaction.data.to), BigInt(safeTransaction.data.value), - safeTransaction.data.data, + asHex(safeTransaction.data.data), safeTransaction.data.operation, BigInt(safeTransaction.data.safeTxGas), BigInt(safeTransaction.data.baseGas), BigInt(safeTransaction.data.gasPrice), - safeTransaction.data.gasToken, - safeTransaction.data.refundReceiver, - safeTransaction.encodedSignatures() + asAddress(safeTransaction.data.gasToken), + asAddress(safeTransaction.data.refundReceiver), + asHex(safeTransaction.encodedSignatures()) ], options )) - const txResponse = await this.contract.execTransaction( - safeTransaction.data.to, - safeTransaction.data.value, - safeTransaction.data.data, - safeTransaction.data.operation, - safeTransaction.data.safeTxGas, - safeTransaction.data.baseGas, - safeTransaction.data.gasPrice, - safeTransaction.data.gasToken, - safeTransaction.data.refundReceiver, - safeTransaction.encodedSignatures(), - { ...options, gasLimit } + const txResponse = await this.contract.write.execTransaction( + [ + asAddress(safeTransaction.data.to), + BigInt(safeTransaction.data.value), + asHex(safeTransaction.data.data), + safeTransaction.data.operation, + BigInt(safeTransaction.data.safeTxGas), + BigInt(safeTransaction.data.baseGas), + BigInt(safeTransaction.data.gasPrice), + asAddress(safeTransaction.data.gasToken), + asAddress(safeTransaction.data.refundReceiver), + asHex(safeTransaction.encodedSignatures()) + ], + await this.convertOptions({ ...options, gasLimit }) ) - return toTxResult(txResponse, options) + return toTxResult(this.runner!, txResponse, options) } /** @@ -295,10 +303,14 @@ class SafeContract_v1_3_0 * @returns Transaction result. */ async approveHash(hash: string, options?: TransactionOptions): Promise { - const gasLimit = options?.gasLimit || (await this.estimateGas('approveHash', [hash], options)) - const txResponse = await this.contract.approveHash(hash, { ...options, gasLimit }) + const gasLimit = + options?.gasLimit || (await this.estimateGas('approveHash', [asHash(hash)], options)) + const txResponse = await this.contract.write.approveHash( + [asHash(hash)], + await this.convertOptions({ ...options, gasLimit }) + ) - return toTxResult(txResponse, options) + return toTxResult(this.runner!, txResponse, options) } /** @@ -306,7 +318,7 @@ class SafeContract_v1_3_0 * @returns Array[chainId] */ async getChainId(): Promise<[bigint]> { - return [await this.contract.getChainId()] + return [await this.contract.read.getChainId()] } /** diff --git a/packages/protocol-kit/src/contracts/Safe/v1.4.1/SafeContract_v1_4_1.ts b/packages/protocol-kit/src/contracts/Safe/v1.4.1/SafeContract_v1_4_1.ts index c77c1131a..e08f322fa 100644 --- a/packages/protocol-kit/src/contracts/Safe/v1.4.1/SafeContract_v1_4_1.ts +++ b/packages/protocol-kit/src/contracts/Safe/v1.4.1/SafeContract_v1_4_1.ts @@ -12,6 +12,7 @@ import { TransactionOptions, TransactionResult } from '@safe-global/safe-core-sdk-types' +import { asHash, asHex, asAddress } from '@safe-global/protocol-kit/utils/types' /** * SafeContract_v1_4_1 is the implementation specific to the Safe contract version 1.4.1. @@ -63,7 +64,7 @@ class SafeContract_v1_4_1 * @returns Array[safeContractVersion] */ VERSION: SafeContract_v1_4_1_Function<'VERSION'> = async () => { - return [await this.contract.VERSION()] + return [await this.contract.read.VERSION()] } /** @@ -71,7 +72,7 @@ class SafeContract_v1_4_1 * @returns Array[approvedHashes] */ approvedHashes: SafeContract_v1_4_1_Function<'approvedHashes'> = async (args) => { - return [await this.contract.approvedHashes(...args)] + return [await this.contract.read.approvedHashes(args)] } /** @@ -81,7 +82,7 @@ class SafeContract_v1_4_1 * @returns Empty array */ checkNSignatures: SafeContract_v1_4_1_Function<'checkNSignatures'> = async (args) => { - await this.contract.checkNSignatures(...args) + await this.contract.read.checkNSignatures(args) return [] } @@ -91,7 +92,7 @@ class SafeContract_v1_4_1 * @returns Empty array */ checkSignatures: SafeContract_v1_4_1_Function<'checkSignatures'> = async (args) => { - await this.contract.checkSignatures(...args) + await this.contract.read.checkSignatures(args) return [] } @@ -99,7 +100,7 @@ class SafeContract_v1_4_1 * @returns Array[domainSeparator] */ domainSeparator: SafeContract_v1_4_1_Function<'domainSeparator'> = async () => { - return [await this.contract.domainSeparator()] + return [await this.contract.read.domainSeparator()] } /** @@ -108,7 +109,7 @@ class SafeContract_v1_4_1 * @returns Array[encodedData] */ encodeTransactionData: SafeContract_v1_4_1_Function<'encodeTransactionData'> = async (args) => { - return [await this.contract.encodeTransactionData(...args)] + return [await this.contract.read.encodeTransactionData(args)] } /** @@ -117,8 +118,8 @@ class SafeContract_v1_4_1 * @returns Array[Array[modules], next] */ getModulesPaginated: SafeContract_v1_4_1_Function<'getModulesPaginated'> = async (args) => { - const res = await this.contract.getModulesPaginated(...args) - return [res.array, res.next] + const [array, next] = await this.contract.read.getModulesPaginated(args) + return [array, next] } /** @@ -126,7 +127,7 @@ class SafeContract_v1_4_1 * @returns Array[Array[owners]] */ getOwners: SafeContract_v1_4_1_Function<'getOwners'> = async () => { - return [await this.contract.getOwners()] + return [await this.contract.read.getOwners()] } /** @@ -135,7 +136,7 @@ class SafeContract_v1_4_1 * @returns Array[storage] */ getStorageAt: SafeContract_v1_4_1_Function<'getStorageAt'> = async (args) => { - return [await this.contract.getStorageAt(...args)] + return [await this.contract.read.getStorageAt(args)] } /** @@ -143,7 +144,7 @@ class SafeContract_v1_4_1 * @returns Array[threshold] */ getThreshold: SafeContract_v1_4_1_Function<'getThreshold'> = async () => { - return [await this.contract.getThreshold()] + return [await this.contract.read.getThreshold()] } /** @@ -152,7 +153,7 @@ class SafeContract_v1_4_1 * @returns Array[transactionHash] */ getTransactionHash: SafeContract_v1_4_1_Function<'getTransactionHash'> = async (args) => { - return [await this.contract.getTransactionHash(...args)] + return [await this.contract.read.getTransactionHash(args)] } /** @@ -161,7 +162,7 @@ class SafeContract_v1_4_1 * @returns Array[isEnabled] */ isModuleEnabled: SafeContract_v1_4_1_Function<'isModuleEnabled'> = async (args) => { - return [await this.contract.isModuleEnabled(...args)] + return [await this.contract.read.isModuleEnabled(args)] } /** @@ -170,7 +171,7 @@ class SafeContract_v1_4_1 * @returns Array[isOwner] */ isOwner: SafeContract_v1_4_1_Function<'isOwner'> = async (args) => { - return [await this.contract.isOwner(...args)] + return [await this.contract.read.isOwner(args)] } /** @@ -178,7 +179,7 @@ class SafeContract_v1_4_1 * @returns Array[nonce] */ nonce: SafeContract_v1_4_1_Function<'nonce'> = async () => { - return [await this.contract.nonce()] + return [await this.contract.read.nonce()] } /** @@ -186,7 +187,7 @@ class SafeContract_v1_4_1 * @returns Array[signedMessages] */ signedMessages: SafeContract_v1_4_1_Function<'signedMessages'> = async (args) => { - return [await this.contract.signedMessages(...args)] + return [await this.contract.read.signedMessages(args)] } /** @@ -202,33 +203,37 @@ class SafeContract_v1_4_1 (await this.estimateGas( 'execTransaction', [ - safeTransaction.data.to, + asAddress(safeTransaction.data.to), BigInt(safeTransaction.data.value), - safeTransaction.data.data, + asHex(safeTransaction.data.data), safeTransaction.data.operation, BigInt(safeTransaction.data.safeTxGas), BigInt(safeTransaction.data.baseGas), BigInt(safeTransaction.data.gasPrice), - safeTransaction.data.gasToken, - safeTransaction.data.refundReceiver, - safeTransaction.encodedSignatures() + asAddress(safeTransaction.data.gasToken), + asAddress(safeTransaction.data.refundReceiver), + asHex(safeTransaction.encodedSignatures()) ], options )) - return await this.contract.execTransaction.staticCall( - safeTransaction.data.to, - BigInt(safeTransaction.data.value), - safeTransaction.data.data, - safeTransaction.data.operation, - BigInt(safeTransaction.data.safeTxGas), - BigInt(safeTransaction.data.baseGas), - BigInt(safeTransaction.data.gasPrice), - safeTransaction.data.gasToken, - safeTransaction.data.refundReceiver, - safeTransaction.encodedSignatures(), - { ...options, gasLimit } + const txResult = await this.contract.simulate.execTransaction( + [ + asAddress(safeTransaction.data.to), + BigInt(safeTransaction.data.value), + asHex(safeTransaction.data.data), + safeTransaction.data.operation, + BigInt(safeTransaction.data.safeTxGas), + BigInt(safeTransaction.data.baseGas), + BigInt(safeTransaction.data.gasPrice), + asAddress(safeTransaction.data.gasToken), + asAddress(safeTransaction.data.refundReceiver), + asHex(safeTransaction.encodedSignatures()) + ], + await this.convertOptions({ ...options, gasLimit }) ) + + return txResult.result } catch (error) { return false } @@ -249,35 +254,37 @@ class SafeContract_v1_4_1 (await this.estimateGas( 'execTransaction', [ - safeTransaction.data.to, + asAddress(safeTransaction.data.to), BigInt(safeTransaction.data.value), - safeTransaction.data.data, + asHex(safeTransaction.data.data), safeTransaction.data.operation, BigInt(safeTransaction.data.safeTxGas), BigInt(safeTransaction.data.baseGas), BigInt(safeTransaction.data.gasPrice), - safeTransaction.data.gasToken, - safeTransaction.data.refundReceiver, - safeTransaction.encodedSignatures() + asAddress(safeTransaction.data.gasToken), + asAddress(safeTransaction.data.refundReceiver), + asHex(safeTransaction.encodedSignatures()) ], options )) - const txResponse = await this.contract.execTransaction( - safeTransaction.data.to, - safeTransaction.data.value, - safeTransaction.data.data, - safeTransaction.data.operation, - safeTransaction.data.safeTxGas, - safeTransaction.data.baseGas, - safeTransaction.data.gasPrice, - safeTransaction.data.gasToken, - safeTransaction.data.refundReceiver, - safeTransaction.encodedSignatures(), - { ...options, gasLimit } + const txResponse = await this.contract.write.execTransaction( + [ + asAddress(safeTransaction.data.to), + BigInt(safeTransaction.data.value), + asHex(safeTransaction.data.data), + safeTransaction.data.operation, + BigInt(safeTransaction.data.safeTxGas), + BigInt(safeTransaction.data.baseGas), + BigInt(safeTransaction.data.gasPrice), + asAddress(safeTransaction.data.gasToken), + asAddress(safeTransaction.data.refundReceiver), + asHex(safeTransaction.encodedSignatures()) + ], + await this.convertOptions({ ...options, gasLimit }) ) - return toTxResult(txResponse, options) + return toTxResult(this.runner!, txResponse, options) } /** @@ -296,10 +303,14 @@ class SafeContract_v1_4_1 * @returns Transaction result. */ async approveHash(hash: string, options?: TransactionOptions): Promise { - const gasLimit = options?.gasLimit || (await this.estimateGas('approveHash', [hash], options)) - const txResponse = await this.contract.approveHash(hash, { ...options, gasLimit }) + const gasLimit = + options?.gasLimit || (await this.estimateGas('approveHash', [asHash(hash)], options)) + const txResponse = await this.contract.write.approveHash( + [asHash(hash)], + await this.convertOptions({ ...options, gasLimit }) + ) - return toTxResult(txResponse, options) + return toTxResult(this.runner!, txResponse, options) } /** @@ -307,7 +318,7 @@ class SafeContract_v1_4_1 * @returns Array[chainId] */ async getChainId(): Promise<[bigint]> { - return [await this.contract.getChainId()] + return [await this.contract.read.getChainId()] } /** diff --git a/packages/protocol-kit/src/contracts/SafeProxyFactory/SafeProxyFactoryBaseContract.ts b/packages/protocol-kit/src/contracts/SafeProxyFactory/SafeProxyFactoryBaseContract.ts index 67d8c9e4e..5b65e3c95 100644 --- a/packages/protocol-kit/src/contracts/SafeProxyFactory/SafeProxyFactoryBaseContract.ts +++ b/packages/protocol-kit/src/contracts/SafeProxyFactory/SafeProxyFactoryBaseContract.ts @@ -1,5 +1,5 @@ import { Abi } from 'abitype' -import { ContractRunner, InterfaceAbi } from 'ethers' +import { PublicClient } from 'viem' import SafeProvider from '@safe-global/protocol-kit/SafeProvider' import BaseContract from '@safe-global/protocol-kit/contracts/BaseContract' import { @@ -30,7 +30,7 @@ export interface CreateProxyProps extends CreateProxyPropsGeneral { * - SafeProxyFactoryContract_v1_0_0 extends SafeProxyFactoryBaseContract */ abstract class SafeProxyFactoryBaseContract< - SafeProxyFactoryContractAbiType extends InterfaceAbi & Abi + SafeProxyFactoryContractAbiType extends Abi > extends BaseContract { contractName: contractName @@ -52,7 +52,7 @@ abstract class SafeProxyFactoryBaseContract< safeVersion: SafeVersion, customContractAddress?: string, customContractAbi?: SafeProxyFactoryContractAbiType, - runner?: ContractRunner | null + runner?: PublicClient | null ) { const contractName = 'safeProxyFactoryVersion' diff --git a/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.0.0/SafeProxyFactoryContract_v1_0_0.ts b/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.0.0/SafeProxyFactoryContract_v1_0_0.ts index 100e61e67..ad86ff8d7 100644 --- a/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.0.0/SafeProxyFactoryContract_v1_0_0.ts +++ b/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.0.0/SafeProxyFactoryContract_v1_0_0.ts @@ -1,4 +1,4 @@ -import { ContractRunner, EventLog } from 'ethers' +import { PublicClient, parseEventLogs } from 'viem' import SafeProxyFactoryBaseContract, { CreateProxyProps } from '@safe-global/protocol-kit/contracts/SafeProxyFactory/SafeProxyFactoryBaseContract' @@ -10,6 +10,8 @@ import { SafeProxyFactoryContract_v1_0_0_Function, safeProxyFactory_1_0_0_ContractArtifacts } from '@safe-global/safe-core-sdk-types' +import { waitForTransactionReceipt } from '@safe-global/protocol-kit/utils' +import { asAddress, asHex } from '@safe-global/protocol-kit/utils/types' /** * SafeProxyFactoryContract_v1_0_0 is the implementation specific to the Safe Proxy Factory contract version 1.0.0. @@ -38,7 +40,7 @@ class SafeProxyFactoryContract_v1_0_0 safeProvider: SafeProvider, customContractAddress?: string, customContractAbi?: SafeProxyFactoryContract_v1_0_0_Abi, - runner?: ContractRunner | null + runner?: PublicClient | null ) { const safeVersion = '1.0.0' const defaultAbi = safeProxyFactory_1_0_0_ContractArtifacts.abi @@ -61,7 +63,7 @@ class SafeProxyFactoryContract_v1_0_0 * @returns Array[creationCode] */ proxyCreationCode: SafeProxyFactoryContract_v1_0_0_Function<'proxyCreationCode'> = async () => { - return [await this.contract.proxyCreationCode()] + return [await this.contract.read.proxyCreationCode()] } /** @@ -69,7 +71,7 @@ class SafeProxyFactoryContract_v1_0_0 * @returns Array[runtimeCode] */ proxyRuntimeCode: SafeProxyFactoryContract_v1_0_0_Function<'proxyRuntimeCode'> = async () => { - return [await this.contract.proxyRuntimeCode()] + return [await this.contract.read.proxyRuntimeCode()] } /** @@ -78,18 +80,18 @@ class SafeProxyFactoryContract_v1_0_0 * @returns Array[proxyAddress] */ createProxy: SafeProxyFactoryContract_v1_0_0_Function<'createProxy'> = async (args) => { - return [await this.contract.createProxy(...args)] + return [await this.contract.write.createProxy(args, await this.convertOptions({}))] } /** * Allows to create new proxy contract and execute a message call to the new proxy within one transaction. - * @param args - Array[masterCopy, initializer, saltNonce] + * @param args - Array[masterCopy, initializer, saltNonceBigInt] * @returns Array[proxyAddress] */ createProxyWithNonce: SafeProxyFactoryContract_v1_0_0_Function<'createProxyWithNonce'> = async ( args ) => { - return [await this.contract.createProxyWithNonce(...args)] + return [await this.contract.write.createProxyWithNonce(args, await this.convertOptions({}))] } /** @@ -112,27 +114,30 @@ class SafeProxyFactoryContract_v1_0_0 options.gasLimit = ( await this.estimateGas( 'createProxyWithNonce', - [safeSingletonAddress, initializer, saltNonceBigInt], + [asAddress(safeSingletonAddress), asHex(initializer), saltNonceBigInt], { ...options } ) ).toString() } - const proxyAddress = this.contract - .createProxyWithNonce(safeSingletonAddress, initializer, saltNonce, { ...options }) - .then(async (txResponse) => { + const proxyAddress = await this.contract.write + .createProxyWithNonce( + [asAddress(safeSingletonAddress), asHex(initializer), saltNonceBigInt], + await this.convertOptions(options) + ) + .then(async (hash) => { if (callback) { - callback(txResponse.hash) + callback(hash) } - const txReceipt = await txResponse.wait() - const events = txReceipt?.logs as EventLog[] + const { logs } = await waitForTransactionReceipt(this.runner!, hash) + const events = parseEventLogs({ logs, abi: this.contractAbi }) const proxyCreationEvent = events.find((event) => event?.eventName === 'ProxyCreation') if (!proxyCreationEvent || !proxyCreationEvent.args) { throw new Error('SafeProxy was not deployed correctly') } - const proxyAddress: string = proxyCreationEvent.args[0] - return proxyAddress + return proxyCreationEvent.args.proxy }) + return proxyAddress } } diff --git a/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.1.1/SafeProxyFactoryContract_v1_1_1.ts b/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.1.1/SafeProxyFactoryContract_v1_1_1.ts index 8cd499342..245833075 100644 --- a/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.1.1/SafeProxyFactoryContract_v1_1_1.ts +++ b/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.1.1/SafeProxyFactoryContract_v1_1_1.ts @@ -1,4 +1,4 @@ -import { ContractRunner, EventLog } from 'ethers' +import { parseEventLogs, PublicClient } from 'viem' import SafeProxyFactoryBaseContract, { CreateProxyProps } from '@safe-global/protocol-kit/contracts/SafeProxyFactory/SafeProxyFactoryBaseContract' @@ -10,6 +10,8 @@ import { SafeProxyFactoryContract_v1_1_1_Function, safeProxyFactory_1_1_1_ContractArtifacts } from '@safe-global/safe-core-sdk-types' +import { waitForTransactionReceipt } from '@safe-global/protocol-kit/utils' +import { asHex, asAddress } from '@safe-global/protocol-kit/utils/types' /** * SafeProxyFactoryContract_v1_1_1 is the implementation specific to the Safe Proxy Factory contract version 1.1.1. @@ -38,7 +40,7 @@ class SafeProxyFactoryContract_v1_1_1 safeProvider: SafeProvider, customContractAddress?: string, customContractAbi?: SafeProxyFactoryContract_v1_1_1_Abi, - runner?: ContractRunner | null + runner?: PublicClient | null ) { const safeVersion = '1.1.1' const defaultAbi = safeProxyFactory_1_1_1_ContractArtifacts.abi @@ -61,7 +63,7 @@ class SafeProxyFactoryContract_v1_1_1 * @returns Array[creationCode] */ proxyCreationCode: SafeProxyFactoryContract_v1_1_1_Function<'proxyCreationCode'> = async () => { - return [await this.contract.proxyCreationCode()] + return [await this.contract.read.proxyCreationCode()] } /** @@ -69,17 +71,22 @@ class SafeProxyFactoryContract_v1_1_1 * @returns Array[runtimeCode] */ proxyRuntimeCode: SafeProxyFactoryContract_v1_1_1_Function<'proxyRuntimeCode'> = async () => { - return [await this.contract.proxyRuntimeCode()] + return [await this.contract.read.proxyRuntimeCode()] } /** * Allows to get the address for a new proxy contact created via `createProxyWithNonce`. - * @param args - Array[masterCopy, initializer, saltNonce] + * @param args - Array[masterCopy, initializer, saltNonceBigInt] * @returns Array[proxyAddress] */ calculateCreateProxyWithNonceAddress: SafeProxyFactoryContract_v1_1_1_Function<'calculateCreateProxyWithNonceAddress'> = async (args) => { - return [await this.contract.calculateCreateProxyWithNonceAddress(...args)] + return [ + await this.contract.write.calculateCreateProxyWithNonceAddress( + args, + await this.convertOptions({}) + ) + ] } /** @@ -88,7 +95,7 @@ class SafeProxyFactoryContract_v1_1_1 * @returns Array[proxyAddress] */ createProxy: SafeProxyFactoryContract_v1_1_1_Function<'createProxy'> = async (args) => { - return [await this.contract.createProxy(...args)] + return [await this.contract.write.createProxy(args, await this.convertOptions({}))] } /** @@ -98,18 +105,20 @@ class SafeProxyFactoryContract_v1_1_1 */ createProxyWithCallback: SafeProxyFactoryContract_v1_1_1_Function<'createProxyWithCallback'> = async (args) => { - return [await this.contract.createProxyWithCallback(...args)] + return [ + await this.contract.write.createProxyWithCallback(args, await this.convertOptions({})) + ] } /** * Allows to create new proxy contract and execute a message call to the new proxy within one transaction. - * @param args - Array[masterCopy, initializer, saltNonce] + * @param args - Array[masterCopy, initializer, saltNonceBigInt] * @returns Array[proxyAddress] */ createProxyWithNonce: SafeProxyFactoryContract_v1_1_1_Function<'createProxyWithNonce'> = async ( args ) => { - return [await this.contract.createProxyWithNonce(...args)] + return [await this.contract.write.createProxyWithNonce(args, await this.convertOptions({}))] } /** @@ -132,27 +141,30 @@ class SafeProxyFactoryContract_v1_1_1 options.gasLimit = ( await this.estimateGas( 'createProxyWithNonce', - [safeSingletonAddress, initializer, saltNonceBigInt], + [asAddress(safeSingletonAddress), asHex(initializer), saltNonceBigInt], { ...options } ) ).toString() } - const proxyAddress = this.contract - .createProxyWithNonce(safeSingletonAddress, initializer, saltNonce, { ...options }) - .then(async (txResponse) => { + const proxyAddress = this.contract.write + .createProxyWithNonce( + [asAddress(safeSingletonAddress), asHex(initializer), saltNonceBigInt], + await this.convertOptions(options) + ) + .then(async (hash) => { if (callback) { - callback(txResponse.hash) + callback(hash) } - const txReceipt = await txResponse.wait() - const events = txReceipt?.logs as EventLog[] + const { logs } = await waitForTransactionReceipt(this.runner!, hash) + const events = parseEventLogs({ logs, abi: this.contractAbi }) const proxyCreationEvent = events.find((event) => event?.eventName === 'ProxyCreation') if (!proxyCreationEvent || !proxyCreationEvent.args) { throw new Error('SafeProxy was not deployed correctly') } - const proxyAddress: string = proxyCreationEvent.args[0] - return proxyAddress + return proxyCreationEvent.args.proxy }) + return proxyAddress } } diff --git a/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.3.0/SafeProxyFactoryContract_v1_3_0.ts b/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.3.0/SafeProxyFactoryContract_v1_3_0.ts index 66ca7aabb..fa595ad92 100644 --- a/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.3.0/SafeProxyFactoryContract_v1_3_0.ts +++ b/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.3.0/SafeProxyFactoryContract_v1_3_0.ts @@ -1,4 +1,4 @@ -import { ContractRunner, EventLog } from 'ethers' +import { parseEventLogs, PublicClient } from 'viem' import SafeProxyFactoryBaseContract, { CreateProxyProps } from '@safe-global/protocol-kit/contracts/SafeProxyFactory/SafeProxyFactoryBaseContract' @@ -10,6 +10,8 @@ import { SafeProxyFactoryContract_v1_3_0_Function, safeProxyFactory_1_3_0_ContractArtifacts } from '@safe-global/safe-core-sdk-types' +import { waitForTransactionReceipt } from '@safe-global/protocol-kit/utils' +import { asAddress, asHex } from '@safe-global/protocol-kit/utils/types' /** * SafeProxyFactoryContract_v1_3_0 is the implementation specific to the Safe Proxy Factory contract version 1.3.0. @@ -38,7 +40,7 @@ class SafeProxyFactoryContract_v1_3_0 safeProvider: SafeProvider, customContractAddress?: string, customContractAbi?: SafeProxyFactoryContract_v1_3_0_Abi, - runner?: ContractRunner | null + runner?: PublicClient | null ) { const safeVersion = '1.3.0' const defaultAbi = safeProxyFactory_1_3_0_ContractArtifacts.abi @@ -61,7 +63,7 @@ class SafeProxyFactoryContract_v1_3_0 * @returns Array[creationCode] */ proxyCreationCode: SafeProxyFactoryContract_v1_3_0_Function<'proxyCreationCode'> = async () => { - return [await this.contract.proxyCreationCode()] + return [await this.contract.read.proxyCreationCode()] } /** @@ -69,17 +71,22 @@ class SafeProxyFactoryContract_v1_3_0 * @returns Array[runtimeCode] */ proxyRuntimeCode: SafeProxyFactoryContract_v1_3_0_Function<'proxyRuntimeCode'> = async () => { - return [await this.contract.proxyRuntimeCode()] + return [await this.contract.read.proxyRuntimeCode()] } /** * Allows to get the address for a new proxy contact created via `createProxyWithNonce`. - * @param args - Array[singleton, initializer, saltNonce] + * @param args - Array[singleton, initializer, saltNonceBigInt] * @returns Array[proxyAddress] */ calculateCreateProxyWithNonceAddress: SafeProxyFactoryContract_v1_3_0_Function<'calculateCreateProxyWithNonceAddress'> = async (args) => { - return [await this.contract.calculateCreateProxyWithNonceAddress(...args)] + return [ + await this.contract.write.calculateCreateProxyWithNonceAddress( + args, + await this.convertOptions({}) + ) + ] } /** @@ -88,7 +95,7 @@ class SafeProxyFactoryContract_v1_3_0 * @returns Array[proxyAddress] */ createProxy: SafeProxyFactoryContract_v1_3_0_Function<'createProxy'> = async (args) => { - return [await this.contract.createProxy(...args)] + return [await this.contract.write.createProxy(args, await this.convertOptions({}))] } /** @@ -98,18 +105,20 @@ class SafeProxyFactoryContract_v1_3_0 */ createProxyWithCallback: SafeProxyFactoryContract_v1_3_0_Function<'createProxyWithCallback'> = async (args) => { - return [await this.contract.createProxyWithCallback(...args)] + return [ + await this.contract.write.createProxyWithCallback(args, await this.convertOptions({})) + ] } /** * Allows to create new proxy contract and execute a message call to the new proxy within one transaction. - * @param args - Array[singleton, initializer, saltNonce] + * @param args - Array[singleton, initializer, saltNonceBigInt] * @returns Array[proxyAddress] */ createProxyWithNonce: SafeProxyFactoryContract_v1_3_0_Function<'createProxyWithNonce'> = async ( args ) => { - return [await this.contract.createProxyWithNonce(...args)] + return [await this.contract.write.createProxyWithNonce(args, await this.convertOptions({}))] } /** @@ -132,27 +141,30 @@ class SafeProxyFactoryContract_v1_3_0 options.gasLimit = ( await this.estimateGas( 'createProxyWithNonce', - [safeSingletonAddress, initializer, saltNonceBigInt], + [asAddress(safeSingletonAddress), asHex(initializer), saltNonceBigInt], { ...options } ) ).toString() } - const proxyAddress = this.contract - .createProxyWithNonce(safeSingletonAddress, initializer, saltNonce, { ...options }) - .then(async (txResponse) => { + const proxyAddress = this.contract.write + .createProxyWithNonce( + [asAddress(safeSingletonAddress), asHex(initializer), saltNonceBigInt], + await this.convertOptions(options) + ) + .then(async (hash) => { if (callback) { - callback(txResponse.hash) + callback(hash) } - const txReceipt = await txResponse.wait() - const events = txReceipt?.logs as EventLog[] + const { logs } = await waitForTransactionReceipt(this.runner!, hash) + const events = parseEventLogs({ logs, abi: this.contractAbi }) const proxyCreationEvent = events.find((event) => event?.eventName === 'ProxyCreation') if (!proxyCreationEvent || !proxyCreationEvent.args) { throw new Error('SafeProxy was not deployed correctly') } - const proxyAddress: string = proxyCreationEvent.args[0] - return proxyAddress + return proxyCreationEvent.args.proxy }) + return proxyAddress } } diff --git a/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.4.1/SafeProxyFactoryContract_v1_4_1.ts b/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.4.1/SafeProxyFactoryContract_v1_4_1.ts index 425a11e26..e0a8eff0e 100644 --- a/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.4.1/SafeProxyFactoryContract_v1_4_1.ts +++ b/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.4.1/SafeProxyFactoryContract_v1_4_1.ts @@ -1,4 +1,4 @@ -import { ContractRunner, EventLog } from 'ethers' +import { parseEventLogs, PublicClient } from 'viem' import SafeProxyFactoryBaseContract, { CreateProxyProps } from '@safe-global/protocol-kit/contracts/SafeProxyFactory/SafeProxyFactoryBaseContract' @@ -10,6 +10,8 @@ import { safeProxyFactory_1_4_1_ContractArtifacts } from '@safe-global/safe-core-sdk-types' import SafeProvider from '@safe-global/protocol-kit/SafeProvider' +import { waitForTransactionReceipt } from '@safe-global/protocol-kit/utils' +import { asAddress, asHex } from '@safe-global/protocol-kit/utils/types' /** * SafeProxyFactoryContract_v1_4_1 is the implementation specific to the Safe Proxy Factory contract version 1.4.1. @@ -38,7 +40,7 @@ class SafeProxyFactoryContract_v1_4_1 safeProvider: SafeProvider, customContractAddress?: string, customContractAbi?: SafeProxyFactoryContract_v1_4_1_Abi, - runner?: ContractRunner | null + runner?: PublicClient | null ) { const safeVersion = '1.4.1' const defaultAbi = safeProxyFactory_1_4_1_ContractArtifacts.abi @@ -61,7 +63,7 @@ class SafeProxyFactoryContract_v1_4_1 * @returns Array[chainId] */ getChainId: SafeProxyFactoryContract_v1_4_1_Function<'getChainId'> = async () => { - return [await this.contract.getChainId()] + return [await this.contract.read.getChainId()] } /** @@ -69,17 +71,22 @@ class SafeProxyFactoryContract_v1_4_1 * @returns Array[creationCode] */ proxyCreationCode: SafeProxyFactoryContract_v1_4_1_Function<'proxyCreationCode'> = async () => { - return [await this.contract.proxyCreationCode()] + return [await this.contract.read.proxyCreationCode()] } /** * Deploys a new chain-specific proxy with singleton and salt. Optionally executes an initializer call to a new proxy. - * @param args - Array[singleton, initializer, saltNonce] + * @param args - Array[singleton, initializer, saltNonceBigInt] * @returns Array[proxy] */ createChainSpecificProxyWithNonce: SafeProxyFactoryContract_v1_4_1_Function<'createChainSpecificProxyWithNonce'> = async (args) => { - return [await this.contract.createChainSpecificProxyWithNonce(...args)] + return [ + await this.contract.write.createChainSpecificProxyWithNonce( + args, + await this.convertOptions({}) + ) + ] } /** @@ -90,18 +97,20 @@ class SafeProxyFactoryContract_v1_4_1 */ createProxyWithCallback: SafeProxyFactoryContract_v1_4_1_Function<'createProxyWithCallback'> = async (args) => { - return [await this.contract.createProxyWithCallback(...args)] + return [ + await this.contract.write.createProxyWithCallback(args, await this.convertOptions({})) + ] } /** * Deploys a new proxy with singleton and salt. Optionally executes an initializer call to a new proxy. - * @param args - Array[singleton, initializer, saltNonce] + * @param args - Array[singleton, initializer, saltNonceBigInt] * @returns Array[proxy] */ createProxyWithNonce: SafeProxyFactoryContract_v1_4_1_Function<'createProxyWithNonce'> = async ( args ) => { - return [await this.contract.createProxyWithNonce(...args)] + return [await this.contract.write.createProxyWithNonce(args, await this.convertOptions({}))] } /** @@ -124,27 +133,30 @@ class SafeProxyFactoryContract_v1_4_1 options.gasLimit = ( await this.estimateGas( 'createProxyWithNonce', - [safeSingletonAddress, initializer, saltNonceBigInt], + [asAddress(safeSingletonAddress), asHex(initializer), saltNonceBigInt], { ...options } ) ).toString() } - const proxyAddress = this.contract - .createProxyWithNonce(safeSingletonAddress, initializer, saltNonce, { ...options }) - .then(async (txResponse) => { + const proxyAddress = this.contract.write + .createProxyWithNonce( + [asAddress(safeSingletonAddress), asHex(initializer), saltNonceBigInt], + await this.convertOptions(options) + ) + .then(async (hash) => { if (callback) { - callback(txResponse.hash) + callback(hash) } - const txReceipt = await txResponse.wait() - const events = txReceipt?.logs as EventLog[] + const { logs } = await waitForTransactionReceipt(this.runner!, hash) + const events = parseEventLogs({ logs, abi: this.contractAbi }) const proxyCreationEvent = events.find((event) => event?.eventName === 'ProxyCreation') if (!proxyCreationEvent || !proxyCreationEvent.args) { throw new Error('SafeProxy was not deployed correctly') } - const proxyAddress: string = proxyCreationEvent.args[0] - return proxyAddress + return proxyCreationEvent.args.proxy }) + return proxyAddress } } diff --git a/packages/protocol-kit/src/contracts/SignMessageLib/SignMessageLibBaseContract.ts b/packages/protocol-kit/src/contracts/SignMessageLib/SignMessageLibBaseContract.ts index 264019128..7d811ea16 100644 --- a/packages/protocol-kit/src/contracts/SignMessageLib/SignMessageLibBaseContract.ts +++ b/packages/protocol-kit/src/contracts/SignMessageLib/SignMessageLibBaseContract.ts @@ -1,5 +1,4 @@ import { Abi } from 'abitype' -import { InterfaceAbi } from 'ethers' import SafeProvider from '@safe-global/protocol-kit/SafeProvider' import { SafeVersion } from '@safe-global/safe-core-sdk-types' @@ -20,7 +19,7 @@ import { contractName } from '@safe-global/protocol-kit/contracts/config' * - SignMessageLibContract_v1_3_0 extends SignMessageLibBaseContract */ abstract class SignMessageLibBaseContract< - SignMessageLibContractAbiType extends InterfaceAbi & Abi + SignMessageLibContractAbiType extends Abi > extends BaseContract { contractName: contractName diff --git a/packages/protocol-kit/src/contracts/SignMessageLib/v1.3.0/SignMessageLibContract_v1_3_0.ts b/packages/protocol-kit/src/contracts/SignMessageLib/v1.3.0/SignMessageLibContract_v1_3_0.ts index f506a61de..0c05575dc 100644 --- a/packages/protocol-kit/src/contracts/SignMessageLib/v1.3.0/SignMessageLibContract_v1_3_0.ts +++ b/packages/protocol-kit/src/contracts/SignMessageLib/v1.3.0/SignMessageLibContract_v1_3_0.ts @@ -49,7 +49,7 @@ class SignMessageLibContract_v1_3_0 * @param args - Array[message] */ getMessageHash: SignMessageLibContract_v1_3_0_Function<'getMessageHash'> = async (args) => { - return [await this.contract.getMessageHash(...args)] + return [await this.contract.read.getMessageHash(args)] } /** @@ -63,9 +63,12 @@ class SignMessageLibContract_v1_3_0 options.gasLimit = Number(await this.estimateGas('signMessage', data, { ...options })) } - const txResponse = await this.contract.signMessage(data, { ...options }) + const txResponse = await this.contract.write.signMessage( + data, + await this.convertOptions(options) + ) - return toTxResult(txResponse, options) + return toTxResult(this.runner!, txResponse, options) } } diff --git a/packages/protocol-kit/src/contracts/SignMessageLib/v1.4.1/SignMessageLibContract_v1_4_1.ts b/packages/protocol-kit/src/contracts/SignMessageLib/v1.4.1/SignMessageLibContract_v1_4_1.ts index e00dc2183..ec7a27d82 100644 --- a/packages/protocol-kit/src/contracts/SignMessageLib/v1.4.1/SignMessageLibContract_v1_4_1.ts +++ b/packages/protocol-kit/src/contracts/SignMessageLib/v1.4.1/SignMessageLibContract_v1_4_1.ts @@ -50,7 +50,7 @@ class SignMessageLibContract_v1_4_1 * @param args - Array[message] */ getMessageHash: SignMessageLibContract_v1_4_1_Function<'getMessageHash'> = async (args) => { - return [await this.contract.getMessageHash(...args)] + return [await this.contract.read.getMessageHash(args)] } /** @@ -64,9 +64,12 @@ class SignMessageLibContract_v1_4_1 options.gasLimit = Number(await this.estimateGas('signMessage', data, { ...options })) } - const txResponse = await this.contract.signMessage(data, { ...options }) + const txResponse = await this.contract.write.signMessage( + data, + await this.convertOptions(options) + ) - return toTxResult(txResponse, options) + return toTxResult(this.runner!, txResponse, options) } } diff --git a/packages/protocol-kit/src/contracts/SimulateTxAccessor/SimulateTxAccessorBaseContract.ts b/packages/protocol-kit/src/contracts/SimulateTxAccessor/SimulateTxAccessorBaseContract.ts index 1fda7217b..95dbc7042 100644 --- a/packages/protocol-kit/src/contracts/SimulateTxAccessor/SimulateTxAccessorBaseContract.ts +++ b/packages/protocol-kit/src/contracts/SimulateTxAccessor/SimulateTxAccessorBaseContract.ts @@ -1,5 +1,5 @@ import { Abi } from 'abitype' -import { ContractRunner, InterfaceAbi } from 'ethers' +import { PublicClient } from 'viem' import BaseContract from '@safe-global/protocol-kit/contracts/BaseContract' import SafeProvider from '@safe-global/protocol-kit/SafeProvider' @@ -20,7 +20,7 @@ import { contractName } from '@safe-global/protocol-kit/contracts/config' * - SimulateTxAccessorContract_v1_3_0 extends SimulateTxAccessorBaseContract */ abstract class SimulateTxAccessorBaseContract< - SimulateTxAccessorContractAbiType extends InterfaceAbi & Abi + SimulateTxAccessorContractAbiType extends Abi > extends BaseContract { contractName: contractName @@ -42,7 +42,7 @@ abstract class SimulateTxAccessorBaseContract< safeVersion: SafeVersion, customContractAddress?: string, customContractAbi?: SimulateTxAccessorContractAbiType, - runner?: ContractRunner | null + runner?: PublicClient | null ) { const contractName = 'simulateTxAccessorVersion' diff --git a/packages/protocol-kit/src/contracts/SimulateTxAccessor/v1.3.0/SimulateTxAccessorContract_v1_3_0.ts b/packages/protocol-kit/src/contracts/SimulateTxAccessor/v1.3.0/SimulateTxAccessorContract_v1_3_0.ts index 97d04b92a..9f660d5bc 100644 --- a/packages/protocol-kit/src/contracts/SimulateTxAccessor/v1.3.0/SimulateTxAccessorContract_v1_3_0.ts +++ b/packages/protocol-kit/src/contracts/SimulateTxAccessor/v1.3.0/SimulateTxAccessorContract_v1_3_0.ts @@ -8,6 +8,8 @@ import { SimulateTxAccessorContract_v1_3_0_Function } from '@safe-global/safe-core-sdk-types' +import { asHex } from '@safe-global/protocol-kit/utils/types' + /** * SimulateTxAccessorContract_v1_3_0 is the implementation specific to the SimulateTxAccessor contract version 1.3.0. * @@ -48,8 +50,12 @@ class SimulateTxAccessorContract_v1_3_0 * @param args - Array[to, value, data, operation] * @returns Array[estimate, success, returnData] */ - simulate: SimulateTxAccessorContract_v1_3_0_Function<'simulate'> = (args) => { - return this.contract.simulate(...args) + simulate: SimulateTxAccessorContract_v1_3_0_Function<'simulate'> = async (args) => { + const [estimate, success, returnData] = await this.contract.write.simulate( + args, + await this.convertOptions({}) + ) + return [BigInt(estimate), !!success, asHex(returnData)] } } diff --git a/packages/protocol-kit/src/contracts/SimulateTxAccessor/v1.4.1/SimulateTxAccessorContract_v1_4_1.ts b/packages/protocol-kit/src/contracts/SimulateTxAccessor/v1.4.1/SimulateTxAccessorContract_v1_4_1.ts index 294562199..5936b2fb7 100644 --- a/packages/protocol-kit/src/contracts/SimulateTxAccessor/v1.4.1/SimulateTxAccessorContract_v1_4_1.ts +++ b/packages/protocol-kit/src/contracts/SimulateTxAccessor/v1.4.1/SimulateTxAccessorContract_v1_4_1.ts @@ -7,6 +7,7 @@ import { SimulateTxAccessorContract_v1_4_1_Contract, SimulateTxAccessorContract_v1_4_1_Function } from '@safe-global/safe-core-sdk-types' +import { asHex } from '@safe-global/protocol-kit/utils/types' /** * SimulateTxAccessorContract_v1_4_1 is the implementation specific to the SimulateTxAccessor contract version 1.4.1. * @@ -47,8 +48,12 @@ class SimulateTxAccessorContract_v1_4_1 * @param args - Array[to, value, data, operation] * @returns Array[estimate, success, returnData] */ - simulate: SimulateTxAccessorContract_v1_4_1_Function<'simulate'> = (args) => { - return this.contract.simulate(...args) + simulate: SimulateTxAccessorContract_v1_4_1_Function<'simulate'> = async (args) => { + const [estimate, success, returnData] = await this.contract.write.simulate( + args, + await this.convertOptions({}) + ) + return [BigInt(estimate), !!success, asHex(returnData)] } } diff --git a/packages/protocol-kit/src/contracts/constants.ts b/packages/protocol-kit/src/contracts/constants.ts index b8a31c39f..a1f01e03d 100644 --- a/packages/protocol-kit/src/contracts/constants.ts +++ b/packages/protocol-kit/src/contracts/constants.ts @@ -1,3 +1,4 @@ -export const ZERO_ADDRESS = `0x${'0'.repeat(40)}` -export const EMPTY_DATA = '0x' -export const SENTINEL_ADDRESS = '0x0000000000000000000000000000000000000001' +import { Address, Hex } from 'viem' +export const ZERO_ADDRESS: Address = `0x${'0'.repeat(40)}` +export const EMPTY_DATA: Hex = '0x' +export const SENTINEL_ADDRESS: Address = '0x0000000000000000000000000000000000000001' diff --git a/packages/protocol-kit/src/contracts/contractInstances.ts b/packages/protocol-kit/src/contracts/contractInstances.ts index 4021c9bfb..3f5e09705 100644 --- a/packages/protocol-kit/src/contracts/contractInstances.ts +++ b/packages/protocol-kit/src/contracts/contractInstances.ts @@ -1,4 +1,4 @@ -import { JsonFragment, AbstractSigner, Provider } from 'ethers' +import { PublicClient, Abi } from 'viem' import { SafeVersion, SafeContract_v1_3_0_Abi, @@ -52,7 +52,7 @@ export async function getSafeContractInstance( safeVersion: SafeVersion, safeProvider: SafeProvider, contractAddress?: string, - customContractAbi?: JsonFragment | JsonFragment[] | undefined, + customContractAbi?: Abi, isL1SafeSingleton?: boolean ): Promise< | SafeContract_v1_4_1 @@ -123,7 +123,7 @@ export async function getCompatibilityFallbackHandlerContractInstance( safeVersion: SafeVersion, safeProvider: SafeProvider, contractAddress?: string, - customContractAbi?: JsonFragment | JsonFragment[] | undefined + customContractAbi?: Abi ): Promise< CompatibilityFallbackHandlerContract_v1_4_1 | CompatibilityFallbackHandlerContract_v1_3_0 > { @@ -162,7 +162,7 @@ export async function getMultiSendContractInstance( safeVersion: SafeVersion, safeProvider: SafeProvider, contractAddress?: string, - customContractAbi?: JsonFragment | JsonFragment[] | undefined + customContractAbi?: Abi ): Promise { const chainId = await safeProvider.getChainId() let multiSendContractInstance @@ -207,7 +207,7 @@ export async function getMultiSendCallOnlyContractInstance( safeVersion: SafeVersion, safeProvider: SafeProvider, contractAddress?: string, - customContractAbi?: JsonFragment | JsonFragment[] | undefined + customContractAbi?: Abi ): Promise { const chainId = await safeProvider.getChainId() let multiSendCallOnlyContractInstance @@ -245,9 +245,9 @@ export async function getSafeProxyFactoryContractInstance( safeVersion: SafeVersion, safeProvider: SafeProvider, // TODO: remove this ?? - signerOrProvider: AbstractSigner | Provider, + signerOrProvider: PublicClient, contractAddress?: string, - customContractAbi?: JsonFragment | JsonFragment[] | undefined + customContractAbi?: Abi ): Promise< | SafeProxyFactoryContract_v1_4_1 | SafeProxyFactoryContract_v1_3_0 @@ -308,7 +308,7 @@ export async function getSignMessageLibContractInstance( safeVersion: SafeVersion, safeProvider: SafeProvider, contractAddress?: string, - customContractAbi?: JsonFragment | JsonFragment[] | undefined + customContractAbi?: Abi ): Promise { const chainId = await safeProvider.getChainId() let signMessageLibContractInstance @@ -343,7 +343,7 @@ export async function getCreateCallContractInstance( safeVersion: SafeVersion, safeProvider: SafeProvider, contractAddress?: string, - customContractAbi?: JsonFragment | JsonFragment[] | undefined + customContractAbi?: Abi ): Promise { const chainId = await safeProvider.getChainId() let createCallContractInstance @@ -381,7 +381,7 @@ export async function getSimulateTxAccessorContractInstance( safeVersion: SafeVersion, safeProvider: SafeProvider, contractAddress?: string, - customContractAbi?: JsonFragment | JsonFragment[] | undefined + customContractAbi?: Abi ): Promise { const chainId = await safeProvider.getChainId() let simulateTxAccessorContractInstance diff --git a/packages/protocol-kit/src/contracts/safeDeploymentContracts.ts b/packages/protocol-kit/src/contracts/safeDeploymentContracts.ts index cff605dca..cc42e8a7f 100644 --- a/packages/protocol-kit/src/contracts/safeDeploymentContracts.ts +++ b/packages/protocol-kit/src/contracts/safeDeploymentContracts.ts @@ -91,9 +91,8 @@ export async function getMultiSendContract({ customContractAddress: customContracts?.multiSendAddress, customContractAbi: customContracts?.multiSendAbi }) - const isContractDeployed = await safeProvider.isContractDeployed( - await multiSendContract.getAddress() - ) + const address = await multiSendContract.getAddress() + const isContractDeployed = await safeProvider.isContractDeployed(address) if (!isContractDeployed) { throw new Error('MultiSend contract is not deployed on the current network') } diff --git a/packages/protocol-kit/src/contracts/utils.ts b/packages/protocol-kit/src/contracts/utils.ts index 55bccc402..1bcbba4fe 100644 --- a/packages/protocol-kit/src/contracts/utils.ts +++ b/packages/protocol-kit/src/contracts/utils.ts @@ -1,10 +1,4 @@ -import { - ContractTransactionResponse, - Provider, - AbstractSigner, - isAddress, - zeroPadValue -} from 'ethers' +import { Hash, isAddress, PublicClient, WalletClient, pad } from 'viem' import { keccak_256 } from '@noble/hashes/sha3' import { DEFAULT_SAFE_VERSION } from '@safe-global/protocol-kit/contracts/config' import { EMPTY_DATA, ZERO_ADDRESS } from '@safe-global/protocol-kit/utils/constants' @@ -17,7 +11,7 @@ import { } from '@safe-global/safe-core-sdk-types' import { generateAddress2, keccak256, toBuffer } from 'ethereumjs-util' import semverSatisfies from 'semver/functions/satisfies' - +import { asAddress, asHex } from '../utils/types' import { GetContractInstanceProps, GetSafeContractInstanceProps, @@ -32,6 +26,7 @@ import { SafeDeploymentConfig } from '../types' import SafeProvider from '@safe-global/protocol-kit/SafeProvider' +import { ContractLegacyTransactionOptions, ContractTransactionOptions } from '../types' // keccak256(toUtf8Bytes('Safe Account Abstraction')) export const PREDETERMINED_SALT_NONCE = @@ -82,8 +77,8 @@ export function encodeCreateProxyWithNonce( salt?: string ) { return safeProxyFactoryContract.encode('createProxyWithNonce', [ - safeSingletonAddress, - initializer, + asAddress(safeSingletonAddress), + asHex(initializer), BigInt(salt || PREDETERMINED_SALT_NONCE) ]) } @@ -92,6 +87,58 @@ const memoizedGetCompatibilityFallbackHandlerContract = createMemoizedFunction( getCompatibilityFallbackHandlerContract ) +export function isLegacyTransaction(options?: TransactionOptions) { + return !!options?.gasPrice +} + +export function createLegacyTxOptions( + options?: TransactionOptions +): Partial { + const converted: Partial = {} + if (options?.from) { + converted.account = asAddress(options.from) + } + + if (options?.gasLimit) { + converted.gas = BigInt(options.gasLimit) + } + + if (options?.gasPrice) { + converted.gasPrice = BigInt(options.gasPrice) + } + + if (options?.nonce) { + converted.nonce = options.nonce + } + + return converted +} + +export function createTxOptions(options?: TransactionOptions): Partial { + const converted: Partial = {} + if (options?.from) { + converted.account = asAddress(options.from) + } + + if (options?.gasLimit) { + converted.gas = BigInt(options.gasLimit) + } + + if (options?.maxFeePerGas) { + converted.maxFeePerGas = BigInt(options.maxFeePerGas) + } + + if (options?.maxPriorityFeePerGas) { + converted.maxPriorityFeePerGas = BigInt(options.maxPriorityFeePerGas) + } + + if (options?.nonce) { + converted.nonce = options.nonce + } + + return converted +} + export async function encodeSetupCallData({ safeProvider, safeAccountConfig, @@ -116,11 +163,11 @@ export async function encodeSetupCallData({ return safeContract.encode('setup', [ owners, threshold, - to, - data, - paymentToken, + asAddress(to), + asHex(data), + asAddress(paymentToken), payment, - paymentReceiver + asAddress(paymentReceiver) ]) } @@ -235,7 +282,7 @@ export async function getPredictedSafeAddressInitCode({ customSafeVersion: safeVersion // it is more efficient if we provide the safeVersion manually }) - const encodedNonce = toBuffer(safeProvider.encodeParameters(['uint256'], [saltNonce])).toString( + const encodedNonce = toBuffer(safeProvider.encodeParameters('uint256', [saltNonce])).toString( 'hex' ) const safeSingletonAddress = await safeContract.getAddress() @@ -300,14 +347,14 @@ export async function predictSafeAddress({ customSafeVersion: safeVersion // it is more efficient if we provide the safeVersion manually }) - const encodedNonce = toBuffer(safeProvider.encodeParameters(['uint256'], [saltNonce])).toString( + const encodedNonce = toBuffer(safeProvider.encodeParameters('uint256', [saltNonce])).toString( 'hex' ) const salt = keccak256( toBuffer('0x' + keccak256(toBuffer(initializer)).toString('hex') + encodedNonce) ) - const input = safeProvider.encodeParameters(['address'], [await safeContract.getAddress()]) + const input = safeProvider.encodeParameters('address', [await safeContract.getAddress()]) const from = await safeProxyFactoryContract.getAddress() @@ -362,7 +409,7 @@ export function zkSyncEraCreate2Address( const addressBytes = keccak256( toBuffer( ZKSYNC_CREATE2_PREFIX + - zeroPadValue(from, 32).slice(2) + + pad(asHex(from), { size: 32 }).slice(2) + salt.toString('hex') + bytecodeHash.slice(2) + inputHash.toString('hex') @@ -375,31 +422,22 @@ export function zkSyncEraCreate2Address( } export function toTxResult( - transactionResponse: ContractTransactionResponse, + runner: PublicClient, + hash: Hash, options?: TransactionOptions ): TransactionResult { + const wait = async () => { + return runner.getTransactionReceipt({ hash }) + } return { - hash: transactionResponse.hash, + hash, options, - transactionResponse + transactionResponse: { + wait + } } } -export function isTypedDataSigner(signer: any): signer is AbstractSigner { - return (signer as unknown as AbstractSigner).signTypedData !== undefined -} - -/** - * Check if the signerOrProvider is compatible with `Signer` - * @param signerOrProvider - Signer or provider - * @returns true if the parameter is compatible with `Signer` - */ -export function isSignerCompatible(signerOrProvider: AbstractSigner | Provider): boolean { - const candidate = signerOrProvider as AbstractSigner - - const isSigntransactionCompatible = typeof candidate.signTransaction === 'function' - const isSignMessageCompatible = typeof candidate.signMessage === 'function' - const isGetAddressCompatible = typeof candidate.getAddress === 'function' - - return isSigntransactionCompatible && isSignMessageCompatible && isGetAddressCompatible +export function isTypedDataSigner(signer: any): signer is WalletClient { + return (signer as unknown as WalletClient).signTypedData !== undefined } diff --git a/packages/protocol-kit/src/managers/fallbackHandlerManager.ts b/packages/protocol-kit/src/managers/fallbackHandlerManager.ts index 088581747..c688c8555 100644 --- a/packages/protocol-kit/src/managers/fallbackHandlerManager.ts +++ b/packages/protocol-kit/src/managers/fallbackHandlerManager.ts @@ -8,6 +8,7 @@ import { import { ZERO_ADDRESS } from '@safe-global/protocol-kit/utils/constants' import { SafeContractImplementationType } from '@safe-global/protocol-kit/types' import SafeProvider from '../SafeProvider' +import { asAddress } from '../utils/types' class FallbackHandlerManager { #safeProvider: SafeProvider @@ -69,7 +70,7 @@ class FallbackHandlerManager { const currentFallbackHandler = await this.getFallbackHandler() this.validateFallbackHandlerIsNotEnabled(currentFallbackHandler, fallbackHandlerAddress) - return safeContract.encode('setFallbackHandler', [fallbackHandlerAddress]) + return safeContract.encode('setFallbackHandler', [asAddress(fallbackHandlerAddress)]) } async encodeDisableFallbackHandlerData(): Promise { diff --git a/packages/protocol-kit/src/managers/guardManager.ts b/packages/protocol-kit/src/managers/guardManager.ts index 9f82e96ac..d05461348 100644 --- a/packages/protocol-kit/src/managers/guardManager.ts +++ b/packages/protocol-kit/src/managers/guardManager.ts @@ -8,6 +8,7 @@ import { import { ZERO_ADDRESS } from '@safe-global/protocol-kit/utils/constants' import { SafeContractImplementationType } from '@safe-global/protocol-kit/types' import SafeProvider from '../SafeProvider' +import { asAddress } from '../utils/types' class GuardManager { #safeProvider: SafeProvider @@ -65,7 +66,7 @@ class GuardManager { this.validateGuardAddress(guardAddress) const currentGuard = await this.getGuard() this.validateGuardIsNotEnabled(currentGuard, guardAddress) - return safeContract.encode('setGuard', [guardAddress]) + return safeContract.encode('setGuard', [asAddress(guardAddress)]) } async encodeDisableGuardData(): Promise { diff --git a/packages/protocol-kit/src/managers/moduleManager.ts b/packages/protocol-kit/src/managers/moduleManager.ts index f90d626fc..c7150254f 100644 --- a/packages/protocol-kit/src/managers/moduleManager.ts +++ b/packages/protocol-kit/src/managers/moduleManager.ts @@ -5,6 +5,7 @@ import { SafeModulesPaginated } from '@safe-global/protocol-kit/types' import SafeProvider from '../SafeProvider' +import { asAddress } from '../utils/types' class ModuleManager { #safeProvider: SafeProvider @@ -54,7 +55,10 @@ class ModuleManager { throw new Error('Safe is not deployed') } - const [modules, next] = await this.#safeContract.getModulesPaginated([start, BigInt(pageSize)]) + const [modules, next] = await this.#safeContract.getModulesPaginated([ + asAddress(start), + BigInt(pageSize) + ]) return { modules: modules as string[], next } } @@ -63,7 +67,7 @@ class ModuleManager { throw new Error('Safe is not deployed') } - const [isModuleEnabled] = await this.#safeContract.isModuleEnabled([moduleAddress]) + const [isModuleEnabled] = await this.#safeContract.isModuleEnabled([asAddress(moduleAddress)]) return isModuleEnabled } diff --git a/packages/protocol-kit/src/managers/ownerManager.ts b/packages/protocol-kit/src/managers/ownerManager.ts index 6ede3460b..6cb1aa424 100644 --- a/packages/protocol-kit/src/managers/ownerManager.ts +++ b/packages/protocol-kit/src/managers/ownerManager.ts @@ -2,6 +2,7 @@ import { isRestrictedAddress, sameString } from '@safe-global/protocol-kit/utils import { SENTINEL_ADDRESS } from '@safe-global/protocol-kit/utils/constants' import { SafeContractImplementationType } from '../types' import SafeProvider from '../SafeProvider' +import { asAddress } from '../utils/types' class OwnerManager { #safeProvider: SafeProvider @@ -76,7 +77,7 @@ class OwnerManager { throw new Error('Safe is not deployed') } - const [isOwner] = await this.#safeContract.isOwner([ownerAddress]) + const [isOwner] = await this.#safeContract.isOwner([asAddress(ownerAddress)]) return isOwner } diff --git a/packages/protocol-kit/src/types/contracts.ts b/packages/protocol-kit/src/types/contracts.ts index 612f3fd28..258386ea9 100644 --- a/packages/protocol-kit/src/types/contracts.ts +++ b/packages/protocol-kit/src/types/contracts.ts @@ -1,6 +1,5 @@ -import { JsonFragment } from 'ethers' +import { Abi, Address, Chain } from 'viem' import { SafeVersion } from '@safe-global/safe-core-sdk-types' - import SafeContract_v1_0_0 from '@safe-global/protocol-kit/contracts/Safe/v1.0.0/SafeContract_v1_0_0' import SafeContract_v1_1_1 from '@safe-global/protocol-kit/contracts/Safe/v1.1.1/SafeContract_v1_1_1' import SafeContract_v1_2_0 from '@safe-global/protocol-kit/contracts/Safe/v1.2.0/SafeContract_v1_2_0' @@ -73,7 +72,7 @@ export type CreateCallContractImplementationType = export type GetContractProps = { safeVersion: SafeVersion customContractAddress?: string - customContractAbi?: JsonFragment | JsonFragment[] + customContractAbi?: Abi isL1SafeSingleton?: boolean } @@ -81,38 +80,55 @@ export type ContractNetworkConfig = { /** safeSingletonAddress - Address of the Safe Singleton contract deployed on a specific network */ safeSingletonAddress: string /** safeSingletonAbi - Abi of the Safe Singleton contract deployed on a specific network */ - safeSingletonAbi?: JsonFragment | JsonFragment[] + safeSingletonAbi?: Abi /** safeProxyFactoryAddress - Address of the SafeProxyFactory contract deployed on a specific network */ safeProxyFactoryAddress: string /** safeProxyFactoryAbi - Abi of the SafeProxyFactory contract deployed on a specific network */ - safeProxyFactoryAbi?: JsonFragment | JsonFragment[] + safeProxyFactoryAbi?: Abi /** multiSendAddress - Address of the MultiSend contract deployed on a specific network */ multiSendAddress: string /** multiSendAbi - Abi of the MultiSend contract deployed on a specific network */ - multiSendAbi?: JsonFragment | JsonFragment[] + multiSendAbi?: Abi /** multiSendCallOnlyAddress - Address of the MultiSendCallOnly contract deployed on a specific network */ multiSendCallOnlyAddress: string /** multiSendCallOnlyAbi - Abi of the MultiSendCallOnly contract deployed on a specific network */ - multiSendCallOnlyAbi?: JsonFragment | JsonFragment[] + multiSendCallOnlyAbi?: Abi /** fallbackHandlerAddress - Address of the Fallback Handler contract deployed on a specific network */ fallbackHandlerAddress: string /** fallbackHandlerAbi - Abi of the Fallback Handler contract deployed on a specific network */ - fallbackHandlerAbi?: JsonFragment | JsonFragment[] + fallbackHandlerAbi?: Abi /** signMessageLibAddress - Address of the SignMessageLib contract deployed on a specific network */ signMessageLibAddress: string /** signMessageLibAbi - Abi of the SignMessageLib contract deployed on a specific network */ - signMessageLibAbi?: JsonFragment | JsonFragment[] + signMessageLibAbi?: Abi /** createCallAddress - Address of the CreateCall contract deployed on a specific network */ createCallAddress: string /** createCallAbi - Abi of the CreateCall contract deployed on a specific network */ - createCallAbi?: JsonFragment | JsonFragment[] + createCallAbi?: Abi /** simulateTxAccessorAddress - Address of the SimulateTxAccessor contract deployed on a specific network */ simulateTxAccessorAddress: string /** simulateTxAccessorAbi - Abi of the SimulateTxAccessor contract deployed on a specific network */ - simulateTxAccessorAbi?: JsonFragment | JsonFragment[] + simulateTxAccessorAbi?: Abi } export type ContractNetworksConfig = { /** id - Network id */ [id: string]: ContractNetworkConfig } + +export type ContractTransactionOptions = { + chain: Chain + account: Address + gas?: bigint + maxFeePerGas?: bigint + maxPriorityFeePerGas?: bigint + nonce?: number +} + +export type ContractLegacyTransactionOptions = { + chain: Chain + account: Address + gas?: bigint + gasPrice?: bigint + nonce?: number +} diff --git a/packages/protocol-kit/src/types/safeProvider.ts b/packages/protocol-kit/src/types/safeProvider.ts index af47b84bb..2fb1d4eef 100644 --- a/packages/protocol-kit/src/types/safeProvider.ts +++ b/packages/protocol-kit/src/types/safeProvider.ts @@ -25,7 +25,7 @@ export type SafeProviderTransaction = { data: string value?: string gasPrice?: number | string - gasLimit?: number | string + gasLimit?: number | string | bigint maxFeePerGas?: number | string maxPriorityFeePerGas?: number | string } diff --git a/packages/protocol-kit/src/utils/address.ts b/packages/protocol-kit/src/utils/address.ts index 472011460..54a7edb0f 100644 --- a/packages/protocol-kit/src/utils/address.ts +++ b/packages/protocol-kit/src/utils/address.ts @@ -1,7 +1,7 @@ import { SENTINEL_ADDRESS, ZERO_ADDRESS } from './constants' -export function sameString(str1: string, str2: string): boolean { - return str1.toLowerCase() === str2.toLowerCase() +export function sameString(str1?: string, str2?: string): boolean { + return !!str1 && !!str2 && str1.toLowerCase() === str2.toLowerCase() } export function isZeroAddress(address: string): boolean { diff --git a/packages/protocol-kit/src/utils/constants.ts b/packages/protocol-kit/src/utils/constants.ts index b8a31c39f..f6871c4be 100644 --- a/packages/protocol-kit/src/utils/constants.ts +++ b/packages/protocol-kit/src/utils/constants.ts @@ -1,3 +1,5 @@ -export const ZERO_ADDRESS = `0x${'0'.repeat(40)}` -export const EMPTY_DATA = '0x' -export const SENTINEL_ADDRESS = '0x0000000000000000000000000000000000000001' +import { Address, Hex } from 'viem' + +export const ZERO_ADDRESS: Address = `0x${'0'.repeat(40)}` +export const EMPTY_DATA: Hex = '0x' +export const SENTINEL_ADDRESS: Address = '0x0000000000000000000000000000000000000001' diff --git a/packages/protocol-kit/src/utils/eip-3770/index.ts b/packages/protocol-kit/src/utils/eip-3770/index.ts index ff2319cc4..ec3d5f54c 100644 --- a/packages/protocol-kit/src/utils/eip-3770/index.ts +++ b/packages/protocol-kit/src/utils/eip-3770/index.ts @@ -1,4 +1,4 @@ -import { ethers } from 'ethers' +import { isAddress } from 'viem' import { Eip3770Address } from '@safe-global/safe-core-sdk-types' import { networks } from './config' @@ -29,8 +29,7 @@ export function validateEip3770NetworkPrefix(prefix: string, currentChainId: big } export function validateEthereumAddress(address: string): void { - const isValidAddress = ethers.isHexString(address) && ethers.isAddress(address) - if (!isValidAddress) { + if (!isAddress(address)) { throw new Error(`Invalid Ethereum address ${address}`) } } diff --git a/packages/protocol-kit/src/utils/eip-712/encode.ts b/packages/protocol-kit/src/utils/eip-712/encode.ts new file mode 100644 index 000000000..1401419fe --- /dev/null +++ b/packages/protocol-kit/src/utils/eip-712/encode.ts @@ -0,0 +1,211 @@ +import { EIP712TypedData, TypedDataTypes, TypedMessageTypes } from 'packages/safe-core-sdk-types' +import { + keccak256, + concat, + AbiParameter, + encodeAbiParameters, + getTypesForEIP712Domain, + validateTypedData, + hashDomain, + toHex, + Hex, + HashTypedDataParameters +} from 'viem' +import { asHex } from '../types' + +// This whole file was copied (and softly adapted) from viem in order to expose the function that provides just the encoding. +function encodeField({ + types, + name, + type, + value +}: { + types: Record + name: string + type: string + value: any +}): [type: AbiParameter, value: any] { + if (types[type] !== undefined) { + return [{ type: 'bytes32' }, keccak256(encodeData({ data: value, primaryType: type, types }))] + } + + if (type === 'bytes') { + const prepend = value.length % 2 ? '0' : '' + value = `0x${prepend + value.slice(2)}` + return [{ type: 'bytes32' }, keccak256(value)] + } + + if (type === 'string') return [{ type: 'bytes32' }, keccak256(toHex(value))] + + if (type.lastIndexOf(']') === type.length - 1) { + const parsedType = type.slice(0, type.lastIndexOf('[')) + const typeValuePairs = (value as [AbiParameter, any][]).map((item) => + encodeField({ + name, + type: parsedType, + types, + value: item + }) + ) + return [ + { type: 'bytes32' }, + keccak256( + encodeAbiParameters( + typeValuePairs.map(([t]) => t), + typeValuePairs.map(([, v]) => v) + ) + ) + ] + } + + return [{ type }, value] +} + +function findTypeDependencies( + { + primaryType: primaryType_, + types + }: { + primaryType: string + types: Record + }, + results: Set = new Set() +): Set { + const match = primaryType_.match(/^\w*/u) + const primaryType = match?.[0] || '' + if (results.has(primaryType) || types[primaryType] === undefined) { + return results + } + + results.add(primaryType) + + for (const field of types[primaryType]) { + findTypeDependencies({ primaryType: field.type, types }, results) + } + return results +} + +function encodeType({ + primaryType, + types +}: { + primaryType: string + types: Record +}) { + let result = '' + const unsortedDeps = findTypeDependencies({ primaryType, types }) + unsortedDeps.delete(primaryType) + + const deps = [primaryType, ...Array.from(unsortedDeps).sort()] + for (const type of deps) { + result += `${type}(${types[type].map(({ name, type: t }) => `${t} ${name}`).join(',')})` + } + + return result +} + +function hashType({ + primaryType, + types +}: { + primaryType: string + types: Record +}) { + const encodedHashType = toHex(encodeType({ primaryType, types })) + return keccak256(encodedHashType) +} + +function encodeData({ + data, + primaryType, + types +}: { + data: Record + primaryType: string + types: Record +}) { + const encodedTypes: AbiParameter[] = [{ type: 'bytes32' }] + const encodedValues: unknown[] = [hashType({ primaryType, types })] + + for (const field of types[primaryType]) { + const [type, value] = encodeField({ + types, + name: field.name, + type: field.type, + value: data[field.name] + }) + encodedTypes.push(type) + encodedValues.push(value) + } + + return encodeAbiParameters(encodedTypes, encodedValues) +} + +function hashStruct({ + data, + primaryType, + types +}: { + data: Record + primaryType: string + types: Record +}) { + const encoded = encodeData({ + data, + primaryType, + types + }) + return keccak256(encoded) +} + +function deducePrimaryType(types: TypedMessageTypes) { + // In ethers the primaryType is assumed to be the first inserted yielded by a forEach of the types keys + // https://github.com/ethers-io/ethers.js/blob/a4b1d1f43fca14f2e826e3c60e0d45f5b6ef3ec4/src.ts/hash/typed-data.ts#L278C13-L278C20 + return Object.keys(types)[0] +} + +export function hashTypedData(typedData: EIP712TypedData): string { + const data = encodeTypedData(typedData) + return keccak256(asHex(data)) +} + +export function encodeTypedData(typedData: EIP712TypedData): string { + typedData.primaryType = !typedData?.primaryType + ? deducePrimaryType(typedData.types) + : typedData?.primaryType + + const { domain = {}, message, primaryType } = typedData as any as HashTypedDataParameters + const types = { + EIP712Domain: getTypesForEIP712Domain({ domain: domain as Record }), + ...typedData.types + } + + // Need to do a runtime validation check on addresses, byte ranges, integer ranges, etc + // as we can't statically check this with TypeScript. + validateTypedData({ + domain: domain as any, + message, + primaryType: primaryType as any, + types + }) + + const parts: Hex[] = ['0x1901'] + if (domain) + parts.push( + hashDomain({ + domain, + types: types + }) + ) + + if (primaryType !== 'EIP712Domain') + parts.push( + hashStruct({ + data: message, + primaryType: primaryType, + types: types + }) + ) + + return concat(parts) +} diff --git a/packages/protocol-kit/src/utils/eip-712/index.ts b/packages/protocol-kit/src/utils/eip-712/index.ts index e155020e2..2b83cee42 100644 --- a/packages/protocol-kit/src/utils/eip-712/index.ts +++ b/packages/protocol-kit/src/utils/eip-712/index.ts @@ -1,4 +1,4 @@ -import { ethers, TypedDataDomain } from 'ethers' +import { hashMessage as performMessageHash } from 'viem' import { EIP712MessageTypes, EIP712TxTypes, @@ -9,6 +9,7 @@ import { EIP712TypedDataTx } from '@safe-global/safe-core-sdk-types' import semverSatisfies from 'semver/functions/satisfies' +import { hashTypedData as hashTypedStructuredData } from './encode' const EQ_OR_GT_1_3_0 = '>=1.3.0' @@ -59,14 +60,11 @@ export function getEip712MessageTypes(safeVersion: string): EIP712MessageTypes { } export const hashTypedData = (typedData: EIP712TypedData): string => { - // `ethers` doesn't require `EIP712Domain` and otherwise throws - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const { EIP712Domain: _, ...types } = typedData.types - return ethers.TypedDataEncoder.hash(typedData.domain as TypedDataDomain, types, typedData.message) + return hashTypedStructuredData(typedData) } const hashMessage = (message: string): string => { - return ethers.hashMessage(message) + return performMessageHash(message) } export const hashSafeMessage = (message: string | EIP712TypedData): string => { @@ -117,7 +115,7 @@ export function generateTypedData({ } if (eip712WithChainId) { - typedData.domain.chainId = chainId.toString() + typedData.domain.chainId = Number(chainId) } return typedData diff --git a/packages/protocol-kit/src/utils/erc-20/index.ts b/packages/protocol-kit/src/utils/erc-20/index.ts index 57273e4c9..acc5f4e1e 100644 --- a/packages/protocol-kit/src/utils/erc-20/index.ts +++ b/packages/protocol-kit/src/utils/erc-20/index.ts @@ -1,7 +1,6 @@ -import { Interface } from 'ethers' import Safe from '@safe-global/protocol-kit/Safe' import { Transaction } from '@safe-global/safe-core-sdk-types' - +import { encodeFunctionData, parseAbi } from 'viem' import { ZERO_ADDRESS } from '../constants' const ERC20_ABI = [ @@ -20,13 +19,16 @@ const ERC20_ABI = [ */ export async function getERC20Decimals(tokenAddress: string, safe: Safe): Promise { const safeProvider = safe.getSafeProvider() - const erc20Interface = new Interface(ERC20_ABI) + const data = encodeFunctionData({ + abi: parseAbi(ERC20_ABI), + functionName: 'decimals' + }) const getTokenDecimalsTransaction = { to: tokenAddress, from: tokenAddress, value: '0', - data: erc20Interface.encodeFunctionData('decimals') + data } const response = await safeProvider.call(getTokenDecimalsTransaction) @@ -83,12 +85,16 @@ export function createERC20TokenTransferTransaction( toAddress: string, amount: string ): Transaction { - const erc20Interface = new Interface(ERC20_ABI) + const data = encodeFunctionData({ + abi: parseAbi(ERC20_ABI), + functionName: 'transfer', + args: [toAddress, amount] + }) const transferTransaction = { to: tokenAddress, value: '0', - data: erc20Interface.encodeFunctionData('transfer', [toAddress, amount]) + data } return transferTransaction diff --git a/packages/protocol-kit/src/utils/signatures/utils.ts b/packages/protocol-kit/src/utils/signatures/utils.ts index dcc26c477..fc08681cf 100644 --- a/packages/protocol-kit/src/utils/signatures/utils.ts +++ b/packages/protocol-kit/src/utils/signatures/utils.ts @@ -1,4 +1,3 @@ -import { ethers } from 'ethers' import SafeProvider from '@safe-global/protocol-kit/SafeProvider' import { SafeSignature, @@ -11,6 +10,8 @@ import { sameString } from '../address' import { EthSafeSignature } from './SafeSignature' import { getEip712MessageTypes, getEip712TxTypes } from '../eip-712' import { SigningMethod } from '@safe-global/protocol-kit/types' +import { hashTypedData } from '../eip-712' +import { encodeTypedData } from '../eip-712/encode' export function generatePreValidatedSignature(ownerAddress: string): SafeSignature { const signature = @@ -197,11 +198,12 @@ export const preimageSafeTransactionHash = ( ): string => { const safeTxTypes = getEip712TxTypes(safeVersion) - return ethers.TypedDataEncoder.encode( - { verifyingContract: safeAddress, chainId }, - { SafeTx: safeTxTypes.SafeTx }, - safeTx - ) + const message = safeTx as unknown as Record + return encodeTypedData({ + domain: { verifyingContract: safeAddress, chainId: Number(chainId) }, + types: { SafeTx: safeTxTypes.SafeTx }, + message + }) } export const preimageSafeMessageHash = ( @@ -212,11 +214,11 @@ export const preimageSafeMessageHash = ( ): string => { const safeMessageTypes = getEip712MessageTypes(safeVersion) - return ethers.TypedDataEncoder.encode( - { verifyingContract: safeAddress, chainId }, - { SafeMessage: safeMessageTypes.SafeMessage }, - { message } - ) + return encodeTypedData({ + domain: { verifyingContract: safeAddress, chainId: Number(chainId) }, + types: { SafeMessage: safeMessageTypes.SafeMessage }, + message: { message } + }) } const EQ_OR_GT_1_3_0 = '>=1.3.0' @@ -229,15 +231,17 @@ export const calculateSafeTransactionHash = ( ): string => { const safeTxTypes = getEip712TxTypes(safeVersion) const domain: { - chainId?: bigint + chainId?: number verifyingContract: string } = { verifyingContract: safeAddress } if (semverSatisfies(safeVersion, EQ_OR_GT_1_3_0)) { - domain.chainId = chainId + domain.chainId = Number(chainId) } - return ethers.TypedDataEncoder.hash(domain, { SafeTx: safeTxTypes.SafeTx }, safeTx) + const message = safeTx as unknown as Record + + return hashTypedData({ domain, types: { SafeTx: safeTxTypes.SafeTx }, message }) } export const calculateSafeMessageHash = ( @@ -248,9 +252,9 @@ export const calculateSafeMessageHash = ( ): string => { const safeMessageTypes = getEip712MessageTypes(safeVersion) - return ethers.TypedDataEncoder.hash( - { verifyingContract: safeAddress, chainId }, - { SafeMessage: safeMessageTypes.SafeMessage }, - { message } - ) + return hashTypedData({ + domain: { verifyingContract: safeAddress, chainId: Number(chainId) }, + types: { SafeMessage: safeMessageTypes.SafeMessage }, + message: { message } + }) } diff --git a/packages/protocol-kit/src/utils/transactions/gas.ts b/packages/protocol-kit/src/utils/transactions/gas.ts index dff83c07b..dafb12577 100644 --- a/packages/protocol-kit/src/utils/transactions/gas.ts +++ b/packages/protocol-kit/src/utils/transactions/gas.ts @@ -15,6 +15,7 @@ import { isSafeContractCompatibleWithRequiredTxGas, isSafeContractCompatibleWithSimulateAndRevert } from '../safeVersions' +import { asAddress, asHex } from '../types' // Every byte == 00 -> 4 Gas cost const CALL_DATA_ZERO_BYTE_GAS_COST = 4 @@ -78,9 +79,9 @@ export async function estimateGas( }) const transactionDataToEstimate = simulateTxAccessorContract.encode('simulate', [ - to, + asAddress(to), BigInt(valueInWei), - data, + asHex(data), operation ]) @@ -89,7 +90,7 @@ export async function estimateGas( const safeFunctionToEstimate = safeContractContractCompatibleWithSimulateAndRevert.encode( 'simulateAndRevert', - [await simulateTxAccessorContract.getAddress(), transactionDataToEstimate] + [asAddress(await simulateTxAccessorContract.getAddress()), asHex(transactionDataToEstimate)] ) const safeAddress = await safeContract.getAddress() const transactionToEstimateGas = { @@ -116,50 +117,7 @@ export async function estimateTxGas( data: string, operation: OperationType ): Promise { - let txGasEstimation = 0 const safeAddress = await safeContract.getAddress() - - const safeContractCompatibleWithRequiredTxGas = - await isSafeContractCompatibleWithRequiredTxGas(safeContract) - - const estimateData = safeContractCompatibleWithRequiredTxGas.encode('requiredTxGas', [ - to, - BigInt(valueInWei), - data, - operation - ]) - - try { - const estimateResponse = await safeProvider.estimateGas({ - to: safeAddress, - from: safeAddress, - data: estimateData - }) - txGasEstimation = Number('0x' + estimateResponse.substring(138)) + 10000 - } catch (error) {} - - if (txGasEstimation > 0) { - const dataGasEstimation = estimateDataGasCosts(estimateData) - let additionalGas = 10000 - for (let i = 0; i < 10; i++) { - try { - const estimateResponse = await safeProvider.call({ - to: safeAddress, - from: safeAddress, - data: estimateData, - gasPrice: '0', - gasLimit: (txGasEstimation + dataGasEstimation + additionalGas).toString() - }) - if (estimateResponse !== '0x') { - break - } - } catch (error) {} - txGasEstimation = txGasEstimation + additionalGas - additionalGas *= 2 - } - return (txGasEstimation + additionalGas).toString() - } - try { const estimateGas = await safeProvider.estimateGas({ to, @@ -343,9 +301,9 @@ async function estimateSafeTxGasWithRequiredTxGas( const transactionDataToEstimate: string = safeContractCompatibleWithRequiredTxGas.encode( 'requiredTxGas', [ - safeTransaction.data.to, + asAddress(safeTransaction.data.to), BigInt(safeTransaction.data.value), - safeTransaction.data.data, + asHex(safeTransaction.data.data), safeTransaction.data.operation ] ) @@ -401,10 +359,12 @@ function decodeSafeTxGas(encodedDataResponse: string): string { type GnosisChainEstimationError = { info: { error: { data: string | { data: string } } } } type EthersEstimationError = { data: string } type ViemEstimationError = { info: { error: { message: string } } } +type CallExecutionError = { details: string } type EstimationError = Error & EthersEstimationError & GnosisChainEstimationError & - ViemEstimationError + ViemEstimationError & + CallExecutionError /** * Parses the SafeTxGas estimation response from different providers. @@ -422,7 +382,7 @@ function parseSafeTxGasErrorResponse(error: EstimationError) { } // viem - const viemError = error?.info?.error?.message + const viemError = error?.info?.error?.message || error?.details if (viemError) { return decodeSafeTxGas(viemError) } @@ -485,9 +445,9 @@ async function estimateSafeTxGasWithSimulate( }) const transactionDataToEstimate: string = simulateTxAccessorContract.encode('simulate', [ - safeTransaction.data.to, + asAddress(safeTransaction.data.to), BigInt(safeTransaction.data.value), - safeTransaction.data.data, + asHex(safeTransaction.data.data), safeTransaction.data.operation ]) @@ -499,7 +459,7 @@ async function estimateSafeTxGasWithSimulate( const safeFunctionToEstimate: string = SafeContractCompatibleWithSimulateAndRevert.encode( 'simulateAndRevert', - [await simulateTxAccessorContract.getAddress(), transactionDataToEstimate] + [asAddress(await simulateTxAccessorContract.getAddress()), asHex(transactionDataToEstimate)] ) const transactionToEstimateGas = { diff --git a/packages/protocol-kit/src/utils/transactions/utils.ts b/packages/protocol-kit/src/utils/transactions/utils.ts index e5657a4d5..d225c6a0c 100644 --- a/packages/protocol-kit/src/utils/transactions/utils.ts +++ b/packages/protocol-kit/src/utils/transactions/utils.ts @@ -1,9 +1,10 @@ -import { ethers, Interface, getBytes, solidityPacked as solidityPack } from 'ethers' +import { toBytes, getAddress, encodePacked, bytesToHex, decodeFunctionData, parseAbi } from 'viem' import SafeProvider from '@safe-global/protocol-kit/SafeProvider' import { DEFAULT_SAFE_VERSION } from '@safe-global/protocol-kit/contracts/config' import { StandardizeSafeTransactionDataProps } from '@safe-global/protocol-kit/types' import { hasSafeFeature, SAFE_FEATURES } from '@safe-global/protocol-kit/utils' import { ZERO_ADDRESS } from '@safe-global/protocol-kit/utils/constants' +import { asAddress, asHex } from '../types' import { MetaTransactionData, OperationType, @@ -15,6 +16,13 @@ import { } from '@safe-global/safe-core-sdk-types' import semverSatisfies from 'semver/functions/satisfies' import { estimateGas, estimateTxGas } from './gas' +import { PublicClient, Hash, EstimateGasParameters, TransactionRequest, UnionOmit } from 'viem' +import { SafeProviderTransaction } from '@safe-global/protocol-kit/types' +import { + isLegacyTransaction, + createLegacyTxOptions, + createTxOptions +} from '@safe-global/protocol-kit/contracts/utils' export function standardizeMetaTransactionData( tx: SafeTransactionDataPartial @@ -26,6 +34,10 @@ export function standardizeMetaTransactionData( return standardizedTxs } +export function waitForTransactionReceipt(client: PublicClient, hash: Hash) { + return client.waitForTransactionReceipt({ hash }) +} + export async function standardizeSafeTransactionData({ safeContract, predictedSafe, @@ -108,10 +120,16 @@ export async function standardizeSafeTransactionData({ } function encodeMetaTransaction(tx: MetaTransactionData): string { - const data = getBytes(tx.data) - const encoded = solidityPack( + const data = toBytes(tx.data) + const encoded = encodePacked( ['uint8', 'address', 'uint256', 'uint256', 'bytes'], - [tx.operation, tx.to, tx.value, data.length, data] + [ + tx.operation ?? OperationType.Call, + asAddress(tx.to), + BigInt(tx.value), + BigInt(data.length), + bytesToHex(data) + ] ) return encoded.slice(2) } @@ -121,32 +139,36 @@ export function encodeMultiSendData(txs: MetaTransactionData[]): string { } export function decodeMultiSendData(encodedData: string): MetaTransactionData[] { - const multiSendInterface = new Interface([ - 'function multiSend(bytes memory transactions) public payable' - ]) - const [decodedData] = multiSendInterface.decodeFunctionData('multiSend', encodedData) + const decodedData = decodeFunctionData({ + abi: parseAbi(['function multiSend(bytes memory transactions) public payable']), + data: asHex(encodedData) + }) + const args = decodedData.args const txs: MetaTransactionData[] = [] // Decode after 0x let index = 2 - while (index < decodedData.length) { - // As we are decoding hex encoded bytes calldata, each byte is represented by 2 chars - // uint8 operation, address to, value uint256, dataLength uint256 - - const operation = `0x${decodedData.slice(index, (index += 2))}` - const to = `0x${decodedData.slice(index, (index += 40))}` - const value = `0x${decodedData.slice(index, (index += 64))}` - const dataLength = parseInt(decodedData.slice(index, (index += 64)), 16) * 2 - const data = `0x${decodedData.slice(index, (index += dataLength))}` - - txs.push({ - operation: Number(operation) as OperationType, - to: ethers.getAddress(to), - value: BigInt(value).toString(), - data - }) + if (args) { + const [transactionBytes] = args + while (index < transactionBytes.length) { + // As we are decoding hex encoded bytes calldata, each byte is represented by 2 chars + // uint8 operation, address to, value uint256, dataLength uint256 + + const operation = `0x${transactionBytes.slice(index, (index += 2))}` + const to = `0x${transactionBytes.slice(index, (index += 40))}` + const value = `0x${transactionBytes.slice(index, (index += 64))}` + const dataLength = parseInt(`${transactionBytes.slice(index, (index += 64))}`, 16) * 2 + const data = `0x${transactionBytes.slice(index, (index += dataLength))}` + + txs.push({ + operation: Number(operation) as OperationType, + to: getAddress(to), + value: BigInt(value).toString(), + data + }) + } } return txs @@ -157,3 +179,40 @@ export function isSafeMultisigTransactionResponse( ): safeTransaction is SafeMultisigTransactionResponse { return (safeTransaction as SafeMultisigTransactionResponse).isExecuted !== undefined } + +export function toEstimateGasParameters(tx: SafeProviderTransaction): EstimateGasParameters { + const params: EstimateGasParameters = isLegacyTransaction(tx) + ? createLegacyTxOptions(tx) + : createTxOptions(tx) + if (tx.value) { + params.value = BigInt(tx.value) + } + + if (tx.to) { + params.to = asAddress(tx.to) + } + + if (tx.data) { + params.data = asHex(tx.data) + } + + return params +} + +export function toCallGasParameters( + tx: SafeProviderTransaction +): UnionOmit { + const params: UnionOmit = isLegacyTransaction(tx) + ? createLegacyTxOptions(tx) + : createTxOptions(tx) + + if (tx.to) { + params.to = asAddress(tx.to) + } + + if (tx.data) { + params.data = asHex(tx.data) + } + + return params +} diff --git a/packages/protocol-kit/src/utils/types.ts b/packages/protocol-kit/src/utils/types.ts index aaf21542e..74ec23392 100644 --- a/packages/protocol-kit/src/utils/types.ts +++ b/packages/protocol-kit/src/utils/types.ts @@ -1,7 +1,24 @@ import { SafeConfig, SafeConfigWithPredictedSafe } from '../types' +import { getAddress, Address, isHex, Hex, Hash } from 'viem' export function isSafeConfigWithPredictedSafe( config: SafeConfig ): config is SafeConfigWithPredictedSafe { return (config as unknown as SafeConfigWithPredictedSafe).predictedSafe !== undefined } + +export function asAddresses(addresses: string[]): Address[] { + return addresses.map(asAddress) +} + +export function asAddress(address: string): Address { + return getAddress(address) +} + +export function asHash(hash: string): Hash { + return hash as Hash +} + +export function asHex(hex?: string): Hex { + return isHex(hex) ? (hex as Hex) : (`0x${hex}` as Hex) +} diff --git a/packages/protocol-kit/tests/e2e/contractManager.test.ts b/packages/protocol-kit/tests/e2e/contractManager.test.ts index c96983d76..978c5b845 100644 --- a/packages/protocol-kit/tests/e2e/contractManager.test.ts +++ b/packages/protocol-kit/tests/e2e/contractManager.test.ts @@ -60,7 +60,7 @@ describe('Safe contracts manager', () => { it('should fail if the current network is not a default network and no contractNetworks is provided', async () => { const { safe, provider } = await setupTests() - const safeAddress = await safe.getAddress() + const safeAddress = safe.address await chai .expect( Safe.init({ @@ -107,7 +107,7 @@ describe('Safe contracts manager', () => { } } - const safeAddress = await safe.getAddress() + const safeAddress = safe.address await chai .expect( Safe.init({ @@ -121,7 +121,7 @@ describe('Safe contracts manager', () => { it('should set the MultiSend contract available on the current network', async () => { const { safe, chainId, contractNetworks, provider } = await setupTests() - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, diff --git a/packages/protocol-kit/tests/e2e/core.test.ts b/packages/protocol-kit/tests/e2e/core.test.ts index a61c6c81b..975fadca1 100644 --- a/packages/protocol-kit/tests/e2e/core.test.ts +++ b/packages/protocol-kit/tests/e2e/core.test.ts @@ -10,6 +10,9 @@ import { getSafeWithOwners } from './utils/setupContracts' import { getEip1193Provider } from './utils/setupProvider' import { getAccounts } from './utils/setupTestNetwork' import { waitSafeTxReceipt } from './utils/transactions' +import { asAddress } from '@safe-global/protocol-kit/utils/types' +import { waitTransactionReceipt } from './utils/transactions' +import { sameString } from '@safe-global/protocol-kit/utils' chai.use(chaiAsPromised) @@ -44,7 +47,7 @@ describe('Safe Info', () => { 'should fail to connect a Safe { const { predictedSafe, safe, contractNetworks, provider } = await setupTests() - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, @@ -59,57 +62,69 @@ describe('Safe Info', () => { } ) - itif(safeVersionDeployed >= '1.3.0')( - 'should connect a Safe >=v1.3.0 that is not deployed', - async () => { - const { predictedSafe, safe, accounts, contractNetworks, provider } = await setupTests() - const [account1] = accounts - const safeAddress = await safe.getAddress() - const safeSdk = await Safe.init({ - provider, - safeAddress, - contractNetworks - }) - const safeSdk2 = await safeSdk.connect({ predictedSafe }) - chai - .expect(await safeSdk2.getSafeProvider().getSignerAddress()) - .to.be.eq(await account1.signer.getAddress()) - } - ) + it('should connect a Safe >=v1.3.0 that is not deployed', async () => { + const { predictedSafe, safe, accounts, contractNetworks, provider } = await setupTests() + const [account1] = accounts + const safeAddress = safe.address + const safeSdk = await Safe.init({ + provider, + safeAddress, + contractNetworks + }) + const safeSdk2 = await safeSdk.connect({ predictedSafe }) + chai.expect( + sameString( + await safeSdk2.getSafeProvider().getSignerAddress(), + await account1.signer.account?.address + ) + ).to.be.true + }) it('should connect a deployed Safe', async () => { const { safe, accounts, contractNetworks, provider } = await setupTests() const [account1, account2, account3] = accounts - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, contractNetworks }) chai.expect(await safeSdk.getAddress()).to.be.eq(safeAddress) - chai - .expect(await safeSdk.getSafeProvider().getSignerAddress()) - .to.be.eq(await account1.signer.getAddress()) + + chai.expect( + sameString( + await safeSdk.getSafeProvider().getSignerAddress(), + await account1.signer.account?.address + ) + ).to.be.true const safeSdk2 = await safeSdk.connect({ signer: account2.address, contractNetworks }) + const signer = await safeSdk2.getSafeProvider().getExternalSigner() + chai.expect(signer) chai.expect(await safeSdk2.getAddress()).to.be.eq(safeAddress) - chai - .expect(await safeSdk2.getSafeProvider().getSignerAddress()) - .to.be.eq(await account2.signer.getAddress()) + chai.expect( + sameString( + await safeSdk2.getSafeProvider().getSignerAddress(), + await account2.signer.account?.address + ) + ).to.be.true const safe2 = await getSafeWithOwners([account3.address]) - const safe2Address = await safe2.getAddress() + const safe2Address = safe2.address const safeSdk3 = await safeSdk2.connect({ safeAddress: safe2Address, signer: account3.address }) chai.expect(await safeSdk3.getAddress()).to.be.eq(safe2Address) - chai - .expect(await safeSdk3.getSafeProvider().getSignerAddress()) - .to.be.eq(await account3.signer.getAddress()) + chai.expect( + sameString( + await safeSdk3.getSafeProvider().getSignerAddress(), + await account3.signer.account?.address + ) + ).to.be.true }) }) @@ -142,7 +157,7 @@ describe('Safe Info', () => { it('should return the Safe contract version', async () => { const { safe, contractNetworks, provider } = await setupTests() - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, @@ -197,7 +212,7 @@ describe('Safe Info', () => { it('should return the address of a deployed Safe', async () => { const { safe, contractNetworks, provider } = await setupTests() - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, @@ -211,15 +226,19 @@ describe('Safe Info', () => { it('should return the connected SafeProvider', async () => { const { safe, accounts, contractNetworks, provider } = await setupTests() const [account1] = accounts - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress: safeAddress, contractNetworks }) - chai - .expect(await safeSdk.getSafeProvider().getSignerAddress()) - .to.be.eq(await account1.signer.getAddress()) + + chai.expect( + sameString( + await safeSdk.getSafeProvider().getSignerAddress(), + await account1.signer.account?.address + ) + ).to.be.true }) }) @@ -238,7 +257,7 @@ describe('Safe Info', () => { const { accounts, contractNetworks, provider } = await setupTests() const [account1, account2] = accounts const safe = await getSafeWithOwners([account1.address]) - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress: safeAddress, @@ -271,7 +290,7 @@ describe('Safe Info', () => { it('should return the chainId of the current network', async () => { const { safe, chainId, contractNetworks, provider } = await setupTests() - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress: safeAddress, @@ -311,14 +330,14 @@ describe('Safe Info', () => { }) chai.expect(await safeSdk.getBalance()).to.be.eq(0n) - const txResponse = await account1.signer.sendTransaction({ - to: await safeSdk.getAddress(), + const hash = await account1.signer.sendTransaction({ + to: asAddress(await safeSdk.getAddress()), value: BigInt(`${1e18}`) }) - await txResponse.wait(1) + await waitTransactionReceipt(hash) // TODO: Not working without this delay - await new Promise((resolve) => setTimeout(resolve, 500)) + // await new Promise((resolve) => setTimeout(resolve, 500)) chai.expect(await safeSdk.getBalance()).to.be.eq(BigInt(`${1e18}`)) } @@ -327,7 +346,7 @@ describe('Safe Info', () => { it('should return the balance of a deployed Safe', async () => { const { safe, accounts, contractNetworks, provider } = await setupTests() const [account1] = accounts - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, signer: account1.address, @@ -336,11 +355,11 @@ describe('Safe Info', () => { }) chai.expect(await safeSdk.getBalance()).to.be.eq(0n) - const txResponse = await account1.signer.sendTransaction({ + const txHash = await account1.signer.sendTransaction({ to: safeAddress, value: BigInt(`${1e18}`) }) - await txResponse.wait(1) + await waitTransactionReceipt(txHash) // TODO: Not working without this delay await new Promise((resolve) => setTimeout(resolve, 500)) diff --git a/packages/protocol-kit/tests/e2e/createSafeDeploymentTransaction.test.ts b/packages/protocol-kit/tests/e2e/createSafeDeploymentTransaction.test.ts index 3ccba4d55..a7e0c0568 100644 --- a/packages/protocol-kit/tests/e2e/createSafeDeploymentTransaction.test.ts +++ b/packages/protocol-kit/tests/e2e/createSafeDeploymentTransaction.test.ts @@ -54,7 +54,7 @@ describe('createSafeDeploymentTransaction', () => { const deploymentTransaction = await safeSdk.createSafeDeploymentTransaction() - const safeFactoryAddress = await (await getFactory()).contract.getAddress() + const safeFactoryAddress = await (await getFactory()).contract.address chai.expect(deploymentTransaction).to.be.deep.equal({ to: safeFactoryAddress, @@ -75,7 +75,7 @@ describe('createSafeDeploymentTransaction', () => { const deploymentTransaction = await safeSdk.createSafeDeploymentTransaction() - const safeFactoryAddress = await (await getFactory()).contract.getAddress() + const safeFactoryAddress = await (await getFactory()).contract.address chai.expect(deploymentTransaction).to.be.deep.equal({ to: safeFactoryAddress, @@ -96,7 +96,7 @@ describe('createSafeDeploymentTransaction', () => { const deploymentTransaction = await safeSdk.createSafeDeploymentTransaction() - const safeFactoryAddress = await (await getFactory()).contract.getAddress() + const safeFactoryAddress = await (await getFactory()).contract.address chai.expect(deploymentTransaction).to.be.deep.equal({ to: safeFactoryAddress, @@ -117,7 +117,7 @@ describe('createSafeDeploymentTransaction', () => { const deploymentTransaction = await safeSdk.createSafeDeploymentTransaction() - const safeFactoryAddress = await (await getFactory()).contract.getAddress() + const safeFactoryAddress = await (await getFactory()).contract.address chai.expect(deploymentTransaction).to.be.deep.equal({ to: safeFactoryAddress, @@ -138,7 +138,7 @@ describe('createSafeDeploymentTransaction', () => { const deploymentTransaction = await safeSdk.createSafeDeploymentTransaction() - const safeFactoryAddress = await (await getFactory()).contract.getAddress() + const safeFactoryAddress = await (await getFactory()).contract.address chai.expect(deploymentTransaction).to.be.deep.equal({ to: safeFactoryAddress, @@ -189,10 +189,9 @@ describe('createSafeDeploymentTransaction', () => { contractNetworks }) - const predeterminedSaltNonceEncoded = safeProvider.encodeParameters( - ['uint256'], - [`0x${Buffer.from(keccak_256(PREDETERMINED_SALT_NONCE + chainId)).toString('hex')}`] - ) + const predeterminedSaltNonceEncoded = safeProvider.encodeParameters('uint256', [ + `0x${Buffer.from(keccak_256(PREDETERMINED_SALT_NONCE + chainId)).toString('hex')}` + ]) const deploymentTransaction = await safeSdk.createSafeDeploymentTransaction() @@ -214,7 +213,7 @@ describe('createSafeDeploymentTransaction', () => { const customSaltNonce = '123456789' - const customSaltNonceEncoded = safeProvider.encodeParameters(['uint256'], [customSaltNonce]) + const customSaltNonceEncoded = safeProvider.encodeParameters('uint256', [customSaltNonce]) const deploymentTransaction = await safeSdk.createSafeDeploymentTransaction(customSaltNonce) @@ -241,7 +240,7 @@ describe('createSafeDeploymentTransaction', () => { const saltNonceEncoded = safeSdk .getSafeProvider() - .encodeParameters(['uint256'], [customSaltNonce]) + .encodeParameters('uint256', [customSaltNonce]) const deploymentTransaction = await safeSdk.createSafeDeploymentTransaction(customSaltNonce) @@ -255,7 +254,7 @@ describe('createSafeDeploymentTransaction', () => { const [account1] = accounts const safe = await getSafeWithOwners([account1.address]) - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, diff --git a/packages/protocol-kit/tests/e2e/createTransaction.test.ts b/packages/protocol-kit/tests/e2e/createTransaction.test.ts index bf70f6ed3..0569bb3a8 100644 --- a/packages/protocol-kit/tests/e2e/createTransaction.test.ts +++ b/packages/protocol-kit/tests/e2e/createTransaction.test.ts @@ -14,6 +14,7 @@ import { getContractNetworks } from './utils/setupContractNetworks' import { getERC20Mintable, getSafeWithOwners } from './utils/setupContracts' import { getEip1193Provider } from './utils/setupProvider' import { getAccounts } from './utils/setupTestNetwork' +import { encodeFunctionData } from 'viem' chai.use(chaiAsPromised) @@ -60,7 +61,7 @@ describe('Transactions creation', () => { const { accounts, contractNetworks, provider } = await setupTests() const [account1, account2] = accounts const safe = await getSafeWithOwners([account1.address]) - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, @@ -87,7 +88,7 @@ describe('Transactions creation', () => { const { accounts, contractNetworks, provider } = await setupTests() const [account1, account2] = accounts const safe = await getSafeWithOwners([account1.address]) - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, @@ -115,7 +116,7 @@ describe('Transactions creation', () => { const { accounts, contractNetworks, provider } = await setupTests() const [account1, account2] = accounts const safe = await getSafeWithOwners([account1.address]) - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, @@ -144,7 +145,7 @@ describe('Transactions creation', () => { const { accounts, contractNetworks, provider } = await setupTests() const [account1, account2] = accounts const safe = await getSafeWithOwners([account1.address]) - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, @@ -171,7 +172,7 @@ describe('Transactions creation', () => { const { accounts, contractNetworks, provider } = await setupTests() const [account1, account2] = accounts const safe = await getSafeWithOwners([account1.address]) - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, @@ -200,7 +201,7 @@ describe('Transactions creation', () => { const { accounts, contractNetworks, provider } = await setupTests() const [account1, account2] = accounts const safe = await getSafeWithOwners([account1.address]) - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, @@ -250,7 +251,7 @@ describe('Transactions creation', () => { const { accounts, contractNetworks, provider } = await setupTests() const [account1, account2] = accounts const safe = await getSafeWithOwners([account1.address]) - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, @@ -280,7 +281,7 @@ describe('Transactions creation', () => { const { accounts, contractNetworks, provider } = await setupTests() const [account1, account2] = accounts const safe = await getSafeWithOwners([account1.address]) - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, @@ -310,7 +311,7 @@ describe('Transactions creation', () => { const { accounts, contractNetworks, provider } = await setupTests() const [account1, account2] = accounts const safe = await getSafeWithOwners([account1.address]) - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, @@ -331,7 +332,7 @@ describe('Transactions creation', () => { const { accounts, contractNetworks, provider } = await setupTests() const [account1, account2] = accounts const safe = await getSafeWithOwners([account1.address]) - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, @@ -359,7 +360,7 @@ describe('Transactions creation', () => { const { accounts, contractNetworks, provider } = await setupTests() const [account1] = accounts const safe = await getSafeWithOwners([account1.address]) - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, @@ -373,7 +374,7 @@ describe('Transactions creation', () => { const { accounts, contractNetworks, erc20Mintable, chainId, provider } = await setupTests() const [account1, account2] = accounts const safe = await getSafeWithOwners([account1.address]) - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, @@ -381,20 +382,22 @@ describe('Transactions creation', () => { }) const transactions = [ { - to: await erc20Mintable.getAddress(), + to: erc20Mintable.address, value: '0', - data: erc20Mintable.interface.encodeFunctionData('transfer', [ - account2.address, - '1100000000000000000' // 1.1 ERC20 - ]) + data: encodeFunctionData({ + abi: erc20Mintable.abi, + functionName: 'transfer', + args: [account2.address, '1100000000000000000'] // 1.1 ERC20 + }) }, { - to: await erc20Mintable.getAddress(), + to: erc20Mintable.address, value: '0', - data: erc20Mintable.interface.encodeFunctionData('transfer', [ - account2.address, - '100000000000000000' // 0.1 ERC20 - ]) + data: encodeFunctionData({ + abi: erc20Mintable.abi, + functionName: 'transfer', + args: [account2.address, '100000000000000000'] // 0.1 ERC20 + }) } ] const multiSendTx = await safeSdk.createTransaction({ transactions }) @@ -407,7 +410,7 @@ describe('Transactions creation', () => { const { accounts, contractNetworks, erc20Mintable, chainId, provider } = await setupTests() const [account1, account2] = accounts const safe = await getSafeWithOwners([account1.address]) - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, @@ -417,20 +420,22 @@ describe('Transactions creation', () => { const transactions = [ { - to: await erc20Mintable.getAddress(), + to: erc20Mintable.address, value: '0', - data: erc20Mintable.interface.encodeFunctionData('transfer', [ - account2.address, - '1100000000000000000' // 1.1 ERC20 - ]) + data: encodeFunctionData({ + abi: erc20Mintable.abi, + functionName: 'transfer', + args: [account2.address, '1100000000000000000'] // 1.1 ERC20 + }) }, { - to: await erc20Mintable.getAddress(), + to: erc20Mintable.address, value: '0', - data: erc20Mintable.interface.encodeFunctionData('transfer', [ - account2.address, - '100000000000000000' // 0.1 ERC20 - ]) + data: encodeFunctionData({ + abi: erc20Mintable.abi, + functionName: 'transfer', + args: [account2.address, '100000000000000000'] // 0.1 ERC20 + }) } ] const multiSendTx = await safeSdk.createTransaction({ transactions, options }) @@ -450,7 +455,7 @@ describe('Transactions creation', () => { 'should fail to create a transaction if the Safe with version { const { safe, predictedSafe, contractNetworks, provider } = await setupTests() - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, predictedSafe, diff --git a/packages/protocol-kit/tests/e2e/createTransactionBatch.test.ts b/packages/protocol-kit/tests/e2e/createTransactionBatch.test.ts index 0e4547b68..f1ace5d70 100644 --- a/packages/protocol-kit/tests/e2e/createTransactionBatch.test.ts +++ b/packages/protocol-kit/tests/e2e/createTransactionBatch.test.ts @@ -8,6 +8,7 @@ import { getERC20Mintable, getSafeWithOwners, getMultiSendCallOnly } from './uti import { getEip1193Provider } from './utils/setupProvider' import { getAccounts } from './utils/setupTestNetwork' import { OperationType } from '@safe-global/safe-core-sdk-types' +import { encodeFunctionData } from 'viem' chai.use(chaiAsPromised) @@ -45,7 +46,7 @@ describe('createTransactionBatch', () => { const safe = await getSafeWithOwners([account1.address]) const provider = getEip1193Provider() - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, @@ -54,12 +55,13 @@ describe('createTransactionBatch', () => { }) const dumpTransfer = { - to: await erc20Mintable.getAddress(), + to: erc20Mintable.address, value: '0', - data: erc20Mintable.interface.encodeFunctionData('transfer', [ - account2.address, - AMOUNT_TO_TRANSFER - ]), + data: encodeFunctionData({ + abi: erc20Mintable.abi, + functionName: 'transfer', + args: [account2.address, AMOUNT_TO_TRANSFER] // 0.1 ERC20 + }), operation: OperationType.Call } @@ -67,7 +69,7 @@ describe('createTransactionBatch', () => { const batchTransaction = await safeSdk.createTransactionBatch(transactions) - const multiSendContractAddress = await (await getMultiSendCallOnly()).contract.getAddress() + const multiSendContractAddress = await (await getMultiSendCallOnly()).contract.address chai.expect(batchTransaction).to.be.deep.equal({ to: multiSendContractAddress, diff --git a/packages/protocol-kit/tests/e2e/eip1271-contract-signatures.test.ts b/packages/protocol-kit/tests/e2e/eip1271-contract-signatures.test.ts index 6b8ddbc10..cc195fea6 100644 --- a/packages/protocol-kit/tests/e2e/eip1271-contract-signatures.test.ts +++ b/packages/protocol-kit/tests/e2e/eip1271-contract-signatures.test.ts @@ -31,7 +31,7 @@ describe('The EIP1271 implementation', () => { 1, // Require 1 signatures fallbackHandlerAddress ) - const signerSafeAddress1_1 = await signerSafe1_1.getAddress() + const signerSafeAddress1_1 = signerSafe1_1.address // Create a 2/3 signer Safe const signerSafe2_3 = await getSafeWithOwners( @@ -39,7 +39,7 @@ describe('The EIP1271 implementation', () => { 2, // Require 2 signatures fallbackHandlerAddress ) - const signerSafeAddress2_3 = await signerSafe2_3.getAddress() + const signerSafeAddress2_3 = signerSafe2_3.address // Create a 3/4 Safe with the signer Safe as owner const safe = await getSafeWithOwners( @@ -48,7 +48,7 @@ describe('The EIP1271 implementation', () => { fallbackHandlerAddress ) - const safeAddress = await safe.getAddress() + const safeAddress = safe.address return { safe, diff --git a/packages/protocol-kit/tests/e2e/eip1271.test.ts b/packages/protocol-kit/tests/e2e/eip1271.test.ts index 307b639dd..fadad67a9 100644 --- a/packages/protocol-kit/tests/e2e/eip1271.test.ts +++ b/packages/protocol-kit/tests/e2e/eip1271.test.ts @@ -1,4 +1,4 @@ -import { ethers } from 'ethers' +import { hashTypedData } from '@safe-global/protocol-kit/utils/eip-712/encode' import Safe, { hashSafeMessage, buildSignatureBytes, @@ -20,6 +20,7 @@ import { waitSafeTxReceipt } from './utils/transactions' import { itif } from './utils/helpers' import SafeMessage from '../../src/utils/messages/SafeMessage' import semverSatisfies from 'semver/functions/satisfies' +import { asHash } from '@safe-global/protocol-kit/utils/types' chai.use(chaiAsPromised) @@ -28,13 +29,13 @@ export const calculateSafeMessageHash = ( message: string, chainId: number ): string => { - return ethers.TypedDataEncoder.hash( - { verifyingContract: safeAddress, chainId }, - { + return hashTypedData({ + domain: { verifyingContract: safeAddress, chainId }, + types: { SafeMessage: [{ type: 'bytes', name: 'message' }] }, - { message } - ) + message: { message } + }) } const MESSAGE = 'I am the owner of this Safe account' @@ -56,7 +57,7 @@ describe('The EIP1271 implementation', () => { 1, fallbackHandlerAddress ) - const signerSafeAddress = await signerSafe.getAddress() + const signerSafeAddress = signerSafe.address // Create a 2/3 Safe const safe = await getSafeWithOwners( @@ -64,7 +65,7 @@ describe('The EIP1271 implementation', () => { 2, fallbackHandlerAddress ) - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk1 = await Safe.init({ provider, @@ -122,7 +123,7 @@ describe('The EIP1271 implementation', () => { const messageHash = hashSafeMessage(MESSAGE) - const txData = signMessageLibContract.encode('signMessage', [messageHash]) + const txData = signMessageLibContract.encode('signMessage', [asHash(messageHash)]) const safeTransactionData: SafeTransactionDataPartial = { to: customContract.signMessageLibAddress, diff --git a/packages/protocol-kit/tests/e2e/erc-20.test.ts b/packages/protocol-kit/tests/e2e/erc-20.test.ts index 5229e1ee8..f875b0b6b 100644 --- a/packages/protocol-kit/tests/e2e/erc-20.test.ts +++ b/packages/protocol-kit/tests/e2e/erc-20.test.ts @@ -51,7 +51,7 @@ describe('ERC-20 utils', () => { async () => { const { safe, contractNetworks, provider } = await setupTests() - const safeAddress = await safe.getAddress() + const safeAddress = safe.address // mock decimals() call callStub = sinon.stub(SafeProvider.prototype, 'call').returns(Promise.resolve('0x12')) @@ -72,7 +72,7 @@ describe('ERC-20 utils', () => { 'should return the correct decimals for a non-standard ERC20 token', async () => { const { safe, contractNetworks, provider } = await setupTests() - const safeAddress = await safe.getAddress() + const safeAddress = safe.address // mock decimals() call callStub = sinon.stub(SafeProvider.prototype, 'call').returns(Promise.resolve('0x06')) @@ -93,7 +93,7 @@ describe('ERC-20 utils', () => { 'should throw an error if decimals() fn is not defined', async () => { const { safe, contractNetworks, provider } = await setupTests() - const safeAddress = await safe.getAddress() + const safeAddress = safe.address // mock decimals() call callStub = sinon.stub(SafeProvider.prototype, 'call').returns(Promise.resolve('0x')) @@ -116,7 +116,7 @@ describe('ERC-20 utils', () => { 'should return true if it is the Native token', async () => { const { safe, contractNetworks, provider } = await setupTests() - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, @@ -137,7 +137,7 @@ describe('ERC-20 utils', () => { 'should return true if it is an standard ERC20 token', async () => { const { safe, contractNetworks, provider } = await setupTests() - const safeAddress = await safe.getAddress() + const safeAddress = safe.address // mock decimals() call callStub = sinon.stub(SafeProvider.prototype, 'call').returns(Promise.resolve('0x12')) @@ -161,7 +161,7 @@ describe('ERC-20 utils', () => { 'should return false for a non-standard ERC20 token', async () => { const { safe, contractNetworks, provider } = await setupTests() - const safeAddress = await safe.getAddress() + const safeAddress = safe.address // mock decimals() call callStub = sinon.stub(SafeProvider.prototype, 'call').returns(Promise.resolve('0x06')) diff --git a/packages/protocol-kit/tests/e2e/execution.test.ts b/packages/protocol-kit/tests/e2e/execution.test.ts index 4191ce9cf..36cdf8716 100644 --- a/packages/protocol-kit/tests/e2e/execution.test.ts +++ b/packages/protocol-kit/tests/e2e/execution.test.ts @@ -10,6 +10,7 @@ import { getERC20Mintable, getSafeWithOwners } from './utils/setupContracts' import { getEip1193Provider } from './utils/setupProvider' import { getAccounts } from './utils/setupTestNetwork' import { waitSafeTxReceipt } from './utils/transactions' +import { encodeFunctionData } from 'viem' chai.use(chaiAsPromised) @@ -35,7 +36,7 @@ describe('Transactions execution', () => { const { accounts, contractNetworks, provider } = await setupTests() const [account1, account2] = accounts const safe = await getSafeWithOwners([account1.address]) - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk1 = await Safe.init({ provider, safeAddress, @@ -71,7 +72,7 @@ describe('Transactions execution', () => { const { accounts, contractNetworks, provider } = await setupTests() const [account1, account2] = accounts const safe = await getSafeWithOwners([account1.address]) - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk1 = await Safe.init({ provider, safeAddress, @@ -100,7 +101,7 @@ describe('Transactions execution', () => { const { accounts, contractNetworks, provider } = await setupTests() const [account1, account2] = accounts const safe = await getSafeWithOwners([account1.address]) - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk1 = await Safe.init({ provider, safeAddress, @@ -123,7 +124,7 @@ describe('Transactions execution', () => { const { accounts, contractNetworks, provider } = await setupTests() const [account1, account2, account3] = accounts const safe = await getSafeWithOwners([account1.address, account2.address, account3.address]) - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk1 = await Safe.init({ provider, safeAddress, @@ -152,7 +153,7 @@ describe('Transactions execution', () => { const { accounts, contractNetworks, provider } = await setupTests() const [account1, account2, account3] = accounts const safe = await getSafeWithOwners([account1.address, account2.address, account3.address]) - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk1 = await Safe.init({ provider, safeAddress, @@ -173,7 +174,7 @@ describe('Transactions execution', () => { const { accounts, contractNetworks, provider } = await setupTests() const [account1, account2] = accounts const safe = await getSafeWithOwners([account1.address]) - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk1 = await Safe.init({ provider, safeAddress, @@ -208,7 +209,7 @@ describe('Transactions execution', () => { await safeSdk2.executeTransaction(signedTx) } catch (error) { chai - .expect((error as any)?.info?.error?.message) + .expect((error as any)?.message) .includes(safeVersionDeployed >= '1.3.0' ? 'GS026' : 'Invalid owner provided') } } else { @@ -222,7 +223,7 @@ describe('Transactions execution', () => { const { accounts, contractNetworks, provider } = await setupTests() const [account1, account2] = accounts const safe = await getSafeWithOwners([account1.address]) - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk1 = await Safe.init({ provider, safeAddress, @@ -248,7 +249,7 @@ describe('Transactions execution', () => { const { accounts, contractNetworks, provider } = await setupTests() const [account1, account2] = accounts const safe = await getSafeWithOwners([account1.address]) - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk1 = await Safe.init({ provider, safeAddress, @@ -286,7 +287,7 @@ describe('Transactions execution', () => { account4.address, account5.address ]) - const safeAddress = await safe.getAddress() + const safeAddress = safe.address await account1.signer.sendTransaction({ to: safeAddress, value: 1_000_000_000_000_000_000n // 1 ETH @@ -354,7 +355,7 @@ describe('Transactions execution', () => { account5.address, account6.address ]) - const safeAddress = await safe.getAddress() + const safeAddress = safe.address await account1.signer.sendTransaction({ to: safeAddress, value: 1_000_000_000_000_000_000n // 1 ETH @@ -418,7 +419,7 @@ describe('Transactions execution', () => { it('should execute a transaction when is not submitted by an owner', async () => { const { safe, accounts, contractNetworks, provider } = await setupTests() const [, account2, account3] = accounts - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk1 = await Safe.init({ provider, safeAddress, @@ -457,7 +458,7 @@ describe('Transactions execution', () => { const { accounts, contractNetworks, provider } = await setupTests() const [account1, account2] = accounts const safe = await getSafeWithOwners([account1.address]) - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk1 = await Safe.init({ provider, safeAddress, @@ -477,14 +478,14 @@ describe('Transactions execution', () => { const txResponse = await safeSdk1.executeTransaction(tx, execOptions) await waitSafeTxReceipt(txResponse) const txConfirmed = await safeSdk1.getSafeProvider().getTransaction(txResponse.hash) - chai.expect(execOptions.gasLimit).to.be.eq(Number(txConfirmed.gasLimit)) + chai.expect(execOptions.gasLimit).to.be.eq(Number(txConfirmed.gas)) }) it('should execute a transaction with options: { gasLimit, gasPrice }', async () => { const { accounts, contractNetworks, provider } = await setupTests() const [account1, account2] = accounts const safe = await getSafeWithOwners([account1.address]) - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk1 = await Safe.init({ provider, safeAddress, @@ -508,14 +509,14 @@ describe('Transactions execution', () => { await waitSafeTxReceipt(txResponse) const txConfirmed = await safeSdk1.getSafeProvider().getTransaction(txResponse.hash) chai.expect(execOptions.gasPrice).to.be.eq(Number(txConfirmed.gasPrice)) - chai.expect(execOptions.gasLimit).to.be.eq(Number(txConfirmed.gasLimit)) + chai.expect(execOptions.gasLimit).to.be.eq(Number(txConfirmed.gas)) }) it('should execute a transaction with options: { maxFeePerGas, maxPriorityFeePerGas }', async () => { const { accounts, contractNetworks, provider } = await setupTests() const [account1, account2] = accounts const safe = await getSafeWithOwners([account1.address]) - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk1 = await Safe.init({ provider, safeAddress, @@ -548,7 +549,7 @@ describe('Transactions execution', () => { const { accounts, contractNetworks, provider } = await setupTests() const [account1, account2] = accounts const safe = await getSafeWithOwners([account1.address]) - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk1 = await Safe.init({ provider, safeAddress, @@ -578,7 +579,7 @@ describe('Transactions execution', () => { const { accounts, contractNetworks, provider } = await setupTests() const [account1, account2, account3] = accounts const safe = await getSafeWithOwners([account1.address, account2.address, account3.address]) - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk1 = await Safe.init({ provider, safeAddress, @@ -626,7 +627,7 @@ describe('Transactions execution', () => { const { accounts, contractNetworks, erc20Mintable, provider } = await setupTests() const [account1, account2, account3] = accounts const safe = await getSafeWithOwners([account1.address, account2.address, account3.address]) - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk1 = await Safe.init({ provider, safeAddress, @@ -641,28 +642,36 @@ describe('Transactions execution', () => { signer: account3.address }) - await erc20Mintable.mint(safeAddress, '1200000000000000000') // 1.2 ERC20 - const safeInitialERC20Balance = await erc20Mintable.balanceOf(safeAddress) - chai.expect(safeInitialERC20Balance.toString()).to.be.eq('1200000000000000000') // 1.2 ERC20 - const accountInitialERC20Balance = await erc20Mintable.balanceOf(account2.address) - chai.expect(accountInitialERC20Balance.toString()).to.be.eq('0') // 0 ERC20 + await erc20Mintable.write.mint([safeAddress, '1200000000000000000']) // 1.2 ERC20 + const safeInitialERC20Balance = await erc20Mintable.read.balanceOf([safeAddress]) + chai.expect(safeInitialERC20Balance).to.be.eq(1200000000000000000n) // 1.2 ERC20 + const accountInitialERC20Balance = await erc20Mintable.read.balanceOf([account2.address]) + chai.expect(accountInitialERC20Balance).to.be.eq(0n) // 0 ERC20 const transactions: MetaTransactionData[] = [ { - to: await erc20Mintable.getAddress(), + to: erc20Mintable.address, value: '0', - data: erc20Mintable.interface.encodeFunctionData('transfer', [ - account2.address, - '1100000000000000000' // 1.1 ERC20 - ]) + data: encodeFunctionData({ + abi: erc20Mintable.abi, + functionName: 'transfer', + args: [ + account2.address, + '1100000000000000000' // 1.1 ERC20 + ] + }) }, { - to: await erc20Mintable.getAddress(), + to: erc20Mintable.address, value: '0', - data: erc20Mintable.interface.encodeFunctionData('transfer', [ - account2.address, - '100000000000000000' // 0.1 ERC20 - ]) + data: encodeFunctionData({ + abi: erc20Mintable.abi, + functionName: 'transfer', + args: [ + account2.address, + '100000000000000000' // 0.1 ERC20 + ] + }) } ] const multiSendTx = await safeSdk1.createTransaction({ transactions }) @@ -673,10 +682,10 @@ describe('Transactions execution', () => { const txResponse2 = await safeSdk3.executeTransaction(signedMultiSendTx) await waitSafeTxReceipt(txResponse2) - const safeFinalERC20Balance = await erc20Mintable.balanceOf(safeAddress) - chai.expect(safeFinalERC20Balance.toString()).to.be.eq('0') // 0 ERC20 - const accountFinalERC20Balance = await erc20Mintable.balanceOf(account2.address) - chai.expect(accountFinalERC20Balance.toString()).to.be.eq('1200000000000000000') // 1.2 ERC20 + const safeFinalERC20Balance = await erc20Mintable.read.balanceOf([safeAddress]) + chai.expect(safeFinalERC20Balance).to.be.eq(0n) // 0 ERC20 + const accountFinalERC20Balance = await erc20Mintable.read.balanceOf([account2.address]) + chai.expect(accountFinalERC20Balance).to.be.eq(1200000000000000000n) // 1.2 ERC20 }) }) }) diff --git a/packages/protocol-kit/tests/e2e/fallbackHandlerManager.test.ts b/packages/protocol-kit/tests/e2e/fallbackHandlerManager.test.ts index bfd136163..7504c9c0c 100644 --- a/packages/protocol-kit/tests/e2e/fallbackHandlerManager.test.ts +++ b/packages/protocol-kit/tests/e2e/fallbackHandlerManager.test.ts @@ -52,7 +52,7 @@ describe('Fallback handler manager', () => { 'should fail if getting the enabled fallback handler is not supported', async () => { const { safe, contractNetworks, provider } = await setupTests() - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, @@ -79,7 +79,7 @@ describe('Fallback handler manager', () => { itif(safeVersionDeployed >= '1.1.1')('should return the enabled fallback handler', async () => { const { safe, contractNetworks, defaultCallbackHandler, provider } = await setupTests() - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, @@ -87,16 +87,12 @@ describe('Fallback handler manager', () => { }) const compatibilityFallbackHandler = await ( await getCompatibilityFallbackHandler() - ).contract.getAddress() + ).contract.address chai.expect(await safeSdk.getFallbackHandler()).to.be.eq(compatibilityFallbackHandler) - const tx = await safeSdk.createEnableFallbackHandlerTx( - await defaultCallbackHandler.getAddress() - ) + const tx = await safeSdk.createEnableFallbackHandlerTx(defaultCallbackHandler.address) const txResponse = await safeSdk.executeTransaction(tx) await waitSafeTxReceipt(txResponse) - chai - .expect(await safeSdk.getFallbackHandler()) - .to.be.eq(await defaultCallbackHandler.getAddress()) + chai.expect(await safeSdk.getFallbackHandler()).to.be.eq(defaultCallbackHandler.address) }) }) @@ -111,7 +107,7 @@ describe('Fallback handler manager', () => { predictedSafe, contractNetworks }) - const tx = safeSdk.createEnableFallbackHandlerTx(await defaultCallbackHandler.getAddress()) + const tx = safeSdk.createEnableFallbackHandlerTx(defaultCallbackHandler.address) await chai .expect(tx) .to.be.rejectedWith( @@ -130,7 +126,7 @@ describe('Fallback handler manager', () => { predictedSafe, contractNetworks }) - const tx = safeSdk.createEnableFallbackHandlerTx(await defaultCallbackHandler.getAddress()) + const tx = safeSdk.createEnableFallbackHandlerTx(defaultCallbackHandler.address) await chai.expect(tx).to.be.rejectedWith('Safe is not deployed') } ) @@ -139,13 +135,13 @@ describe('Fallback handler manager', () => { 'should fail if enabling a fallback handler is not supported', async () => { const { safe, contractNetworks, defaultCallbackHandler, provider } = await setupTests() - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, contractNetworks }) - const tx = safeSdk.createEnableFallbackHandlerTx(await defaultCallbackHandler.getAddress()) + const tx = safeSdk.createEnableFallbackHandlerTx(defaultCallbackHandler.address) await chai .expect(tx) .to.be.rejectedWith( @@ -156,7 +152,7 @@ describe('Fallback handler manager', () => { itif(safeVersionDeployed >= '1.1.1')('should fail if address is invalid', async () => { const { safe, contractNetworks, provider } = await setupTests() - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, @@ -170,7 +166,7 @@ describe('Fallback handler manager', () => { 'should fail if address is equal to 0x address', async () => { const { safe, contractNetworks, provider } = await setupTests() - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, @@ -183,18 +179,16 @@ describe('Fallback handler manager', () => { itif(safeVersionDeployed >= '1.1.1')('should fail if address is already enabled', async () => { const { safe, contractNetworks, defaultCallbackHandler, provider } = await setupTests() - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, contractNetworks }) - const tx1 = await safeSdk.createEnableFallbackHandlerTx( - await defaultCallbackHandler.getAddress() - ) + const tx1 = await safeSdk.createEnableFallbackHandlerTx(defaultCallbackHandler.address) const txResponse = await safeSdk.executeTransaction(tx1) await waitSafeTxReceipt(txResponse) - const tx2 = safeSdk.createEnableFallbackHandlerTx(await defaultCallbackHandler.getAddress()) + const tx2 = safeSdk.createEnableFallbackHandlerTx(defaultCallbackHandler.address) await chai.expect(tx2).to.be.rejectedWith('Fallback handler provided is already enabled') }) @@ -202,7 +196,7 @@ describe('Fallback handler manager', () => { 'should build the transaction with the optional props', async () => { const { safe, contractNetworks, defaultCallbackHandler, provider } = await setupTests() - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, @@ -217,7 +211,7 @@ describe('Fallback handler manager', () => { safeTxGas: '666' } const tx = await safeSdk.createEnableFallbackHandlerTx( - await defaultCallbackHandler.getAddress(), + defaultCallbackHandler.address, options ) chai.expect(tx.data.baseGas).to.be.eq('111') @@ -231,7 +225,7 @@ describe('Fallback handler manager', () => { itif(safeVersionDeployed >= '1.1.1')('should enable a fallback handler', async () => { const { safe, contractNetworks, defaultCallbackHandler, provider } = await setupTests() - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, @@ -239,16 +233,12 @@ describe('Fallback handler manager', () => { }) const compatibilityFallbackHandler = await ( await getCompatibilityFallbackHandler() - ).contract.getAddress() + ).contract.address chai.expect(await safeSdk.getFallbackHandler()).to.be.eq(compatibilityFallbackHandler) - const tx = await safeSdk.createEnableFallbackHandlerTx( - await defaultCallbackHandler.getAddress() - ) + const tx = await safeSdk.createEnableFallbackHandlerTx(defaultCallbackHandler.address) const txResponse = await safeSdk.executeTransaction(tx) await waitSafeTxReceipt(txResponse) - chai - .expect(await safeSdk.getFallbackHandler()) - .to.be.eq(await defaultCallbackHandler.getAddress()) + chai.expect(await safeSdk.getFallbackHandler()).to.be.eq(defaultCallbackHandler.address) }) }) @@ -281,7 +271,7 @@ describe('Fallback handler manager', () => { predictedSafe, contractNetworks }) - const tx = safeSdk.createDisableFallbackHandlerTx(await defaultCallbackHandler.getAddress()) + const tx = safeSdk.createDisableFallbackHandlerTx(defaultCallbackHandler.address) await chai.expect(tx).to.be.rejectedWith('Safe is not deployed') } ) @@ -292,7 +282,7 @@ describe('Fallback handler manager', () => { const { accounts, contractNetworks, provider } = await setupTests() const [account1] = accounts const safe = await getSafeWithOwners([account1.address]) - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, @@ -311,7 +301,7 @@ describe('Fallback handler manager', () => { 'should fail if no fallback handler is enabled', async () => { const { safe, contractNetworks, provider } = await setupTests() - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, @@ -334,21 +324,17 @@ describe('Fallback handler manager', () => { const { accounts, contractNetworks, defaultCallbackHandler, provider } = await setupTests() const [account1] = accounts const safe = await getSafeWithOwners([account1.address]) - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, contractNetworks }) - const tx1 = await safeSdk.createEnableFallbackHandlerTx( - await defaultCallbackHandler.getAddress() - ) + const tx1 = await safeSdk.createEnableFallbackHandlerTx(defaultCallbackHandler.address) const txResponse1 = await safeSdk.executeTransaction(tx1) await waitSafeTxReceipt(txResponse1) - chai - .expect(await safeSdk.getFallbackHandler()) - .to.be.eq(await defaultCallbackHandler.getAddress()) + chai.expect(await safeSdk.getFallbackHandler()).to.be.eq(defaultCallbackHandler.address) const options: SafeTransactionOptionalProps = { baseGas: '111', gasPrice: '222', @@ -371,22 +357,18 @@ describe('Fallback handler manager', () => { const { accounts, contractNetworks, defaultCallbackHandler, provider } = await setupTests() const [account1] = accounts const safe = await getSafeWithOwners([account1.address]) - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, contractNetworks }) - const tx = await safeSdk.createEnableFallbackHandlerTx( - await defaultCallbackHandler.getAddress() - ) + const tx = await safeSdk.createEnableFallbackHandlerTx(defaultCallbackHandler.address) const txResponse = await safeSdk.executeTransaction(tx) await waitSafeTxReceipt(txResponse) await new Promise((resolve) => setTimeout(resolve, 500)) - chai - .expect(await safeSdk.getFallbackHandler()) - .to.be.eq(await defaultCallbackHandler.getAddress()) + chai.expect(await safeSdk.getFallbackHandler()).to.be.eq(defaultCallbackHandler.address) const tx1 = await safeSdk.createDisableFallbackHandlerTx() const txResponse1 = await safeSdk.executeTransaction(tx1) diff --git a/packages/protocol-kit/tests/e2e/getEncodedTransaction.test.ts b/packages/protocol-kit/tests/e2e/getEncodedTransaction.test.ts index 7ddeb3c19..e11e3c341 100644 --- a/packages/protocol-kit/tests/e2e/getEncodedTransaction.test.ts +++ b/packages/protocol-kit/tests/e2e/getEncodedTransaction.test.ts @@ -28,7 +28,7 @@ describe('getEncodedTransaction', () => { const [account1, account2] = accounts const safe = await getSafeWithOwners([account1.address]) - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, @@ -58,7 +58,7 @@ describe('getEncodedTransaction', () => { const [account1, account2] = accounts const safe = await getSafeWithOwners([account1.address]) - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, @@ -88,7 +88,7 @@ describe('getEncodedTransaction', () => { const [account1, account2] = accounts const safe = await getSafeWithOwners([account1.address]) - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, diff --git a/packages/protocol-kit/tests/e2e/guardManager.test.ts b/packages/protocol-kit/tests/e2e/guardManager.test.ts index 50b830a5a..49fc8cefe 100644 --- a/packages/protocol-kit/tests/e2e/guardManager.test.ts +++ b/packages/protocol-kit/tests/e2e/guardManager.test.ts @@ -47,7 +47,7 @@ describe('Safe guard manager', () => { 'should fail if getting the enabled guard is not supported', async () => { const { safe, contractNetworks, provider } = await setupTests() - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, @@ -76,7 +76,7 @@ describe('Safe guard manager', () => { 'should return 0x address when no Safe guard is enabled', async () => { const { safe, contractNetworks, provider } = await setupTests() - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, @@ -88,17 +88,17 @@ describe('Safe guard manager', () => { itif(safeVersionDeployed >= '1.3.0')('should return the enabled Safe guard', async () => { const { safe, contractNetworks, debugTransactionGuard, provider } = await setupTests() - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, contractNetworks }) chai.expect(await safeSdk.getGuard()).to.be.eq(ZERO_ADDRESS) - const tx = await safeSdk.createEnableGuardTx(await debugTransactionGuard.getAddress()) + const tx = await safeSdk.createEnableGuardTx(debugTransactionGuard.address) const txResponse = await safeSdk.executeTransaction(tx) await waitSafeTxReceipt(txResponse) - chai.expect(await safeSdk.getGuard()).to.be.eq(await debugTransactionGuard.getAddress()) + chai.expect(await safeSdk.getGuard()).to.be.eq(debugTransactionGuard.address) }) }) @@ -107,13 +107,13 @@ describe('Safe guard manager', () => { 'should fail if enabling a Safe guard is not supported', async () => { const { safe, contractNetworks, debugTransactionGuard, provider } = await setupTests() - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, contractNetworks }) - const tx = safeSdk.createEnableGuardTx(await debugTransactionGuard.getAddress()) + const tx = safeSdk.createEnableGuardTx(debugTransactionGuard.address) await chai .expect(tx) .to.be.rejectedWith( @@ -131,13 +131,13 @@ describe('Safe guard manager', () => { predictedSafe, contractNetworks }) - const tx = safeSdk.createEnableGuardTx(await debugTransactionGuard.getAddress()) + const tx = safeSdk.createEnableGuardTx(debugTransactionGuard.address) await chai.expect(tx).to.be.rejectedWith('Safe is not deployed') }) itif(safeVersionDeployed >= '1.3.0')('should fail if address is invalid', async () => { const { safe, contractNetworks, provider } = await setupTests() - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, @@ -152,7 +152,7 @@ describe('Safe guard manager', () => { async () => { const { safe, contractNetworks, provider } = await setupTests() - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, @@ -166,16 +166,16 @@ describe('Safe guard manager', () => { itif(safeVersionDeployed >= '1.3.0')('should fail if address is already enabled', async () => { const { safe, contractNetworks, debugTransactionGuard, provider } = await setupTests() - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, contractNetworks }) - const tx1 = await safeSdk.createEnableGuardTx(await debugTransactionGuard.getAddress()) + const tx1 = await safeSdk.createEnableGuardTx(debugTransactionGuard.address) const txResponse = await safeSdk.executeTransaction(tx1) await waitSafeTxReceipt(txResponse) - const tx2 = safeSdk.createEnableGuardTx(await debugTransactionGuard.getAddress()) + const tx2 = safeSdk.createEnableGuardTx(debugTransactionGuard.address) await chai.expect(tx2).to.be.rejectedWith('Guard provided is already enabled') }) @@ -184,7 +184,7 @@ describe('Safe guard manager', () => { async () => { const { safe, contractNetworks, debugTransactionGuard, provider } = await setupTests() - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, @@ -198,10 +198,7 @@ describe('Safe guard manager', () => { nonce: 555, safeTxGas: '666' } - const tx = await safeSdk.createEnableGuardTx( - await debugTransactionGuard.getAddress(), - options - ) + const tx = await safeSdk.createEnableGuardTx(debugTransactionGuard.address, options) chai.expect(tx.data.baseGas).to.be.eq('111') chai.expect(tx.data.gasPrice).to.be.eq('222') chai.expect(tx.data.gasToken).to.be.eq('0x333') @@ -214,17 +211,17 @@ describe('Safe guard manager', () => { itif(safeVersionDeployed >= '1.3.0')('should enable a Safe guard', async () => { const { safe, contractNetworks, debugTransactionGuard, provider } = await setupTests() - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, contractNetworks }) chai.expect(await safeSdk.getGuard()).to.be.eq(ZERO_ADDRESS) - const tx = await safeSdk.createEnableGuardTx(await debugTransactionGuard.getAddress()) + const tx = await safeSdk.createEnableGuardTx(debugTransactionGuard.address) const txResponse = await safeSdk.executeTransaction(tx) await waitSafeTxReceipt(txResponse) - chai.expect(await safeSdk.getGuard()).to.be.eq(await debugTransactionGuard.getAddress()) + chai.expect(await safeSdk.getGuard()).to.be.eq(debugTransactionGuard.address) }) }) @@ -235,7 +232,7 @@ describe('Safe guard manager', () => { const { accounts, contractNetworks, provider } = await setupTests() const [account1] = accounts const safe = await getSafeWithOwners([account1.address]) - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, @@ -265,7 +262,7 @@ describe('Safe guard manager', () => { itif(safeVersionDeployed >= '1.3.0')('should fail if no Safe guard is enabled', async () => { const { safe, contractNetworks, provider } = await setupTests() - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, @@ -281,16 +278,16 @@ describe('Safe guard manager', () => { const { accounts, contractNetworks, debugTransactionGuard, provider } = await setupTests() const [account1] = accounts const safe = await getSafeWithOwners([account1.address]) - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, contractNetworks }) - const tx1 = await safeSdk.createEnableGuardTx(await debugTransactionGuard.getAddress()) + const tx1 = await safeSdk.createEnableGuardTx(debugTransactionGuard.address) const txResponse1 = await safeSdk.executeTransaction(tx1) await waitSafeTxReceipt(txResponse1) - chai.expect(await safeSdk.getGuard()).to.be.eq(await debugTransactionGuard.getAddress()) + chai.expect(await safeSdk.getGuard()).to.be.eq(debugTransactionGuard.address) const options: SafeTransactionOptionalProps = { baseGas: '111', gasPrice: '222', @@ -313,17 +310,17 @@ describe('Safe guard manager', () => { const { accounts, contractNetworks, debugTransactionGuard, provider } = await setupTests() const [account1] = accounts const safe = await getSafeWithOwners([account1.address]) - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, contractNetworks }) - const tx = await safeSdk.createEnableGuardTx(await debugTransactionGuard.getAddress()) + const tx = await safeSdk.createEnableGuardTx(debugTransactionGuard.address) const txResponse = await safeSdk.executeTransaction(tx) await waitSafeTxReceipt(txResponse) - chai.expect(await safeSdk.getGuard()).to.be.eq(await debugTransactionGuard.getAddress()) + chai.expect(await safeSdk.getGuard()).to.be.eq(debugTransactionGuard.address) const tx1 = await safeSdk.createDisableGuardTx() const txResponse1 = await safeSdk.executeTransaction(tx1) diff --git a/packages/protocol-kit/tests/e2e/moduleManager.test.ts b/packages/protocol-kit/tests/e2e/moduleManager.test.ts index 40881c571..c6058f9ee 100644 --- a/packages/protocol-kit/tests/e2e/moduleManager.test.ts +++ b/packages/protocol-kit/tests/e2e/moduleManager.test.ts @@ -66,20 +66,18 @@ describe('Safe modules manager', () => { it('should return all the enabled modules', async () => { const { safe, dailyLimitModule, socialRecoveryModule, contractNetworks, provider } = await setupTests() - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, contractNetworks }) chai.expect((await safeSdk.getModules()).length).to.be.eq(0) - const enableDailyLimitModuleTx = await safeSdk.createEnableModuleTx( - await dailyLimitModule.getAddress() - ) + const enableDailyLimitModuleTx = await safeSdk.createEnableModuleTx(dailyLimitModule.address) const enableDailyLimitModuleTxResponse = await safeSdk.executeTransaction(enableDailyLimitModuleTx) const socialRecoveryModuleTx = await safeSdk.createEnableModuleTx( - await socialRecoveryModule.getAddress() + socialRecoveryModule.address ) const socialRecoveryModuleTxResponse = await safeSdk.executeTransaction(socialRecoveryModuleTx) @@ -106,7 +104,7 @@ describe('Safe modules manager', () => { it('should return the enabled modules', async () => { const { safe, dailyLimitModule, contractNetworks, provider } = await setupTests() - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, @@ -114,7 +112,7 @@ describe('Safe modules manager', () => { }) const emptyModuleList = await safeSdk.getModulesPaginated(SENTINEL_ADDRESS, 10) - const tx = await safeSdk.createEnableModuleTx(await dailyLimitModule.getAddress()) + const tx = await safeSdk.createEnableModuleTx(dailyLimitModule.address) const txResponse = await safeSdk.executeTransaction(tx) await waitSafeTxReceipt(txResponse) const moduleList = await safeSdk.getModulesPaginated(SENTINEL_ADDRESS, 10) @@ -135,11 +133,11 @@ describe('Safe modules manager', () => { whiteListModule, provider } = await setupTests() - const safeAddress = await safe.getAddress() - const dailyLimitsAddress = await dailyLimitModule.getAddress() - const socialRecoveryAddress = await socialRecoveryModule.getAddress() - const stateChannelAddress = await stateChannelModule.getAddress() - const whiteListAddress = await whiteListModule.getAddress() + const safeAddress = safe.address + const dailyLimitsAddress = dailyLimitModule.address + const socialRecoveryAddress = socialRecoveryModule.address + const stateChannelAddress = stateChannelModule.address + const whiteListAddress = whiteListModule.address const safeSdk = await Safe.init({ provider, safeAddress, @@ -200,11 +198,11 @@ describe('Safe modules manager', () => { whiteListModule, provider } = await setupTests() - const safeAddress = await safe.getAddress() - const dailyLimitsAddress = await dailyLimitModule.getAddress() - const socialRecoveryAddress = await socialRecoveryModule.getAddress() - const stateChannelAddress = await stateChannelModule.getAddress() - const whiteListAddress = await whiteListModule.getAddress() + const safeAddress = safe.address + const dailyLimitsAddress = dailyLimitModule.address + const socialRecoveryAddress = socialRecoveryModule.address + const stateChannelAddress = stateChannelModule.address + const whiteListAddress = whiteListModule.address const safeSdk = await Safe.init({ provider, safeAddress, @@ -266,23 +264,23 @@ describe('Safe modules manager', () => { predictedSafe, contractNetworks }) - const tx = safeSdk.isModuleEnabled(await dailyLimitModule.getAddress()) + const tx = safeSdk.isModuleEnabled(dailyLimitModule.address) chai.expect(tx).to.be.rejectedWith('Safe is not deployed') }) it('should return true if a module is enabled', async () => { const { safe, dailyLimitModule, contractNetworks, provider } = await setupTests() - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, contractNetworks }) - chai.expect(await safeSdk.isModuleEnabled(await dailyLimitModule.getAddress())).to.be.false - const tx = await safeSdk.createEnableModuleTx(await dailyLimitModule.getAddress()) + chai.expect(await safeSdk.isModuleEnabled(dailyLimitModule.address)).to.be.false + const tx = await safeSdk.createEnableModuleTx(dailyLimitModule.address) const txResponse = await safeSdk.executeTransaction(tx) await waitSafeTxReceipt(txResponse) - chai.expect(await safeSdk.isModuleEnabled(await dailyLimitModule.getAddress())).to.be.true + chai.expect(await safeSdk.isModuleEnabled(dailyLimitModule.address)).to.be.true }) }) @@ -294,13 +292,13 @@ describe('Safe modules manager', () => { predictedSafe, contractNetworks }) - const tx = safeSdk.createEnableModuleTx(await dailyLimitModule.getAddress()) + const tx = safeSdk.createEnableModuleTx(dailyLimitModule.address) chai.expect(tx).to.be.rejectedWith('Safe is not deployed') }) it('should fail if address is invalid', async () => { const { safe, contractNetworks, provider } = await setupTests() - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, @@ -312,7 +310,7 @@ describe('Safe modules manager', () => { it('should fail if address is equal to sentinel', async () => { const { safe, contractNetworks, provider } = await setupTests() - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, @@ -324,7 +322,7 @@ describe('Safe modules manager', () => { it('should fail if address is equal to 0x address', async () => { const { safe, contractNetworks, provider } = await setupTests() - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, @@ -336,22 +334,22 @@ describe('Safe modules manager', () => { it('should fail if address is already enabled', async () => { const { safe, dailyLimitModule, contractNetworks, provider } = await setupTests() - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, contractNetworks }) - const tx1 = await safeSdk.createEnableModuleTx(await dailyLimitModule.getAddress()) + const tx1 = await safeSdk.createEnableModuleTx(dailyLimitModule.address) const txResponse = await safeSdk.executeTransaction(tx1) await waitSafeTxReceipt(txResponse) - const tx2 = safeSdk.createEnableModuleTx(await dailyLimitModule.getAddress()) + const tx2 = safeSdk.createEnableModuleTx(dailyLimitModule.address) await chai.expect(tx2).to.be.rejectedWith('Module provided is already enabled') }) it('should build the transaction with the optional props', async () => { const { safe, dailyLimitModule, contractNetworks, provider } = await setupTests() - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, @@ -365,7 +363,7 @@ describe('Safe modules manager', () => { nonce: 555, safeTxGas: '666' } - const tx = await safeSdk.createEnableModuleTx(await dailyLimitModule.getAddress(), options) + const tx = await safeSdk.createEnableModuleTx(dailyLimitModule.address, options) chai.expect(tx.data.baseGas).to.be.eq('111') chai.expect(tx.data.gasPrice).to.be.eq('222') chai.expect(tx.data.gasToken).to.be.eq('0x333') @@ -376,19 +374,19 @@ describe('Safe modules manager', () => { it('should enable a Safe module', async () => { const { safe, dailyLimitModule, contractNetworks, provider } = await setupTests() - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, contractNetworks }) chai.expect((await safeSdk.getModules()).length).to.be.eq(0) - chai.expect(await safeSdk.isModuleEnabled(await dailyLimitModule.getAddress())).to.be.false - const tx = await safeSdk.createEnableModuleTx(await dailyLimitModule.getAddress()) + chai.expect(await safeSdk.isModuleEnabled(dailyLimitModule.address)).to.be.false + const tx = await safeSdk.createEnableModuleTx(dailyLimitModule.address) const txResponse = await safeSdk.executeTransaction(tx) await waitSafeTxReceipt(txResponse) chai.expect((await safeSdk.getModules()).length).to.be.eq(1) - chai.expect(await safeSdk.isModuleEnabled(await dailyLimitModule.getAddress())).to.be.true + chai.expect(await safeSdk.isModuleEnabled(dailyLimitModule.address)).to.be.true }) }) @@ -400,13 +398,13 @@ describe('Safe modules manager', () => { predictedSafe, contractNetworks }) - const tx = safeSdk.createDisableModuleTx(await dailyLimitModule.getAddress()) + const tx = safeSdk.createDisableModuleTx(dailyLimitModule.address) chai.expect(tx).to.be.rejectedWith('Safe is not deployed') }) it('should fail if address is invalid', async () => { const { safe, contractNetworks, provider } = await setupTests() - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, @@ -418,7 +416,7 @@ describe('Safe modules manager', () => { it('should fail if address is equal to sentinel', async () => { const { safe, contractNetworks, provider } = await setupTests() - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, @@ -430,7 +428,7 @@ describe('Safe modules manager', () => { it('should fail if address is equal to 0x address', async () => { const { safe, contractNetworks, provider } = await setupTests() - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, @@ -442,13 +440,13 @@ describe('Safe modules manager', () => { it('should fail if address is not enabled', async () => { const { safe, dailyLimitModule, contractNetworks, provider } = await setupTests() - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, contractNetworks }) - const tx = safeSdk.createDisableModuleTx(await dailyLimitModule.getAddress()) + const tx = safeSdk.createDisableModuleTx(dailyLimitModule.address) await chai.expect(tx).to.be.rejectedWith('Module provided is not enabled yet') }) @@ -456,18 +454,18 @@ describe('Safe modules manager', () => { const { dailyLimitModule, accounts, contractNetworks, provider } = await setupTests() const [account1] = accounts const safe = await getSafeWithOwners([account1.address]) - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, contractNetworks }) - const tx1 = await safeSdk.createEnableModuleTx(await dailyLimitModule.getAddress()) + const tx1 = await safeSdk.createEnableModuleTx(dailyLimitModule.address) const txResponse1 = await safeSdk.executeTransaction(tx1) await waitSafeTxReceipt(txResponse1) chai.expect((await safeSdk.getModules()).length).to.be.eq(1) - chai.expect(await safeSdk.isModuleEnabled(await dailyLimitModule.getAddress())).to.be.true + chai.expect(await safeSdk.isModuleEnabled(dailyLimitModule.address)).to.be.true const options: SafeTransactionOptionalProps = { baseGas: '111', @@ -477,7 +475,7 @@ describe('Safe modules manager', () => { nonce: 555, safeTxGas: '666' } - const tx2 = await safeSdk.createDisableModuleTx(await dailyLimitModule.getAddress(), options) + const tx2 = await safeSdk.createDisableModuleTx(dailyLimitModule.address, options) chai.expect(tx2.data.baseGas).to.be.eq('111') chai.expect(tx2.data.gasPrice).to.be.eq('222') chai.expect(tx2.data.gasToken).to.be.eq('0x333') @@ -491,37 +489,36 @@ describe('Safe modules manager', () => { await setupTests() const [account1] = accounts const safe = await getSafeWithOwners([account1.address]) - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, contractNetworks }) - const tx1 = await safeSdk.createEnableModuleTx(await dailyLimitModule.getAddress()) + const tx1 = await safeSdk.createEnableModuleTx(dailyLimitModule.address) const txResponse1 = await safeSdk.executeTransaction(tx1) await waitSafeTxReceipt(txResponse1) - const tx2 = await safeSdk.createEnableModuleTx(await socialRecoveryModule.getAddress()) + const tx2 = await safeSdk.createEnableModuleTx(socialRecoveryModule.address) const txResponse2 = await safeSdk.executeTransaction(tx2) await waitSafeTxReceipt(txResponse2) chai.expect((await safeSdk.getModules()).length).to.be.eq(2) - chai.expect(await safeSdk.isModuleEnabled(await dailyLimitModule.getAddress())).to.be.true - chai.expect(await safeSdk.isModuleEnabled(await socialRecoveryModule.getAddress())).to.be.true + chai.expect(await safeSdk.isModuleEnabled(dailyLimitModule.address)).to.be.true + chai.expect(await safeSdk.isModuleEnabled(socialRecoveryModule.address)).to.be.true - const tx3 = await safeSdk.createDisableModuleTx(await dailyLimitModule.getAddress()) + const tx3 = await safeSdk.createDisableModuleTx(dailyLimitModule.address) const txResponse3 = await safeSdk.executeTransaction(tx3) await waitSafeTxReceipt(txResponse3) chai.expect((await safeSdk.getModules()).length).to.be.eq(1) - chai.expect(await safeSdk.isModuleEnabled(await dailyLimitModule.getAddress())).to.be.false - chai.expect(await safeSdk.isModuleEnabled(await socialRecoveryModule.getAddress())).to.be.true + chai.expect(await safeSdk.isModuleEnabled(dailyLimitModule.address)).to.be.false + chai.expect(await safeSdk.isModuleEnabled(socialRecoveryModule.address)).to.be.true - const tx4 = await safeSdk.createDisableModuleTx(await socialRecoveryModule.getAddress()) + const tx4 = await safeSdk.createDisableModuleTx(socialRecoveryModule.address) const txResponse4 = await safeSdk.executeTransaction(tx4) await waitSafeTxReceipt(txResponse4) chai.expect((await safeSdk.getModules()).length).to.be.eq(0) - chai.expect(await safeSdk.isModuleEnabled(await dailyLimitModule.getAddress())).to.be.false - chai.expect(await safeSdk.isModuleEnabled(await socialRecoveryModule.getAddress())).to.be - .false + chai.expect(await safeSdk.isModuleEnabled(dailyLimitModule.address)).to.be.false + chai.expect(await safeSdk.isModuleEnabled(socialRecoveryModule.address)).to.be.false }) }) }) diff --git a/packages/protocol-kit/tests/e2e/offChainSignatures.test.ts b/packages/protocol-kit/tests/e2e/offChainSignatures.test.ts index b10a3c7db..47c2ea302 100644 --- a/packages/protocol-kit/tests/e2e/offChainSignatures.test.ts +++ b/packages/protocol-kit/tests/e2e/offChainSignatures.test.ts @@ -53,7 +53,7 @@ describe('Off-chain signatures', () => { it('should sign a transaction hash with the current signer', async () => { const { safe, contractNetworks, provider } = await setupTests() - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, @@ -81,7 +81,7 @@ describe('Off-chain signatures', () => { predictedSafe, contractNetworks }) - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdkExistingSafe = await Safe.init({ provider, safeAddress, @@ -113,7 +113,7 @@ describe('Off-chain signatures', () => { predictedSafe, contractNetworks }) - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeTransactionData = { to: safeAddress, value: '0', @@ -130,7 +130,7 @@ describe('Off-chain signatures', () => { it('should fail if the signature is added by an account that is not an owner', async () => { const { safe, accounts, contractNetworks, provider } = await setupTests() const account3 = accounts[2] - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, @@ -150,7 +150,7 @@ describe('Off-chain signatures', () => { it('should ignore duplicated signatures', async () => { const { safe, contractNetworks, provider } = await setupTests() - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, @@ -174,7 +174,7 @@ describe('Off-chain signatures', () => { 'should fail if the signature of the current signer is added using eth_sign and safeVersion===1.0.0', async () => { const { safe, contractNetworks, provider } = await setupTests() - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress: safeAddress, @@ -196,7 +196,7 @@ describe('Off-chain signatures', () => { 'should add the signature of the current signer using eth_sign if safeVersion>1.0.0', async () => { const { safe, contractNetworks, provider } = await setupTests() - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, @@ -217,7 +217,7 @@ describe('Off-chain signatures', () => { it('should add the signature of the current signer using eth_signTypedData', async () => { const { safe, contractNetworks, provider } = await setupTests() - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, @@ -237,7 +237,7 @@ describe('Off-chain signatures', () => { it('should add the signature of the current signer using eth_signTypedData_v3', async () => { const { safe, contractNetworks, provider } = await setupTests() - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, @@ -257,7 +257,7 @@ describe('Off-chain signatures', () => { it('should add the signature of the current signer using eth_signTypedData_v4', async () => { const { safe, contractNetworks, provider } = await setupTests() - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, @@ -277,7 +277,7 @@ describe('Off-chain signatures', () => { it('should add the signature of the current signer using eth_signTypedData_v4 by default', async () => { const { safe, contractNetworks, provider } = await setupTests() - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, @@ -298,7 +298,7 @@ describe('Off-chain signatures', () => { it('should sign a transaction received from the Safe Transaction Service', async () => { const { safe, accounts, contractNetworks, provider } = await setupTests() const [account1, account2] = accounts - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, safeAddress, diff --git a/packages/protocol-kit/tests/e2e/onChainSignatures.test.ts b/packages/protocol-kit/tests/e2e/onChainSignatures.test.ts index b18b456e8..8f42793e4 100644 --- a/packages/protocol-kit/tests/e2e/onChainSignatures.test.ts +++ b/packages/protocol-kit/tests/e2e/onChainSignatures.test.ts @@ -54,7 +54,7 @@ describe('On-chain signatures', () => { it('should fail if a transaction hash is approved by an account that is not an owner', async () => { const { safe, accounts, contractNetworks, provider } = await setupTests() const account3 = accounts[2] - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk1 = await Safe.init({ provider, signer: account3.address, @@ -76,7 +76,7 @@ describe('On-chain signatures', () => { it('should approve the transaction hash', async () => { const { safe, accounts, contractNetworks, provider } = await setupTests() const [account1] = accounts - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk1 = await Safe.init({ provider, safeAddress, @@ -91,13 +91,13 @@ describe('On-chain signatures', () => { const txHash = await safeSdk1.getTransactionHash(tx) const txResponse = await safeSdk1.approveTransactionHash(txHash) await waitSafeTxReceipt(txResponse) - chai.expect(await safe.approvedHashes(account1.address, txHash)).to.be.equal(1n) + chai.expect(await safe.read.approvedHashes([account1.address, txHash])).to.be.equal(1n) }) it('should ignore a duplicated signatures', async () => { const { safe, accounts, contractNetworks, provider } = await setupTests() const [account1] = accounts - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk1 = await Safe.init({ provider, safeAddress, @@ -110,13 +110,13 @@ describe('On-chain signatures', () => { } const tx = await safeSdk1.createTransaction({ transactions: [safeTransactionData] }) const txHash = await safeSdk1.getTransactionHash(tx) - chai.expect(await safe.approvedHashes(account1.address, txHash)).to.be.equal(0n) + chai.expect(await safe.read.approvedHashes([account1.address, txHash])).to.be.equal(0n) const txResponse1 = await safeSdk1.approveTransactionHash(txHash) await waitSafeTxReceipt(txResponse1) - chai.expect(await safe.approvedHashes(account1.address, txHash)).to.be.equal(1n) + chai.expect(await safe.read.approvedHashes([account1.address, txHash])).to.be.equal(1n) const txResponse2 = await safeSdk1.approveTransactionHash(txHash) await waitSafeTxReceipt(txResponse2) - chai.expect(await safe.approvedHashes(account1.address, txHash)).to.be.equal(1n) + chai.expect(await safe.read.approvedHashes([account1.address, txHash])).to.be.equal(1n) }) }) @@ -136,7 +136,7 @@ describe('On-chain signatures', () => { it('should return the list of owners who approved a transaction hash', async () => { const { safe, accounts, contractNetworks, provider } = await setupTests() const [, account2] = accounts - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk1 = await Safe.init({ provider, safeAddress: safeAddress, diff --git a/packages/protocol-kit/tests/e2e/ownerManager.test.ts b/packages/protocol-kit/tests/e2e/ownerManager.test.ts index 735e520dc..0fa757244 100644 --- a/packages/protocol-kit/tests/e2e/ownerManager.test.ts +++ b/packages/protocol-kit/tests/e2e/ownerManager.test.ts @@ -61,7 +61,7 @@ describe('Safe owners manager', () => { const safe = await getSafeWithOwners([account1.address, account2.address]) const safeSdk = await Safe.init({ provider, - safeAddress: await safe.getAddress(), + safeAddress: safe.address, contractNetworks }) const owners = await safeSdk.getOwners() @@ -89,7 +89,7 @@ describe('Safe owners manager', () => { const safe = await getSafeWithOwners([account1.address]) const safeSdk = await Safe.init({ provider, - safeAddress: await safe.getAddress(), + safeAddress: safe.address, contractNetworks }) const isOwner = await safeSdk.isOwner(account1.address) @@ -102,7 +102,7 @@ describe('Safe owners manager', () => { const safe = await getSafeWithOwners([account1.address]) const safeSdk = await Safe.init({ provider, - safeAddress: await safe.getAddress(), + safeAddress: safe.address, contractNetworks }) const isOwner = await safeSdk.isOwner(account2.address) @@ -129,7 +129,7 @@ describe('Safe owners manager', () => { const safe = await getSafeWithOwners([account1.address]) const safeSdk = await Safe.init({ provider, - safeAddress: await safe.getAddress(), + safeAddress: safe.address, contractNetworks }) const tx = safeSdk.createAddOwnerTx({ ownerAddress: '0x123' }) @@ -142,7 +142,7 @@ describe('Safe owners manager', () => { const safe = await getSafeWithOwners([account1.address]) const safeSdk = await Safe.init({ provider, - safeAddress: await safe.getAddress(), + safeAddress: safe.address, contractNetworks }) const tx = safeSdk.createAddOwnerTx({ ownerAddress: SENTINEL_ADDRESS }) @@ -155,7 +155,7 @@ describe('Safe owners manager', () => { const safe = await getSafeWithOwners([account1.address]) const safeSdk = await Safe.init({ provider, - safeAddress: await safe.getAddress(), + safeAddress: safe.address, contractNetworks }) const tx = safeSdk.createAddOwnerTx({ ownerAddress: ZERO_ADDRESS }) @@ -168,7 +168,7 @@ describe('Safe owners manager', () => { const safe = await getSafeWithOwners([account1.address]) const safeSdk = await Safe.init({ provider, - safeAddress: await safe.getAddress(), + safeAddress: safe.address, contractNetworks }) const tx = safeSdk.createAddOwnerTx({ ownerAddress: account1.address }) @@ -181,7 +181,7 @@ describe('Safe owners manager', () => { const safe = await getSafeWithOwners([account1.address]) const safeSdk = await Safe.init({ provider, - safeAddress: await safe.getAddress(), + safeAddress: safe.address, contractNetworks }) const newThreshold = 3 @@ -200,7 +200,7 @@ describe('Safe owners manager', () => { const safe = await getSafeWithOwners([account1.address]) const safeSdk = await Safe.init({ provider, - safeAddress: await safe.getAddress(), + safeAddress: safe.address, contractNetworks }) const tx = safeSdk.createAddOwnerTx({ ownerAddress: account2.address, threshold: 0 }) @@ -213,7 +213,7 @@ describe('Safe owners manager', () => { const safe = await getSafeWithOwners([account1.address]) const safeSdk = await Safe.init({ provider, - safeAddress: await safe.getAddress(), + safeAddress: safe.address, contractNetworks }) const options: SafeTransactionOptionalProps = { @@ -239,7 +239,7 @@ describe('Safe owners manager', () => { const safe = await getSafeWithOwners([account1.address]) const safeSdk = await Safe.init({ provider, - safeAddress: await safe.getAddress(), + safeAddress: safe.address, contractNetworks }) const initialThreshold = await safeSdk.getThreshold() @@ -263,7 +263,7 @@ describe('Safe owners manager', () => { const safe = await getSafeWithOwners([account1.address]) const safeSdk = await Safe.init({ provider, - safeAddress: await safe.getAddress(), + safeAddress: safe.address, contractNetworks }) const newThreshold = 2 @@ -301,7 +301,7 @@ describe('Safe owners manager', () => { const { safe, contractNetworks, provider } = await setupTests() const safeSdk = await Safe.init({ provider, - safeAddress: await safe.getAddress(), + safeAddress: safe.address, contractNetworks }) const tx = safeSdk.createRemoveOwnerTx({ ownerAddress: '0x123' }) @@ -312,7 +312,7 @@ describe('Safe owners manager', () => { const { safe, contractNetworks, provider } = await setupTests() const safeSdk = await Safe.init({ provider, - safeAddress: await safe.getAddress(), + safeAddress: safe.address, contractNetworks }) const tx = safeSdk.createRemoveOwnerTx({ ownerAddress: SENTINEL_ADDRESS }) @@ -323,7 +323,7 @@ describe('Safe owners manager', () => { const { safe, contractNetworks, provider } = await setupTests() const safeSdk = await Safe.init({ provider, - safeAddress: await safe.getAddress(), + safeAddress: safe.address, contractNetworks }) const tx = safeSdk.createRemoveOwnerTx({ ownerAddress: ZERO_ADDRESS }) @@ -335,7 +335,7 @@ describe('Safe owners manager', () => { const [, , , account4] = accounts const safeSdk = await Safe.init({ provider, - safeAddress: await safe.getAddress(), + safeAddress: safe.address, contractNetworks }) const tx = safeSdk.createRemoveOwnerTx({ ownerAddress: account4.address }) @@ -347,7 +347,7 @@ describe('Safe owners manager', () => { const [account1] = accounts const safeSdk = await Safe.init({ provider, - safeAddress: await safe.getAddress(), + safeAddress: safe.address, contractNetworks }) const newThreshold = 3 @@ -365,7 +365,7 @@ describe('Safe owners manager', () => { const [account1] = accounts const safeSdk = await Safe.init({ provider, - safeAddress: await safe.getAddress(), + safeAddress: safe.address, contractNetworks }) const tx = safeSdk.createRemoveOwnerTx({ ownerAddress: account1.address, threshold: 0 }) @@ -377,7 +377,7 @@ describe('Safe owners manager', () => { const [account1] = accounts const safeSdk1 = await Safe.init({ provider, - safeAddress: await safe.getAddress(), + safeAddress: safe.address, contractNetworks }) const options: SafeTransactionOptionalProps = { @@ -402,7 +402,7 @@ describe('Safe owners manager', () => { const [account1, account2, account3] = accounts const safeSdk1 = await Safe.init({ provider, - safeAddress: await safe.getAddress(), + safeAddress: safe.address, contractNetworks }) const safeSdk2 = await safeSdk1.connect({ @@ -435,7 +435,7 @@ describe('Safe owners manager', () => { const [account1, account2, account3] = accounts const safeSdk1 = await Safe.init({ provider, - safeAddress: await safe.getAddress(), + safeAddress: safe.address, contractNetworks }) const safeSdk2 = await safeSdk1.connect({ @@ -469,7 +469,7 @@ describe('Safe owners manager', () => { const [account1, account2, account3] = accounts const safeSdk1 = await Safe.init({ provider, - safeAddress: await safe.getAddress(), + safeAddress: safe.address, contractNetworks }) const safeSdk2 = await safeSdk1.connect({ @@ -522,7 +522,7 @@ describe('Safe owners manager', () => { const safe = await getSafeWithOwners([account1.address]) const safeSdk = await Safe.init({ provider, - safeAddress: await safe.getAddress(), + safeAddress: safe.address, contractNetworks }) const tx = safeSdk.createSwapOwnerTx({ @@ -538,7 +538,7 @@ describe('Safe owners manager', () => { const safe = await getSafeWithOwners([account1.address]) const safeSdk = await Safe.init({ provider, - safeAddress: await safe.getAddress(), + safeAddress: safe.address, contractNetworks }) const tx = safeSdk.createSwapOwnerTx({ @@ -554,7 +554,7 @@ describe('Safe owners manager', () => { const safe = await getSafeWithOwners([account1.address]) const safeSdk = await Safe.init({ provider, - safeAddress: await safe.getAddress(), + safeAddress: safe.address, contractNetworks }) const tx = safeSdk.createSwapOwnerTx({ @@ -570,7 +570,7 @@ describe('Safe owners manager', () => { const safe = await getSafeWithOwners([account1.address]) const safeSdk = await Safe.init({ provider, - safeAddress: await safe.getAddress(), + safeAddress: safe.address, contractNetworks }) const tx = safeSdk.createSwapOwnerTx({ @@ -586,7 +586,7 @@ describe('Safe owners manager', () => { const safe = await getSafeWithOwners([account1.address]) const safeSdk = await Safe.init({ provider, - safeAddress: await safe.getAddress(), + safeAddress: safe.address, contractNetworks }) const tx = safeSdk.createSwapOwnerTx({ @@ -602,7 +602,7 @@ describe('Safe owners manager', () => { const safe = await getSafeWithOwners([account1.address]) const safeSdk = await Safe.init({ provider, - safeAddress: await safe.getAddress(), + safeAddress: safe.address, contractNetworks }) const tx = safeSdk.createSwapOwnerTx({ @@ -618,7 +618,7 @@ describe('Safe owners manager', () => { const safe = await getSafeWithOwners([account1.address]) const safeSdk = await Safe.init({ provider, - safeAddress: await safe.getAddress(), + safeAddress: safe.address, contractNetworks }) const tx = safeSdk.createSwapOwnerTx({ @@ -634,7 +634,7 @@ describe('Safe owners manager', () => { const safe = await getSafeWithOwners([account1.address]) const safeSdk = await Safe.init({ provider, - safeAddress: await safe.getAddress(), + safeAddress: safe.address, contractNetworks }) const tx = safeSdk.createSwapOwnerTx({ @@ -650,7 +650,7 @@ describe('Safe owners manager', () => { const safe = await getSafeWithOwners([account1.address]) const safeSdk = await Safe.init({ provider, - safeAddress: await safe.getAddress(), + safeAddress: safe.address, contractNetworks }) const options: SafeTransactionOptionalProps = { @@ -679,7 +679,7 @@ describe('Safe owners manager', () => { const safe = await getSafeWithOwners([account1.address]) const safeSdk = await Safe.init({ provider, - safeAddress: await safe.getAddress(), + safeAddress: safe.address, contractNetworks }) const initialOwners = await safeSdk.getOwners() @@ -701,7 +701,7 @@ describe('Safe owners manager', () => { const [account1, account2, account3, account4] = accounts const safeSdk1 = await Safe.init({ provider, - safeAddress: await safe.getAddress(), + safeAddress: safe.address, contractNetworks }) const safeSdk2 = await safeSdk1.connect({ diff --git a/packages/protocol-kit/tests/e2e/safeFactory.test.ts b/packages/protocol-kit/tests/e2e/safeFactory.test.ts index 20998fd50..08cea2961 100644 --- a/packages/protocol-kit/tests/e2e/safeFactory.test.ts +++ b/packages/protocol-kit/tests/e2e/safeFactory.test.ts @@ -95,9 +95,7 @@ describe('SafeProxyFactory', () => { const { accounts, contractNetworks, provider } = await setupTests() const [account1] = accounts const safeFactory = await SafeFactory.init({ provider, contractNetworks }) - chai - .expect(await safeFactory.getSafeProvider().getSignerAddress()) - .to.be.eq(await account1.signer.getAddress()) + chai.expect(await safeFactory.getSafeProvider().getSignerAddress()).to.be.eq(account1.address) }) }) @@ -216,7 +214,7 @@ describe('SafeProxyFactory', () => { chai.expect(counterfactualSafeAddress).to.be.eq(await safe.getAddress()) const compatibilityFallbackHandler = await ( await getCompatibilityFallbackHandler() - ).contract.getAddress() + ).contract.address chai.expect(compatibilityFallbackHandler).to.be.eq(await safe.getFallbackHandler()) } ) @@ -236,7 +234,7 @@ describe('SafeProxyFactory', () => { const safeAccountConfig: SafeAccountConfig = { owners, threshold, - fallbackHandler: await defaultCallbackHandler.getAddress() + fallbackHandler: defaultCallbackHandler.address } const saltNonce = '12345' const counterfactualSafeAddress = await safeFactory.predictSafeAddress( @@ -246,9 +244,7 @@ describe('SafeProxyFactory', () => { const deploySafeProps: DeploySafeProps = { safeAccountConfig, saltNonce } const safe = await safeFactory.deploySafe(deploySafeProps) chai.expect(counterfactualSafeAddress).to.be.eq(await safe.getAddress()) - chai - .expect(await defaultCallbackHandler.getAddress()) - .to.be.eq(await safe.getFallbackHandler()) + chai.expect(defaultCallbackHandler.address).to.be.eq(await safe.getFallbackHandler()) } ) }) @@ -325,7 +321,7 @@ describe('SafeProxyFactory', () => { const safeAccountConfig: SafeAccountConfig = { owners, threshold, - fallbackHandler: await defaultCallbackHandler.getAddress() + fallbackHandler: defaultCallbackHandler.address } const deploySafeProps: DeploySafeProps = { safeAccountConfig } const safe = await safeFactory.deploySafe(deploySafeProps) @@ -334,7 +330,7 @@ describe('SafeProxyFactory', () => { const deployedSafeThreshold = await safe.getThreshold() chai.expect(deployedSafeThreshold).to.be.eq(threshold) const fallbackHandler = await safe.getFallbackHandler() - chai.expect(await defaultCallbackHandler.getAddress()).to.be.eq(fallbackHandler) + chai.expect(defaultCallbackHandler.address).to.be.eq(fallbackHandler) } ) @@ -356,7 +352,7 @@ describe('SafeProxyFactory', () => { const fallbackHandler = await safe.getFallbackHandler() const compatibilityFallbackHandler = await ( await getCompatibilityFallbackHandler() - ).contract.getAddress() + ).contract.address chai.expect(compatibilityFallbackHandler).to.be.eq(fallbackHandler) } ) diff --git a/packages/protocol-kit/tests/e2e/safeProvider.test.ts b/packages/protocol-kit/tests/e2e/safeProvider.test.ts index 1b1a13c71..d4b141a28 100644 --- a/packages/protocol-kit/tests/e2e/safeProvider.test.ts +++ b/packages/protocol-kit/tests/e2e/safeProvider.test.ts @@ -15,7 +15,7 @@ import { import { getEip1193Provider, getSafeProviderFromNetwork } from './utils/setupProvider' import { getAccounts } from './utils/setupTestNetwork' import { SafeProvider } from '@safe-global/protocol-kit/index' -import { AbstractSigner, BrowserProvider, JsonRpcProvider } from 'ethers' +import { publicActions, walletActions } from 'viem' chai.use(chaiAsPromised) @@ -94,7 +94,7 @@ describe('Safe contracts', () => { }) chai .expect(await safeContract.getAddress()) - .to.be.eq(await (await getSafeSingleton()).contract.getAddress()) + .to.be.eq(await (await getSafeSingleton()).contract.address) }) }) @@ -122,7 +122,7 @@ describe('Safe contracts', () => { }) chai .expect(await multiSendContract.getAddress()) - .to.be.eq(await (await getMultiSend()).contract.getAddress()) + .to.be.eq(await (await getMultiSend()).contract.address) }) }) @@ -150,7 +150,7 @@ describe('Safe contracts', () => { }) chai .expect(await multiSendCallOnlyContract.getAddress()) - .to.be.eq(await (await getMultiSendCallOnly()).contract.getAddress()) + .to.be.eq(await (await getMultiSendCallOnly()).contract.address) }) }) @@ -180,7 +180,7 @@ describe('Safe contracts', () => { }) chai .expect(await compatibilityFallbackHandlerContract.getAddress()) - .to.be.eq(await (await getCompatibilityFallbackHandler()).contract.getAddress()) + .to.be.eq(await (await getCompatibilityFallbackHandler()).contract.address) }) }) @@ -208,7 +208,7 @@ describe('Safe contracts', () => { }) chai .expect(await factoryContract.getAddress()) - .to.be.eq(await (await getFactory()).contract.getAddress()) + .to.be.eq(await (await getFactory()).contract.address) }) }) @@ -236,7 +236,7 @@ describe('Safe contracts', () => { }) chai .expect(await signMessageLibContract.getAddress()) - .to.be.eq(await (await getSignMessageLib()).contract.getAddress()) + .to.be.eq(await (await getSignMessageLib()).contract.address) }) }) @@ -264,26 +264,26 @@ describe('Safe contracts', () => { }) chai .expect(await createCallContract.getAddress()) - .to.be.eq(await (await getCreateCall()).contract.getAddress()) + .to.be.eq(await (await getCreateCall()).contract.address) }) - it('should return an external provider (BrowserProvider) and signer (AbstractSigner) when using an EIP1193 provider', async () => { + it('should return an external provider (PublicClient) and signer (WalletClient) when using an EIP1193 provider', async () => { const { provider } = await setupTests() const safeProvider = new SafeProvider({ provider }) - chai.expect(safeProvider.getExternalProvider()).to.be.instanceOf(BrowserProvider) - chai.expect(await safeProvider.getExternalSigner()).to.be.instanceOf(AbstractSigner) + chai.expect(safeProvider.getExternalProvider()).to.deep.include(publicActions) + chai.expect(await safeProvider.getExternalSigner()).to.deep.include(walletActions) }) - it('should return an external provider (JsonRpcProvider) and signer (AbstractSigner) when using a private key', async () => { + it('should return an external provider (PublicClient) and signer (WalletClient) when using a private key', async () => { const safeProvider = new SafeProvider({ provider: 'https://sepolia.gateway.tenderly.co', signer: '4ff03ace1395691975678c93449d552dc83df6b773a8024d4c368b39042a7610' }) - chai.expect(safeProvider.getExternalProvider()).to.be.instanceOf(JsonRpcProvider) - chai.expect(await safeProvider.getExternalSigner()).to.be.instanceOf(AbstractSigner) + chai.expect(safeProvider.getExternalProvider()).to.deep.include(publicActions) + chai.expect(await safeProvider.getExternalSigner()).to.deep.include(walletActions) }) it('should return an undefined signer when using an RPC without signer', async () => { @@ -291,7 +291,7 @@ describe('Safe contracts', () => { provider: 'https://sepolia.gateway.tenderly.co' }) - chai.expect(safeProvider.getExternalProvider()).to.be.instanceOf(JsonRpcProvider) + chai.expect(safeProvider.getExternalProvider()).to.deep.include(publicActions) chai.expect(await safeProvider.getExternalSigner()).to.be.undefined }) }) diff --git a/packages/protocol-kit/tests/e2e/threshold.test.ts b/packages/protocol-kit/tests/e2e/threshold.test.ts index 03df88b85..2629bb76f 100644 --- a/packages/protocol-kit/tests/e2e/threshold.test.ts +++ b/packages/protocol-kit/tests/e2e/threshold.test.ts @@ -55,7 +55,7 @@ describe('Safe Threshold', () => { const { safe, contractNetworks, provider } = await setupTests() const safeSdk = await Safe.init({ provider, - safeAddress: await safe.getAddress(), + safeAddress: safe.address, contractNetworks }) chai.expect(await safeSdk.getThreshold()).to.be.eq(1) @@ -80,7 +80,7 @@ describe('Safe Threshold', () => { const { safe, contractNetworks, provider } = await setupTests() const safeSdk = await Safe.init({ provider, - safeAddress: await safe.getAddress(), + safeAddress: safe.address, contractNetworks }) const newThreshold = 2 @@ -95,7 +95,7 @@ describe('Safe Threshold', () => { const { safe, contractNetworks, provider } = await setupTests() const safeSdk = await Safe.init({ provider, - safeAddress: await safe.getAddress(), + safeAddress: safe.address, contractNetworks }) const newThreshold = 0 @@ -110,7 +110,7 @@ describe('Safe Threshold', () => { const safe = await getSafeWithOwners([account1.address, account2.address], 1) const safeSdk = await Safe.init({ provider, - safeAddress: await safe.getAddress(), + safeAddress: safe.address, contractNetworks }) const newThreshold = 2 @@ -138,7 +138,7 @@ describe('Safe Threshold', () => { const safe = await getSafeWithOwners([account1.address, account2.address], 1) const safeSdk = await Safe.init({ provider, - safeAddress: await safe.getAddress(), + safeAddress: safe.address, contractNetworks }) const newThreshold = 2 diff --git a/packages/protocol-kit/tests/e2e/transactionUtils.test.ts b/packages/protocol-kit/tests/e2e/transactionUtils.test.ts index fc5cfbb78..ddd756b4d 100644 --- a/packages/protocol-kit/tests/e2e/transactionUtils.test.ts +++ b/packages/protocol-kit/tests/e2e/transactionUtils.test.ts @@ -1,6 +1,5 @@ import { OperationType } from '@safe-global/safe-core-sdk-types' import chai from 'chai' - import { decodeMultiSendData } from '@safe-global/protocol-kit/utils/transactions/utils' describe('Transaction utils', () => { diff --git a/packages/protocol-kit/tests/e2e/utils/setupContractNetworks.ts b/packages/protocol-kit/tests/e2e/utils/setupContractNetworks.ts index 8e0fc4f6a..48eafbbd5 100644 --- a/packages/protocol-kit/tests/e2e/utils/setupContractNetworks.ts +++ b/packages/protocol-kit/tests/e2e/utils/setupContractNetworks.ts @@ -13,21 +13,21 @@ import { export async function getContractNetworks(chainId: bigint): Promise { return { [chainId.toString()]: { - safeSingletonAddress: await (await getSafeSingleton()).contract.getAddress(), + safeSingletonAddress: await (await getSafeSingleton()).contract.address, safeSingletonAbi: (await getSafeSingleton()).abi, - safeProxyFactoryAddress: await (await getFactory()).contract.getAddress(), + safeProxyFactoryAddress: await (await getFactory()).contract.address, safeProxyFactoryAbi: (await getFactory()).abi, - multiSendAddress: await (await getMultiSend()).contract.getAddress(), + multiSendAddress: await (await getMultiSend()).contract.address, multiSendAbi: (await getMultiSend()).abi, - multiSendCallOnlyAddress: await (await getMultiSendCallOnly()).contract.getAddress(), + multiSendCallOnlyAddress: await (await getMultiSendCallOnly()).contract.address, multiSendCallOnlyAbi: (await getMultiSendCallOnly()).abi, - fallbackHandlerAddress: await (await getCompatibilityFallbackHandler()).contract.getAddress(), + fallbackHandlerAddress: await (await getCompatibilityFallbackHandler()).contract.address, fallbackHandlerAbi: (await getCompatibilityFallbackHandler()).abi, - signMessageLibAddress: await (await getSignMessageLib()).contract.getAddress(), + signMessageLibAddress: await (await getSignMessageLib()).contract.address, signMessageLibAbi: (await getSignMessageLib()).abi, - createCallAddress: await (await getCreateCall()).contract.getAddress(), + createCallAddress: await (await getCreateCall()).contract.address, createCallAbi: (await getCreateCall()).abi, - simulateTxAccessorAddress: await (await getSimulateTxAccessor()).contract.getAddress(), + simulateTxAccessorAddress: await (await getSimulateTxAccessor()).contract.address, simulateTxAccessorAbi: (await getSimulateTxAccessor()).abi } } diff --git a/packages/protocol-kit/tests/e2e/utils/setupContracts.ts b/packages/protocol-kit/tests/e2e/utils/setupContracts.ts index af82e3ba7..76051bd08 100644 --- a/packages/protocol-kit/tests/e2e/utils/setupContracts.ts +++ b/packages/protocol-kit/tests/e2e/utils/setupContracts.ts @@ -1,4 +1,5 @@ -import { Contract, ZeroAddress, JsonFragment } from 'ethers' +import { ZERO_ADDRESS } from '@safe-global/protocol-kit/utils/constants' +import { Address, GetContractReturnType, Abi, WalletClient } from 'viem' import { compatibilityFallbackHandlerDeployed, createCallDeployed, @@ -10,203 +11,220 @@ import { signMessageLibDeployed, simulateTxAccessorDeployed } from '@safe-global/protocol-kit/hardhat/deploy/deploy-contracts' -import { deployments, ethers } from 'hardhat' +import { deployments, viem } from 'hardhat' import semverSatisfies from 'semver/functions/satisfies' +import { getDeployer, waitTransactionReceipt } from './transactions' +import { asAddress } from '@safe-global/protocol-kit/utils/types' // TODO: changue contract por abitype objts - export const getSafeSingleton = async (): Promise<{ - contract: Contract - abi: JsonFragment | JsonFragment[] + contract: GetContractReturnType + abi: Abi }> => { - const SafeDeployment = await deployments.get(safeDeployed.name) - const Safe = await ethers.getContractFactory(safeDeployed.name) + const safeDeployment = await deployments.get(safeDeployed.name) + const contract = await viem.getContractAt(safeDeployed.name, asAddress(safeDeployment.address)) return { - contract: Safe.attach(SafeDeployment.address), - abi: SafeDeployment.abi + contract, + abi: safeDeployment.abi } } export const getFactory = async (): Promise<{ - contract: Contract - abi: JsonFragment | JsonFragment[] + contract: GetContractReturnType + abi: Abi }> => { - const FactoryDeployment = await deployments.get(proxyFactoryDeployed.name) - const Factory = await ethers.getContractFactory(proxyFactoryDeployed.name) + const factoryDeployment = await deployments.get(proxyFactoryDeployed.name) + const factoryAddress = asAddress(factoryDeployment.address) + const contract = await viem.getContractAt(proxyFactoryDeployed.name, asAddress(factoryAddress), { + client: { wallet: await getDeployer() } + }) return { - contract: Factory.attach(FactoryDeployment.address), - abi: FactoryDeployment.abi + contract, + abi: factoryDeployment.abi } } -export const getSafeTemplate = async (): Promise => { +export const getSafeTemplate = async (): Promise> => { const randomSaltNonce = Math.floor(Math.random() * 1000000000) + 1 const singleton = (await getSafeSingleton()).contract const factory = (await getFactory()).contract - const singletonAddress = await singleton.getAddress() - const template = await factory.createProxyWithNonce.staticCall( + const singletonAddress = await singleton.address + + const { result } = await factory.simulate.createProxyWithNonce([ singletonAddress, '0x', randomSaltNonce - ) - await factory - .createProxyWithNonce(singletonAddress, '0x', randomSaltNonce) - .then((tx: any) => tx.wait()) - const Safe = await ethers.getContractFactory(safeDeployed.name) - return Safe.attach(template) + ]) + const hash = await factory.write.createProxyWithNonce([singletonAddress, '0x', randomSaltNonce]) + await waitTransactionReceipt(hash) + return viem.getContractAt(safeDeployed.name, result as Address) } export const getSafeWithOwners = async ( owners: string[], threshold?: number, fallbackHandler?: string -): Promise => { +): Promise> => { const template = await getSafeTemplate() if (semverSatisfies(safeVersionDeployed, '<=1.0.0')) { - await template.setup( + await template.write.setup([ owners, threshold || owners.length, - ZeroAddress, + ZERO_ADDRESS, '0x', - ZeroAddress, + ZERO_ADDRESS, 0, - ZeroAddress - ) + ZERO_ADDRESS + ]) } else { - await template.setup( + await template.write.setup([ owners, threshold || owners.length, - ZeroAddress, + ZERO_ADDRESS, '0x', - fallbackHandler || (await (await getCompatibilityFallbackHandler()).contract.getAddress()), - ZeroAddress, + fallbackHandler || (await getCompatibilityFallbackHandler()).contract.address, + ZERO_ADDRESS, 0, - ZeroAddress - ) + ZERO_ADDRESS + ]) } return template } export const getCompatibilityFallbackHandler = async (): Promise<{ - contract: Contract - abi: JsonFragment | JsonFragment[] + contract: GetContractReturnType + abi: Abi }> => { - const CompatibilityFallbackHandlerDeployment = await deployments.get( + const compatibilityFallbackHandlerDeployment = await deployments.get( compatibilityFallbackHandlerDeployed.name ) - const CompatibilityFallbackHandler = await ethers.getContractFactory( - compatibilityFallbackHandlerDeployed.name + const compatibilityFallbackHandlerDeploymentAddress = asAddress( + compatibilityFallbackHandlerDeployment.address + ) + const contract = await viem.getContractAt( + compatibilityFallbackHandlerDeployed.name, + compatibilityFallbackHandlerDeploymentAddress ) return { - contract: CompatibilityFallbackHandler.attach(CompatibilityFallbackHandlerDeployment.address), - abi: CompatibilityFallbackHandlerDeployment.abi + contract, + abi: compatibilityFallbackHandlerDeployment.abi } } export const getMultiSend = async (): Promise<{ - contract: Contract - abi: JsonFragment | JsonFragment[] + contract: GetContractReturnType + abi: Abi }> => { - const MultiSendDeployment = await deployments.get(multiSendDeployed.name) - const MultiSend = await ethers.getContractFactory(multiSendDeployed.name) + const multiSendDeployment = await deployments.get(multiSendDeployed.name) + const multiSendAddress = asAddress(multiSendDeployment.address) + const contract = await viem.getContractAt(multiSendDeployed.name, multiSendAddress) return { - contract: MultiSend.attach(MultiSendDeployment.address), - abi: MultiSendDeployment.abi + contract, + abi: multiSendDeployment.abi } } export const getMultiSendCallOnly = async (): Promise<{ - contract: Contract - abi: JsonFragment | JsonFragment[] + contract: GetContractReturnType + abi: Abi }> => { - const MultiSendCallOnlyDeployment = await deployments.get(multiSendCallOnlyDeployed.name) - const MultiSendCallOnly = await ethers.getContractFactory(multiSendCallOnlyDeployed.name) + const multiSendCallOnlyDeployment = await deployments.get(multiSendCallOnlyDeployed.name) + const multiSendAddress = asAddress(multiSendCallOnlyDeployment.address) + const contract = await viem.getContractAt(multiSendCallOnlyDeployed.name, multiSendAddress) return { - contract: MultiSendCallOnly.attach(MultiSendCallOnlyDeployment.address), - abi: MultiSendCallOnlyDeployment.abi + contract, + abi: multiSendCallOnlyDeployment.abi } } export const getSignMessageLib = async (): Promise<{ - contract: Contract - abi: JsonFragment | JsonFragment[] + contract: GetContractReturnType + abi: Abi }> => { - const SignMessageLibDeployment = await deployments.get(signMessageLibDeployed.name) - const SignMessageLib = await ethers.getContractFactory(signMessageLibDeployed.name) + const signMessageLibDeployment = await deployments.get(signMessageLibDeployed.name) + const signMessageLibAddress = asAddress(signMessageLibDeployment.address) + const contract = await viem.getContractAt(signMessageLibDeployed.name, signMessageLibAddress) return { - contract: SignMessageLib.attach(SignMessageLibDeployment.address), - abi: SignMessageLibDeployment.abi + contract, + abi: signMessageLibDeployment.abi } } export const getCreateCall = async (): Promise<{ - contract: Contract - abi: JsonFragment | JsonFragment[] + contract: GetContractReturnType + abi: Abi }> => { - const CreateCallDeployment = await deployments.get(createCallDeployed.name) - const CreateCall = await ethers.getContractFactory(createCallDeployed.name) + const createCallDeployment = await deployments.get(createCallDeployed.name) + const createCallAddress = asAddress(createCallDeployment.address) + const contract = await viem.getContractAt(createCallDeployed.name, createCallAddress) return { - contract: CreateCall.attach(CreateCallDeployment.address), - abi: CreateCallDeployment.abi + contract, + abi: createCallDeployment.abi } } export const getSimulateTxAccessor = async (): Promise<{ - contract: Contract - abi: JsonFragment | JsonFragment[] + contract: GetContractReturnType + abi: Abi }> => { - const SimulateTxAccessorDeployment = await deployments.get(simulateTxAccessorDeployed.name) - const SimulateTxAccessor = await ethers.getContractFactory(simulateTxAccessorDeployed.name) + const simulateTxAccessorDeployment = await deployments.get(simulateTxAccessorDeployed.name) + const simulateTxAccessorAddress = asAddress(simulateTxAccessorDeployment.address) + const contract = await viem.getContractAt( + simulateTxAccessorDeployed.name, + simulateTxAccessorAddress + ) return { - contract: SimulateTxAccessor.attach(SimulateTxAccessorDeployment.address), - abi: SimulateTxAccessorDeployment.abi + contract, + abi: simulateTxAccessorDeployment.abi } } -export const getDailyLimitModule = async (): Promise => { - const DailyLimitModuleDeployment = await deployments.get('DailyLimitModule') - const DailyLimitModule = await ethers.getContractFactory('DailyLimitModule') - return DailyLimitModule.attach(DailyLimitModuleDeployment.address) +export const getDailyLimitModule = async (): Promise> => { + const dailyLimitModuleDeployment = await deployments.get('DailyLimitModule') + const dailyLimitModuleAddress = asAddress(dailyLimitModuleDeployment.address) + return await viem.getContractAt('DailyLimitModule', dailyLimitModuleAddress) } -export const getSocialRecoveryModule = async (): Promise => { - const SocialRecoveryModuleDeployment = await deployments.get('SocialRecoveryModule') - const SocialRecoveryModule = await ethers.getContractFactory('SocialRecoveryModule') - return SocialRecoveryModule.attach(SocialRecoveryModuleDeployment.address) +export const getSocialRecoveryModule = async (): Promise> => { + const socialRecoveryModuleDeployment = await deployments.get('SocialRecoveryModule') + const socialRecoveryModuleAddress = asAddress(socialRecoveryModuleDeployment.address) + return await viem.getContractAt('SocialRecoveryModule', socialRecoveryModuleAddress) } -export const getStateChannelModule = async (): Promise => { - const StateChannelModuleDeployment = await deployments.get('StateChannelModule') - const StateChannelModule = await ethers.getContractFactory('StateChannelModule') - return StateChannelModule.attach(StateChannelModuleDeployment.address) +export const getStateChannelModule = async (): Promise> => { + const stateChannelModuleDeployment = await deployments.get('StateChannelModule') + const stateChannelModuleAddress = asAddress(stateChannelModuleDeployment.address) + return await viem.getContractAt('StateChannelModule', stateChannelModuleAddress) } -export const getWhiteListModule = async (): Promise => { - const WhiteListModuleDeployment = await deployments.get('WhitelistModule') - const WhiteListModule = await ethers.getContractFactory('WhitelistModule') - return WhiteListModule.attach(WhiteListModuleDeployment.address) +export const getWhiteListModule = async (): Promise> => { + const whiteListModuleDeployment = await deployments.get('WhitelistModule') + const whiteListModuleAddress = asAddress(whiteListModuleDeployment.address) + return await viem.getContractAt('WhitelistModule', whiteListModuleAddress) } -export const getERC20Mintable = async (): Promise => { - const ERC20MintableDeployment = await deployments.get('ERC20Mintable') - const ERC20Mintable = await ethers.getContractFactory('ERC20Mintable') - return ERC20Mintable.attach(ERC20MintableDeployment.address) +export const getERC20Mintable = async (): Promise> => { + const eRC20MintableDeployment = await deployments.get('ERC20Mintable') + const eRC20MintableAddress = asAddress(eRC20MintableDeployment.address) + return await viem.getContractAt('ERC20Mintable', eRC20MintableAddress, { + client: { wallet: await getDeployer() } + }) } -export const getDebugTransactionGuard = async (): Promise => { +export const getDebugTransactionGuard = async (): Promise> => { const contractName = semverSatisfies(safeVersionDeployed, '<=1.3.0') ? 'DebugTransactionGuard_SV1_3_0' : 'DebugTransactionGuard_SV1_4_1' - const DebugTransactionGuardDeployment = await deployments.get(contractName) - const DebugTransactionGuard = await ethers.getContractFactory(contractName) - return DebugTransactionGuard.attach(DebugTransactionGuardDeployment.address) + const debugTransactionGuardDeployment = await deployments.get(contractName) + const debugTransactionGuardAddress = asAddress(debugTransactionGuardDeployment.address) + return await viem.getContractAt(contractName, debugTransactionGuardAddress) } -export const getDefaultCallbackHandler = async (): Promise => { +export const getDefaultCallbackHandler = async (): Promise> => { const contractName = semverSatisfies(safeVersionDeployed, '<=1.3.0') ? 'DefaultCallbackHandler_SV1_3_0' : 'TokenCallbackHandler_SV1_4_1' - const DefaultCallbackHandlerDeployment = await deployments.get(contractName) - const DefaultCallbackHandler = await ethers.getContractFactory(contractName) - return DefaultCallbackHandler.attach(DefaultCallbackHandlerDeployment.address) + const defaultCallbackHandlerDeployment = await deployments.get(contractName) + const defaultCallbackHandlerAddress = asAddress(defaultCallbackHandlerDeployment.address) + return await viem.getContractAt(contractName, defaultCallbackHandlerAddress) } diff --git a/packages/protocol-kit/tests/e2e/utils/setupProvider.ts b/packages/protocol-kit/tests/e2e/utils/setupProvider.ts index 35d8bf59b..aa42df326 100644 --- a/packages/protocol-kit/tests/e2e/utils/setupProvider.ts +++ b/packages/protocol-kit/tests/e2e/utils/setupProvider.ts @@ -1,7 +1,7 @@ -import hre, { ethers } from 'hardhat' +import hre from 'hardhat' import Web3 from 'web3' -import { HardhatEthersSigner } from '@nomicfoundation/hardhat-ethers/signers' -import { custom, createWalletClient } from 'viem' +import { ethers } from 'ethers' +import { custom, createWalletClient, Account } from 'viem' import { SafeProvider } from '@safe-global/protocol-kit/index' import { Eip1193Provider } from '@safe-global/protocol-kit/types' @@ -35,10 +35,7 @@ export function getEip1193Provider(): Eip1193Provider { } } -export function getSafeProviderFromNetwork( - network: Network, - signer?: HardhatEthersSigner -): SafeProvider { +export function getSafeProviderFromNetwork(network: Network, account?: Account): SafeProvider { let rpcUrl: string switch (network) { case 'zksync': @@ -60,5 +57,5 @@ export function getSafeProviderFromNetwork( throw new Error('Chain not supported') } - return new SafeProvider({ provider: rpcUrl, signer: signer?.address }) + return new SafeProvider({ provider: rpcUrl, signer: account?.address }) } diff --git a/packages/protocol-kit/tests/e2e/utils/setupTestNetwork.ts b/packages/protocol-kit/tests/e2e/utils/setupTestNetwork.ts index 43455ad0d..d3370feec 100644 --- a/packages/protocol-kit/tests/e2e/utils/setupTestNetwork.ts +++ b/packages/protocol-kit/tests/e2e/utils/setupTestNetwork.ts @@ -1,18 +1,18 @@ -import { HardhatEthersSigner } from '@nomicfoundation/hardhat-ethers/signers' -import { ethers } from 'hardhat' +import { viem } from 'hardhat' +import { WalletClient, Chain, Transport, getAddress, Account as ViemAccount } from 'viem' interface Account { - signer: HardhatEthersSigner + signer: WalletClient address: string } async function getHardhatAccounts(): Promise { - const wallets = await ethers.getSigners() + const wallets = await viem.getWalletClients() const accounts: Account[] = [] for (let i = 0; i < 10; i++) { const wallet = wallets[i] - const account: Account = { signer: wallet, address: wallet.address } + const account: Account = { signer: wallet, address: getAddress(wallet.account.address) } accounts.push(account) } diff --git a/packages/protocol-kit/tests/e2e/utils/transactions.ts b/packages/protocol-kit/tests/e2e/utils/transactions.ts index 27265dbd1..5c7f0fc11 100644 --- a/packages/protocol-kit/tests/e2e/utils/transactions.ts +++ b/packages/protocol-kit/tests/e2e/utils/transactions.ts @@ -1,12 +1,14 @@ -import { ContractTransactionReceipt } from 'ethers' +import { GetTransactionReceiptReturnType, Hex, WalletClient, Transport, Chain, Account } from 'viem' import { TransactionResult } from '@safe-global/safe-core-sdk-types' import SafeProvider from '@safe-global/protocol-kit/SafeProvider' +import { asAddress } from '@safe-global/protocol-kit/utils/types' +import hre, { viem } from 'hardhat' export async function waitSafeTxReceipt( txResult: TransactionResult -): Promise { - const receipt: ContractTransactionReceipt | null | undefined = - txResult.transactionResponse && (await txResult.transactionResponse.wait()) +): Promise { + const receipt: GetTransactionReceiptReturnType | null | undefined = + txResult.transactionResponse && (await txResult?.transactionResponse?.wait()) return receipt } @@ -17,3 +19,12 @@ export async function getTransaction( ): Promise { return safeProvider.getTransaction(transactionHash) } + +export async function waitTransactionReceipt(hash: Hex) { + return (await viem.getPublicClient()).waitForTransactionReceipt({ hash }) +} + +export async function getDeployer(): Promise> { + const { deployer } = await hre.getNamedAccounts() + return viem.getWalletClient(asAddress(deployer)) +} diff --git a/packages/protocol-kit/tests/e2e/wrapSafeTransactionIntoDeploymentBatch.test.ts b/packages/protocol-kit/tests/e2e/wrapSafeTransactionIntoDeploymentBatch.test.ts index be1f3bb03..27b6842a3 100644 --- a/packages/protocol-kit/tests/e2e/wrapSafeTransactionIntoDeploymentBatch.test.ts +++ b/packages/protocol-kit/tests/e2e/wrapSafeTransactionIntoDeploymentBatch.test.ts @@ -45,7 +45,7 @@ describe('wrapSafeTransactionIntoDeploymentBatch', () => { const [account1, account2] = accounts const safe = await getSafeWithOwners([account1.address]) - const safeAddress = await safe.getAddress() + const safeAddress = safe.address const safeSdk = await Safe.init({ provider, @@ -92,7 +92,7 @@ describe('wrapSafeTransactionIntoDeploymentBatch', () => { const batchTransaction = await safeSdk.wrapSafeTransactionIntoDeploymentBatch(safeTransaction) - const multiSendContractAddress = await (await getMultiSendCallOnly()).contract.getAddress() + const multiSendContractAddress = await (await getMultiSendCallOnly()).contract.address chai.expect(batchTransaction).to.be.deep.equal({ to: multiSendContractAddress, @@ -126,7 +126,7 @@ describe('wrapSafeTransactionIntoDeploymentBatch', () => { const batchTransaction = await safeSdk.wrapSafeTransactionIntoDeploymentBatch(safeTransaction) - const multiSendContractAddress = await (await getMultiSendCallOnly()).contract.getAddress() + const multiSendContractAddress = await (await getMultiSendCallOnly()).contract.address chai.expect(batchTransaction).to.be.deep.equal({ to: multiSendContractAddress, @@ -168,7 +168,7 @@ describe('wrapSafeTransactionIntoDeploymentBatch', () => { const customSaltNonceEncoded = safeSdk .getSafeProvider() - .encodeParameters(['uint256'], [customSaltNonce]) + .encodeParameters('uint256', [customSaltNonce]) // custom salt nonce included in the deployment data chai.expect(batchTransaction.data).to.contains(customSaltNonceEncoded.replace('0x', '')) diff --git a/packages/protocol-kit/tests/unit/eip-712.test.ts b/packages/protocol-kit/tests/unit/eip-712.test.ts index 6ed9ad222..89db5fa98 100644 --- a/packages/protocol-kit/tests/unit/eip-712.test.ts +++ b/packages/protocol-kit/tests/unit/eip-712.test.ts @@ -6,6 +6,7 @@ import { generateTypedData, getEip712TxTypes } from '@safe-global/protocol-kit/utils' +import { EIP712TypedData } from '@safe-global/safe-core-sdk-types' const safeAddress = '0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1' const safeTransactionData: SafeTransactionData = { @@ -87,7 +88,7 @@ describe('EIP-712 sign typed data', () => { data: safeTransactionData }) chai.expect(domain.verifyingContract).to.be.eq(safeAddress) - chai.expect(domain.chainId).to.be.eq(chainId.toString()) + chai.expect(domain.chainId).to.be.eq(Number(chainId)) }) it('should generate the correct types for a EIP-191 message for >= 1.3.0 Safes', () => { @@ -115,7 +116,7 @@ describe('EIP-712 sign typed data', () => { SafeMessage: [{ name: 'message', type: 'bytes' }] }, domain: { - chainId: '1', + chainId: 1, verifyingContract: safeAddress }, primaryType: 'SafeMessage', @@ -156,9 +157,9 @@ describe('EIP-712 sign typed data', () => { }) it('should generate the correct types for an EIP-712 message for >=1.3.0 Safes', () => { - const message = { + const message: EIP712TypedData = { domain: { - chainId: '1', + chainId: 1, name: 'Ether Mail', verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC', version: '1' @@ -225,7 +226,7 @@ describe('EIP-712 sign typed data', () => { SafeMessage: [{ name: 'message', type: 'bytes' }] }, domain: { - chainId: '1', + chainId: 1, verifyingContract: safeAddress }, primaryType: 'SafeMessage', @@ -238,7 +239,7 @@ describe('EIP-712 sign typed data', () => { it('should generate the correct types for an EIP-712 message for <1.3.0 Safes', () => { const message = { domain: { - chainId: 1n, + chainId: 1, name: 'Ether Mail', verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC', version: '1' diff --git a/packages/safe-core-sdk-types/src/index.ts b/packages/safe-core-sdk-types/src/index.ts index ef9abd2ee..b24debaf7 100644 --- a/packages/safe-core-sdk-types/src/index.ts +++ b/packages/safe-core-sdk-types/src/index.ts @@ -8,19 +8,3 @@ export * from './contracts/SimulateTxAccessor' export * from './contracts/common/BaseContract' export * from './contracts/assets' export * from './types' - -// see docs: https://abitype.dev/config -declare module 'abitype' { - export interface Register { - // AddressType: `0x${string}` - // BytesType: { - // inputs: `0x${string}` | Uint8Array - // outputs: `0x${string}` - // } - AddressType: string - BytesType: { - inputs: string - outputs: string - } - } -} diff --git a/packages/safe-core-sdk-types/src/types.ts b/packages/safe-core-sdk-types/src/types.ts index c19502521..6e7361731 100644 --- a/packages/safe-core-sdk-types/src/types.ts +++ b/packages/safe-core-sdk-types/src/types.ts @@ -83,7 +83,7 @@ export interface TransactionBase { export interface TransactionOptions { from?: string - gasLimit?: number | string + gasLimit?: number | string | bigint gasPrice?: number | string maxFeePerGas?: number | string maxPriorityFeePerGas?: number | string @@ -170,20 +170,20 @@ export interface EIP712TypedDataMessage { } } -interface TypedDataDomain { +export interface TypedDataDomain { name?: string version?: string - chainId?: unknown + chainId?: number verifyingContract?: string salt?: ArrayLike | string } -interface TypedDataTypes { +export interface TypedDataTypes { name: string type: string } -type TypedMessageTypes = { +export type TypedMessageTypes = { [key: string]: TypedDataTypes[] } diff --git a/yarn.lock b/yarn.lock index 3cc81e3f8..cf973a9b8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1256,6 +1256,20 @@ dependencies: "@noble/hashes" "1.3.2" +"@noble/curves@1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.4.0.tgz#f05771ef64da724997f69ee1261b2417a49522d6" + integrity sha512-p+4cb332SFCrReJkCYe8Xzm0OWi4Jji5jVdIZRL/PmacmDkFNw6MrrV+gGpiPxLHbV+zKFRywUWbaseT+tZRXg== + dependencies: + "@noble/hashes" "1.4.0" + +"@noble/curves@~1.4.0": + version "1.4.2" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.4.2.tgz#40309198c76ed71bc6dbf7ba24e81ceb4d0d1fe9" + integrity sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw== + dependencies: + "@noble/hashes" "1.4.0" + "@noble/hashes@1.1.2": version "1.1.2" resolved "https://registry.npmjs.org/@noble/hashes/-/hashes-1.1.2.tgz" @@ -1276,6 +1290,11 @@ resolved "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz" integrity sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ== +"@noble/hashes@1.4.0", "@noble/hashes@~1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.4.0.tgz#45814aa329f30e4fe0ba49426f49dfccdd066426" + integrity sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg== + "@noble/hashes@^1.3.1", "@noble/hashes@^1.3.3", "@noble/hashes@~1.3.0", "@noble/hashes@~1.3.1", "@noble/hashes@~1.3.2": version "1.3.3" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.3.tgz#39908da56a4adc270147bb07968bf3b16cfe1699" @@ -1441,13 +1460,13 @@ mcl-wasm "^0.7.1" rustbn.js "~0.2.0" -"@nomicfoundation/hardhat-ethers@^3.0.6": - version "3.0.6" - resolved "https://registry.yarnpkg.com/@nomicfoundation/hardhat-ethers/-/hardhat-ethers-3.0.6.tgz#e8ba7f9719de360c03501b85dae4999bb3a7e1c5" - integrity sha512-/xzkFQAaHQhmIAYOQmvHBPwL+NkwLzT9gRZBsgWUYeV+E6pzXsBQsHfRYbAZ3XEYare+T7S+5Tg/1KDJgepSkA== +"@nomicfoundation/hardhat-viem@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@nomicfoundation/hardhat-viem/-/hardhat-viem-2.0.2.tgz#91d7a6d3e66c93bc39b2322420a1bad82360df7d" + integrity sha512-Ek2lGjrt15IdDkq5+24CGeAQzlr/4UwUx0UKx6IVW/QOHGr1bk21KipUugFIyEjEltcgyUJcPJ02XFTcjgnwZA== dependencies: - debug "^4.1.1" - lodash.isequal "^4.5.0" + abitype "^0.9.8" + lodash.memoize "^4.1.2" "@nomicfoundation/solidity-analyzer-darwin-arm64@0.1.1": version "0.1.1" @@ -1842,6 +1861,11 @@ resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.6.tgz#8ce5d304b436e4c84f896e0550c83e4d88cb917d" integrity sha512-ok9AWwhcgYuGG3Zfhyqg+zwl+Wn5uE+dwC0NV/2qQkx4dABbb/bx96vWu8NSj+BNjjSjno+JRYRjle1jV08k3g== +"@scure/base@~1.1.6": + version "1.1.7" + resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.7.tgz#fe973311a5c6267846aa131bc72e96c5d40d2b30" + integrity sha512-PPNYBslrLNNUQ/Yad37MHYsNQtK67EhWb6WtSvNLLPo7SdVZgkUjD6Dg+5On7zNwmskf8OX7I7Nx5oN+MIWE0g== + "@scure/bip32@1.1.5": version "1.1.5" resolved "https://registry.npmjs.org/@scure/bip32/-/bip32-1.1.5.tgz" @@ -1869,6 +1893,15 @@ "@noble/hashes" "~1.3.2" "@scure/base" "~1.1.2" +"@scure/bip32@1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.4.0.tgz#4e1f1e196abedcef395b33b9674a042524e20d67" + integrity sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg== + dependencies: + "@noble/curves" "~1.4.0" + "@noble/hashes" "~1.4.0" + "@scure/base" "~1.1.6" + "@scure/bip39@1.1.1": version "1.1.1" resolved "https://registry.npmjs.org/@scure/bip39/-/bip39-1.1.1.tgz" @@ -1885,6 +1918,14 @@ "@noble/hashes" "~1.3.0" "@scure/base" "~1.1.0" +"@scure/bip39@1.3.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.3.0.tgz#0f258c16823ddd00739461ac31398b4e7d6a18c3" + integrity sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ== + dependencies: + "@noble/hashes" "~1.4.0" + "@scure/base" "~1.1.6" + "@sentry/core@5.30.0": version "5.30.0" resolved "https://registry.npmjs.org/@sentry/core/-/core-5.30.0.tgz" @@ -2646,6 +2687,16 @@ abitype@1.0.4: resolved "https://registry.yarnpkg.com/abitype/-/abitype-1.0.4.tgz#a817ff44860e8a84e9a37ed22aa9b738dbb51dba" integrity sha512-UivtYZOGJGE8rsrM/N5vdRkUpqEZVmuTumfTuolm7m/6O09wprd958rx8kUBwVAAAhQDveGAgD0GJdBuR8s6tw== +abitype@1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/abitype/-/abitype-1.0.5.tgz#29d0daa3eea867ca90f7e4123144c1d1270774b6" + integrity sha512-YzDhti7cjlfaBhHutMaboYB21Ha3rXR9QTkNJFzYC4kC8YclaiwPBBBJY8ejFdu2wnJeZCVZSMlQJ7fi8S6hsw== + +abitype@^0.9.8: + version "0.9.10" + resolved "https://registry.yarnpkg.com/abitype/-/abitype-0.9.10.tgz#fa6fa30a6465da98736f98b6c601a02ed49f6eec" + integrity sha512-FIS7U4n7qwAT58KibwYig5iFG4K61rbhAqaQh/UWj8v1Y8mjX3F8TC9gd8cz9yT1TYel9f8nS5NO5kZp2RW0jQ== + abitype@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/abitype/-/abitype-1.0.2.tgz#183c28f2f3b4278810ed1543941b555bb73f301d" @@ -4431,32 +4482,6 @@ ethers@^6.13.1, ethers@^6.8.1: tslib "2.4.0" ws "8.17.1" -ethers@^6.13.1: - version "6.13.1" - resolved "https://registry.yarnpkg.com/ethers/-/ethers-6.13.1.tgz#2b9f9c7455cde9d38b30fe6589972eb083652961" - integrity sha512-hdJ2HOxg/xx97Lm9HdCWk949BfYqYWpyw4//78SiwOLgASyfrNszfMUNB2joKjvGUdwhHfaiMMFFwacVVoLR9A== - dependencies: - "@adraffy/ens-normalize" "1.10.1" - "@noble/curves" "1.2.0" - "@noble/hashes" "1.3.2" - "@types/node" "18.15.13" - aes-js "4.0.0-beta.5" - tslib "2.4.0" - ws "8.17.1" - -ethers@^6.13.1: - version "6.13.1" - resolved "https://registry.yarnpkg.com/ethers/-/ethers-6.13.1.tgz#2b9f9c7455cde9d38b30fe6589972eb083652961" - integrity sha512-hdJ2HOxg/xx97Lm9HdCWk949BfYqYWpyw4//78SiwOLgASyfrNszfMUNB2joKjvGUdwhHfaiMMFFwacVVoLR9A== - dependencies: - "@adraffy/ens-normalize" "1.10.1" - "@noble/curves" "1.2.0" - "@noble/hashes" "1.3.2" - "@types/node" "18.15.13" - aes-js "4.0.0-beta.5" - tslib "2.4.0" - ws "8.17.1" - ethjs-util@0.1.6, ethjs-util@^0.1.6: version "0.1.6" resolved "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.6.tgz" @@ -5099,11 +5124,6 @@ hard-rejection@^2.1.0: resolved "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz" integrity sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA== -hardhat-deploy-ethers@^0.4.2: - version "0.4.2" - resolved "https://registry.yarnpkg.com/hardhat-deploy-ethers/-/hardhat-deploy-ethers-0.4.2.tgz#10aa44ef806ec8cf3d67ad9692f3762ed965b5e7" - integrity sha512-AskNH/XRYYYqPT94MvO5s1yMi+/QvoNjS4oU5VcVqfDU99kgpGETl+uIYHIrSXtH5sy7J6gyVjpRMf4x0tjLSQ== - hardhat-deploy@^0.11.45: version "0.11.45" resolved "https://registry.yarnpkg.com/hardhat-deploy/-/hardhat-deploy-0.11.45.tgz#bed86118175a38a03bb58aba2ce1ed5e80a20bc8" @@ -6689,17 +6709,12 @@ lodash.get@^4.4.2: resolved "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz" integrity sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ== -lodash.isequal@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" - integrity sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ== - lodash.ismatch@^4.4.0: version "4.4.0" resolved "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz" integrity sha512-fPMfXjGQEV9Xsq/8MTSgUf255gawYRbjwMyDbcvDhXgV7enSZA0hynz6vMPnpAb5iONEzBHBPsT+0zes5Z301g== -lodash.memoize@4.x: +lodash.memoize@4.x, lodash.memoize@^4.1.2: version "4.1.2" resolved "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz" integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag== @@ -9545,6 +9560,20 @@ viem@^2.16.1: isows "1.0.4" ws "8.17.1" +viem@^2.17.0: + version "2.17.1" + resolved "https://registry.yarnpkg.com/viem/-/viem-2.17.1.tgz#33447c1ab1b0875a0ab7276139400c4fd6b1ed0d" + integrity sha512-iLwFAfn7aWfvc1KY176YNTJQpPdepRhvaltae6TomZ+DU5M7LdASP2ywdAHw/rezdEmrH/ytwG2WWnjWioE0fA== + dependencies: + "@adraffy/ens-normalize" "1.10.0" + "@noble/curves" "1.4.0" + "@noble/hashes" "1.4.0" + "@scure/bip32" "1.4.0" + "@scure/bip39" "1.3.0" + abitype "1.0.5" + isows "1.0.4" + ws "8.17.1" + w3c-xmlserializer@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz" From de3ccc87686d138ddf0ec83d8ad4b07d59305954 Mon Sep 17 00:00:00 2001 From: leonardotc Date: Thu, 11 Jul 2024 16:56:46 +0200 Subject: [PATCH 20/85] Fix onramp kit --- .../packs/monerium/SafeMoneriumClient.test.ts | 28 ++++++++++++++----- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/packages/onramp-kit/src/packs/monerium/SafeMoneriumClient.test.ts b/packages/onramp-kit/src/packs/monerium/SafeMoneriumClient.test.ts index 061a86841..e2a778a72 100644 --- a/packages/onramp-kit/src/packs/monerium/SafeMoneriumClient.test.ts +++ b/packages/onramp-kit/src/packs/monerium/SafeMoneriumClient.test.ts @@ -1,5 +1,4 @@ -import { Contract } from 'ethers' -import { hashMessage } from 'viem' +import { createPublicClient, hashMessage, getContract, custom } from 'viem' import { PaymentStandard } from '@monerium/sdk' import Safe, * as protocolKitPackage from '@safe-global/protocol-kit' import { @@ -7,9 +6,9 @@ import { signMessageLib_1_4_1_ContractArtifacts } from '@safe-global/safe-core-sdk-types' import SafeApiKit from '@safe-global/api-kit' - import { SafeMoneriumClient } from './SafeMoneriumClient' import { MAGIC_VALUE } from './signatures' +import { SignMessageLibContractImplementationType } from '@safe-global/protocol-kit' const newOrder = { amount: '100', @@ -223,10 +222,16 @@ describe('SafeMoneriumClient', () => { nonce: 0 } - jest.spyOn(protocolKitPackage, 'getSignMessageLibContract').mockResolvedValueOnce({ + const contract = { safeVersion: '1.3.0', contractName: 'signMessageLibVersion', - contract: new Contract('0x0000000000000000000000000000000000000001', []), + contract: getContract({ + address: '0x0000000000000000000000000000000000000001', + abi: signMessageLib_1_4_1_ContractArtifacts.abi, + client: createPublicClient({ + transport: custom({ request: jest.fn() }) + }) + }), safeProvider: protocolKit.getSafeProvider() as protocolKitPackage.SafeProvider, encode: jest.fn(), contractAbi: signMessageLib_1_4_1_ContractArtifacts.abi, @@ -235,8 +240,17 @@ describe('SafeMoneriumClient', () => { getMessageHash: jest.fn(), signMessage: jest.fn(), estimateGas: jest.fn(), - init: jest.fn() - }) + init: jest.fn(), + runner: createPublicClient({ + transport: custom({ request: jest.fn() }) + }), + chainId: 1n, + getChain: jest.fn(), + convertOptions: jest.fn(), + getTransactionReceipt: jest.fn() + } as SignMessageLibContractImplementationType + + jest.spyOn(protocolKitPackage, 'getSignMessageLibContract').mockResolvedValueOnce(contract) protocolKit.createTransaction = jest.fn().mockResolvedValueOnce({ data: txData From 82d451257f0a0ea3d3b905f225bafbf5d3320ae0 Mon Sep 17 00:00:00 2001 From: leonardotc Date: Thu, 11 Jul 2024 17:07:33 +0200 Subject: [PATCH 21/85] Fix build --- .../relay-kit/src/packs/safe-4337/utils.ts | 19 ++++++++++--------- .../extensions/messages/onChainMessages.ts | 4 ++-- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/packages/relay-kit/src/packs/safe-4337/utils.ts b/packages/relay-kit/src/packs/safe-4337/utils.ts index 54b164211..29b63243b 100644 --- a/packages/relay-kit/src/packs/safe-4337/utils.ts +++ b/packages/relay-kit/src/packs/safe-4337/utils.ts @@ -61,22 +61,23 @@ export async function signSafeOp( } const chainId = await safeProvider.getChainId() - const signerAddress = await signer.getAddress() - const signature = await signer.signTypedData( - { - chainId, - verifyingContract: safe4337ModuleAddress + const signerAddress = await signer.account.address + const signature = await signer.signTypedData({ + domain: { + chainId: Number(chainId), + verifyingContract: safe4337ModuleAddress as Address }, - EIP712_SAFE_OPERATION_TYPE, - { + types: EIP712_SAFE_OPERATION_TYPE, + message: { ...safeUserOperation, nonce: toHex(safeUserOperation.nonce), validAfter: toHex(safeUserOperation.validAfter), validUntil: toHex(safeUserOperation.validUntil), maxFeePerGas: toHex(safeUserOperation.maxFeePerGas), maxPriorityFeePerGas: toHex(safeUserOperation.maxPriorityFeePerGas) - } - ) + }, + primaryType: 'SafeOp' + }) return new EthSafeSignature(signerAddress, signature) } diff --git a/packages/safe-kit/src/extensions/messages/onChainMessages.ts b/packages/safe-kit/src/extensions/messages/onChainMessages.ts index 85bf2b348..a11d1501a 100644 --- a/packages/safe-kit/src/extensions/messages/onChainMessages.ts +++ b/packages/safe-kit/src/extensions/messages/onChainMessages.ts @@ -7,7 +7,7 @@ import { import { SafeClient } from '@safe-global/safe-kit/SafeClient' import { SafeClientResult } from '@safe-global/safe-kit/types' - +import { Hash } from 'viem' /** * Extend the SafeClient with the ability to use on-chain messages * The on-chain messages are regular transactions created using the SignMessageLib so after sendMessage() @@ -47,7 +47,7 @@ export function onChainMessages() { const transaction = { to: await signMessageLibContract.getAddress(), value: '0', - data: signMessageLibContract.encode('signMessage', [hashSafeMessage(message)]), + data: signMessageLibContract.encode('signMessage', [hashSafeMessage(message) as Hash]), operation: OperationType.DelegateCall } From 4d91289d7d49b59944aa879f4ce233039cec9547 Mon Sep 17 00:00:00 2001 From: leonardotc Date: Fri, 12 Jul 2024 10:11:06 +0200 Subject: [PATCH 22/85] Api kit fixes --- packages/api-kit/package.json | 5 ++--- packages/api-kit/tests/utils/setupKits.ts | 3 ++- packages/protocol-kit/src/SafeProvider.ts | 22 +++++++++++++++++----- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/packages/api-kit/package.json b/packages/api-kit/package.json index 070aeb608..c38faa68b 100644 --- a/packages/api-kit/package.json +++ b/packages/api-kit/package.json @@ -15,11 +15,11 @@ "test:web3": "export TESTS_PATH=tests/endpoint && export ETH_LIB=web3 && nyc hardhat test", "test:ethers": "export TESTS_PATH=tests/endpoint && export ETH_LIB=ethers && nyc --reporter=lcov hardhat test", "test:viem": "export TESTS_PATH=tests/endpoint && export ETH_LIB=viem && nyc hardhat test", - "test": "yarn test:ethers", + "test": "yarn test:viem", "test:ci:web3": "export TESTS_PATH=tests/e2e && export ETH_LIB=web3 && nyc hardhat test", "test:ci:ethers": "export TESTS_PATH=tests/e2e && export ETH_LIB=ethers && nyc --reporter=lcov hardhat test", "test:ci:viem": "export TESTS_PATH=tests/e2e && export ETH_LIB=viem && nyc --reporter=lcov hardhat test", - "test:ci": "yarn test:ci:ethers", + "test:ci": "yarn test:ci:viem", "format:check": "prettier --check \"*/**/*.{js,json,md,ts}\"", "format": "prettier --write \"*/**/*.{js,json,md,ts}\"", "unbuild": "rimraf dist .nyc_output cache", @@ -61,7 +61,6 @@ "dependencies": { "@safe-global/protocol-kit": "^4.0.2", "@safe-global/safe-core-sdk-types": "^5.0.2", - "ethers": "^6.13.1", "node-fetch": "^2.7.0" } } diff --git a/packages/api-kit/tests/utils/setupKits.ts b/packages/api-kit/tests/utils/setupKits.ts index 9da1eff87..18f950c19 100644 --- a/packages/api-kit/tests/utils/setupKits.ts +++ b/packages/api-kit/tests/utils/setupKits.ts @@ -1,4 +1,5 @@ -import hre, { ethers } from 'hardhat' +import hre from 'hardhat' +import ethers from 'ethers' import Web3 from 'web3' import { custom, createWalletClient } from 'viem' diff --git a/packages/protocol-kit/src/SafeProvider.ts b/packages/protocol-kit/src/SafeProvider.ts index 4de47381d..7e1be9468 100644 --- a/packages/protocol-kit/src/SafeProvider.ts +++ b/packages/protocol-kit/src/SafeProvider.ts @@ -44,7 +44,11 @@ import { Chain } from 'viem' import { privateKeyToAccount, Account } from 'viem/accounts' -import { toEstimateGasParameters, toCallGasParameters } from '@safe-global/protocol-kit/utils' +import { + toEstimateGasParameters, + toCallGasParameters, + sameString +} from '@safe-global/protocol-kit/utils' function asBlockId(blockId: number | string | undefined) { return typeof blockId === 'number' ? blockNumber(blockId) : blockTag(blockId) @@ -305,10 +309,18 @@ class SafeProvider { throw new Error('SafeProvider must be initialized with a signer to use this method') } - return (await signer?.signMessage!({ - account: asHex(account), - message: { raw: toBytes(message) } - })) as string + // This means that the address on the `WalletClient` is the one we are passing so we let viem make assertions about that account + // That is because if we pass a typeof account === 'string' to singMessage, viem assumes a json-rpc account on their parseAccount function insteado of a local one + if (sameString(signer.account.address, account)) { + return (await signer?.signMessage!({ + message: { raw: toBytes(message) } + })) as string + } else { + return (await signer?.signMessage!({ + account: asAddress(account), + message: { raw: toBytes(message) } + })) as string + } } async signTypedData(safeEIP712Args: SafeEIP712Args): Promise { From 4320cfaa7429bd07343bd1b87ff22f2d0c7446bd Mon Sep 17 00:00:00 2001 From: leonardotc Date: Fri, 12 Jul 2024 11:13:52 +0200 Subject: [PATCH 23/85] Fix import --- .../tests/e2e/addSafeOperation.test.ts | 36 +++++++++---------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/packages/api-kit/tests/e2e/addSafeOperation.test.ts b/packages/api-kit/tests/e2e/addSafeOperation.test.ts index 7c373b591..d6d438eb9 100644 --- a/packages/api-kit/tests/e2e/addSafeOperation.test.ts +++ b/packages/api-kit/tests/e2e/addSafeOperation.test.ts @@ -6,7 +6,7 @@ import Safe from '@safe-global/protocol-kit' import SafeApiKit from '@safe-global/api-kit/index' import { getAddSafeOperationProps } from '@safe-global/api-kit/utils/safeOperation' import { Safe4337Pack } from '@safe-global/relay-kit' -import viem from 'viem' +import * as viem from 'viem' import { generateTransferCallData } from '@safe-global/relay-kit/packs/safe-4337/testing-utils/helpers' import { ENTRYPOINT_ABI, @@ -37,26 +37,24 @@ describe('addSafeOperation', () => { operation: 0 } - // Setup mocks for the bundler client const requestStub = sinon.stub() - - sinon.stub(viem, 'createPublicClient').get( - () => () => - ({ - request: requestStub, - readContract: sinon - .stub() - .withArgs({ - address: ENTRYPOINT_ADDRESS_V06, - abi: ENTRYPOINT_ABI, - functionName: 'getNonce', - args: [SAFE_ADDRESS, BigInt(0)] - }) - .resolves(123n) - }) as unknown as viem.PublicClient - ) - + // Setup mocks for the bundler client before(async () => { + sinon.stub(viem, 'createPublicClient').get( + () => () => + ({ + request: requestStub, + readContract: sinon + .stub() + .withArgs({ + address: ENTRYPOINT_ADDRESS_V06, + abi: ENTRYPOINT_ABI, + functionName: 'getNonce', + args: [SAFE_ADDRESS, BigInt(0)] + }) + .resolves(123n) + }) as unknown as viem.PublicClient + ) ;({ safeApiKit, protocolKit } = await getKits({ safeAddress: SAFE_ADDRESS, signer: SIGNER_PK, From 65bda3a1b05e5bfa0d6ef6bfec134ddb103f93ab Mon Sep 17 00:00:00 2001 From: leonardotc Date: Fri, 12 Jul 2024 13:06:44 +0200 Subject: [PATCH 24/85] Remove heap-size parameter --- packages/protocol-kit/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/protocol-kit/package.json b/packages/protocol-kit/package.json index 241c4ba0c..b80f3f251 100644 --- a/packages/protocol-kit/package.json +++ b/packages/protocol-kit/package.json @@ -33,7 +33,7 @@ "format:check": "prettier --check \"*/**/*.{js,json,md,ts}\"", "format": "prettier --write \"*/**/*.{js,json,md,ts}\"", "unbuild": "rimraf dist artifacts deployments cache .nyc_output *.tsbuildinfo", - "build": "yarn unbuild && hardhat compile && yarn safe-deployments && NODE_OPTIONS=--max-old-space-size=8192 tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json" + "build": "yarn unbuild && hardhat compile && yarn safe-deployments && tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json" }, "repository": { "type": "git", From e95fc3c9011b7086c8951cfd445ea5a9e232068a Mon Sep 17 00:00:00 2001 From: leonardotc Date: Fri, 12 Jul 2024 15:34:19 +0200 Subject: [PATCH 25/85] Remove ethers from onramp kit --- packages/onramp-kit/package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/onramp-kit/package.json b/packages/onramp-kit/package.json index 4cf20fb91..464d6bc49 100644 --- a/packages/onramp-kit/package.json +++ b/packages/onramp-kit/package.json @@ -41,7 +41,6 @@ "@safe-global/safe-core-sdk-types": "^5.0.2", "@stripe/crypto": "^0.0.4", "@stripe/stripe-js": "^1.54.2", - "ethers": "^6.13.1", "viem": "^2.17.0" }, "devDependencies": { From 1fcc9eb2aada0bdf01fdfbe3ba07ccc75f10be29 Mon Sep 17 00:00:00 2001 From: leonardotc Date: Mon, 15 Jul 2024 10:07:55 +0200 Subject: [PATCH 26/85] Add comment on global polyfill --- packages/auth-kit/jest.setup.ts | 6 +++++- packages/onramp-kit/jest.setup.ts | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/auth-kit/jest.setup.ts b/packages/auth-kit/jest.setup.ts index 3c03d4839..39c7bf169 100644 --- a/packages/auth-kit/jest.setup.ts +++ b/packages/auth-kit/jest.setup.ts @@ -1,4 +1,8 @@ import { TextEncoder } from 'util' -// TextEncoder is used by viem but not bundled with it. Therefore we need to polyfill it for the tests. +// TextEncoder is used by viem, supported by Browsers natively for over five years and node since 11. All as a global export: https://developer.mozilla.org/en-US/docs/Web/API/TextEncoder +// Since both on-ramp and auth-kit rely on being on a browser (i.e.: we access things directly from `window`) the tests are set with the configuration of `testEnvironment: 'jsdom'` +// js-dom doesnt set some of the globals: https://github.com/jestjs/jest/blob/v29.7.0/packages/jest-environment-jsdom/src/index.ts +// for reference, node does: https://github.com/jestjs/jest/blob/4e56991693da7cd4c3730dc3579a1dd1403ee630/packages/jest-environment-node/src/index.ts#L40 + Object.assign(global, { TextEncoder }) diff --git a/packages/onramp-kit/jest.setup.ts b/packages/onramp-kit/jest.setup.ts index 3c03d4839..39c7bf169 100644 --- a/packages/onramp-kit/jest.setup.ts +++ b/packages/onramp-kit/jest.setup.ts @@ -1,4 +1,8 @@ import { TextEncoder } from 'util' -// TextEncoder is used by viem but not bundled with it. Therefore we need to polyfill it for the tests. +// TextEncoder is used by viem, supported by Browsers natively for over five years and node since 11. All as a global export: https://developer.mozilla.org/en-US/docs/Web/API/TextEncoder +// Since both on-ramp and auth-kit rely on being on a browser (i.e.: we access things directly from `window`) the tests are set with the configuration of `testEnvironment: 'jsdom'` +// js-dom doesnt set some of the globals: https://github.com/jestjs/jest/blob/v29.7.0/packages/jest-environment-jsdom/src/index.ts +// for reference, node does: https://github.com/jestjs/jest/blob/4e56991693da7cd4c3730dc3579a1dd1403ee630/packages/jest-environment-node/src/index.ts#L40 + Object.assign(global, { TextEncoder }) From 435ae4d035d416f75516a277091ed3002a155a39 Mon Sep 17 00:00:00 2001 From: leonardotc Date: Mon, 15 Jul 2024 11:02:33 +0200 Subject: [PATCH 27/85] Change encode type conversion --- packages/onramp-kit/src/packs/monerium/SafeMoneriumClient.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/onramp-kit/src/packs/monerium/SafeMoneriumClient.ts b/packages/onramp-kit/src/packs/monerium/SafeMoneriumClient.ts index 905f932d5..f23d3b8b0 100644 --- a/packages/onramp-kit/src/packs/monerium/SafeMoneriumClient.ts +++ b/packages/onramp-kit/src/packs/monerium/SafeMoneriumClient.ts @@ -1,4 +1,4 @@ -import { Hash, encodeFunctionData, hashMessage } from 'viem' +import { Hex, encodeFunctionData, hashMessage } from 'viem' import { getChain as getMoneriumChain, getNetwork as getMoneriumNetwork, @@ -18,7 +18,6 @@ import { parseIsValidSignatureErrorResponse } from '@safe-global/onramp-kit/lib/errors' import { OperationType, SafeMultisigTransactionResponse } from '@safe-global/safe-core-sdk-types' - import { EIP_1271_ABI, EIP_1271_BYTES_ABI, MAGIC_VALUE, MAGIC_VALUE_BYTES } from './signatures' import { SafeMoneriumOrder } from './types' @@ -194,7 +193,7 @@ export class SafeMoneriumClient extends MoneriumClient { encodeFunctionData({ abi, functionName: 'isValidSignature', - args: [messageHash as Hash, '0x'] + args: [messageHash as Hex, '0x'] }) ) From 6bc1f123a8191ee03a8029eec61b424138713dac Mon Sep 17 00:00:00 2001 From: leonardotc Date: Mon, 15 Jul 2024 13:29:59 +0200 Subject: [PATCH 28/85] Fix build after merge --- packages/relay-kit/src/packs/safe-4337/Safe4337Pack.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.ts b/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.ts index 2d9a3f413..aec20383d 100644 --- a/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.ts +++ b/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.ts @@ -1,4 +1,4 @@ -import { Address, Hash, encodeFunctionData, zeroAddress } from 'viem' +import { Address, Hash, encodeFunctionData, zeroAddress, toHex, Hex, concat } from 'viem' import semverSatisfies from 'semver/functions/satisfies' import Safe, { EthSafeSignature, @@ -488,6 +488,8 @@ export class Safe4337Pack extends RelayKitBasePack<{ #toSafeOperation(safeOperationResponse: SafeOperationResponse): EthSafeOperation { const { validUntil, validAfter, userOperation } = safeOperationResponse + const paymaster = userOperation?.paymaster || '0x' + const paymasterData = userOperation?.paymasterData || '0x' const safeOperation = new EthSafeOperation( { sender: userOperation?.sender || '0x', @@ -499,9 +501,7 @@ export class Safe4337Pack extends RelayKitBasePack<{ preVerificationGas: BigInt(userOperation?.preVerificationGas || 0), maxFeePerGas: BigInt(userOperation?.maxFeePerGas || 0), maxPriorityFeePerGas: BigInt(userOperation?.maxPriorityFeePerGas || 0), - paymasterAndData: ethers.hexlify( - ethers.concat([userOperation?.paymaster || '0x', userOperation?.paymasterData || '0x']) - ), + paymasterAndData: toHex(concat([paymaster as Hex, paymasterData as Hex])), signature: safeOperationResponse.preparedSignature || '0x' }, { From 330f05cf4bb6d732cdb63c5a2df7c56a93fd505d Mon Sep 17 00:00:00 2001 From: Tim Schwarz <4171783+tmjssz@users.noreply.github.com> Date: Mon, 15 Jul 2024 17:08:51 +0200 Subject: [PATCH 29/85] api-kit: Move `viem` from devDependencies to dependencies --- packages/api-kit/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/api-kit/package.json b/packages/api-kit/package.json index c38faa68b..cb80f1ba5 100644 --- a/packages/api-kit/package.json +++ b/packages/api-kit/package.json @@ -54,13 +54,13 @@ "sinon": "^14.0.2", "sinon-chai": "^3.7.0", "tsconfig-paths": "^4.2.0", - "viem": "^2.15.1", "web3": "^4.7.0", "yargs": "^17.7.2" }, "dependencies": { "@safe-global/protocol-kit": "^4.0.2", "@safe-global/safe-core-sdk-types": "^5.0.2", - "node-fetch": "^2.7.0" + "node-fetch": "^2.7.0", + "viem": "^2.15.1" } } From eaca0899b14091952a018ffcd0761a1287b48e33 Mon Sep 17 00:00:00 2001 From: Tim Schwarz <4171783+tmjssz@users.noreply.github.com> Date: Mon, 15 Jul 2024 17:10:10 +0200 Subject: [PATCH 30/85] api-kit: Add `ethers` to devDependencies because it's still needed for tests --- packages/api-kit/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/api-kit/package.json b/packages/api-kit/package.json index cb80f1ba5..cb4dd8b7b 100644 --- a/packages/api-kit/package.json +++ b/packages/api-kit/package.json @@ -48,6 +48,7 @@ "@types/yargs": "^17.0.32", "chai": "^4.3.10", "chai-as-promised": "^7.1.1", + "ethers": "^6.13.1", "hardhat": "^2.19.3", "mocha": "^10.2.0", "semver": "^7.6.1", From ed70a3876126f0eedc167eedbf7dc86eaeca7fd8 Mon Sep 17 00:00:00 2001 From: Tim Schwarz <4171783+tmjssz@users.noreply.github.com> Date: Mon, 15 Jul 2024 17:10:45 +0200 Subject: [PATCH 31/85] api-kit: Fix import --- packages/api-kit/tests/e2e/getSafeOperationsByAddress.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/api-kit/tests/e2e/getSafeOperationsByAddress.test.ts b/packages/api-kit/tests/e2e/getSafeOperationsByAddress.test.ts index a8f0cdb28..5fbd716b3 100644 --- a/packages/api-kit/tests/e2e/getSafeOperationsByAddress.test.ts +++ b/packages/api-kit/tests/e2e/getSafeOperationsByAddress.test.ts @@ -2,7 +2,7 @@ import SafeApiKit from '@safe-global/api-kit/index' import chai from 'chai' import chaiAsPromised from 'chai-as-promised' import { getApiKit } from '../utils/setupKits' -import { SafeOperationResponse } from 'packages/safe-core-sdk-types/dist/src' +import { SafeOperationResponse } from '@safe-global/safe-core-sdk-types' chai.use(chaiAsPromised) From 65127b4b32e7fed1acb93d1fa19949f86ebad1d5 Mon Sep 17 00:00:00 2001 From: Tim Schwarz <4171783+tmjssz@users.noreply.github.com> Date: Mon, 15 Jul 2024 17:19:49 +0200 Subject: [PATCH 32/85] api-kit: Fix tests for `addSafeOperation` --- packages/api-kit/tests/endpoint/index.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/api-kit/tests/endpoint/index.test.ts b/packages/api-kit/tests/endpoint/index.test.ts index d216072dd..5cdb94dba 100644 --- a/packages/api-kit/tests/endpoint/index.test.ts +++ b/packages/api-kit/tests/endpoint/index.test.ts @@ -691,10 +691,10 @@ describe('Endpoint tests', () => { const entryPoint = '0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789' const ethersProvider = protocolKit.getSafeProvider().getExternalProvider() - const timestamp = (await ethersProvider.getBlock('latest'))?.timestamp || 0 + const timestamp = (await ethersProvider.getBlock())?.timestamp || 0n - const validAfter = timestamp - 60_000 - const validUntil = timestamp + 60_000 + const validAfter = Number(timestamp - 60_000n) + const validUntil = Number(timestamp + 60_000n) const options = { validAfter, validUntil } await chai From 4ff0dd849f1cca8fecb8cbf37d5130c5b6a775b1 Mon Sep 17 00:00:00 2001 From: Tim Schwarz <4171783+tmjssz@users.noreply.github.com> Date: Mon, 15 Jul 2024 17:21:17 +0200 Subject: [PATCH 33/85] api-kit: Fix e2e tests for `addSafeOperation` --- .../tests/e2e/addSafeOperation.test.ts | 31 +++++++++---------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/packages/api-kit/tests/e2e/addSafeOperation.test.ts b/packages/api-kit/tests/e2e/addSafeOperation.test.ts index d6d438eb9..20f1edfd4 100644 --- a/packages/api-kit/tests/e2e/addSafeOperation.test.ts +++ b/packages/api-kit/tests/e2e/addSafeOperation.test.ts @@ -5,14 +5,14 @@ import sinonChai from 'sinon-chai' import Safe from '@safe-global/protocol-kit' import SafeApiKit from '@safe-global/api-kit/index' import { getAddSafeOperationProps } from '@safe-global/api-kit/utils/safeOperation' -import { Safe4337Pack } from '@safe-global/relay-kit' -import * as viem from 'viem' +import { BundlerClient, Safe4337Pack } from '@safe-global/relay-kit' import { generateTransferCallData } from '@safe-global/relay-kit/packs/safe-4337/testing-utils/helpers' import { ENTRYPOINT_ABI, ENTRYPOINT_ADDRESS_V06, RPC_4337_CALLS } from '@safe-global/relay-kit/packs/safe-4337/constants' +import * as safe4337Utils from '@safe-global/relay-kit/dist/src/packs/safe-4337/utils' import { getKits } from '../utils/setupKits' chai.use(chaiAsPromised) @@ -40,21 +40,18 @@ describe('addSafeOperation', () => { const requestStub = sinon.stub() // Setup mocks for the bundler client before(async () => { - sinon.stub(viem, 'createPublicClient').get( - () => () => - ({ - request: requestStub, - readContract: sinon - .stub() - .withArgs({ - address: ENTRYPOINT_ADDRESS_V06, - abi: ENTRYPOINT_ABI, - functionName: 'getNonce', - args: [SAFE_ADDRESS, BigInt(0)] - }) - .resolves(123n) - }) as unknown as viem.PublicClient - ) + sinon.stub(safe4337Utils, 'getEip4337BundlerProvider').returns({ + request: requestStub, + readContract: sinon + .stub() + .withArgs({ + address: ENTRYPOINT_ADDRESS_V06, + abi: ENTRYPOINT_ABI, + functionName: 'getNonce', + args: [SAFE_ADDRESS, BigInt(0)] + }) + .resolves(123n) + } as unknown as BundlerClient) ;({ safeApiKit, protocolKit } = await getKits({ safeAddress: SAFE_ADDRESS, signer: SIGNER_PK, From 096ac25ce3a1b89bc7ed75a255ac73c768609299 Mon Sep 17 00:00:00 2001 From: Tim Schwarz <4171783+tmjssz@users.noreply.github.com> Date: Mon, 15 Jul 2024 17:26:19 +0200 Subject: [PATCH 34/85] api-kit: Add `@safe-global/relay-kit` to devDependencies because it's used by the tests --- packages/api-kit/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/api-kit/package.json b/packages/api-kit/package.json index cb4dd8b7b..cc01f34fb 100644 --- a/packages/api-kit/package.json +++ b/packages/api-kit/package.json @@ -40,6 +40,7 @@ "homepage": "https://github.com/safe-global/safe-core-sdk#readme", "devDependencies": { "@nomicfoundation/hardhat-viem": "^2.0.2", + "@safe-global/relay-kit": "^3.0.2", "@types/chai": "^4.3.16", "@types/chai-as-promised": "^7.1.8", "@types/mocha": "^10.0.6", From a570ceb25210840a08efa585e509d7aa9bfd8f99 Mon Sep 17 00:00:00 2001 From: Tim Schwarz <4171783+tmjssz@users.noreply.github.com> Date: Mon, 15 Jul 2024 17:46:58 +0200 Subject: [PATCH 35/85] api-kit: Fix `BrowserProvider` import --- packages/api-kit/tests/utils/setupKits.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/api-kit/tests/utils/setupKits.ts b/packages/api-kit/tests/utils/setupKits.ts index 18f950c19..8b2137683 100644 --- a/packages/api-kit/tests/utils/setupKits.ts +++ b/packages/api-kit/tests/utils/setupKits.ts @@ -1,6 +1,6 @@ import hre from 'hardhat' -import ethers from 'ethers' import Web3 from 'web3' +import { BrowserProvider } from 'ethers' import { custom, createWalletClient } from 'viem' import Safe, { SafeProviderConfig, Eip1193Provider } from '@safe-global/protocol-kit' @@ -34,7 +34,7 @@ export function getEip1193Provider(): Eip1193Provider { return web3Provider.currentProvider as Eip1193Provider case 'ethers': - const browserProvider = new ethers.BrowserProvider(hre.network.provider) + const browserProvider = new BrowserProvider(hre.network.provider) return { request: async (request) => { From f7cc1cd70a3e2f154bb6e9ba9ed52abae6146a3e Mon Sep 17 00:00:00 2001 From: leonardotc Date: Tue, 16 Jul 2024 09:33:40 +0200 Subject: [PATCH 36/85] Fix transaction encode test --- .../onramp-kit/src/packs/monerium/SafeMoneriumClient.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/onramp-kit/src/packs/monerium/SafeMoneriumClient.test.ts b/packages/onramp-kit/src/packs/monerium/SafeMoneriumClient.test.ts index e2a778a72..c5e2b5ea2 100644 --- a/packages/onramp-kit/src/packs/monerium/SafeMoneriumClient.test.ts +++ b/packages/onramp-kit/src/packs/monerium/SafeMoneriumClient.test.ts @@ -108,7 +108,7 @@ describe('SafeMoneriumClient', () => { expect(signMessageSpy).toHaveBeenCalledTimes(1) }) - it('should allow to check if a message is signed in the smart contract if the promise is fulfilled', async () => { + it.only('should allow to check if a message is signed in the smart contract if the promise is fulfilled', async () => { const isMessageSigned = await safeMoneriumClient.isMessageSigned( '0xSafeAddress', 'message to sign' From 78979ed9f7bb3eed6c5a96b40c756d813f378fb1 Mon Sep 17 00:00:00 2001 From: leonardotc Date: Tue, 16 Jul 2024 10:40:26 +0200 Subject: [PATCH 37/85] Changed paymasterAndData --- packages/relay-kit/src/packs/safe-4337/Safe4337Pack.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.ts b/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.ts index 7aa169a60..8003fd406 100644 --- a/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.ts +++ b/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.ts @@ -1,4 +1,4 @@ -import { Address, Hash, encodeFunctionData, zeroAddress, toHex, Hex, concat } from 'viem' +import { Address, Hash, encodeFunctionData, zeroAddress, Hex, concat } from 'viem' import semverSatisfies from 'semver/functions/satisfies' import Safe, { EthSafeSignature, @@ -421,7 +421,7 @@ export class Safe4337Pack extends RelayKitBasePack<{ data: encodeFunctionData({ abi: ABI, functionName: 'approve', - args: [paymasterOptions.paymasterTokenAddress as Address, amountToApprove] + args: [paymasterOptions.paymasterAddress as Address, amountToApprove] }), value: '0', operation: OperationType.Call // Call for approve @@ -503,7 +503,7 @@ export class Safe4337Pack extends RelayKitBasePack<{ preVerificationGas: BigInt(userOperation?.preVerificationGas || 0), maxFeePerGas: BigInt(userOperation?.maxFeePerGas || 0), maxPriorityFeePerGas: BigInt(userOperation?.maxPriorityFeePerGas || 0), - paymasterAndData: toHex(concat([paymaster as Hex, paymasterData as Hex])), + paymasterAndData: concat([paymaster as Hex, paymasterData as Hex]), signature: safeOperationResponse.preparedSignature || '0x' }, { From 9ae53849d31aa01305d92d11d2f221e71b1f4537 Mon Sep 17 00:00:00 2001 From: leonardotc Date: Tue, 16 Jul 2024 11:05:00 +0200 Subject: [PATCH 38/85] Remove only on tests --- .../src/packs/monerium/SafeMoneriumClient.test.ts | 2 +- .../relay-kit/src/packs/safe-4337/Safe4337Pack.test.ts | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/onramp-kit/src/packs/monerium/SafeMoneriumClient.test.ts b/packages/onramp-kit/src/packs/monerium/SafeMoneriumClient.test.ts index c5e2b5ea2..e2a778a72 100644 --- a/packages/onramp-kit/src/packs/monerium/SafeMoneriumClient.test.ts +++ b/packages/onramp-kit/src/packs/monerium/SafeMoneriumClient.test.ts @@ -108,7 +108,7 @@ describe('SafeMoneriumClient', () => { expect(signMessageSpy).toHaveBeenCalledTimes(1) }) - it.only('should allow to check if a message is signed in the smart contract if the promise is fulfilled', async () => { + it('should allow to check if a message is signed in the smart contract if the promise is fulfilled', async () => { const isMessageSigned = await safeMoneriumClient.isMessageSigned( '0xSafeAddress', 'message to sign' diff --git a/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.test.ts b/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.test.ts index ee262113c..503d269b1 100644 --- a/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.test.ts +++ b/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.test.ts @@ -482,9 +482,9 @@ describe('Safe4337Pack', () => { abi: constants.ABI, functionName: 'executeUserOp', args: [ - transferUSDC.to as viem.Hash, + transferUSDC.to as viem.Address, BigInt(transferUSDC.value), - transferUSDC.data as viem.Hash, + transferUSDC.data as viem.Hex, OperationType.Call ] }), @@ -560,12 +560,12 @@ describe('Safe4337Pack', () => { abi: constants.ABI, functionName: 'executeUserOp', args: [ - (await safe4337Pack.protocolKit.getMultiSendAddress()) as viem.Hash, + (await safe4337Pack.protocolKit.getMultiSendAddress()) as viem.Address, 0n, viem.encodeFunctionData({ abi: constants.ABI, functionName: 'multiSend', - args: [protocolKit.encodeMultiSendData(batch) as viem.Hash] + args: [protocolKit.encodeMultiSendData(batch) as viem.Hex] }), OperationType.DelegateCall ] From ec89e7a1e74382a389ed72909102bdd821a29b09 Mon Sep 17 00:00:00 2001 From: Tim Schwarz <4171783+tmjssz@users.noreply.github.com> Date: Tue, 16 Jul 2024 11:59:20 +0200 Subject: [PATCH 39/85] api-kit: Fix `confirmSafeOperation` tests --- .../tests/e2e/addSafeOperation.test.ts | 4 ++ .../tests/e2e/confirmSafeOperation.test.ts | 38 ++++++++++++++++++- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/packages/api-kit/tests/e2e/addSafeOperation.test.ts b/packages/api-kit/tests/e2e/addSafeOperation.test.ts index 20f1edfd4..04e174bed 100644 --- a/packages/api-kit/tests/e2e/addSafeOperation.test.ts +++ b/packages/api-kit/tests/e2e/addSafeOperation.test.ts @@ -85,6 +85,10 @@ describe('addSafeOperation', () => { }) }) + after(() => { + sinon.restore() + }) + describe('should fail', () => { it('if safeAddress is empty', async () => { const safeOperation = await safe4337Pack.createTransaction({ transactions: [transferUSDC] }) diff --git a/packages/api-kit/tests/e2e/confirmSafeOperation.test.ts b/packages/api-kit/tests/e2e/confirmSafeOperation.test.ts index f12dd00d4..9961d0515 100644 --- a/packages/api-kit/tests/e2e/confirmSafeOperation.test.ts +++ b/packages/api-kit/tests/e2e/confirmSafeOperation.test.ts @@ -1,13 +1,22 @@ import chai from 'chai' import chaiAsPromised from 'chai-as-promised' -import { Safe4337InitOptions, Safe4337Pack } from '@safe-global/relay-kit' +import sinon from 'sinon' +import sinonChai from 'sinon-chai' +import { BundlerClient, Safe4337InitOptions, Safe4337Pack } from '@safe-global/relay-kit' import { generateTransferCallData } from '@safe-global/relay-kit/packs/safe-4337/testing-utils/helpers' import SafeApiKit from '@safe-global/api-kit/index' import { getAddSafeOperationProps } from '@safe-global/api-kit/utils/safeOperation' import { SafeOperation } from '@safe-global/safe-core-sdk-types' +import * as safe4337Utils from '@safe-global/relay-kit/dist/src/packs/safe-4337/utils' import { getApiKit, getEip1193Provider } from '../utils/setupKits' +import { + ENTRYPOINT_ABI, + ENTRYPOINT_ADDRESS_V06, + RPC_4337_CALLS +} from '@safe-global/relay-kit/packs/safe-4337/constants' chai.use(chaiAsPromised) +chai.use(sinonChai) const PRIVATE_KEY_1 = '0x83a415ca62e11f5fa5567e98450d0f82ae19ff36ef876c10a8d448c788a53676' const PRIVATE_KEY_2 = '0xb88ad5789871315d0dab6fc5961d6714f24f35a6393f13a6f426dfecfc00ab44' @@ -61,7 +70,30 @@ describe('confirmSafeOperation', () => { return signedSafeOperation } + const requestStub = sinon.stub() + before(async () => { + sinon.stub(safe4337Utils, 'getEip4337BundlerProvider').returns({ + request: requestStub, + readContract: sinon + .stub() + .withArgs({ + address: ENTRYPOINT_ADDRESS_V06, + abi: ENTRYPOINT_ABI, + functionName: 'getNonce', + args: [SAFE_ADDRESS, BigInt(0)] + }) + .resolves(BigInt(Date.now())) + } as unknown as BundlerClient) + + requestStub.withArgs({ method: RPC_4337_CALLS.CHAIN_ID }).resolves('0xaa36a7') + requestStub + .withArgs({ method: RPC_4337_CALLS.SUPPORTED_ENTRY_POINTS }) + .resolves([ENTRYPOINT_ADDRESS_V06]) + requestStub + .withArgs({ method: 'pimlico_getUserOperationGasPrice' }) + .resolves({ fast: { maxFeePerGas: '0x3b9aca00', maxPriorityFeePerGas: '0x3b9aca00' } }) + safe4337Pack = await getSafe4337Pack({ signer: PRIVATE_KEY_1 }) safeApiKit = getApiKit(TX_SERVICE_URL) @@ -70,6 +102,10 @@ describe('confirmSafeOperation', () => { safeOpHash = await safeOperation.getHash() }) + after(() => { + sinon.restore() + }) + describe('should fail', () => { it('if SafeOperation hash is empty', async () => { const signature = await createSignature(safeOperation, PRIVATE_KEY_2) From 25e54f78e5b4cdb7b8b1df03193484f4ef0ce669 Mon Sep 17 00:00:00 2001 From: leonardotc Date: Tue, 16 Jul 2024 15:23:35 +0200 Subject: [PATCH 40/85] Fix (or maybe not) paymaster estimation on sponsored transaction --- .../src/packs/safe-4337/Safe4337Pack.test.ts | 3 +-- .../src/packs/safe-4337/Safe4337Pack.ts | 8 ++++---- .../estimators/PimlicoFeeEstimator.ts | 20 +++++++------------ .../packs/safe-4337/testing-utils/fixtures.ts | 10 +++++----- .../relay-kit/src/packs/safe-4337/utils.ts | 6 +++--- 5 files changed, 20 insertions(+), 27 deletions(-) diff --git a/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.test.ts b/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.test.ts index 503d269b1..b943ac8cb 100644 --- a/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.test.ts +++ b/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.test.ts @@ -22,7 +22,6 @@ const requestResponseMap = { [constants.RPC_4337_CALLS.ESTIMATE_USER_OPERATION_GAS]: fixtures.GAS_ESTIMATION, [constants.RPC_4337_CALLS.GET_USER_OPERATION_BY_HASH]: fixtures.USER_OPERATION_BY_HASH, [constants.RPC_4337_CALLS.GET_USER_OPERATION_RECEIPT]: fixtures.USER_OPERATION_RECEIPT, - [constants.RPC_4337_CALLS.SPONSOR_USER_OPERATION]: fixtures.SPONSORED_GAS_ESTIMATION, ['pimlico_getUserOperationGasPrice']: fixtures.USER_OPERATION_GAS_PRICE } @@ -489,7 +488,7 @@ describe('Safe4337Pack', () => { ] }), nonce: 1n, - callGasLimit: 100000n, + callGasLimit: 150000n, validAfter: 0, validUntil: 0, maxFeePerGas: 100000n, diff --git a/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.ts b/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.ts index 8003fd406..30d935602 100644 --- a/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.ts +++ b/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.ts @@ -242,7 +242,7 @@ export class Safe4337Pack extends RelayKitBasePack<{ const batchData = encodeFunctionData({ abi: ABI, functionName: 'multiSend', - args: [encodeMultiSendData(setupBatch) as Hash] + args: [encodeMultiSendData(setupBatch) as Hex] }) const multiSendContract = await getMultiSendContract({ @@ -503,7 +503,7 @@ export class Safe4337Pack extends RelayKitBasePack<{ preVerificationGas: BigInt(userOperation?.preVerificationGas || 0), maxFeePerGas: BigInt(userOperation?.maxFeePerGas || 0), maxPriorityFeePerGas: BigInt(userOperation?.maxPriorityFeePerGas || 0), - paymasterAndData: concat([paymaster as Hex, paymasterData as Hex]), + paymasterAndData: concat([paymaster as Address, paymasterData as Hex]), signature: safeOperationResponse.preparedSignature || '0x' }, { @@ -703,9 +703,9 @@ export class Safe4337Pack extends RelayKitBasePack<{ abi: ABI, functionName: 'executeUserOp', args: [ - transaction.to as Hash, + transaction.to as Address, BigInt(transaction.value), - transaction.data as Hash, + transaction.data as Hex, transaction.operation || OperationType.Call ] }) diff --git a/packages/relay-kit/src/packs/safe-4337/estimators/PimlicoFeeEstimator.ts b/packages/relay-kit/src/packs/safe-4337/estimators/PimlicoFeeEstimator.ts index 7e23dd550..3e85eb733 100644 --- a/packages/relay-kit/src/packs/safe-4337/estimators/PimlicoFeeEstimator.ts +++ b/packages/relay-kit/src/packs/safe-4337/estimators/PimlicoFeeEstimator.ts @@ -35,20 +35,14 @@ export class PimlicoFeeEstimator implements IFeeEstimator { }: EstimateSponsoredFeeFunctionProps): Promise { const paymasterClient = getEip4337BundlerProvider(paymasterUrl) - const { paymasterAndData, callGasLimit, verificationGasLimit, preVerificationGas } = - await paymasterClient.request({ - method: RPC_4337_CALLS.SPONSOR_USER_OPERATION, - params: sponsorshipPolicyId - ? [userOperationToHexValues(userOperation), entryPoint, { sponsorshipPolicyId }] - : [userOperationToHexValues(userOperation), entryPoint] - }) + const gasEstimate = await paymasterClient.request({ + method: RPC_4337_CALLS.SPONSOR_USER_OPERATION, + params: sponsorshipPolicyId + ? [userOperationToHexValues(userOperation), entryPoint, { sponsorshipPolicyId }] + : [userOperationToHexValues(userOperation), entryPoint] + }) - return { - paymasterAndData, - callGasLimit: BigInt(callGasLimit), - verificationGasLimit: BigInt(verificationGasLimit), - preVerificationGas: BigInt(preVerificationGas) - } + return gasEstimate } async #getFeeData( diff --git a/packages/relay-kit/src/packs/safe-4337/testing-utils/fixtures.ts b/packages/relay-kit/src/packs/safe-4337/testing-utils/fixtures.ts index ba63f9d53..9b9f3c016 100644 --- a/packages/relay-kit/src/packs/safe-4337/testing-utils/fixtures.ts +++ b/packages/relay-kit/src/packs/safe-4337/testing-utils/fixtures.ts @@ -20,7 +20,7 @@ export const PAYMASTER_URL = 'https://paymaster.url' export const USER_OPERATION_HASH = '0x3cb881d1969036174f38d636d22108d1d032145518b53104fc0b1e1296d2cc9c' -export const ENTRYPOINTS = [ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07] as const +export const ENTRYPOINTS = [ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07] export const USER_OPERATION_RECEIPT = { userOpHash: '0x3cb881d1969036174f38d636d22108d1d032145518b53104fc0b1e1296d2cc9c', @@ -89,9 +89,9 @@ export const USER_OPERATION_BY_HASH = { } export const GAS_ESTIMATION = { - verificationGasLimit: 100000n, - preVerificationGas: 100000n, - callGasLimit: 100000n + verificationGasLimit: '0x186A0', + preVerificationGas: '0x186A0', + callGasLimit: '0x186A0' } export const SAFE_OPERATION_RESPONSE = { @@ -140,5 +140,5 @@ export const SPONSORED_GAS_ESTIMATION = { } export const USER_OPERATION_GAS_PRICE = { - fast: { maxFeePerGas: 100000n, maxPriorityFeePerGas: 200000n } + fast: { maxFeePerGas: '0x186A0', maxPriorityFeePerGas: '0x30D40' } } diff --git a/packages/relay-kit/src/packs/safe-4337/utils.ts b/packages/relay-kit/src/packs/safe-4337/utils.ts index 29b63243b..8b756447f 100644 --- a/packages/relay-kit/src/packs/safe-4337/utils.ts +++ b/packages/relay-kit/src/packs/safe-4337/utils.ts @@ -1,6 +1,6 @@ import { Address, - Hash, + Hex, PublicRpcSchema, createPublicClient, encodeFunctionData, @@ -95,7 +95,7 @@ export function encodeMultiSendCallData(transactions: MetaTransactionData[]): st args: [ encodeMultiSendData( transactions.map((tx) => ({ ...tx, operation: tx.operation ?? OperationType.Call })) - ) as Hash + ) as Hex ] }) } @@ -166,7 +166,7 @@ export function addDummySignature( ...userOperation, signature: encodePacked( ['uint48', 'uint48', 'bytes'], - [0, 0, buildSignatureBytes(signatures) as Hash] + [0, 0, buildSignatureBytes(signatures) as Hex] ) } } From a04a860a12abbbfe9deac8ecb86bd0d9b8a6ba2a Mon Sep 17 00:00:00 2001 From: leonardotc Date: Tue, 16 Jul 2024 17:17:38 +0200 Subject: [PATCH 41/85] Fix gas estimation issue --- .../packs/safe-4337/estimators/PimlicoFeeEstimator.test.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/relay-kit/src/packs/safe-4337/estimators/PimlicoFeeEstimator.test.ts b/packages/relay-kit/src/packs/safe-4337/estimators/PimlicoFeeEstimator.test.ts index 5335b86dd..401097fd2 100644 --- a/packages/relay-kit/src/packs/safe-4337/estimators/PimlicoFeeEstimator.test.ts +++ b/packages/relay-kit/src/packs/safe-4337/estimators/PimlicoFeeEstimator.test.ts @@ -32,9 +32,10 @@ describe('PimlicoFeeEstimator', () => { entryPoint: fixtures.ENTRYPOINTS[0] }) - expect(sponsoredGasEstimation).toEqual(fixtures.USER_OPERATION_GAS_PRICE.fast) + expect(sponsoredGasEstimation).toEqual({ maxFeePerGas: 100000n, maxPriorityFeePerGas: 200000n }) }) + // TODO: This tests breaks because of the BigInt serialization and requires further investigation it('should enable to adjust the gas estimation', async () => { const sponsoredGasEstimation = await estimator.adjustEstimation({ bundlerUrl: fixtures.BUNDLER_URL, @@ -43,8 +44,9 @@ describe('PimlicoFeeEstimator', () => { }) expect(sponsoredGasEstimation).toEqual({ + callGasLimit: 181_176n, verificationGasLimit: 124_584n, - callGasLimit: 181_176n + preVerificationGas: 50_996n }) }) From 9e16f42b1c6891e30f30dd8c5218a333c51a0dca Mon Sep 17 00:00:00 2001 From: Daniel <25051234+dasanra@users.noreply.github.com> Date: Wed, 17 Jul 2024 09:27:08 +0200 Subject: [PATCH 42/85] chore: remove deprecated ethereum utils lib (#884) * chore: remove deprecated ethereum utils lib * remove @noble/hashes as direct dependency --- packages/protocol-kit/package.json | 6 +- packages/protocol-kit/src/contracts/utils.ts | 85 ++++++++++--------- .../src/utils/signatures/utils.ts | 37 ++++---- .../createSafeDeploymentTransaction.test.ts | 4 +- .../tests/e2e/utilsSignatures.test.ts | 26 +++--- yarn.lock | 27 +----- 6 files changed, 82 insertions(+), 103 deletions(-) diff --git a/packages/protocol-kit/package.json b/packages/protocol-kit/package.json index b80f3f251..f4e2d5a6f 100644 --- a/packages/protocol-kit/package.json +++ b/packages/protocol-kit/package.json @@ -66,17 +66,15 @@ "mocha": "^10.2.0", "nyc": "^15.1.0", "tsconfig-paths": "^4.2.0", - "viem": "^2.15.1", "web3": "^4.7.0", "yargs": "^17.7.2" }, "dependencies": { - "@noble/hashes": "^1.3.3", "@safe-global/safe-core-sdk-types": "^5.0.2", "@safe-global/safe-deployments": "^1.37.0", "abitype": "^1.0.2", - "ethereumjs-util": "^7.1.5", "ethers": "^6.13.1", - "semver": "^7.6.2" + "semver": "^7.6.2", + "viem": "^2.15.1" } } diff --git a/packages/protocol-kit/src/contracts/utils.ts b/packages/protocol-kit/src/contracts/utils.ts index 1bcbba4fe..1b605c82f 100644 --- a/packages/protocol-kit/src/contracts/utils.ts +++ b/packages/protocol-kit/src/contracts/utils.ts @@ -1,5 +1,14 @@ -import { Hash, isAddress, PublicClient, WalletClient, pad } from 'viem' -import { keccak_256 } from '@noble/hashes/sha3' +import { + concat, + getContractAddress, + Hash, + isAddress, + keccak256, + pad, + PublicClient, + toHex, + WalletClient +} from 'viem' import { DEFAULT_SAFE_VERSION } from '@safe-global/protocol-kit/contracts/config' import { EMPTY_DATA, ZERO_ADDRESS } from '@safe-global/protocol-kit/utils/constants' import { createMemoizedFunction } from '@safe-global/protocol-kit/utils/memoized' @@ -9,7 +18,6 @@ import { TransactionOptions, TransactionResult } from '@safe-global/safe-core-sdk-types' -import { generateAddress2, keccak256, toBuffer } from 'ethereumjs-util' import semverSatisfies from 'semver/functions/satisfies' import { asAddress, asHex } from '../utils/types' import { @@ -240,7 +248,7 @@ const memoizedGetSafeContract = createMemoizedFunction( * @returns {string} The chain-specific salt nonce in hexadecimal format. */ export function getChainSpecificDefaultSaltNonce(chainId: bigint): string { - return `0x${Buffer.from(keccak_256(PREDETERMINED_SALT_NONCE + chainId)).toString('hex')}` + return keccak256(toHex(PREDETERMINED_SALT_NONCE + chainId)) } export async function getPredictedSafeAddressInitCode({ @@ -282,15 +290,13 @@ export async function getPredictedSafeAddressInitCode({ customSafeVersion: safeVersion // it is more efficient if we provide the safeVersion manually }) - const encodedNonce = toBuffer(safeProvider.encodeParameters('uint256', [saltNonce])).toString( - 'hex' - ) + const encodedNonce = safeProvider.encodeParameters('uint256', [saltNonce]) const safeSingletonAddress = await safeContract.getAddress() const initCodeCallData = encodeCreateProxyWithNonce( safeProxyFactoryContract, safeSingletonAddress, initializer, - '0x' + encodedNonce + encodedNonce ) const safeProxyFactoryAddress = await safeProxyFactoryContract.getAddress() const initCode = `0x${[safeProxyFactoryAddress, initCodeCallData].reduce( @@ -339,24 +345,24 @@ export async function predictSafeAddress({ chainId: chainId.toString() }) - const initializer = await encodeSetupCallData({ + const initializer = (await encodeSetupCallData({ safeProvider, safeAccountConfig, safeContract, customContracts, customSafeVersion: safeVersion // it is more efficient if we provide the safeVersion manually - }) + })) as `0x${string}` + const initializerHash = keccak256(initializer) - const encodedNonce = toBuffer(safeProvider.encodeParameters('uint256', [saltNonce])).toString( - 'hex' - ) - const salt = keccak256( - toBuffer('0x' + keccak256(toBuffer(initializer)).toString('hex') + encodedNonce) - ) + const encodedNonce = safeProvider.encodeParameters('uint256', [saltNonce]) as `0x${string}` + + const salt = keccak256(concat([initializerHash, encodedNonce])) - const input = safeProvider.encodeParameters('address', [await safeContract.getAddress()]) + const input = safeProvider.encodeParameters('address', [ + await safeContract.getAddress() + ]) as `0x${string}` - const from = await safeProxyFactoryContract.getAddress() + const from = (await safeProxyFactoryContract.getAddress()) as `0x${string}` // On the zkSync Era chain, the counterfactual deployment address is calculated differently const isZkSyncEraChain = [ZKSYNC_MAINNET, ZKSYNC_TESTNET].includes(chainId) @@ -366,10 +372,14 @@ export async function predictSafeAddress({ return safeProvider.getChecksummedAddress(proxyAddress) } - const constructorData = toBuffer(input).toString('hex') - const initCode = proxyCreationCode + constructorData - const proxyAddress = - '0x' + generateAddress2(toBuffer(from), toBuffer(salt), toBuffer(initCode)).toString('hex') + const initCode = (proxyCreationCode + input.slice(2)) as `0x${string}` + + const proxyAddress = getContractAddress({ + from, + bytecode: initCode, + opcode: 'CREATE2', + salt + }) return safeProvider.getChecksummedAddress(proxyAddress) } @@ -388,35 +398,28 @@ export const validateSafeDeploymentConfig = ({ saltNonce }: SafeDeploymentConfig /** * Generates a zkSync Era address. zkSync Era uses a distinct address derivation method compared to Ethereum - * see: https://era.zksync.io/docs/reference/architecture/differences-with-ethereum.html#address-derivation + * see: https://docs.zksync.io/build/developer-reference/ethereum-differences/evm-instructions/#address-derivation * - * @param {string} from - The sender's address. + * @param {`0x${string}`} from - The sender's address. * @param {SafeVersion} safeVersion - The version of the safe. - * @param {Buffer} salt - The salt used for address derivation. - * @param {string} input - Additional input data for the derivation. + * @param {`0x${string}`} salt - The salt used for address derivation. + * @param {`0x${string}`} input - Additional input data for the derivation. * * @returns {string} The derived zkSync Era address. */ export function zkSyncEraCreate2Address( - from: string, + from: `0x${string}`, safeVersion: SafeVersion, - salt: Buffer, - input: string + salt: `0x${string}`, + input: `0x${string}` ): string { - const bytecodeHash = ZKSYNC_SAFE_PROXY_DEPLOYED_BYTECODE[safeVersion].deployedBytecodeHash - const inputHash = keccak256(toBuffer(input)) + const bytecodeHash = ZKSYNC_SAFE_PROXY_DEPLOYED_BYTECODE[safeVersion] + .deployedBytecodeHash as `0x${string}` + const inputHash = keccak256(input) const addressBytes = keccak256( - toBuffer( - ZKSYNC_CREATE2_PREFIX + - pad(asHex(from), { size: 32 }).slice(2) + - salt.toString('hex') + - bytecodeHash.slice(2) + - inputHash.toString('hex') - ) - ) - .toString('hex') - .slice(24) + concat([ZKSYNC_CREATE2_PREFIX, pad(from), salt, bytecodeHash, inputHash]) + ).slice(26) return addressBytes } diff --git a/packages/protocol-kit/src/utils/signatures/utils.ts b/packages/protocol-kit/src/utils/signatures/utils.ts index fc08681cf..202388bcd 100644 --- a/packages/protocol-kit/src/utils/signatures/utils.ts +++ b/packages/protocol-kit/src/utils/signatures/utils.ts @@ -1,10 +1,10 @@ +import { recoverAddress } from 'viem' import SafeProvider from '@safe-global/protocol-kit/SafeProvider' import { SafeSignature, SafeEIP712Args, SafeTransactionData } from '@safe-global/safe-core-sdk-types' -import { bufferToHex, ecrecover, pubToAddress } from 'ethereumjs-util' import semverSatisfies from 'semver/functions/satisfies' import { sameString } from '../address' import { EthSafeSignature } from './SafeSignature' @@ -23,25 +23,18 @@ export function generatePreValidatedSignature(ownerAddress: string): SafeSignatu return new EthSafeSignature(ownerAddress, signature) } -export function isTxHashSignedWithPrefix( +export async function isTxHashSignedWithPrefix( txHash: string, signature: string, ownerAddress: string -): boolean { +): Promise { let hasPrefix try { - const rsvSig = { - r: Buffer.from(signature.slice(2, 66), 'hex'), - s: Buffer.from(signature.slice(66, 130), 'hex'), - v: parseInt(signature.slice(130, 132), 16) - } - const recoveredData = ecrecover( - Buffer.from(txHash.slice(2), 'hex'), - rsvSig.v, - rsvSig.r, - rsvSig.s - ) - const recoveredAddress = bufferToHex(pubToAddress(recoveredData)) + const recoveredAddress = await recoverAddress({ + hash: txHash as `0x${string}`, + signature: signature as `0x${string}` + }) + hasPrefix = !sameString(recoveredAddress, ownerAddress) } catch (e) { hasPrefix = true @@ -50,21 +43,21 @@ export function isTxHashSignedWithPrefix( } type AdjustVOverload = { - (signingMethod: SigningMethod.ETH_SIGN_TYPED_DATA, signature: string): string + (signingMethod: SigningMethod.ETH_SIGN_TYPED_DATA, signature: string): Promise ( signingMethod: SigningMethod.ETH_SIGN, signature: string, safeTxHash: string, sender: string - ): string + ): Promise } -export const adjustVInSignature: AdjustVOverload = ( +export const adjustVInSignature: AdjustVOverload = async ( signingMethod: SigningMethod.ETH_SIGN | SigningMethod.ETH_SIGN_TYPED_DATA, signature: string, safeTxHash?: string, signerAddress?: string -): string => { +): Promise => { const ETHEREUM_V_VALUES = [0, 1, 27, 28] const MIN_VALID_V_VALUE_FOR_SAFE_ECDSA = 27 let signatureV = parseInt(signature.slice(-2), 16) @@ -87,7 +80,7 @@ export const adjustVInSignature: AdjustVOverload = ( signatureV += MIN_VALID_V_VALUE_FOR_SAFE_ECDSA } const adjustedSignature = signature.slice(0, -2) + signatureV.toString(16) - const signatureHasPrefix = isTxHashSignedWithPrefix( + const signatureHasPrefix = await isTxHashSignedWithPrefix( safeTxHash as string, adjustedSignature, signerAddress as string @@ -117,7 +110,7 @@ export async function generateSignature( let signature = await safeProvider.signMessage(hash) - signature = adjustVInSignature(SigningMethod.ETH_SIGN, signature, hash, signerAddress) + signature = await adjustVInSignature(SigningMethod.ETH_SIGN, signature, hash, signerAddress) return new EthSafeSignature(signerAddress, signature) } @@ -134,7 +127,7 @@ export async function generateEIP712Signature( //@ts-expect-error: Evaluate removal of methodVersion and use v4 let signature = await safeProvider.signTypedData(safeEIP712Args, methodVersion) - signature = adjustVInSignature(SigningMethod.ETH_SIGN_TYPED_DATA, signature) + signature = await adjustVInSignature(SigningMethod.ETH_SIGN_TYPED_DATA, signature) return new EthSafeSignature(signerAddress, signature) } diff --git a/packages/protocol-kit/tests/e2e/createSafeDeploymentTransaction.test.ts b/packages/protocol-kit/tests/e2e/createSafeDeploymentTransaction.test.ts index a7e0c0568..b3eee32bf 100644 --- a/packages/protocol-kit/tests/e2e/createSafeDeploymentTransaction.test.ts +++ b/packages/protocol-kit/tests/e2e/createSafeDeploymentTransaction.test.ts @@ -1,7 +1,7 @@ import chai from 'chai' import chaiAsPromised from 'chai-as-promised' import { deployments } from 'hardhat' -import { keccak_256 } from '@noble/hashes/sha3' +import { keccak256, toHex } from 'viem' import { safeVersionDeployed } from '@safe-global/protocol-kit/hardhat/deploy/deploy-contracts' import Safe, { PREDETERMINED_SALT_NONCE, @@ -190,7 +190,7 @@ describe('createSafeDeploymentTransaction', () => { }) const predeterminedSaltNonceEncoded = safeProvider.encodeParameters('uint256', [ - `0x${Buffer.from(keccak_256(PREDETERMINED_SALT_NONCE + chainId)).toString('hex')}` + keccak256(toHex(PREDETERMINED_SALT_NONCE + chainId)) ]) const deploymentTransaction = await safeSdk.createSafeDeploymentTransaction() diff --git a/packages/protocol-kit/tests/e2e/utilsSignatures.test.ts b/packages/protocol-kit/tests/e2e/utilsSignatures.test.ts index e7f7d038d..66a166162 100644 --- a/packages/protocol-kit/tests/e2e/utilsSignatures.test.ts +++ b/packages/protocol-kit/tests/e2e/utilsSignatures.test.ts @@ -10,47 +10,53 @@ const signerAddress = '0xbc2BB26a6d821e69A38016f3858561a1D80d4182' describe('Signature utils', () => { describe('isTxHashSignedWithPrefix', () => { - it('returns false if message was signed without a prefix', () => { + it('returns false if message was signed without a prefix', async () => { const ownerAddress = '0xbc2BB26a6d821e69A38016f3858561a1D80d4182' const signature = '0x12f8d73b47a0a664294caac0bd6ccf03a0d1d3d1943bdd138a9757f993cb4f7c432f029873af8ad898d3f83a8a42f765628f36d39a01c90708ce5bd6d77a269d1b' - chai.expect(isTxHashSignedWithPrefix(safeTxHash, signature, ownerAddress)).to.be.false + chai.expect(await isTxHashSignedWithPrefix(safeTxHash, signature, ownerAddress)).to.be.false }) - it('returns true if message was signed with a prefix', () => { + it('returns true if message was signed with a prefix', async () => { const ownerAddress = '0xa088642a83BF49189d5160e2632392949Bb4296D' const signature = '0x4d44abdcc39e259238870493c29d26fbe14b0564afe2b25326311ddc397cff8d4014e09a2a296efb2dc0231c622289e015d0cbd469ae67d509675e6112bd0b061b' - chai.expect(isTxHashSignedWithPrefix(safeTxHash, signature, ownerAddress)).to.be.true + chai.expect(await isTxHashSignedWithPrefix(safeTxHash, signature, ownerAddress)).to.be.true }) }) describe('adjustVInSignature', () => { - it('eth_sign: adjusts V to V > 30 when message is signed with a prefix', () => { + it('eth_sign: adjusts V to V > 30 when message is signed with a prefix', async () => { const hex27 = '1b' const hex31 = '1f' const signature = `0x4d44abdcc39e259238870493c29d26fbe14b0564afe2b25326311ddc397cff8d4014e09a2a296efb2dc0231c622289e015d0cbd469ae67d509675e6112bd0b06${hex27}` const adjustedSignature = `0x4d44abdcc39e259238870493c29d26fbe14b0564afe2b25326311ddc397cff8d4014e09a2a296efb2dc0231c622289e015d0cbd469ae67d509675e6112bd0b06${hex31}` chai - .expect(adjustVInSignature(SigningMethod.ETH_SIGN, signature, safeTxHash, signerAddress)) + .expect( + await adjustVInSignature(SigningMethod.ETH_SIGN, signature, safeTxHash, signerAddress) + ) .to.be.eq(adjustedSignature) }) - it('eth_sign: adjusts V to V > 30 when message is signed with a prefix and V < 27', () => { + it('eth_sign: adjusts V to V > 30 when message is signed with a prefix and V < 27', async () => { const hex01 = '01' const hex32 = '20' const signature = `0x4d44abdcc39e259238870493c29d26fbe14b0564afe2b25326311ddc397cff8d4014e09a2a296efb2dc0231c622289e015d0cbd469ae67d509675e6112bd0b06${hex01}` const adjustedSignature = `0x4d44abdcc39e259238870493c29d26fbe14b0564afe2b25326311ddc397cff8d4014e09a2a296efb2dc0231c622289e015d0cbd469ae67d509675e6112bd0b06${hex32}` chai - .expect(adjustVInSignature(SigningMethod.ETH_SIGN, signature, safeTxHash, signerAddress)) + .expect( + await adjustVInSignature(SigningMethod.ETH_SIGN, signature, safeTxHash, signerAddress) + ) .to.be.eq(adjustedSignature) }) - it("eth_sign: doesn't touch V when message is signed without a prefix and V is one of {27, 28}", () => { + it("eth_sign: doesn't touch V when message is signed without a prefix and V is one of {27, 28}", async () => { const hex27 = '1b' const signature = `0x12f8d73b47a0a664294caac0bd6ccf03a0d1d3d1943bdd138a9757f993cb4f7c432f029873af8ad898d3f83a8a42f765628f36d39a01c90708ce5bd6d77a269d${hex27}` chai - .expect(adjustVInSignature(SigningMethod.ETH_SIGN, signature, safeTxHash, signerAddress)) + .expect( + await adjustVInSignature(SigningMethod.ETH_SIGN, signature, safeTxHash, signerAddress) + ) .to.be.eq(signature) }) }) diff --git a/yarn.lock b/yarn.lock index cf973a9b8..7b812138e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1295,7 +1295,7 @@ resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.4.0.tgz#45814aa329f30e4fe0ba49426f49dfccdd066426" integrity sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg== -"@noble/hashes@^1.3.1", "@noble/hashes@^1.3.3", "@noble/hashes@~1.3.0", "@noble/hashes@~1.3.1", "@noble/hashes@~1.3.2": +"@noble/hashes@^1.3.1", "@noble/hashes@~1.3.0", "@noble/hashes@~1.3.1", "@noble/hashes@~1.3.2": version "1.3.3" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.3.tgz#39908da56a4adc270147bb07968bf3b16cfe1699" integrity sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA== @@ -3114,7 +3114,7 @@ bn.js@^4.11.0, bn.js@^4.11.8, bn.js@^4.11.9: resolved "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz" integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== -bn.js@^5.1.2, bn.js@^5.2.0, bn.js@^5.2.1: +bn.js@^5.2.0, bn.js@^5.2.1: version "5.2.1" resolved "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz" integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== @@ -4409,17 +4409,6 @@ ethereumjs-util@^6.0.0, ethereumjs-util@^6.2.1: ethjs-util "0.1.6" rlp "^2.2.3" -ethereumjs-util@^7.1.5: - version "7.1.5" - resolved "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz" - integrity sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg== - dependencies: - "@types/bn.js" "^5.1.0" - bn.js "^5.1.2" - create-hash "^1.1.2" - ethereum-cryptography "^0.1.3" - rlp "^2.2.4" - ethers@6.7.0: version "6.7.0" resolved "https://registry.npmjs.org/ethers/-/ethers-6.7.0.tgz" @@ -8477,7 +8466,7 @@ ripemd160@^2.0.0, ripemd160@^2.0.1: hash-base "^3.0.0" inherits "^2.0.1" -rlp@^2.2.3, rlp@^2.2.4: +rlp@^2.2.3: version "2.2.7" resolved "https://registry.npmjs.org/rlp/-/rlp-2.2.7.tgz" integrity sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ== @@ -10015,16 +10004,6 @@ ws@8.17.1, ws@^8.11.0, ws@^8.5.0, ws@^8.8.1: resolved "https://registry.yarnpkg.com/ws/-/ws-8.17.1.tgz#9293da530bb548febc95371d90f9c878727d919b" integrity sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ== -ws@8.17.1: - version "8.17.1" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.17.1.tgz#9293da530bb548febc95371d90f9c878727d919b" - integrity sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ== - -ws@8.17.1: - version "8.17.1" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.17.1.tgz#9293da530bb548febc95371d90f9c878727d919b" - integrity sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ== - ws@8.5.0: version "8.5.0" resolved "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz" From 4f074f2b165dcff317f2ebc02726b004bd206ffd Mon Sep 17 00:00:00 2001 From: leonardotc Date: Wed, 17 Jul 2024 10:53:05 +0200 Subject: [PATCH 43/85] Remove ethers from safe-kit --- .../src/contracts/BaseContract.ts | 13 +-- packages/protocol-kit/src/contracts/utils.ts | 53 ------------ packages/protocol-kit/src/types/contracts.ts | 19 +---- .../src/utils/transactions/types.ts | 18 ++++ .../src/utils/transactions/utils.ts | 82 +++++++++++++++++-- .../safe-kit/src/utils/sendTransaction.ts | 59 ++++++++++--- 6 files changed, 148 insertions(+), 96 deletions(-) diff --git a/packages/protocol-kit/src/contracts/BaseContract.ts b/packages/protocol-kit/src/contracts/BaseContract.ts index 10c42910b..379ba347b 100644 --- a/packages/protocol-kit/src/contracts/BaseContract.ts +++ b/packages/protocol-kit/src/contracts/BaseContract.ts @@ -20,8 +20,11 @@ import { TransactionOptions } from '@safe-global/safe-core-sdk-types' import { asAddress } from '../utils/types' -import { ContractTransactionOptions, ContractLegacyTransactionOptions } from '../types/contracts' -import { isLegacyTransaction, createTxOptions, createLegacyTxOptions } from './utils' +import { + WalletTransactionOptions, + WalletLegacyTransactionOptions, + converTransactionOptions +} from '@safe-global/protocol-kit/utils' /** * Abstract class BaseContract @@ -110,14 +113,12 @@ class BaseContract { async convertOptions( options?: TransactionOptions - ): Promise { + ): Promise { const chain = this.getChain() if (!chain) throw new Error('Invalid chainId') const signerAddress = await this.safeProvider.getSignerAddress() const account = asAddress(signerAddress!) - const txOptions = isLegacyTransaction(options) - ? createLegacyTxOptions(options) - : createTxOptions(options) + const txOptions = await converTransactionOptions(options) return { chain, account, ...txOptions } // Needs to be in this order to override the `account` if necessary } diff --git a/packages/protocol-kit/src/contracts/utils.ts b/packages/protocol-kit/src/contracts/utils.ts index 1b605c82f..b14797752 100644 --- a/packages/protocol-kit/src/contracts/utils.ts +++ b/packages/protocol-kit/src/contracts/utils.ts @@ -34,7 +34,6 @@ import { SafeDeploymentConfig } from '../types' import SafeProvider from '@safe-global/protocol-kit/SafeProvider' -import { ContractLegacyTransactionOptions, ContractTransactionOptions } from '../types' // keccak256(toUtf8Bytes('Safe Account Abstraction')) export const PREDETERMINED_SALT_NONCE = @@ -95,58 +94,6 @@ const memoizedGetCompatibilityFallbackHandlerContract = createMemoizedFunction( getCompatibilityFallbackHandlerContract ) -export function isLegacyTransaction(options?: TransactionOptions) { - return !!options?.gasPrice -} - -export function createLegacyTxOptions( - options?: TransactionOptions -): Partial { - const converted: Partial = {} - if (options?.from) { - converted.account = asAddress(options.from) - } - - if (options?.gasLimit) { - converted.gas = BigInt(options.gasLimit) - } - - if (options?.gasPrice) { - converted.gasPrice = BigInt(options.gasPrice) - } - - if (options?.nonce) { - converted.nonce = options.nonce - } - - return converted -} - -export function createTxOptions(options?: TransactionOptions): Partial { - const converted: Partial = {} - if (options?.from) { - converted.account = asAddress(options.from) - } - - if (options?.gasLimit) { - converted.gas = BigInt(options.gasLimit) - } - - if (options?.maxFeePerGas) { - converted.maxFeePerGas = BigInt(options.maxFeePerGas) - } - - if (options?.maxPriorityFeePerGas) { - converted.maxPriorityFeePerGas = BigInt(options.maxPriorityFeePerGas) - } - - if (options?.nonce) { - converted.nonce = options.nonce - } - - return converted -} - export async function encodeSetupCallData({ safeProvider, safeAccountConfig, diff --git a/packages/protocol-kit/src/types/contracts.ts b/packages/protocol-kit/src/types/contracts.ts index 258386ea9..41f7771b6 100644 --- a/packages/protocol-kit/src/types/contracts.ts +++ b/packages/protocol-kit/src/types/contracts.ts @@ -1,4 +1,4 @@ -import { Abi, Address, Chain } from 'viem' +import { Abi } from 'viem' import { SafeVersion } from '@safe-global/safe-core-sdk-types' import SafeContract_v1_0_0 from '@safe-global/protocol-kit/contracts/Safe/v1.0.0/SafeContract_v1_0_0' import SafeContract_v1_1_1 from '@safe-global/protocol-kit/contracts/Safe/v1.1.1/SafeContract_v1_1_1' @@ -115,20 +115,3 @@ export type ContractNetworksConfig = { /** id - Network id */ [id: string]: ContractNetworkConfig } - -export type ContractTransactionOptions = { - chain: Chain - account: Address - gas?: bigint - maxFeePerGas?: bigint - maxPriorityFeePerGas?: bigint - nonce?: number -} - -export type ContractLegacyTransactionOptions = { - chain: Chain - account: Address - gas?: bigint - gasPrice?: bigint - nonce?: number -} diff --git a/packages/protocol-kit/src/utils/transactions/types.ts b/packages/protocol-kit/src/utils/transactions/types.ts index b73233ee2..19994fc52 100644 --- a/packages/protocol-kit/src/utils/transactions/types.ts +++ b/packages/protocol-kit/src/utils/transactions/types.ts @@ -1,6 +1,24 @@ import { SafeTransactionDataPartial } from '@safe-global/safe-core-sdk-types' +import { Chain, Address } from 'viem' export type SafeTransactionOptionalProps = Pick< SafeTransactionDataPartial, 'safeTxGas' | 'baseGas' | 'gasPrice' | 'gasToken' | 'refundReceiver' | 'nonce' > + +export type WalletTransactionOptions = { + chain: Chain + account: Address + gas?: bigint + maxFeePerGas?: bigint + maxPriorityFeePerGas?: bigint + nonce?: number +} + +export type WalletLegacyTransactionOptions = { + chain: Chain + account: Address + gas?: bigint + gasPrice?: bigint + nonce?: number +} diff --git a/packages/protocol-kit/src/utils/transactions/utils.ts b/packages/protocol-kit/src/utils/transactions/utils.ts index d225c6a0c..2f1b67414 100644 --- a/packages/protocol-kit/src/utils/transactions/utils.ts +++ b/packages/protocol-kit/src/utils/transactions/utils.ts @@ -1,4 +1,3 @@ -import { toBytes, getAddress, encodePacked, bytesToHex, decodeFunctionData, parseAbi } from 'viem' import SafeProvider from '@safe-global/protocol-kit/SafeProvider' import { DEFAULT_SAFE_VERSION } from '@safe-global/protocol-kit/contracts/config' import { StandardizeSafeTransactionDataProps } from '@safe-global/protocol-kit/types' @@ -12,17 +11,26 @@ import { SafeTransaction, SafeTransactionData, SafeTransactionDataPartial, - SafeVersion + SafeVersion, + TransactionOptions } from '@safe-global/safe-core-sdk-types' import semverSatisfies from 'semver/functions/satisfies' import { estimateGas, estimateTxGas } from './gas' -import { PublicClient, Hash, EstimateGasParameters, TransactionRequest, UnionOmit } from 'viem' -import { SafeProviderTransaction } from '@safe-global/protocol-kit/types' import { - isLegacyTransaction, - createLegacyTxOptions, - createTxOptions -} from '@safe-global/protocol-kit/contracts/utils' + PublicClient, + Hash, + EstimateGasParameters, + TransactionRequest, + UnionOmit, + toBytes, + getAddress, + encodePacked, + bytesToHex, + decodeFunctionData, + parseAbi +} from 'viem' +import { SafeProviderTransaction } from '@safe-global/protocol-kit/types' +import { WalletLegacyTransactionOptions, WalletTransactionOptions } from './types' export function standardizeMetaTransactionData( tx: SafeTransactionDataPartial @@ -216,3 +224,61 @@ export function toCallGasParameters( return params } + +export function converTransactionOptions( + options?: TransactionOptions +): Partial { + return isLegacyTransaction(options) ? createLegacyTxOptions(options) : createTxOptions(options) +} + +export function isLegacyTransaction(options?: TransactionOptions) { + return !!options?.gasPrice +} + +export function createLegacyTxOptions( + options?: TransactionOptions +): Partial { + const converted: Partial = {} + if (options?.from) { + converted.account = asAddress(options.from) + } + + if (options?.gasLimit) { + converted.gas = BigInt(options.gasLimit) + } + + if (options?.gasPrice) { + converted.gasPrice = BigInt(options.gasPrice) + } + + if (options?.nonce) { + converted.nonce = options.nonce + } + + return converted +} + +export function createTxOptions(options?: TransactionOptions): Partial { + const converted: Partial = {} + if (options?.from) { + converted.account = asAddress(options.from) + } + + if (options?.gasLimit) { + converted.gas = BigInt(options.gasLimit) + } + + if (options?.maxFeePerGas) { + converted.maxFeePerGas = BigInt(options.maxFeePerGas) + } + + if (options?.maxPriorityFeePerGas) { + converted.maxPriorityFeePerGas = BigInt(options.maxPriorityFeePerGas) + } + + if (options?.nonce) { + converted.nonce = options.nonce + } + + return converted +} diff --git a/packages/safe-kit/src/utils/sendTransaction.ts b/packages/safe-kit/src/utils/sendTransaction.ts index ed1ff1be2..a63a81b55 100644 --- a/packages/safe-kit/src/utils/sendTransaction.ts +++ b/packages/safe-kit/src/utils/sendTransaction.ts @@ -1,7 +1,6 @@ import Safe from '@safe-global/protocol-kit' import { TransactionBase, TransactionOptions } from '@safe-global/safe-core-sdk-types' -import { AbstractSigner } from 'ethers' - +import { Address, WalletClient, Transport, Chain, Hex } from 'viem' /** * Sends a transaction using the signer (owner) * It's useful to deploy Safe accounts @@ -10,22 +9,60 @@ import { AbstractSigner } from 'ethers' * @param {TransactionOptions} options Options for executing the transaction. * @param {Safe} protocolKit The protocolKit instance * @returns {Promise} A promise that resolves with the transaction hash + * @throws */ export const sendTransaction = async ( transaction: TransactionBase, options: TransactionOptions, protocolKit: Safe ): Promise => { - const signer = (await protocolKit - .getSafeProvider() - .getExternalSigner()) as unknown as AbstractSigner - const txResponsePromise = await signer.sendTransaction({ - from: (await protocolKit.getSafeProvider().getSignerAddress()) || '0x', - ...transaction, - ...options + const signer = (await protocolKit.getSafeProvider().getExternalSigner()) as WalletClient< + Transport, + Chain + > + const client = await protocolKit.getSafeProvider().getExternalProvider() + + const account = (await protocolKit.getSafeProvider().getSignerAddress()) || '0x' + if (!signer) + throw new Error('SafeProvider must be initialized with a signer to use this function') + const hash = await signer.sendTransaction({ + account: account as Address, + to: transaction.to as Address, + data: transaction.data as Hex, + value: BigInt(transaction.value), + ...createLegacyTxOptions(options) }) - const txResponse = await txResponsePromise.wait() + const receipt = await client.waitForTransactionReceipt({ hash }) + + return receipt.transactionHash +} + +export function createLegacyTxOptions(options?: TransactionOptions) { + const converted: any = {} + if (options?.from) { + converted.account = options.from as Address + } + + if (options?.gasLimit) { + converted.gas = BigInt(options.gasLimit) + } + + if (options?.gasPrice) { + converted.gasPrice = BigInt(options.gasPrice) + } + + if (options?.nonce) { + converted.nonce = options.nonce + } + + if (options?.maxFeePerGas) { + converted.maxFeePerGas = BigInt(options.maxFeePerGas) + } + + if (options?.maxPriorityFeePerGas) { + converted.maxPriorityFeePerGas = BigInt(options.maxPriorityFeePerGas) + } - return txResponse?.hash + return converted } From e926eba52c7e52d0f791fb578f1111f1d9e46a61 Mon Sep 17 00:00:00 2001 From: leonardotc Date: Wed, 17 Jul 2024 11:03:46 +0200 Subject: [PATCH 44/85] Minor PR changes --- packages/protocol-kit/src/contracts/utils.ts | 25 ++++++++----------- .../src/utils/signatures/utils.ts | 8 +++--- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/packages/protocol-kit/src/contracts/utils.ts b/packages/protocol-kit/src/contracts/utils.ts index b14797752..540283266 100644 --- a/packages/protocol-kit/src/contracts/utils.ts +++ b/packages/protocol-kit/src/contracts/utils.ts @@ -277,7 +277,7 @@ export async function predictSafeAddress({ chainId: chainId.toString() }) - const proxyCreationCode = await memoizedGetProxyCreationCode({ + const [proxyCreationCode] = await memoizedGetProxyCreationCode({ safeProvider, safeVersion, customContracts, @@ -292,38 +292,36 @@ export async function predictSafeAddress({ chainId: chainId.toString() }) - const initializer = (await encodeSetupCallData({ + const initializer = await encodeSetupCallData({ safeProvider, safeAccountConfig, safeContract, customContracts, customSafeVersion: safeVersion // it is more efficient if we provide the safeVersion manually - })) as `0x${string}` - const initializerHash = keccak256(initializer) + }) + const initializerHash = keccak256(asHex(initializer)) - const encodedNonce = safeProvider.encodeParameters('uint256', [saltNonce]) as `0x${string}` + const encodedNonce = asHex(safeProvider.encodeParameters('uint256', [saltNonce])) const salt = keccak256(concat([initializerHash, encodedNonce])) - const input = safeProvider.encodeParameters('address', [ - await safeContract.getAddress() - ]) as `0x${string}` + const input = safeProvider.encodeParameters('address', [await safeContract.getAddress()]) - const from = (await safeProxyFactoryContract.getAddress()) as `0x${string}` + const from = asAddress(await safeProxyFactoryContract.getAddress()) // On the zkSync Era chain, the counterfactual deployment address is calculated differently const isZkSyncEraChain = [ZKSYNC_MAINNET, ZKSYNC_TESTNET].includes(chainId) if (isZkSyncEraChain) { - const proxyAddress = zkSyncEraCreate2Address(from, safeVersion, salt, input) + const proxyAddress = zkSyncEraCreate2Address(from, safeVersion, salt, asHex(input)) return safeProvider.getChecksummedAddress(proxyAddress) } - const initCode = (proxyCreationCode + input.slice(2)) as `0x${string}` + const initCode = concat([proxyCreationCode, asHex(input)]) const proxyAddress = getContractAddress({ from, - bytecode: initCode, + bytecode: asHex(initCode), opcode: 'CREATE2', salt }) @@ -360,8 +358,7 @@ export function zkSyncEraCreate2Address( salt: `0x${string}`, input: `0x${string}` ): string { - const bytecodeHash = ZKSYNC_SAFE_PROXY_DEPLOYED_BYTECODE[safeVersion] - .deployedBytecodeHash as `0x${string}` + const bytecodeHash = ZKSYNC_SAFE_PROXY_DEPLOYED_BYTECODE[safeVersion].deployedBytecodeHash as Hash const inputHash = keccak256(input) const addressBytes = keccak256( diff --git a/packages/protocol-kit/src/utils/signatures/utils.ts b/packages/protocol-kit/src/utils/signatures/utils.ts index 202388bcd..a9621c934 100644 --- a/packages/protocol-kit/src/utils/signatures/utils.ts +++ b/packages/protocol-kit/src/utils/signatures/utils.ts @@ -12,6 +12,8 @@ import { getEip712MessageTypes, getEip712TxTypes } from '../eip-712' import { SigningMethod } from '@safe-global/protocol-kit/types' import { hashTypedData } from '../eip-712' import { encodeTypedData } from '../eip-712/encode' +import { asHash, asHex } from '../types' +import { EMPTY_DATA } from '../constants' export function generatePreValidatedSignature(ownerAddress: string): SafeSignature { const signature = @@ -31,8 +33,8 @@ export async function isTxHashSignedWithPrefix( let hasPrefix try { const recoveredAddress = await recoverAddress({ - hash: txHash as `0x${string}`, - signature: signature as `0x${string}` + hash: asHash(txHash), + signature: asHex(signature) }) hasPrefix = !sameString(recoveredAddress, ownerAddress) @@ -151,7 +153,7 @@ export const buildSignatureBytes = (signatures: SafeSignature[]): string => { left.signer.toLowerCase().localeCompare(right.signer.toLowerCase()) ) - let signatureBytes = '0x' + let signatureBytes = EMPTY_DATA let dynamicBytes = '' for (const signature of signatures) { From 35c7cf6aa6da7c93266caac261b6c9c1b719ca49 Mon Sep 17 00:00:00 2001 From: leonardotc Date: Wed, 17 Jul 2024 13:45:16 +0200 Subject: [PATCH 45/85] Remove ethers dependency --- packages/protocol-kit/package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/protocol-kit/package.json b/packages/protocol-kit/package.json index f4e2d5a6f..a8f5327b7 100644 --- a/packages/protocol-kit/package.json +++ b/packages/protocol-kit/package.json @@ -73,7 +73,6 @@ "@safe-global/safe-core-sdk-types": "^5.0.2", "@safe-global/safe-deployments": "^1.37.0", "abitype": "^1.0.2", - "ethers": "^6.13.1", "semver": "^7.6.2", "viem": "^2.15.1" } From e966c671729e5878bf4c12d153240dac5f891f7a Mon Sep 17 00:00:00 2001 From: leonardotc Date: Wed, 17 Jul 2024 13:53:59 +0200 Subject: [PATCH 46/85] Fix coverall file --- packages/api-kit/package.json | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/api-kit/package.json b/packages/api-kit/package.json index cc01f34fb..0c435ea4c 100644 --- a/packages/api-kit/package.json +++ b/packages/api-kit/package.json @@ -12,11 +12,11 @@ "API" ], "scripts": { - "test:web3": "export TESTS_PATH=tests/endpoint && export ETH_LIB=web3 && nyc hardhat test", - "test:ethers": "export TESTS_PATH=tests/endpoint && export ETH_LIB=ethers && nyc --reporter=lcov hardhat test", - "test:viem": "export TESTS_PATH=tests/endpoint && export ETH_LIB=viem && nyc hardhat test", + "test:web3": "export TESTS_PATH=tests/endpoint && export ETH_LIB=web3 && nyc --reporter=lcov hardhat test", + "test:ethers": "export TESTS_PATH=tests/endpoint && export ETH_LIB=ethers && nyc --reporter=lcov hardhat test", + "test:viem": "export TESTS_PATH=tests/endpoint && export ETH_LIB=viem && nyc --reporter=lcov hardhat test", "test": "yarn test:viem", - "test:ci:web3": "export TESTS_PATH=tests/e2e && export ETH_LIB=web3 && nyc hardhat test", + "test:ci:web3": "export TESTS_PATH=tests/e2e && export ETH_LIB=web3 && nyc --reporter=lcov hardhat test", "test:ci:ethers": "export TESTS_PATH=tests/e2e && export ETH_LIB=ethers && nyc --reporter=lcov hardhat test", "test:ci:viem": "export TESTS_PATH=tests/e2e && export ETH_LIB=viem && nyc --reporter=lcov hardhat test", "test:ci": "yarn test:ci:viem", @@ -52,6 +52,7 @@ "ethers": "^6.13.1", "hardhat": "^2.19.3", "mocha": "^10.2.0", + "nyc": "^15.1.0", "semver": "^7.6.1", "sinon": "^14.0.2", "sinon-chai": "^3.7.0", From e553890b0b1c2b48569e23a455fb4b023e7e3084 Mon Sep 17 00:00:00 2001 From: leonardotc Date: Wed, 17 Jul 2024 14:18:16 +0200 Subject: [PATCH 47/85] Re-add ethers but as dev deps --- packages/protocol-kit/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/protocol-kit/package.json b/packages/protocol-kit/package.json index a8f5327b7..8be939429 100644 --- a/packages/protocol-kit/package.json +++ b/packages/protocol-kit/package.json @@ -61,6 +61,7 @@ "chai": "^4.3.10", "chai-as-promised": "^7.1.1", "dotenv": "^16.4.5", + "ethers": "^6.13.1", "hardhat": "^2.19.3", "hardhat-deploy": "^0.11.45", "mocha": "^10.2.0", From 93062e0bff2be8bbdee9c89c6feee76317dbeecc Mon Sep 17 00:00:00 2001 From: leonardotc Date: Wed, 17 Jul 2024 15:55:32 +0200 Subject: [PATCH 48/85] First clean up --- packages/auth-kit/jest.setup.ts | 6 +++--- packages/onramp-kit/jest.setup.ts | 6 +++--- packages/protocol-kit/src/Safe.ts | 2 ++ packages/protocol-kit/src/SafeProvider.ts | 15 ++++++++------- packages/protocol-kit/src/contracts/constants.ts | 4 ++-- 5 files changed, 18 insertions(+), 15 deletions(-) diff --git a/packages/auth-kit/jest.setup.ts b/packages/auth-kit/jest.setup.ts index 39c7bf169..d507e9e56 100644 --- a/packages/auth-kit/jest.setup.ts +++ b/packages/auth-kit/jest.setup.ts @@ -1,8 +1,8 @@ import { TextEncoder } from 'util' -// TextEncoder is used by viem, supported by Browsers natively for over five years and node since 11. All as a global export: https://developer.mozilla.org/en-US/docs/Web/API/TextEncoder -// Since both on-ramp and auth-kit rely on being on a browser (i.e.: we access things directly from `window`) the tests are set with the configuration of `testEnvironment: 'jsdom'` -// js-dom doesnt set some of the globals: https://github.com/jestjs/jest/blob/v29.7.0/packages/jest-environment-jsdom/src/index.ts +// TextEncoder is used by viem, supported by Browsers for over five years and node since v11 as a global export: https://developer.mozilla.org/en-US/docs/Web/API/TextEncoder +// Both on-ramp and auth-kit rely on being on a browser (we access properties directly on `window`) therefore the tests are set with `testEnvironment: 'jsdom'` +// `js-dom` doesn't set some of the globals: https://github.com/jestjs/jest/blob/v29.7.0/packages/jest-environment-jsdom/src/index.ts // for reference, node does: https://github.com/jestjs/jest/blob/4e56991693da7cd4c3730dc3579a1dd1403ee630/packages/jest-environment-node/src/index.ts#L40 Object.assign(global, { TextEncoder }) diff --git a/packages/onramp-kit/jest.setup.ts b/packages/onramp-kit/jest.setup.ts index 39c7bf169..d507e9e56 100644 --- a/packages/onramp-kit/jest.setup.ts +++ b/packages/onramp-kit/jest.setup.ts @@ -1,8 +1,8 @@ import { TextEncoder } from 'util' -// TextEncoder is used by viem, supported by Browsers natively for over five years and node since 11. All as a global export: https://developer.mozilla.org/en-US/docs/Web/API/TextEncoder -// Since both on-ramp and auth-kit rely on being on a browser (i.e.: we access things directly from `window`) the tests are set with the configuration of `testEnvironment: 'jsdom'` -// js-dom doesnt set some of the globals: https://github.com/jestjs/jest/blob/v29.7.0/packages/jest-environment-jsdom/src/index.ts +// TextEncoder is used by viem, supported by Browsers for over five years and node since v11 as a global export: https://developer.mozilla.org/en-US/docs/Web/API/TextEncoder +// Both on-ramp and auth-kit rely on being on a browser (we access properties directly on `window`) therefore the tests are set with `testEnvironment: 'jsdom'` +// `js-dom` doesn't set some of the globals: https://github.com/jestjs/jest/blob/v29.7.0/packages/jest-environment-jsdom/src/index.ts // for reference, node does: https://github.com/jestjs/jest/blob/4e56991693da7cd4c3730dc3579a1dd1403ee630/packages/jest-environment-node/src/index.ts#L40 Object.assign(global, { TextEncoder }) diff --git a/packages/protocol-kit/src/Safe.ts b/packages/protocol-kit/src/Safe.ts index db1edc14b..5c889a7e5 100644 --- a/packages/protocol-kit/src/Safe.ts +++ b/packages/protocol-kit/src/Safe.ts @@ -1512,6 +1512,8 @@ class Safe { const signatureToCheck = signature && Array.isArray(signature) ? buildSignatureBytes(signature) : signature + // both bytes and bytes32 ends up being resolved to a bytes-like structure which is represented by a `0x` prefixed address. + // because there is an overload going on, named-tuples (https://www.typescriptlang.org/play/?ts=4.0.2#example/named-tuples) are used to solve the ambiguity. const bytes32Tuple: [_dataHash: Hash, _signature: Hex] = [ asHash(messageHash), asHex(signatureToCheck) diff --git a/packages/protocol-kit/src/SafeProvider.ts b/packages/protocol-kit/src/SafeProvider.ts index 7e1be9468..10b504a10 100644 --- a/packages/protocol-kit/src/SafeProvider.ts +++ b/packages/protocol-kit/src/SafeProvider.ts @@ -265,11 +265,12 @@ class SafeProvider { } async getContractCode(address: string, blockTag?: string | number): Promise { - const res = this.#externalProvider.getCode({ + const res = await this.#externalProvider.getCode({ address: asAddress(address), ...asBlockId(blockTag) }) - return res?.toString() + + return res ?? '0x' } async isContractDeployed(address: string, blockTag?: string | number): Promise { @@ -309,17 +310,17 @@ class SafeProvider { throw new Error('SafeProvider must be initialized with a signer to use this method') } - // This means that the address on the `WalletClient` is the one we are passing so we let viem make assertions about that account + // This means the address on the `WalletClient` is the one we are passing so we let viem make assertions about that account // That is because if we pass a typeof account === 'string' to singMessage, viem assumes a json-rpc account on their parseAccount function insteado of a local one if (sameString(signer.account.address, account)) { - return (await signer?.signMessage!({ + return await signer?.signMessage!({ message: { raw: toBytes(message) } - })) as string + }) } else { - return (await signer?.signMessage!({ + return await signer?.signMessage!({ account: asAddress(account), message: { raw: toBytes(message) } - })) as string + }) } } diff --git a/packages/protocol-kit/src/contracts/constants.ts b/packages/protocol-kit/src/contracts/constants.ts index a1f01e03d..c41130a25 100644 --- a/packages/protocol-kit/src/contracts/constants.ts +++ b/packages/protocol-kit/src/contracts/constants.ts @@ -1,4 +1,4 @@ -import { Address, Hex } from 'viem' -export const ZERO_ADDRESS: Address = `0x${'0'.repeat(40)}` +import { Address, Hex, zeroAddress } from 'viem' +export const ZERO_ADDRESS: Address = zeroAddress export const EMPTY_DATA: Hex = '0x' export const SENTINEL_ADDRESS: Address = '0x0000000000000000000000000000000000000001' From c5303afdae1955191798db2a975e25c7e931f55f Mon Sep 17 00:00:00 2001 From: leonardotc Date: Thu, 18 Jul 2024 09:23:39 +0200 Subject: [PATCH 49/85] Minor type changes and comments --- packages/protocol-kit/src/SafeProvider.ts | 4 ++-- packages/protocol-kit/src/utils/constants.ts | 4 ++-- packages/protocol-kit/src/utils/eip-712/encode.ts | 2 +- .../relay-kit/src/packs/safe-4337/Safe4337Pack.test.ts | 8 ++++---- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/protocol-kit/src/SafeProvider.ts b/packages/protocol-kit/src/SafeProvider.ts index 10b504a10..c0f393081 100644 --- a/packages/protocol-kit/src/SafeProvider.ts +++ b/packages/protocol-kit/src/SafeProvider.ts @@ -310,8 +310,8 @@ class SafeProvider { throw new Error('SafeProvider must be initialized with a signer to use this method') } - // This means the address on the `WalletClient` is the one we are passing so we let viem make assertions about that account - // That is because if we pass a typeof account === 'string' to singMessage, viem assumes a json-rpc account on their parseAccount function insteado of a local one + // The address on the `WalletClient` is the one we are passing so we let viem make assertions about that account + // For viem, in this context a typeof account === 'string' to singMessage is assumed to be a json-rpc account (returned by parseAccount function) if (sameString(signer.account.address, account)) { return await signer?.signMessage!({ message: { raw: toBytes(message) } diff --git a/packages/protocol-kit/src/utils/constants.ts b/packages/protocol-kit/src/utils/constants.ts index f6871c4be..679aed734 100644 --- a/packages/protocol-kit/src/utils/constants.ts +++ b/packages/protocol-kit/src/utils/constants.ts @@ -1,5 +1,5 @@ -import { Address, Hex } from 'viem' +import { Address, Hex, zeroAddress } from 'viem' -export const ZERO_ADDRESS: Address = `0x${'0'.repeat(40)}` +export const ZERO_ADDRESS: Address = zeroAddress export const EMPTY_DATA: Hex = '0x' export const SENTINEL_ADDRESS: Address = '0x0000000000000000000000000000000000000001' diff --git a/packages/protocol-kit/src/utils/eip-712/encode.ts b/packages/protocol-kit/src/utils/eip-712/encode.ts index 1401419fe..ae94dd069 100644 --- a/packages/protocol-kit/src/utils/eip-712/encode.ts +++ b/packages/protocol-kit/src/utils/eip-712/encode.ts @@ -159,7 +159,7 @@ function hashStruct({ } function deducePrimaryType(types: TypedMessageTypes) { - // In ethers the primaryType is assumed to be the first inserted yielded by a forEach of the types keys + // In ethers the primaryType is assumed to be the first yielded by a forEach of the types keys // https://github.com/ethers-io/ethers.js/blob/a4b1d1f43fca14f2e826e3c60e0d45f5b6ef3ec4/src.ts/hash/typed-data.ts#L278C13-L278C20 return Object.keys(types)[0] } diff --git a/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.test.ts b/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.test.ts index b943ac8cb..3b8ea6f92 100644 --- a/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.test.ts +++ b/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.test.ts @@ -383,12 +383,12 @@ describe('Safe4337Pack', () => { abi: constants.ABI, functionName: 'executeUserOp', args: [ - (await safe4337Pack.protocolKit.getMultiSendAddress()) as viem.Hash, + (await safe4337Pack.protocolKit.getMultiSendAddress()) as viem.Address, 0n, viem.encodeFunctionData({ abi: constants.ABI, functionName: 'multiSend', - args: [protocolKit.encodeMultiSendData(transactions) as viem.Hash] + args: [protocolKit.encodeMultiSendData(transactions) as viem.Hex] }), OperationType.DelegateCall ] @@ -419,9 +419,9 @@ describe('Safe4337Pack', () => { abi: constants.ABI, functionName: 'executeUserOp', args: [ - transferUSDC.to as viem.Hash, + transferUSDC.to as viem.Address, BigInt(transferUSDC.value), - transferUSDC.data as viem.Hash, + transferUSDC.data as viem.Hex, OperationType.Call ] }), From 1adea412072385a063c3a2c1c91a08b02f492ba8 Mon Sep 17 00:00:00 2001 From: leonardotc Date: Thu, 18 Jul 2024 09:27:01 +0200 Subject: [PATCH 50/85] Remove throws --- packages/safe-kit/src/utils/sendTransaction.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/safe-kit/src/utils/sendTransaction.ts b/packages/safe-kit/src/utils/sendTransaction.ts index a63a81b55..33f43bce8 100644 --- a/packages/safe-kit/src/utils/sendTransaction.ts +++ b/packages/safe-kit/src/utils/sendTransaction.ts @@ -9,7 +9,6 @@ import { Address, WalletClient, Transport, Chain, Hex } from 'viem' * @param {TransactionOptions} options Options for executing the transaction. * @param {Safe} protocolKit The protocolKit instance * @returns {Promise} A promise that resolves with the transaction hash - * @throws */ export const sendTransaction = async ( transaction: TransactionBase, From c2b2942f598b068985a2276bb9d19ab7b65a8ce0 Mon Sep 17 00:00:00 2001 From: Tim Schwarz <4171783+tmjssz@users.noreply.github.com> Date: Thu, 18 Jul 2024 09:53:44 +0200 Subject: [PATCH 51/85] playground: Migrate scripts to viem --- packages/protocol-kit/src/SafeProvider.ts | 14 +++---- .../protocol-kit/src/types/safeProvider.ts | 4 ++ playground/relay-kit/paid-transaction.ts | 39 ++++++++++++------- playground/relay-kit/sponsored-transaction.ts | 29 ++++++++------ .../usdc-transfer-4337-counterfactual.ts | 29 +++++++------- ...usdc-transfer-4337-erc20-counterfactual.ts | 20 +++++----- .../relay-kit/usdc-transfer-4337-erc20.ts | 20 +++++----- ...-transfer-4337-sponsored-counterfactual.ts | 20 +++++----- .../relay-kit/usdc-transfer-4337-sponsored.ts | 14 +++---- playground/relay-kit/usdc-transfer-4337.ts | 14 +++---- playground/safe-kit/send-safe-operation.ts | 15 ++++--- playground/utils.ts | 32 +++++++++++---- 12 files changed, 143 insertions(+), 107 deletions(-) diff --git a/packages/protocol-kit/src/SafeProvider.ts b/packages/protocol-kit/src/SafeProvider.ts index c0f393081..7d48dd6ab 100644 --- a/packages/protocol-kit/src/SafeProvider.ts +++ b/packages/protocol-kit/src/SafeProvider.ts @@ -22,13 +22,13 @@ import { SafeProviderConfig, Eip1193Provider, HttpTransport, - SocketTransport + SocketTransport, + ExternalSigner } from '@safe-global/protocol-kit/types' import { asAddress, asHash, asHex } from './utils/types' import { createPublicClient, createWalletClient, - WalletClient, PublicClient, custom, http, @@ -39,11 +39,9 @@ import { encodeAbiParameters, parseAbiParameters, toBytes, - BlockTag, - Transport, - Chain + BlockTag } from 'viem' -import { privateKeyToAccount, Account } from 'viem/accounts' +import { privateKeyToAccount } from 'viem/accounts' import { toEstimateGasParameters, toCallGasParameters, @@ -87,9 +85,7 @@ class SafeProvider { return this.#externalProvider } - async getExternalSigner(): Promise< - WalletClient | undefined - > { + async getExternalSigner(): Promise { // If the signer is not an Ethereum address, it should be a private key const { transport, chain } = this.getExternalProvider() if (this.signer && !this.isAddress(this.signer)) { diff --git a/packages/protocol-kit/src/types/safeProvider.ts b/packages/protocol-kit/src/types/safeProvider.ts index 2fb1d4eef..d2e5047bb 100644 --- a/packages/protocol-kit/src/types/safeProvider.ts +++ b/packages/protocol-kit/src/types/safeProvider.ts @@ -1,3 +1,5 @@ +import { Account, Chain, Transport, WalletClient } from 'viem' + export type RequestArguments = { readonly method: string readonly params?: readonly unknown[] | object @@ -7,6 +9,8 @@ export type Eip1193Provider = { request: (args: RequestArguments) => Promise } +export type ExternalSigner = WalletClient + export type HexAddress = string export type PrivateKey = string export type HttpTransport = string diff --git a/playground/relay-kit/paid-transaction.ts b/playground/relay-kit/paid-transaction.ts index 35ac66378..3739295b3 100644 --- a/playground/relay-kit/paid-transaction.ts +++ b/playground/relay-kit/paid-transaction.ts @@ -1,3 +1,6 @@ +import { Address, formatEther, createWalletClient, custom, Hex } from 'viem' +import { sepolia } from 'viem/chains' +import { privateKeyToAccount } from 'viem/accounts' import { createSafeClient, SafeClient } from '@safe-global/safe-kit' import { GelatoRelayPack } from '@safe-global/relay-kit' import { @@ -6,7 +9,6 @@ import { OperationType, SafeTransaction } from '@safe-global/safe-core-sdk-types' -import { ethers } from 'ethers' // Check the status of a transaction after it is relayed: // https://relay.gelato.digital/tasks/status/ @@ -72,36 +74,43 @@ async function main() { }) // Calculate Safe address - const predictedSafeAddress = await gelatoSafeClient.protocolKit.getAddress() + const predictedSafeAddress = (await gelatoSafeClient.protocolKit.getAddress()) as Address console.log({ predictedSafeAddress }) const isSafeDeployed = await gelatoSafeClient.protocolKit.isSafeDeployed() console.log({ isSafeDeployed }) - const ethersProvider = gelatoSafeClient.protocolKit.getSafeProvider().getExternalProvider() + const externalProvider = gelatoSafeClient.protocolKit.getSafeProvider().getExternalProvider() // Fake on-ramp to transfer enough funds to the Safe address - const chainId = (await ethersProvider.getNetwork()).chainId + const chainId = await externalProvider.getChainId() const relayFee = BigInt( - await gelatoSafeClient.getEstimateFee(chainId, txConfig.GAS_LIMIT, txConfig.GAS_TOKEN) + await gelatoSafeClient.getEstimateFee(BigInt(chainId), txConfig.GAS_LIMIT, txConfig.GAS_TOKEN) ) - const safeBalance = await ethersProvider.getBalance(predictedSafeAddress) - console.log({ minSafeBalance: ethers.formatEther(relayFee.toString()) }) - console.log({ safeBalance: ethers.formatEther(safeBalance.toString()) }) + const safeBalance = await externalProvider.getBalance({ address: predictedSafeAddress }) + console.log({ minSafeBalance: formatEther(relayFee) }) + console.log({ safeBalance: formatEther(safeBalance) }) if (safeBalance < relayFee) { - const fakeOnRampSigner = new ethers.Wallet(mockOnRampConfig.PRIVATE_KEY, ethersProvider) + const fakeOnRampSigner = createWalletClient({ + account: privateKeyToAccount(mockOnRampConfig.PRIVATE_KEY as Hex), + transport: custom(externalProvider), + chain: sepolia + }) + const fundingAmount = safeBalance < relayFee ? relayFee - safeBalance : safeBalance - relayFee - const onRampResponse = await fakeOnRampSigner.sendTransaction({ + const hash = await fakeOnRampSigner.sendTransaction({ to: predictedSafeAddress, - value: fundingAmount + value: fundingAmount, + account: fakeOnRampSigner.account }) - console.log(`Funding the Safe with ${ethers.formatEther(fundingAmount.toString())} ETH`) - await onRampResponse.wait() + console.log(`Funding the Safe with ${formatEther(fundingAmount)} ETH`) + + await externalProvider.waitForTransactionReceipt({ hash }) - const safeBalanceAfter = await ethersProvider.getBalance(predictedSafeAddress) - console.log({ safeBalance: ethers.formatEther(safeBalanceAfter.toString()) }) + const safeBalanceAfter = await externalProvider.getBalance({ address: predictedSafeAddress }) + console.log({ safeBalance: formatEther(safeBalanceAfter) }) } // Relay the transaction diff --git a/playground/relay-kit/sponsored-transaction.ts b/playground/relay-kit/sponsored-transaction.ts index f7d402dea..5c238afb3 100644 --- a/playground/relay-kit/sponsored-transaction.ts +++ b/playground/relay-kit/sponsored-transaction.ts @@ -1,3 +1,5 @@ +import { Address, createWalletClient, custom, formatEther, Hex } from 'viem' +import { privateKeyToAccount } from 'viem/accounts' import { createSafeClient, SafeClient } from '@safe-global/safe-kit' import { GelatoRelayPack } from '@safe-global/relay-kit' import { @@ -6,7 +8,6 @@ import { OperationType, SafeTransaction } from '@safe-global/safe-core-sdk-types' -import { ethers } from 'ethers' // Fund the 1Balance account that will sponsor the transaction and get the API key: // https://relay.gelato.network/ @@ -74,7 +75,7 @@ async function main() { // Calculate Safe address - const predictedSafeAddress = await gelatoSafeClient.protocolKit.getAddress() + const predictedSafeAddress = (await gelatoSafeClient.protocolKit.getAddress()) as Address console.log({ predictedSafeAddress }) const isSafeDeployed = await gelatoSafeClient.protocolKit.isSafeDeployed() @@ -82,20 +83,24 @@ async function main() { // Fake on-ramp to fund the Safe - const ethersProvider = gelatoSafeClient.protocolKit.getSafeProvider().getExternalProvider() - const safeBalance = await ethersProvider.getBalance(predictedSafeAddress) - console.log({ safeBalance: ethers.formatEther(safeBalance.toString()) }) + const externalProvider = gelatoSafeClient.protocolKit.getSafeProvider().getExternalProvider() + const safeBalance = await externalProvider.getBalance({ address: predictedSafeAddress }) + console.log({ safeBalance: formatEther(safeBalance) }) if (safeBalance < BigInt(txConfig.VALUE)) { - const fakeOnRampSigner = new ethers.Wallet(mockOnRampConfig.PRIVATE_KEY, ethersProvider) - const onRampResponse = await fakeOnRampSigner.sendTransaction({ + const fakeOnRampSigner = createWalletClient({ + account: privateKeyToAccount(mockOnRampConfig.PRIVATE_KEY as Hex), + transport: custom(externalProvider) + }) + const hash = await fakeOnRampSigner.sendTransaction({ to: predictedSafeAddress, - value: txConfig.VALUE + value: BigInt(txConfig.VALUE), + chain: undefined }) - console.log(`Funding the Safe with ${ethers.formatEther(txConfig.VALUE.toString())} ETH`) - await onRampResponse.wait() + console.log(`Funding the Safe with ${formatEther(BigInt(txConfig.VALUE))} ETH`) + await externalProvider.waitForTransactionReceipt({ hash }) - const safeBalanceAfter = await ethersProvider.getBalance(predictedSafeAddress) - console.log({ safeBalance: ethers.formatEther(safeBalanceAfter.toString()) }) + const safeBalanceAfter = await externalProvider.getBalance({ address: predictedSafeAddress }) + console.log({ safeBalance: formatEther(safeBalanceAfter) }) } // Relay the transaction diff --git a/playground/relay-kit/usdc-transfer-4337-counterfactual.ts b/playground/relay-kit/usdc-transfer-4337-counterfactual.ts index 6278b37b3..dfea472a7 100644 --- a/playground/relay-kit/usdc-transfer-4337-counterfactual.ts +++ b/playground/relay-kit/usdc-transfer-4337-counterfactual.ts @@ -1,7 +1,7 @@ -import { ethers } from 'ethers' +import { parseEther, Address } from 'viem' +import { sepolia } from 'viem/chains' import { Safe4337Pack } from '@safe-global/relay-kit' -import { generateTransferCallData } from '@safe-global/relay-kit/src/packs/safe-4337/testing-utils/helpers' -import { waitForOperationToFinish, transfer } from '../utils' +import { waitForOperationToFinish, transfer, generateTransferCallData } from '../utils' // Safe owner PK const PRIVATE_KEY = '' @@ -44,7 +44,7 @@ async function main() { console.log('Supported Entry Points', await safe4337Pack.getSupportedEntryPoints()) console.log('Chain Id', await safe4337Pack.getChainId()) - const senderAddress = (await safe4337Pack.protocolKit.getAddress()) as `0x${string}` + const senderAddress = (await safe4337Pack.protocolKit.getAddress()) as Address console.log('senderAddress: ', senderAddress) @@ -56,22 +56,23 @@ async function main() { const fundingSafe = { to: senderAddress, - value: ethers.parseEther(nativeTokenAmount) + value: parseEther(nativeTokenAmount), + chain: sepolia } console.log(`sending ${nativeTokenAmount} ETH...`) - const ethersSigner = await safe4337Pack.protocolKit.getSafeProvider().getExternalSigner() + const externalSigner = await safe4337Pack.protocolKit.getSafeProvider().getExternalSigner() const signerAddress = await safe4337Pack.protocolKit.getSafeProvider().getSignerAddress() - const ethersProvider = safe4337Pack.protocolKit.getSafeProvider().getExternalProvider() + const externalProvider = safe4337Pack.protocolKit.getSafeProvider().getExternalProvider() - if (!ethersSigner || !signerAddress) { + if (!externalSigner || !signerAddress) { throw new Error('No signer found!') } - const transactionFundingResponse = await ethersSigner?.sendTransaction(fundingSafe) + const hash = await externalSigner?.sendTransaction(fundingSafe) - await transactionFundingResponse?.wait() + await externalProvider.waitForTransactionReceipt({ hash }) // Create transaction batch with two 0.1 USDC transfers @@ -80,7 +81,7 @@ async function main() { console.log(`sending USDC...`) // send 0.2 USDC to the Safe - await transfer(ethersSigner, usdcTokenAddress, senderAddress, usdcAmount * 2n) + await transfer(externalSigner, usdcTokenAddress, senderAddress, usdcAmount * 2n) console.log(`creating the Safe batch...`) @@ -91,14 +92,14 @@ async function main() { } const transactions = [transferUSDC, transferUSDC] - const timestamp = (await ethersProvider.getBlock('latest'))?.timestamp || 0 + const timestamp = (await externalProvider.getBlock())?.timestamp || 0n // 2) Create transaction batch const safeOperation = await safe4337Pack.createTransaction({ transactions, options: { - validAfter: timestamp - 60_000, - validUntil: timestamp + 60_000 + validAfter: Number(timestamp - 60_000n), + validUntil: Number(timestamp + 60_000n) } }) diff --git a/playground/relay-kit/usdc-transfer-4337-erc20-counterfactual.ts b/playground/relay-kit/usdc-transfer-4337-erc20-counterfactual.ts index caf41416d..cb042e428 100644 --- a/playground/relay-kit/usdc-transfer-4337-erc20-counterfactual.ts +++ b/playground/relay-kit/usdc-transfer-4337-erc20-counterfactual.ts @@ -1,6 +1,6 @@ +import { Address } from 'viem' import { Safe4337Pack } from '@safe-global/relay-kit' -import { generateTransferCallData } from '@safe-global/relay-kit/src/packs/safe-4337/testing-utils/helpers' -import { waitForOperationToFinish, transfer } from '../utils' +import { waitForOperationToFinish, transfer, generateTransferCallData } from '../utils' // Safe owner PK const PRIVATE_KEY = '' @@ -53,7 +53,7 @@ async function main() { console.log('Chain Id', await safe4337Pack.getChainId()) // Create transaction batch with two 0.1 USDC transfers - const senderAddress = (await safe4337Pack.protocolKit.getAddress()) as `0x${string}` + const senderAddress = (await safe4337Pack.protocolKit.getAddress()) as Address console.log('senderAddress: ', senderAddress) @@ -63,15 +63,15 @@ async function main() { console.log(`sending USDC...`) - const ethersSigner = await safe4337Pack.protocolKit.getSafeProvider().getExternalSigner() - const ethersProvider = safe4337Pack.protocolKit.getSafeProvider().getExternalProvider() + const externalSigner = await safe4337Pack.protocolKit.getSafeProvider().getExternalSigner() + const externalProvider = safe4337Pack.protocolKit.getSafeProvider().getExternalProvider() - if (!ethersSigner) { + if (!externalSigner) { throw new Error('No signer found!') } // send 15 USDC to the Safe - await transfer(ethersSigner, usdcTokenAddress, senderAddress, usdcAmount * 150n) + await transfer(externalSigner, usdcTokenAddress, senderAddress, usdcAmount * 150n) console.log(`creating the Safe batch...`) @@ -81,14 +81,14 @@ async function main() { value: '0' } const transactions = [transferUSDC, transferUSDC] - const timestamp = (await ethersProvider.getBlock('latest'))?.timestamp || 0 + const timestamp = (await externalProvider.getBlock())?.timestamp || 0n // 2) Create transaction batch const safeOperation = await safe4337Pack.createTransaction({ transactions, options: { - validAfter: timestamp - 60_000, - validUntil: timestamp + 60_000 + validAfter: Number(timestamp - 60_000n), + validUntil: Number(timestamp + 60_000n) } }) diff --git a/playground/relay-kit/usdc-transfer-4337-erc20.ts b/playground/relay-kit/usdc-transfer-4337-erc20.ts index b57d2b9ec..3424c2adc 100644 --- a/playground/relay-kit/usdc-transfer-4337-erc20.ts +++ b/playground/relay-kit/usdc-transfer-4337-erc20.ts @@ -1,6 +1,6 @@ +import { Address } from 'viem' import { Safe4337Pack } from '@safe-global/relay-kit' -import { generateTransferCallData } from '@safe-global/relay-kit/src/packs/safe-4337/testing-utils/helpers' -import { waitForOperationToFinish, transfer } from '../utils' +import { waitForOperationToFinish, transfer, generateTransferCallData } from '../utils' // Safe owner PK const PRIVATE_KEY = '' @@ -51,21 +51,21 @@ async function main() { console.log('Chain Id', await safe4337Pack.getChainId()) // Create transaction batch with two 0.1 USDC transfers - const senderAddress = (await safe4337Pack.protocolKit.getAddress()) as `0x${string}` + const senderAddress = (await safe4337Pack.protocolKit.getAddress()) as Address const usdcAmount = 100_000n // 0.1 USDC console.log(`sending USDC...`) - const ethersSigner = await safe4337Pack.protocolKit.getSafeProvider().getExternalSigner() - const ethersProvider = safe4337Pack.protocolKit.getSafeProvider().getExternalProvider() + const externalSigner = await safe4337Pack.protocolKit.getSafeProvider().getExternalSigner() + const externalProvider = safe4337Pack.protocolKit.getSafeProvider().getExternalProvider() - if (!ethersSigner) { + if (!externalSigner) { throw new Error('No signer found!') } // send 5 USDC to the Safe - await transfer(ethersSigner, usdcTokenAddress, senderAddress, usdcAmount * 50n) + await transfer(externalSigner, usdcTokenAddress, senderAddress, usdcAmount * 50n) console.log(`creating the Safe batch...`) @@ -75,14 +75,14 @@ async function main() { value: '0' } const transactions = [transferUSDC, transferUSDC] - const timestamp = (await ethersProvider.getBlock('latest'))?.timestamp || 0 + const timestamp = (await externalProvider.getBlock())?.timestamp || 0n // 2) Create transaction batch const safeOperation = await safe4337Pack.createTransaction({ transactions, options: { - validAfter: timestamp - 60_000, - validUntil: timestamp + 60_000 + validAfter: Number(timestamp - 60_000n), + validUntil: Number(timestamp + 60_000n) } }) diff --git a/playground/relay-kit/usdc-transfer-4337-sponsored-counterfactual.ts b/playground/relay-kit/usdc-transfer-4337-sponsored-counterfactual.ts index 4a7a33820..c85e5765f 100644 --- a/playground/relay-kit/usdc-transfer-4337-sponsored-counterfactual.ts +++ b/playground/relay-kit/usdc-transfer-4337-sponsored-counterfactual.ts @@ -1,6 +1,6 @@ +import { Address } from 'viem' import { Safe4337Pack } from '@safe-global/relay-kit' -import { generateTransferCallData } from '@safe-global/relay-kit/src/packs/safe-4337/testing-utils/helpers' -import { waitForOperationToFinish, transfer } from '../utils' +import { waitForOperationToFinish, transfer, generateTransferCallData } from '../utils' // Safe owner PK const PRIVATE_KEY = '' @@ -60,7 +60,7 @@ async function main() { console.log('Chain Id', await safe4337Pack.getChainId()) // Create transaction batch with two 0.1 USDC transfers - const senderAddress = (await safe4337Pack.protocolKit.getAddress()) as `0x${string}` + const senderAddress = (await safe4337Pack.protocolKit.getAddress()) as Address console.log('senderAddress: ', senderAddress) @@ -70,15 +70,15 @@ async function main() { console.log(`sending USDC...`) - const ethersSigner = await safe4337Pack.protocolKit.getSafeProvider().getExternalSigner() - const ethersProvider = safe4337Pack.protocolKit.getSafeProvider().getExternalProvider() + const externalSigner = await safe4337Pack.protocolKit.getSafeProvider().getExternalSigner() + const externalProvider = safe4337Pack.protocolKit.getSafeProvider().getExternalProvider() - if (!ethersSigner) { + if (!externalSigner) { throw new Error('No signer found!') } // send 0.2 USDC to the Safe - await transfer(ethersSigner, usdcTokenAddress, senderAddress, usdcAmount * 2n) + await transfer(externalSigner, usdcTokenAddress, senderAddress, usdcAmount * 2n) console.log(`creating the Safe batch...`) @@ -88,14 +88,14 @@ async function main() { value: '0' } const transactions = [transferUSDC, transferUSDC] - const timestamp = (await ethersProvider.getBlock('latest'))?.timestamp || 0 + const timestamp = (await externalProvider.getBlock())?.timestamp || 0n // 2) Create transaction batch const safeOperation = await safe4337Pack.createTransaction({ transactions, options: { - validAfter: timestamp - 60_000, - validUntil: timestamp + 60_000 + validAfter: Number(timestamp - 60_000n), + validUntil: Number(timestamp + 60_000n) } }) diff --git a/playground/relay-kit/usdc-transfer-4337-sponsored.ts b/playground/relay-kit/usdc-transfer-4337-sponsored.ts index 7655e4890..40b352c78 100644 --- a/playground/relay-kit/usdc-transfer-4337-sponsored.ts +++ b/playground/relay-kit/usdc-transfer-4337-sponsored.ts @@ -1,6 +1,6 @@ +import { Address } from 'viem' import { Safe4337Pack } from '@safe-global/relay-kit' -import { generateTransferCallData } from '@safe-global/relay-kit/src/packs/safe-4337/testing-utils/helpers' -import { waitForOperationToFinish } from '../utils' +import { generateTransferCallData, waitForOperationToFinish } from '../utils' // Safe owner PK const PRIVATE_KEY = '' @@ -58,7 +58,7 @@ async function main() { console.log('Chain Id', await safe4337Pack.getChainId()) // Create transaction batch with two 0.1 USDC transfers - const senderAddress = (await safe4337Pack.protocolKit.getAddress()) as `0x${string}` + const senderAddress = (await safe4337Pack.protocolKit.getAddress()) as Address const usdcAmount = 100_000n // 0.1 USDC @@ -68,15 +68,15 @@ async function main() { value: '0' } const transactions = [transferUSDC, transferUSDC] - const ethersProvider = safe4337Pack.protocolKit.getSafeProvider().getExternalProvider() - const timestamp = (await ethersProvider.getBlock('latest'))?.timestamp || 0 + const externalProvider = safe4337Pack.protocolKit.getSafeProvider().getExternalProvider() + const timestamp = (await externalProvider.getBlock())?.timestamp || 0n // 2) Create transaction batch const safeOperation = await safe4337Pack.createTransaction({ transactions, options: { - validAfter: timestamp - 60_000, - validUntil: timestamp + 60_000 + validAfter: Number(timestamp - 60_000n), + validUntil: Number(timestamp + 60_000n) } }) diff --git a/playground/relay-kit/usdc-transfer-4337.ts b/playground/relay-kit/usdc-transfer-4337.ts index 91cf6d323..022a818d9 100644 --- a/playground/relay-kit/usdc-transfer-4337.ts +++ b/playground/relay-kit/usdc-transfer-4337.ts @@ -1,6 +1,6 @@ +import { Address } from 'viem' import { Safe4337Pack } from '@safe-global/relay-kit' -import { generateTransferCallData } from '@safe-global/relay-kit/src/packs/safe-4337/testing-utils/helpers' -import { waitForOperationToFinish } from 'playground/utils' +import { generateTransferCallData, waitForOperationToFinish } from '../utils' // Safe owner PK const PRIVATE_KEY = '' @@ -38,7 +38,7 @@ async function main() { console.log('Chain Id', await safe4337Pack.getChainId()) // Create transaction batch with two 0.1 USDC transfers - const senderAddress = (await safe4337Pack.protocolKit.getAddress()) as `0x${string}` + const senderAddress = (await safe4337Pack.protocolKit.getAddress()) as Address const usdcAmount = 100_000n // 0.1 USDC @@ -49,15 +49,15 @@ async function main() { value: '0' } const transactions = [transferUSDC, transferUSDC] - const ethersProvider = safe4337Pack.protocolKit.getSafeProvider().getExternalProvider() - const timestamp = (await ethersProvider.getBlock('latest'))?.timestamp || 0 + const externalProvider = safe4337Pack.protocolKit.getSafeProvider().getExternalProvider() + const timestamp = (await externalProvider.getBlock())?.timestamp || 0n // 2) Create transaction batch const safeOperation = await safe4337Pack.createTransaction({ transactions, options: { - validAfter: timestamp - 60_000, - validUntil: timestamp + 60_000 + validAfter: Number(timestamp - 60_000n), + validUntil: Number(timestamp + 60_000n) } }) diff --git a/playground/safe-kit/send-safe-operation.ts b/playground/safe-kit/send-safe-operation.ts index 45b6a6fe8..3e223d8b0 100644 --- a/playground/safe-kit/send-safe-operation.ts +++ b/playground/safe-kit/send-safe-operation.ts @@ -1,4 +1,5 @@ -import { ethers } from 'ethers' +import { createPublicClient, http } from 'viem' +import { sepolia } from 'viem/chains' import { SafeClientResult, createSafeClient, safeOperations } from '@safe-global/safe-kit' import { generateTransferCallData } from '../utils' @@ -60,14 +61,18 @@ async function send(): Promise { } const transactions = [transferUSDC, transferUSDC] - const ethersProvider = new ethers.JsonRpcProvider(RPC_URL) - const timestamp = (await ethersProvider.getBlock('latest'))?.timestamp || 0 + const publicClient = createPublicClient({ + chain: sepolia, + transport: http(RPC_URL) + }) + + const timestamp = (await publicClient.getBlock())?.timestamp || 0n const safeOperationResult = await safeClientWithSafeOperation.sendSafeOperation({ transactions, options: { - validAfter: timestamp - 60_000, - validUntil: timestamp + 60_000 + validAfter: Number(timestamp - 60_000n), + validUntil: Number(timestamp + 60_000n) } }) diff --git a/playground/utils.ts b/playground/utils.ts index 069bf4daa..120cb5825 100644 --- a/playground/utils.ts +++ b/playground/utils.ts @@ -1,7 +1,17 @@ -import { ethers } from 'ethers' +import { Address, createPublicClient, custom, encodeFunctionData, parseAbi } from 'viem' import { Safe4337Pack } from '@safe-global/relay-kit' -import { generateTransferCallData } from '@safe-global/relay-kit/src/packs/safe-4337/testing-utils/helpers' import { GetSafeOperationListResponse } from '@safe-global/api-kit' +import { ExternalSigner } from '@safe-global/protocol-kit' + +export const generateTransferCallData = (to: string, value: bigint) => { + const functionAbi = parseAbi(['function transfer(address _to, uint256 _value) returns (bool)']) + + return encodeFunctionData({ + abi: functionAbi, + functionName: 'transfer', + args: [to as Address, value] + }) +} export async function waitForOperationToFinish( userOperationHash: string, @@ -26,20 +36,26 @@ export async function waitForOperationToFinish( } export async function transfer( - signer: ethers.AbstractSigner, - tokenAddress: string, - to: string, + signer: ExternalSigner, + tokenAddress: Address, + to: Address, amount: bigint ) { const transferEC20 = { to: tokenAddress, data: generateTransferCallData(to, amount), - value: '0' + value: 0n, + chain: signer.chain } - const transactionResponse = await signer.sendTransaction(transferEC20) + const hash = await signer.sendTransaction(transferEC20) + + const publicClient = createPublicClient({ + chain: signer.chain, + transport: custom(signer.transport) + }) - return await transactionResponse.wait() + return await publicClient.waitForTransactionReceipt({ hash }) } export function sortResultsByCreatedDateDesc( From 32a6da499c83195849db13483d3cb82e28593c12 Mon Sep 17 00:00:00 2001 From: leonardotc Date: Thu, 18 Jul 2024 15:09:29 +0200 Subject: [PATCH 52/85] Pre-pr changes --- .../example/client/src/components/Stripe.tsx | 4 ++-- packages/protocol-kit/src/contracts/utils.ts | 7 +++---- packages/safe-kit/package.json | 2 +- packages/safe-kit/src/utils/index.ts | 17 ++++++++++------- 4 files changed, 16 insertions(+), 14 deletions(-) diff --git a/packages/onramp-kit/example/client/src/components/Stripe.tsx b/packages/onramp-kit/example/client/src/components/Stripe.tsx index f7732effc..20a711934 100644 --- a/packages/onramp-kit/example/client/src/components/Stripe.tsx +++ b/packages/onramp-kit/example/client/src/components/Stripe.tsx @@ -1,5 +1,5 @@ import { useEffect, useState, useRef } from 'react' -import { ethers } from 'ethers' +import { isAddress } from 'viem' import { Grid, TextField, Button } from '@mui/material' import { StripeSession, StripePack } from '@safe-global/onramp-kit' @@ -13,7 +13,7 @@ function Stripe() { const stripeRootRef = useRef(null) const handleCreateSession = async () => { - if (!isSessionValid(sessionId) && !ethers.isAddress(walletAddress)) return + if (!isSessionValid(sessionId) && !isAddress(walletAddress)) return if (stripeRootRef.current) { stripeRootRef.current.innerHTML = '' diff --git a/packages/protocol-kit/src/contracts/utils.ts b/packages/protocol-kit/src/contracts/utils.ts index 540283266..027c6869c 100644 --- a/packages/protocol-kit/src/contracts/utils.ts +++ b/packages/protocol-kit/src/contracts/utils.ts @@ -373,14 +373,13 @@ export function toTxResult( hash: Hash, options?: TransactionOptions ): TransactionResult { - const wait = async () => { - return runner.getTransactionReceipt({ hash }) - } return { hash, options, transactionResponse: { - wait + wait: async () => { + return runner.getTransactionReceipt({ hash }) + } } } } diff --git a/packages/safe-kit/package.json b/packages/safe-kit/package.json index f41ef3e70..201fb1d48 100644 --- a/packages/safe-kit/package.json +++ b/packages/safe-kit/package.json @@ -38,6 +38,6 @@ "@safe-global/relay-kit": "^3.0.2", "@safe-global/safe-core-sdk-types": "^5.0.2", "@safe-global/api-kit": "^2.4.1", - "ethers": "^6.13.1" + "viem": "^2.15.1" } } diff --git a/packages/safe-kit/src/utils/index.ts b/packages/safe-kit/src/utils/index.ts index 18f12fc8d..c942c97e6 100644 --- a/packages/safe-kit/src/utils/index.ts +++ b/packages/safe-kit/src/utils/index.ts @@ -1,6 +1,6 @@ import { validateEthereumAddress } from '@safe-global/protocol-kit' import { TransactionResult } from '@safe-global/safe-core-sdk-types' -import { ContractTransactionReceipt, TransactionResponse } from 'ethers' +import { GetTransactionReceiptReturnType } from 'viem' import { MESSAGES, SafeClientTxStatus } from '@safe-global/safe-kit/constants' import { SafeClientResult, SafeConfig } from '@safe-global/safe-kit/types' @@ -22,12 +22,15 @@ export const isValidSafeConfig = (config: SafeConfig): boolean => { export const waitSafeTxReceipt = async ( txResult: TransactionResult -): Promise => { - const receipt = - txResult.transactionResponse && - (await (txResult.transactionResponse as TransactionResponse).wait()) - - return receipt as ContractTransactionReceipt +): Promise => { + const receipt = txResult.transactionResponse + ? ( + (await txResult.transactionResponse) as { + wait: () => Promise + } + ).wait() + : undefined + return receipt } export const createSafeClientResult = ({ From 47d4e1d9fedb5229a1dc8056a63ab1ee598c1e91 Mon Sep 17 00:00:00 2001 From: Tim Schwarz <4171783+tmjssz@users.noreply.github.com> Date: Thu, 18 Jul 2024 15:31:05 +0200 Subject: [PATCH 53/85] onramp-kit: Remove ethers from example app --- packages/onramp-kit/example/client/package.json | 1 - packages/onramp-kit/example/client/src/AuthContext.tsx | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/onramp-kit/example/client/package.json b/packages/onramp-kit/example/client/package.json index 32a3674ae..3c8449747 100644 --- a/packages/onramp-kit/example/client/package.json +++ b/packages/onramp-kit/example/client/package.json @@ -17,7 +17,6 @@ "@safe-global/onramp-kit": "file:../../", "@safe-global/protocol-kit": "file:../../../protocol-kit", "@safe-global/safe-react-components": "^2.0.6", - "ethers": "^6.11.1", "react": "^18.2.0", "react-dom": "^18.2.0", "react-router-dom": "^6.18.0" diff --git a/packages/onramp-kit/example/client/src/AuthContext.tsx b/packages/onramp-kit/example/client/src/AuthContext.tsx index ca4c401b9..657f59a56 100644 --- a/packages/onramp-kit/example/client/src/AuthContext.tsx +++ b/packages/onramp-kit/example/client/src/AuthContext.tsx @@ -1,6 +1,6 @@ import React, { createContext, useState, useEffect } from 'react' -import { ethers } from 'ethers' import { SafeAuthPack, AuthKitSignInData, SafeAuthInitOptions } from '@safe-global/auth-kit' +import { Eip1193Provider } from '@safe-global/protocol-kit' type AuthContextProviderProps = { children: React.ReactNode @@ -8,7 +8,7 @@ type AuthContextProviderProps = { type AuthContextType = { isLoggedIn: boolean - provider: ethers.Eip1193Provider | null + provider: Eip1193Provider | null data?: AuthKitSignInData selectedSafe: string setSelectedSafe?: (safe: string) => void @@ -26,7 +26,7 @@ const AuthProvider = ({ children }: AuthContextProviderProps) => { const [safeAuthPack, setSafeAuthPack] = useState() const [isAuthenticated, setIsAuthenticated] = useState(!!safeAuthPack?.isAuthenticated) const [safeAuthSignInResponse, setSafeAuthSignInResponse] = useState() - const [provider, setProvider] = useState() + const [provider, setProvider] = useState() const [selectedSafe, setSelectedSafe] = useState('') const storedSafe = sessionStorage.getItem(STORED_SAFE) From ee88653f7eeca18e4dfd485e124d398643266b33 Mon Sep 17 00:00:00 2001 From: leonardotc Date: Fri, 19 Jul 2024 10:18:34 +0200 Subject: [PATCH 54/85] Fix contracts --- .../src/contracts/BaseContract.ts | 22 ++- ...ompatibilityFallbackHandlerBaseContract.ts | 2 +- .../CreateCall/CreateCallBaseContract.ts | 2 +- .../Safe/v1.0.0/SafeContract_v1_0_0.ts | 183 +++++++++++++++--- .../Safe/v1.1.1/SafeContract_v1_1_1.ts | 131 +++++++++++-- .../Safe/v1.2.0/SafeContract_v1_2_0.ts | 140 ++++++++++++-- .../Safe/v1.3.0/SafeContract_v1_3_0.ts | 144 ++++++++++++-- .../Safe/v1.4.1/SafeContract_v1_4_1.ts | 144 ++++++++++++-- .../SafeProxyFactoryBaseContract.ts | 2 +- .../v1.0.0/SafeProxyFactoryContract_v1_0_0.ts | 18 +- .../v1.1.1/SafeProxyFactoryContract_v1_1_1.ts | 18 +- .../v1.3.0/SafeProxyFactoryContract_v1_3_0.ts | 18 +- .../v1.4.1/SafeProxyFactoryContract_v1_4_1.ts | 18 +- .../v1.3.0/SignMessageLibContract_v1_3_0.ts | 10 +- .../v1.4.1/SignMessageLibContract_v1_4_1.ts | 10 +- .../SimulateTxAccessorBaseContract.ts | 2 +- .../src/utils/transactions/types.ts | 6 +- playground/protocol-kit/deploy-safe.ts | 11 +- 18 files changed, 738 insertions(+), 143 deletions(-) diff --git a/packages/protocol-kit/src/contracts/BaseContract.ts b/packages/protocol-kit/src/contracts/BaseContract.ts index 379ba347b..59c8c034c 100644 --- a/packages/protocol-kit/src/contracts/BaseContract.ts +++ b/packages/protocol-kit/src/contracts/BaseContract.ts @@ -1,13 +1,13 @@ import { Abi } from 'abitype' import { PublicClient, - Address, - getContract, + Transport, encodeFunctionData, GetContractReturnType, WalletClient, Hash, - Chain + Chain, + getContract } from 'viem' import { contractName, getContractDeployment } from '@safe-global/protocol-kit/contracts/config' import SafeProvider from '@safe-global/protocol-kit/SafeProvider' @@ -49,7 +49,8 @@ class BaseContract { safeProvider: SafeProvider chainId: bigint contract!: GetContractReturnType - runner: PublicClient | null + runner: PublicClient + wallet?: WalletClient /** * @constructor @@ -71,7 +72,7 @@ class BaseContract { safeVersion: SafeVersion, customContractAddress?: string, customContractAbi?: ContractAbiType, - runner?: PublicClient | null + runner?: PublicClient ) { const deployment = getContractDeployment(safeVersion, chainId, contractName) @@ -98,11 +99,11 @@ class BaseContract { } async init() { - const client = this.runner || (await this.safeProvider.getExternalSigner()) + this.wallet = await this.safeProvider.getExternalSigner() this.contract = getContract({ - address: this.contractAddress as Address, + address: asAddress(this.contractAddress), abi: this.contractAbi, - client: client! + client: this.wallet || this.runner }) } @@ -117,9 +118,10 @@ class BaseContract { const chain = this.getChain() if (!chain) throw new Error('Invalid chainId') const signerAddress = await this.safeProvider.getSignerAddress() - const account = asAddress(signerAddress!) + const signer = this.wallet?.account + const account = signer || asAddress(signerAddress!) const txOptions = await converTransactionOptions(options) - return { chain, account, ...txOptions } // Needs to be in this order to override the `account` if necessary + return { chain, ...txOptions, account } // Needs to be in this order to override the `account` if necessary } getChain(): Chain | undefined { diff --git a/packages/protocol-kit/src/contracts/CompatibilityFallbackHandler/CompatibilityFallbackHandlerBaseContract.ts b/packages/protocol-kit/src/contracts/CompatibilityFallbackHandler/CompatibilityFallbackHandlerBaseContract.ts index fde1eb24a..f93bf6e90 100644 --- a/packages/protocol-kit/src/contracts/CompatibilityFallbackHandler/CompatibilityFallbackHandlerBaseContract.ts +++ b/packages/protocol-kit/src/contracts/CompatibilityFallbackHandler/CompatibilityFallbackHandlerBaseContract.ts @@ -42,7 +42,7 @@ abstract class CompatibilityFallbackHandlerBaseContract< safeVersion: SafeVersion, customContractAddress?: string, customContractAbi?: CompatibilityFallbackHandlerContractAbiType, - runner?: PublicClient | null + runner?: PublicClient ) { const contractName = 'compatibilityFallbackHandler' diff --git a/packages/protocol-kit/src/contracts/CreateCall/CreateCallBaseContract.ts b/packages/protocol-kit/src/contracts/CreateCall/CreateCallBaseContract.ts index f4518daab..3978797b5 100644 --- a/packages/protocol-kit/src/contracts/CreateCall/CreateCallBaseContract.ts +++ b/packages/protocol-kit/src/contracts/CreateCall/CreateCallBaseContract.ts @@ -42,7 +42,7 @@ abstract class CreateCallBaseContract< safeVersion: SafeVersion, customContractAddress?: string, customContractAbi?: CreateCallContractAbiType, - runner?: PublicClient | null + runner?: PublicClient ) { const contractName = 'createCallVersion' diff --git a/packages/protocol-kit/src/contracts/Safe/v1.0.0/SafeContract_v1_0_0.ts b/packages/protocol-kit/src/contracts/Safe/v1.0.0/SafeContract_v1_0_0.ts index 0635625bf..5acc7353f 100644 --- a/packages/protocol-kit/src/contracts/Safe/v1.0.0/SafeContract_v1_0_0.ts +++ b/packages/protocol-kit/src/contracts/Safe/v1.0.0/SafeContract_v1_0_0.ts @@ -65,23 +65,53 @@ class SafeContract_v1_0_0 /* ----- Specific v1.0.0 properties ----- */ DOMAIN_SEPARATOR_TYPEHASH: SafeContract_v1_0_0_Function<'DOMAIN_SEPARATOR_TYPEHASH'> = async () => { - return [await this.contract.read.DOMAIN_SEPARATOR_TYPEHASH()] + return [ + await this.runner.readContract({ + functionName: 'DOMAIN_SEPARATOR_TYPEHASH', + abi: this.contractAbi, + address: asAddress(this.contractAddress) + }) + ] } SENTINEL_MODULES: SafeContract_v1_0_0_Function<'SENTINEL_MODULES'> = async () => { - return [await this.contract.read.SENTINEL_MODULES()] + return [ + await this.runner.readContract({ + functionName: 'SENTINEL_MODULES', + abi: this.contractAbi, + address: asAddress(this.contractAddress) + }) + ] } SENTINEL_OWNERS: SafeContract_v1_0_0_Function<'SENTINEL_OWNERS'> = async () => { - return [await this.contract.read.SENTINEL_OWNERS()] + return [ + await this.runner.readContract({ + functionName: 'SENTINEL_OWNERS', + abi: this.contractAbi, + address: asAddress(this.contractAddress) + }) + ] } SAFE_MSG_TYPEHASH: SafeContract_v1_0_0_Function<'SAFE_MSG_TYPEHASH'> = async () => { - return [await this.contract.read.SAFE_MSG_TYPEHASH()] + return [ + await this.runner.readContract({ + functionName: 'SAFE_MSG_TYPEHASH', + abi: this.contractAbi, + address: asAddress(this.contractAddress) + }) + ] } SAFE_TX_TYPEHASH: SafeContract_v1_0_0_Function<'SAFE_TX_TYPEHASH'> = async () => { - return [await this.contract.read.SAFE_TX_TYPEHASH()] + return [ + await this.runner.readContract({ + functionName: 'SAFE_TX_TYPEHASH', + abi: this.contractAbi, + address: asAddress(this.contractAddress) + }) + ] } /* ----- End of specific v1.0.0 properties ----- */ @@ -89,14 +119,26 @@ class SafeContract_v1_0_0 * @returns Array[contractName] */ NAME: SafeContract_v1_0_0_Function<'NAME'> = async () => { - return [await this.contract.read.NAME()] + return [ + await this.runner.readContract({ + functionName: 'NAME', + abi: this.contractAbi, + address: asAddress(this.contractAddress) + }) + ] } /** * @returns Array[safeContractVersion] */ VERSION: SafeContract_v1_0_0_Function<'VERSION'> = async () => { - return [await this.contract.read.VERSION()] + return [ + await this.runner.readContract({ + functionName: 'VERSION', + abi: this.contractAbi, + address: asAddress(this.contractAddress) + }) + ] } /** @@ -104,14 +146,27 @@ class SafeContract_v1_0_0 * @returns Array[approvedHashes] */ approvedHashes: SafeContract_v1_0_0_Function<'approvedHashes'> = async (args) => { - return [await this.contract.read.approvedHashes(args)] + return [ + await this.runner.readContract({ + functionName: 'approvedHashes', + abi: this.contractAbi, + address: asAddress(this.contractAddress), + args + }) + ] } /** * @returns Array[domainSeparator] */ domainSeparator: SafeContract_v1_0_0_Function<'domainSeparator'> = async () => { - return [await this.contract.read.domainSeparator()] + return [ + await this.runner.readContract({ + functionName: 'domainSeparator', + abi: this.contractAbi, + address: asAddress(this.contractAddress) + }) + ] } /** @@ -119,7 +174,13 @@ class SafeContract_v1_0_0 * @returns Array[Array[modules]] */ getModules: SafeContract_v1_0_0_Function<'getModules'> = async () => { - return [await this.contract.read.getModules()] + return [ + await this.runner.readContract({ + functionName: 'getModules', + abi: this.contractAbi, + address: asAddress(this.contractAddress) + }) + ] } /** @@ -127,7 +188,13 @@ class SafeContract_v1_0_0 * @returns Array[Array[owners]] */ getOwners: SafeContract_v1_0_0_Function<'getOwners'> = async () => { - return [await this.contract.read.getOwners()] + return [ + await this.runner.readContract({ + functionName: 'getOwners', + abi: this.contractAbi, + address: asAddress(this.contractAddress) + }) + ] } /** @@ -135,7 +202,13 @@ class SafeContract_v1_0_0 * @returns Array[threshold] */ getThreshold: SafeContract_v1_0_0_Function<'getThreshold'> = async () => { - return [await this.contract.read.getThreshold()] + return [ + await this.runner.readContract({ + functionName: 'getThreshold', + abi: this.contractAbi, + address: asAddress(this.contractAddress) + }) + ] } /** @@ -144,7 +217,14 @@ class SafeContract_v1_0_0 * @returns Array[isOwner] */ isOwner: SafeContract_v1_0_0_Function<'isOwner'> = async (args) => { - return [await this.contract.read.isOwner(args)] + return [ + await this.runner.readContract({ + functionName: 'isOwner', + abi: this.contractAbi, + address: asAddress(this.contractAddress), + args + }) + ] } /** @@ -152,7 +232,13 @@ class SafeContract_v1_0_0 * @returns Array[nonce] */ nonce: SafeContract_v1_0_0_Function<'nonce'> = async () => { - return [await this.contract.read.nonce()] + return [ + await this.runner.readContract({ + functionName: 'nonce', + abi: this.contractAbi, + address: asAddress(this.contractAddress) + }) + ] } /** @@ -160,7 +246,14 @@ class SafeContract_v1_0_0 * @returns Array[signedMessages] */ signedMessages: SafeContract_v1_0_0_Function<'signedMessages'> = async (args) => { - return [await this.contract.read.signedMessages(args)] + return [ + await this.runner.readContract({ + functionName: 'signedMessages', + abi: this.contractAbi, + address: asAddress(this.contractAddress), + args + }) + ] } /** @@ -169,7 +262,14 @@ class SafeContract_v1_0_0 * @returns Array[messageHash] */ getMessageHash: SafeContract_v1_0_0_Function<'getMessageHash'> = async (args) => { - return [await this.contract.read.getMessageHash(args)] + return [ + await this.runner.readContract({ + functionName: 'getMessageHash', + abi: this.contractAbi, + address: asAddress(this.contractAddress), + args + }) + ] } /** @@ -178,7 +278,14 @@ class SafeContract_v1_0_0 * @returns Array[encodedData] */ encodeTransactionData: SafeContract_v1_0_0_Function<'encodeTransactionData'> = async (args) => { - return [await this.contract.read.encodeTransactionData(args)] + return [ + await this.runner.readContract({ + functionName: 'encodeTransactionData', + abi: this.contractAbi, + address: asAddress(this.contractAddress), + args + }) + ] } /** @@ -187,7 +294,14 @@ class SafeContract_v1_0_0 * @returns Array[transactionHash] */ getTransactionHash: SafeContract_v1_0_0_Function<'getTransactionHash'> = async (args) => { - return [await this.contract.read.getTransactionHash(args)] + return [ + await this.runner.readContract({ + functionName: 'getTransactionHash', + abi: this.contractAbi, + address: asAddress(this.contractAddress), + args + }) + ] } /** @@ -197,15 +311,22 @@ class SafeContract_v1_0_0 * @returns Transaction result. */ async approveHash(hash: string, options?: TransactionOptions): Promise { + if (!this.wallet) throw new Error() const gasLimit = options?.gasLimit || (await this.estimateGas('approveHash', [asHash(hash)], options)) - const txResponse = await this.contract.write.approveHash( - [asHash(hash)], - await this.convertOptions({ - ...options, - gasLimit - }) - ) + + const converted = await this.convertOptions({ + ...options, + gasLimit + }) + + const txResponse = await this.wallet?.writeContract({ + functionName: 'approveHash', + address: asAddress(this.contractAddress), + abi: this.contractAbi, + args: [asHash(hash)], + ...converted + }) return toTxResult(this.runner!, txResponse, options) } @@ -323,8 +444,12 @@ class SafeContract_v1_0_0 options )) - const txResult = await this.contract.simulate.execTransaction( - [ + const converted = await this.convertOptions({ ...options, gasLimit }) + const txResult = await this.runner.simulateContract({ + address: asAddress(this.contractAddress), + functionName: 'execTransaction', + abi: this.contractAbi, + args: [ asAddress(safeTransaction.data.to), BigInt(safeTransaction.data.value), asHex(safeTransaction.data.data), @@ -336,8 +461,8 @@ class SafeContract_v1_0_0 asAddress(safeTransaction.data.refundReceiver), asHex(safeTransaction.encodedSignatures()) ], - await this.convertOptions({ ...options, gasLimit }) - ) + ...converted + }) return txResult.result } catch (error) { diff --git a/packages/protocol-kit/src/contracts/Safe/v1.1.1/SafeContract_v1_1_1.ts b/packages/protocol-kit/src/contracts/Safe/v1.1.1/SafeContract_v1_1_1.ts index 53175a7ef..e00c31d1a 100644 --- a/packages/protocol-kit/src/contracts/Safe/v1.1.1/SafeContract_v1_1_1.ts +++ b/packages/protocol-kit/src/contracts/Safe/v1.1.1/SafeContract_v1_1_1.ts @@ -64,14 +64,26 @@ class SafeContract_v1_1_1 * @returns Array[contractName] */ NAME: SafeContract_v1_1_1_Function<'NAME'> = async () => { - return [await this.contract.read.NAME()] + return [ + await this.runner.readContract({ + functionName: 'NAME', + abi: this.contractAbi, + address: asAddress(this.contractAddress) + }) + ] } /** * @returns Array[safeContractVersion] */ VERSION: SafeContract_v1_1_1_Function<'VERSION'> = async () => { - return [await this.contract.read.VERSION()] + return [ + await this.runner.readContract({ + functionName: 'VERSION', + abi: this.contractAbi, + address: asAddress(this.contractAddress) + }) + ] } /** @@ -79,14 +91,27 @@ class SafeContract_v1_1_1 * @returns Array[approvedHashes] */ approvedHashes: SafeContract_v1_1_1_Function<'approvedHashes'> = async (args) => { - return [await this.contract.read.approvedHashes(args)] + return [ + await this.runner.readContract({ + functionName: 'approvedHashes', + abi: this.contractAbi, + address: asAddress(this.contractAddress), + args + }) + ] } /** * @returns Array[domainSeparator] */ domainSeparator: SafeContract_v1_1_1_Function<'domainSeparator'> = async () => { - return [await this.contract.read.domainSeparator()] + return [ + await this.runner.readContract({ + functionName: 'domainSeparator', + abi: this.contractAbi, + address: asAddress(this.contractAddress) + }) + ] } /** @@ -94,7 +119,13 @@ class SafeContract_v1_1_1 * @returns Array[Array[modules]] */ getModules: SafeContract_v1_1_1_Function<'getModules'> = async () => { - return [await this.contract.read.getModules()] + return [ + await this.runner.readContract({ + functionName: 'getModules', + abi: this.contractAbi, + address: asAddress(this.contractAddress) + }) + ] } /** @@ -103,7 +134,12 @@ class SafeContract_v1_1_1 * @returns Array[Array[modules], next] */ getModulesPaginated: SafeContract_v1_1_1_Function<'getModulesPaginated'> = async (args) => { - const [array, next] = await this.contract.read.getModulesPaginated(args) + const [array, next] = await this.runner.readContract({ + functionName: 'getModulesPaginated', + abi: this.contractAbi, + address: asAddress(this.contractAddress), + args + }) return [array, next] } @@ -112,7 +148,13 @@ class SafeContract_v1_1_1 * @returns Array[Array[owners]] */ getOwners: SafeContract_v1_1_1_Function<'getOwners'> = async () => { - return [await this.contract.read.getOwners()] + return [ + await this.runner.readContract({ + functionName: 'getOwners', + abi: this.contractAbi, + address: asAddress(this.contractAddress) + }) + ] } /** @@ -120,7 +162,13 @@ class SafeContract_v1_1_1 * @returns Array[threshold] */ getThreshold: SafeContract_v1_1_1_Function<'getThreshold'> = async () => { - return [await this.contract.read.getThreshold()] + return [ + await this.runner.readContract({ + functionName: 'getThreshold', + abi: this.contractAbi, + address: asAddress(this.contractAddress) + }) + ] } /** @@ -129,7 +177,14 @@ class SafeContract_v1_1_1 * @returns Array[isOwner] */ isOwner: SafeContract_v1_1_1_Function<'isOwner'> = async (args) => { - return [await this.contract.read.isOwner(args)] + return [ + await this.runner.readContract({ + functionName: 'isOwner', + abi: this.contractAbi, + address: asAddress(this.contractAddress), + args + }) + ] } /** @@ -137,7 +192,13 @@ class SafeContract_v1_1_1 * @returns Array[nonce] */ nonce: SafeContract_v1_1_1_Function<'nonce'> = async () => { - return [await this.contract.read.nonce()] + return [ + await this.runner.readContract({ + functionName: 'nonce', + abi: this.contractAbi, + address: asAddress(this.contractAddress) + }) + ] } /** @@ -145,7 +206,14 @@ class SafeContract_v1_1_1 * @returns Array[signedMessages] */ signedMessages: SafeContract_v1_1_1_Function<'signedMessages'> = async (args) => { - return [await this.contract.read.signedMessages(args)] + return [ + await this.runner.readContract({ + functionName: 'signedMessages', + abi: this.contractAbi, + address: asAddress(this.contractAddress), + args + }) + ] } /** @@ -154,7 +222,14 @@ class SafeContract_v1_1_1 * @returns Array[messageHash] */ getMessageHash: SafeContract_v1_1_1_Function<'getMessageHash'> = async (args) => { - return [await this.contract.read.getMessageHash(args)] + return [ + await this.runner.readContract({ + functionName: 'getMessageHash', + abi: this.contractAbi, + address: asAddress(this.contractAddress), + args + }) + ] } /** @@ -163,7 +238,14 @@ class SafeContract_v1_1_1 * @returns Array[encodedData] */ encodeTransactionData: SafeContract_v1_1_1_Function<'encodeTransactionData'> = async (args) => { - return [await this.contract.read.encodeTransactionData(args)] + return [ + await this.runner.readContract({ + functionName: 'encodeTransactionData', + abi: this.contractAbi, + address: asAddress(this.contractAddress), + args + }) + ] } /** @@ -172,7 +254,14 @@ class SafeContract_v1_1_1 * @returns Array[transactionHash] */ getTransactionHash: SafeContract_v1_1_1_Function<'getTransactionHash'> = async (args) => { - return [await this.contract.read.getTransactionHash(args)] + return [ + await this.runner.readContract({ + functionName: 'getTransactionHash', + abi: this.contractAbi, + address: asAddress(this.contractAddress), + args + }) + ] } /** @@ -283,8 +372,12 @@ class SafeContract_v1_1_1 options )) - const transactionResult = await this.contract.simulate.execTransaction( - [ + const converted = await this.convertOptions({ ...options, gasLimit }) + const txResult = await this.runner.simulateContract({ + address: asAddress(this.contractAddress), + functionName: 'execTransaction', + abi: this.contractAbi, + args: [ asAddress(safeTransaction.data.to), BigInt(safeTransaction.data.value), asHex(safeTransaction.data.data), @@ -296,10 +389,10 @@ class SafeContract_v1_1_1 asAddress(safeTransaction.data.refundReceiver), asHex(safeTransaction.encodedSignatures()) ], - await this.convertOptions({ ...options, gasLimit }) - ) + ...converted + }) - return transactionResult.result + return txResult.result } catch (error) { return false } diff --git a/packages/protocol-kit/src/contracts/Safe/v1.2.0/SafeContract_v1_2_0.ts b/packages/protocol-kit/src/contracts/Safe/v1.2.0/SafeContract_v1_2_0.ts index 3764e0a20..d867ec218 100644 --- a/packages/protocol-kit/src/contracts/Safe/v1.2.0/SafeContract_v1_2_0.ts +++ b/packages/protocol-kit/src/contracts/Safe/v1.2.0/SafeContract_v1_2_0.ts @@ -63,14 +63,26 @@ class SafeContract_v1_2_0 * @returns Array[contractName] */ NAME: SafeContract_v1_2_0_Function<'NAME'> = async () => { - return [await this.contract.read.NAME()] + return [ + await this.runner.readContract({ + functionName: 'NAME', + abi: this.contractAbi, + address: asAddress(this.contractAddress) + }) + ] } /** * @returns Array[safeContractVersion] */ VERSION: SafeContract_v1_2_0_Function<'VERSION'> = async () => { - return [await this.contract.read.VERSION()] + return [ + await this.runner.readContract({ + functionName: 'VERSION', + abi: this.contractAbi, + address: asAddress(this.contractAddress) + }) + ] } /** @@ -78,14 +90,27 @@ class SafeContract_v1_2_0 * @returns Array[approvedHashes] */ approvedHashes: SafeContract_v1_2_0_Function<'approvedHashes'> = async (args) => { - return [await this.contract.read.approvedHashes(args)] + return [ + await this.runner.readContract({ + functionName: 'approvedHashes', + abi: this.contractAbi, + address: asAddress(this.contractAddress), + args + }) + ] } /** * @returns Array[domainSeparator] */ domainSeparator: SafeContract_v1_2_0_Function<'domainSeparator'> = async () => { - return [await this.contract.read.domainSeparator()] + return [ + await this.runner.readContract({ + functionName: 'domainSeparator', + abi: this.contractAbi, + address: asAddress(this.contractAddress) + }) + ] } /** @@ -93,7 +118,13 @@ class SafeContract_v1_2_0 * @returns Array[Array[modules]] */ getModules: SafeContract_v1_2_0_Function<'getModules'> = async () => { - return [await this.contract.read.getModules()] + return [ + await this.runner.readContract({ + functionName: 'getModules', + abi: this.contractAbi, + address: asAddress(this.contractAddress) + }) + ] } /** @@ -102,7 +133,12 @@ class SafeContract_v1_2_0 * @returns Array[Array[modules], next] */ getModulesPaginated: SafeContract_v1_2_0_Function<'getModulesPaginated'> = async (args) => { - const [array, next] = await this.contract.read.getModulesPaginated(args) + const [array, next] = await this.runner.readContract({ + functionName: 'getModulesPaginated', + abi: this.contractAbi, + address: asAddress(this.contractAddress), + args + }) return [array, next] } @@ -111,7 +147,13 @@ class SafeContract_v1_2_0 * @returns Array[Array[owners]] */ getOwners: SafeContract_v1_2_0_Function<'getOwners'> = async () => { - return [await this.contract.read.getOwners()] + return [ + await this.runner.readContract({ + functionName: 'getOwners', + abi: this.contractAbi, + address: asAddress(this.contractAddress) + }) + ] } /** @@ -119,7 +161,13 @@ class SafeContract_v1_2_0 * @returns Array[threshold] */ getThreshold: SafeContract_v1_2_0_Function<'getThreshold'> = async () => { - return [await this.contract.read.getThreshold()] + return [ + await this.runner.readContract({ + functionName: 'getThreshold', + abi: this.contractAbi, + address: asAddress(this.contractAddress) + }) + ] } /** @@ -128,7 +176,14 @@ class SafeContract_v1_2_0 * @returns Array[isEnabled] */ isModuleEnabled: SafeContract_v1_2_0_Function<'isModuleEnabled'> = async (args) => { - return [await this.contract.read.isModuleEnabled(args)] + return [ + await this.runner.readContract({ + functionName: 'isModuleEnabled', + abi: this.contractAbi, + address: asAddress(this.contractAddress), + args + }) + ] } /** @@ -137,7 +192,14 @@ class SafeContract_v1_2_0 * @returns Array[isOwner] */ isOwner: SafeContract_v1_2_0_Function<'isOwner'> = async (args) => { - return [await this.contract.read.isOwner(args)] + return [ + await this.runner.readContract({ + functionName: 'isOwner', + abi: this.contractAbi, + address: asAddress(this.contractAddress), + args + }) + ] } /** @@ -145,7 +207,13 @@ class SafeContract_v1_2_0 * @returns Array[nonce] */ nonce: SafeContract_v1_2_0_Function<'nonce'> = async () => { - return [await this.contract.read.nonce()] + return [ + await this.runner.readContract({ + functionName: 'nonce', + abi: this.contractAbi, + address: asAddress(this.contractAddress) + }) + ] } /** @@ -153,7 +221,14 @@ class SafeContract_v1_2_0 * @returns Array[signedMessages] */ signedMessages: SafeContract_v1_2_0_Function<'signedMessages'> = async (args) => { - return [await this.contract.read.signedMessages(args)] + return [ + await this.runner.readContract({ + functionName: 'signedMessages', + abi: this.contractAbi, + address: asAddress(this.contractAddress), + args + }) + ] } /** @@ -161,7 +236,14 @@ class SafeContract_v1_2_0 * @returns Array[messageHash] */ getMessageHash: SafeContract_v1_2_0_Function<'getMessageHash'> = async (args) => { - return [await this.contract.read.getMessageHash(args)] + return [ + await this.runner.readContract({ + functionName: 'getMessageHash', + abi: this.contractAbi, + address: asAddress(this.contractAddress), + args + }) + ] } /** @@ -171,7 +253,14 @@ class SafeContract_v1_2_0 * @returns Array[encodedData] */ encodeTransactionData: SafeContract_v1_2_0_Function<'encodeTransactionData'> = async (args) => { - return [await this.contract.read.encodeTransactionData(args)] + return [ + await this.runner.readContract({ + functionName: 'encodeTransactionData', + abi: this.contractAbi, + address: asAddress(this.contractAddress), + args + }) + ] } /** @@ -181,7 +270,14 @@ class SafeContract_v1_2_0 * @returns Array[transactionHash] */ getTransactionHash: SafeContract_v1_2_0_Function<'getTransactionHash'> = async (args) => { - return [await this.contract.read.getTransactionHash(args)] + return [ + await this.runner.readContract({ + functionName: 'getTransactionHash', + abi: this.contractAbi, + address: asAddress(this.contractAddress), + args + }) + ] } /** @@ -285,8 +381,12 @@ class SafeContract_v1_2_0 options )) - const transactionResult = await this.contract.simulate.execTransaction( - [ + const converted = await this.convertOptions({ ...options, gasLimit }) + const txResult = await this.runner.simulateContract({ + address: asAddress(this.contractAddress), + functionName: 'execTransaction', + abi: this.contractAbi, + args: [ asAddress(safeTransaction.data.to), BigInt(safeTransaction.data.value), asHex(safeTransaction.data.data), @@ -298,10 +398,10 @@ class SafeContract_v1_2_0 asAddress(safeTransaction.data.refundReceiver), asHex(safeTransaction.encodedSignatures()) ], - await this.convertOptions({ ...options, gasLimit }) - ) + ...converted + }) - return transactionResult.result + return txResult.result } catch (error) { return false } diff --git a/packages/protocol-kit/src/contracts/Safe/v1.3.0/SafeContract_v1_3_0.ts b/packages/protocol-kit/src/contracts/Safe/v1.3.0/SafeContract_v1_3_0.ts index 8dd50ac8f..1b089a48e 100644 --- a/packages/protocol-kit/src/contracts/Safe/v1.3.0/SafeContract_v1_3_0.ts +++ b/packages/protocol-kit/src/contracts/Safe/v1.3.0/SafeContract_v1_3_0.ts @@ -64,7 +64,13 @@ class SafeContract_v1_3_0 * @returns Array[safeContractVersion] */ VERSION: SafeContract_v1_3_0_Function<'VERSION'> = async () => { - return [await this.contract.read.VERSION()] + return [ + await this.runner.readContract({ + functionName: 'VERSION', + abi: this.contractAbi, + address: asAddress(this.contractAddress) + }) + ] } /** @@ -72,7 +78,14 @@ class SafeContract_v1_3_0 * @returns Array[approvedHashes] */ approvedHashes: SafeContract_v1_3_0_Function<'approvedHashes'> = async (args) => { - return [await this.contract.read.approvedHashes(args)] + return [ + await this.runner.readContract({ + functionName: 'approvedHashes', + abi: this.contractAbi, + address: asAddress(this.contractAddress), + args + }) + ] } /** @@ -82,7 +95,12 @@ class SafeContract_v1_3_0 * @returns Empty array */ checkNSignatures: SafeContract_v1_3_0_Function<'checkNSignatures'> = async (args) => { - await this.contract.read.checkNSignatures(args) + await this.runner.readContract({ + functionName: 'checkNSignatures', + abi: this.contractAbi, + address: asAddress(this.contractAddress), + args + }) return [] } @@ -92,7 +110,12 @@ class SafeContract_v1_3_0 * @returns Empty array */ checkSignatures: SafeContract_v1_3_0_Function<'checkSignatures'> = async (args) => { - await this.contract.read.checkSignatures(args) + await this.runner.readContract({ + functionName: 'checkSignatures', + abi: this.contractAbi, + address: asAddress(this.contractAddress), + args + }) return [] } @@ -100,7 +123,13 @@ class SafeContract_v1_3_0 * @returns Array[domainSeparator] */ domainSeparator: SafeContract_v1_3_0_Function<'domainSeparator'> = async () => { - return [await this.contract.read.domainSeparator()] + return [ + await this.runner.readContract({ + functionName: 'domainSeparator', + abi: this.contractAbi, + address: asAddress(this.contractAddress) + }) + ] } /** @@ -109,7 +138,14 @@ class SafeContract_v1_3_0 * @returns Array[encodedData] */ encodeTransactionData: SafeContract_v1_3_0_Function<'encodeTransactionData'> = async (args) => { - return [await this.contract.read.encodeTransactionData(args)] + return [ + await this.runner.readContract({ + functionName: 'encodeTransactionData', + abi: this.contractAbi, + address: asAddress(this.contractAddress), + args + }) + ] } /** @@ -118,7 +154,12 @@ class SafeContract_v1_3_0 * @returns Array[Array[modules], next] */ getModulesPaginated: SafeContract_v1_3_0_Function<'getModulesPaginated'> = async (args) => { - const [array, next] = await this.contract.read.getModulesPaginated(args) + const [array, next] = await this.runner.readContract({ + functionName: 'getModulesPaginated', + abi: this.contractAbi, + address: asAddress(this.contractAddress), + args + }) return [array, next] } @@ -127,7 +168,13 @@ class SafeContract_v1_3_0 * @returns Array[Array[owners]] */ getOwners: SafeContract_v1_3_0_Function<'getOwners'> = async () => { - return [await this.contract.read.getOwners()] + return [ + await this.runner.readContract({ + functionName: 'getOwners', + abi: this.contractAbi, + address: asAddress(this.contractAddress) + }) + ] } /** @@ -136,7 +183,14 @@ class SafeContract_v1_3_0 * @returns Array[storage] */ getStorageAt: SafeContract_v1_3_0_Function<'getStorageAt'> = async (args) => { - return [await this.contract.read.getStorageAt(args)] + return [ + await this.runner.readContract({ + functionName: 'getStorageAt', + abi: this.contractAbi, + address: asAddress(this.contractAddress), + args + }) + ] } /** @@ -144,7 +198,13 @@ class SafeContract_v1_3_0 * @returns Array[threshold] */ getThreshold: SafeContract_v1_3_0_Function<'getThreshold'> = async () => { - return [await this.contract.read.getThreshold()] + return [ + await this.runner.readContract({ + functionName: 'getThreshold', + abi: this.contractAbi, + address: asAddress(this.contractAddress) + }) + ] } /** @@ -153,7 +213,14 @@ class SafeContract_v1_3_0 * @returns Array[transactionHash] */ getTransactionHash: SafeContract_v1_3_0_Function<'getTransactionHash'> = async (args) => { - return [await this.contract.read.getTransactionHash(args)] + return [ + await this.runner.readContract({ + functionName: 'getTransactionHash', + abi: this.contractAbi, + address: asAddress(this.contractAddress), + args + }) + ] } /** @@ -162,7 +229,14 @@ class SafeContract_v1_3_0 * @returns Array[isEnabled] */ isModuleEnabled: SafeContract_v1_3_0_Function<'isModuleEnabled'> = async (args) => { - return [await this.contract.read.isModuleEnabled(args)] + return [ + await this.runner.readContract({ + functionName: 'isModuleEnabled', + abi: this.contractAbi, + address: asAddress(this.contractAddress), + args + }) + ] } /** @@ -171,7 +245,14 @@ class SafeContract_v1_3_0 * @returns Array[isOwner] */ isOwner: SafeContract_v1_3_0_Function<'isOwner'> = async (args) => { - return [await this.contract.read.isOwner(args)] + return [ + await this.runner.readContract({ + functionName: 'isOwner', + abi: this.contractAbi, + address: asAddress(this.contractAddress), + args + }) + ] } /** @@ -179,7 +260,13 @@ class SafeContract_v1_3_0 * @returns Array[nonce] */ nonce: SafeContract_v1_3_0_Function<'nonce'> = async () => { - return [await this.contract.read.nonce()] + return [ + await this.runner.readContract({ + functionName: 'nonce', + abi: this.contractAbi, + address: asAddress(this.contractAddress) + }) + ] } /** @@ -187,7 +274,14 @@ class SafeContract_v1_3_0 * @returns Array[signedMessages] */ signedMessages: SafeContract_v1_3_0_Function<'signedMessages'> = async (args) => { - return [await this.contract.read.signedMessages(args)] + return [ + await this.runner.readContract({ + functionName: 'signedMessages', + abi: this.contractAbi, + address: asAddress(this.contractAddress), + args + }) + ] } /** @@ -217,8 +311,12 @@ class SafeContract_v1_3_0 options )) - const txResult = await this.contract.simulate.execTransaction( - [ + const converted = await this.convertOptions({ ...options, gasLimit }) + const txResult = await this.runner.simulateContract({ + address: asAddress(this.contractAddress), + functionName: 'execTransaction', + abi: this.contractAbi, + args: [ asAddress(safeTransaction.data.to), BigInt(safeTransaction.data.value), asHex(safeTransaction.data.data), @@ -230,8 +328,8 @@ class SafeContract_v1_3_0 asAddress(safeTransaction.data.refundReceiver), asHex(safeTransaction.encodedSignatures()) ], - await this.convertOptions({ ...options, gasLimit }) - ) + ...converted + }) return txResult.result } catch (error) { @@ -318,7 +416,13 @@ class SafeContract_v1_3_0 * @returns Array[chainId] */ async getChainId(): Promise<[bigint]> { - return [await this.contract.read.getChainId()] + return [ + await this.runner.readContract({ + functionName: 'getChainId', + abi: this.contractAbi, + address: asAddress(this.contractAddress) + }) + ] } /** diff --git a/packages/protocol-kit/src/contracts/Safe/v1.4.1/SafeContract_v1_4_1.ts b/packages/protocol-kit/src/contracts/Safe/v1.4.1/SafeContract_v1_4_1.ts index e08f322fa..3f596378f 100644 --- a/packages/protocol-kit/src/contracts/Safe/v1.4.1/SafeContract_v1_4_1.ts +++ b/packages/protocol-kit/src/contracts/Safe/v1.4.1/SafeContract_v1_4_1.ts @@ -64,7 +64,13 @@ class SafeContract_v1_4_1 * @returns Array[safeContractVersion] */ VERSION: SafeContract_v1_4_1_Function<'VERSION'> = async () => { - return [await this.contract.read.VERSION()] + return [ + await this.runner.readContract({ + functionName: 'VERSION', + abi: this.contractAbi, + address: asAddress(this.contractAddress) + }) + ] } /** @@ -72,7 +78,14 @@ class SafeContract_v1_4_1 * @returns Array[approvedHashes] */ approvedHashes: SafeContract_v1_4_1_Function<'approvedHashes'> = async (args) => { - return [await this.contract.read.approvedHashes(args)] + return [ + await this.runner.readContract({ + functionName: 'approvedHashes', + abi: this.contractAbi, + address: asAddress(this.contractAddress), + args + }) + ] } /** @@ -82,7 +95,12 @@ class SafeContract_v1_4_1 * @returns Empty array */ checkNSignatures: SafeContract_v1_4_1_Function<'checkNSignatures'> = async (args) => { - await this.contract.read.checkNSignatures(args) + await this.runner.readContract({ + functionName: 'checkNSignatures', + abi: this.contractAbi, + address: asAddress(this.contractAddress), + args + }) return [] } @@ -92,7 +110,12 @@ class SafeContract_v1_4_1 * @returns Empty array */ checkSignatures: SafeContract_v1_4_1_Function<'checkSignatures'> = async (args) => { - await this.contract.read.checkSignatures(args) + await this.runner.readContract({ + functionName: 'checkSignatures', + abi: this.contractAbi, + address: asAddress(this.contractAddress), + args + }) return [] } @@ -100,7 +123,13 @@ class SafeContract_v1_4_1 * @returns Array[domainSeparator] */ domainSeparator: SafeContract_v1_4_1_Function<'domainSeparator'> = async () => { - return [await this.contract.read.domainSeparator()] + return [ + await this.runner.readContract({ + functionName: 'domainSeparator', + abi: this.contractAbi, + address: asAddress(this.contractAddress) + }) + ] } /** @@ -109,7 +138,14 @@ class SafeContract_v1_4_1 * @returns Array[encodedData] */ encodeTransactionData: SafeContract_v1_4_1_Function<'encodeTransactionData'> = async (args) => { - return [await this.contract.read.encodeTransactionData(args)] + return [ + await this.runner.readContract({ + functionName: 'encodeTransactionData', + abi: this.contractAbi, + address: asAddress(this.contractAddress), + args + }) + ] } /** @@ -118,7 +154,12 @@ class SafeContract_v1_4_1 * @returns Array[Array[modules], next] */ getModulesPaginated: SafeContract_v1_4_1_Function<'getModulesPaginated'> = async (args) => { - const [array, next] = await this.contract.read.getModulesPaginated(args) + const [array, next] = await this.runner.readContract({ + functionName: 'getModulesPaginated', + abi: this.contractAbi, + address: asAddress(this.contractAddress), + args + }) return [array, next] } @@ -127,7 +168,13 @@ class SafeContract_v1_4_1 * @returns Array[Array[owners]] */ getOwners: SafeContract_v1_4_1_Function<'getOwners'> = async () => { - return [await this.contract.read.getOwners()] + return [ + await this.runner.readContract({ + functionName: 'getOwners', + abi: this.contractAbi, + address: asAddress(this.contractAddress) + }) + ] } /** @@ -136,7 +183,14 @@ class SafeContract_v1_4_1 * @returns Array[storage] */ getStorageAt: SafeContract_v1_4_1_Function<'getStorageAt'> = async (args) => { - return [await this.contract.read.getStorageAt(args)] + return [ + await this.runner.readContract({ + functionName: 'getStorageAt', + abi: this.contractAbi, + address: asAddress(this.contractAddress), + args + }) + ] } /** @@ -144,7 +198,13 @@ class SafeContract_v1_4_1 * @returns Array[threshold] */ getThreshold: SafeContract_v1_4_1_Function<'getThreshold'> = async () => { - return [await this.contract.read.getThreshold()] + return [ + await this.runner.readContract({ + functionName: 'getThreshold', + abi: this.contractAbi, + address: asAddress(this.contractAddress) + }) + ] } /** @@ -153,7 +213,14 @@ class SafeContract_v1_4_1 * @returns Array[transactionHash] */ getTransactionHash: SafeContract_v1_4_1_Function<'getTransactionHash'> = async (args) => { - return [await this.contract.read.getTransactionHash(args)] + return [ + await this.runner.readContract({ + functionName: 'getTransactionHash', + abi: this.contractAbi, + address: asAddress(this.contractAddress), + args + }) + ] } /** @@ -162,7 +229,14 @@ class SafeContract_v1_4_1 * @returns Array[isEnabled] */ isModuleEnabled: SafeContract_v1_4_1_Function<'isModuleEnabled'> = async (args) => { - return [await this.contract.read.isModuleEnabled(args)] + return [ + await this.runner.readContract({ + functionName: 'isModuleEnabled', + abi: this.contractAbi, + address: asAddress(this.contractAddress), + args + }) + ] } /** @@ -171,7 +245,14 @@ class SafeContract_v1_4_1 * @returns Array[isOwner] */ isOwner: SafeContract_v1_4_1_Function<'isOwner'> = async (args) => { - return [await this.contract.read.isOwner(args)] + return [ + await this.runner.readContract({ + functionName: 'isOwner', + abi: this.contractAbi, + address: asAddress(this.contractAddress), + args + }) + ] } /** @@ -179,7 +260,13 @@ class SafeContract_v1_4_1 * @returns Array[nonce] */ nonce: SafeContract_v1_4_1_Function<'nonce'> = async () => { - return [await this.contract.read.nonce()] + return [ + await this.runner.readContract({ + functionName: 'nonce', + abi: this.contractAbi, + address: asAddress(this.contractAddress) + }) + ] } /** @@ -187,7 +274,14 @@ class SafeContract_v1_4_1 * @returns Array[signedMessages] */ signedMessages: SafeContract_v1_4_1_Function<'signedMessages'> = async (args) => { - return [await this.contract.read.signedMessages(args)] + return [ + await this.runner.readContract({ + functionName: 'signedMessages', + abi: this.contractAbi, + address: asAddress(this.contractAddress), + args + }) + ] } /** @@ -217,8 +311,12 @@ class SafeContract_v1_4_1 options )) - const txResult = await this.contract.simulate.execTransaction( - [ + const converted = await this.convertOptions({ ...options, gasLimit }) + const txResult = await this.runner.simulateContract({ + address: asAddress(this.contractAddress), + functionName: 'execTransaction', + abi: this.contractAbi, + args: [ asAddress(safeTransaction.data.to), BigInt(safeTransaction.data.value), asHex(safeTransaction.data.data), @@ -230,8 +328,8 @@ class SafeContract_v1_4_1 asAddress(safeTransaction.data.refundReceiver), asHex(safeTransaction.encodedSignatures()) ], - await this.convertOptions({ ...options, gasLimit }) - ) + ...converted + }) return txResult.result } catch (error) { @@ -318,7 +416,13 @@ class SafeContract_v1_4_1 * @returns Array[chainId] */ async getChainId(): Promise<[bigint]> { - return [await this.contract.read.getChainId()] + return [ + await this.runner.readContract({ + functionName: 'getChainId', + abi: this.contractAbi, + address: asAddress(this.contractAddress) + }) + ] } /** diff --git a/packages/protocol-kit/src/contracts/SafeProxyFactory/SafeProxyFactoryBaseContract.ts b/packages/protocol-kit/src/contracts/SafeProxyFactory/SafeProxyFactoryBaseContract.ts index 5b65e3c95..1c7416a7a 100644 --- a/packages/protocol-kit/src/contracts/SafeProxyFactory/SafeProxyFactoryBaseContract.ts +++ b/packages/protocol-kit/src/contracts/SafeProxyFactory/SafeProxyFactoryBaseContract.ts @@ -52,7 +52,7 @@ abstract class SafeProxyFactoryBaseContract< safeVersion: SafeVersion, customContractAddress?: string, customContractAbi?: SafeProxyFactoryContractAbiType, - runner?: PublicClient | null + runner?: PublicClient ) { const contractName = 'safeProxyFactoryVersion' diff --git a/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.0.0/SafeProxyFactoryContract_v1_0_0.ts b/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.0.0/SafeProxyFactoryContract_v1_0_0.ts index ad86ff8d7..c8dd82983 100644 --- a/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.0.0/SafeProxyFactoryContract_v1_0_0.ts +++ b/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.0.0/SafeProxyFactoryContract_v1_0_0.ts @@ -40,7 +40,7 @@ class SafeProxyFactoryContract_v1_0_0 safeProvider: SafeProvider, customContractAddress?: string, customContractAbi?: SafeProxyFactoryContract_v1_0_0_Abi, - runner?: PublicClient | null + runner?: PublicClient ) { const safeVersion = '1.0.0' const defaultAbi = safeProxyFactory_1_0_0_ContractArtifacts.abi @@ -63,7 +63,13 @@ class SafeProxyFactoryContract_v1_0_0 * @returns Array[creationCode] */ proxyCreationCode: SafeProxyFactoryContract_v1_0_0_Function<'proxyCreationCode'> = async () => { - return [await this.contract.read.proxyCreationCode()] + return [ + await this.runner.readContract({ + functionName: 'proxyCreationCode', + abi: this.contractAbi, + address: asAddress(this.contractAddress) + }) + ] } /** @@ -71,7 +77,13 @@ class SafeProxyFactoryContract_v1_0_0 * @returns Array[runtimeCode] */ proxyRuntimeCode: SafeProxyFactoryContract_v1_0_0_Function<'proxyRuntimeCode'> = async () => { - return [await this.contract.read.proxyRuntimeCode()] + return [ + await this.runner.readContract({ + functionName: 'proxyRuntimeCode', + abi: this.contractAbi, + address: asAddress(this.contractAddress) + }) + ] } /** diff --git a/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.1.1/SafeProxyFactoryContract_v1_1_1.ts b/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.1.1/SafeProxyFactoryContract_v1_1_1.ts index 245833075..19d02c0d1 100644 --- a/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.1.1/SafeProxyFactoryContract_v1_1_1.ts +++ b/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.1.1/SafeProxyFactoryContract_v1_1_1.ts @@ -40,7 +40,7 @@ class SafeProxyFactoryContract_v1_1_1 safeProvider: SafeProvider, customContractAddress?: string, customContractAbi?: SafeProxyFactoryContract_v1_1_1_Abi, - runner?: PublicClient | null + runner?: PublicClient ) { const safeVersion = '1.1.1' const defaultAbi = safeProxyFactory_1_1_1_ContractArtifacts.abi @@ -63,7 +63,13 @@ class SafeProxyFactoryContract_v1_1_1 * @returns Array[creationCode] */ proxyCreationCode: SafeProxyFactoryContract_v1_1_1_Function<'proxyCreationCode'> = async () => { - return [await this.contract.read.proxyCreationCode()] + return [ + await this.runner.readContract({ + functionName: 'proxyCreationCode', + abi: this.contractAbi, + address: asAddress(this.contractAddress) + }) + ] } /** @@ -71,7 +77,13 @@ class SafeProxyFactoryContract_v1_1_1 * @returns Array[runtimeCode] */ proxyRuntimeCode: SafeProxyFactoryContract_v1_1_1_Function<'proxyRuntimeCode'> = async () => { - return [await this.contract.read.proxyRuntimeCode()] + return [ + await this.runner.readContract({ + functionName: 'proxyRuntimeCode', + abi: this.contractAbi, + address: asAddress(this.contractAddress) + }) + ] } /** diff --git a/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.3.0/SafeProxyFactoryContract_v1_3_0.ts b/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.3.0/SafeProxyFactoryContract_v1_3_0.ts index fa595ad92..78aee1bfa 100644 --- a/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.3.0/SafeProxyFactoryContract_v1_3_0.ts +++ b/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.3.0/SafeProxyFactoryContract_v1_3_0.ts @@ -40,7 +40,7 @@ class SafeProxyFactoryContract_v1_3_0 safeProvider: SafeProvider, customContractAddress?: string, customContractAbi?: SafeProxyFactoryContract_v1_3_0_Abi, - runner?: PublicClient | null + runner?: PublicClient ) { const safeVersion = '1.3.0' const defaultAbi = safeProxyFactory_1_3_0_ContractArtifacts.abi @@ -63,7 +63,13 @@ class SafeProxyFactoryContract_v1_3_0 * @returns Array[creationCode] */ proxyCreationCode: SafeProxyFactoryContract_v1_3_0_Function<'proxyCreationCode'> = async () => { - return [await this.contract.read.proxyCreationCode()] + return [ + await this.runner.readContract({ + functionName: 'proxyCreationCode', + abi: this.contractAbi, + address: asAddress(this.contractAddress) + }) + ] } /** @@ -71,7 +77,13 @@ class SafeProxyFactoryContract_v1_3_0 * @returns Array[runtimeCode] */ proxyRuntimeCode: SafeProxyFactoryContract_v1_3_0_Function<'proxyRuntimeCode'> = async () => { - return [await this.contract.read.proxyRuntimeCode()] + return [ + await this.runner.readContract({ + functionName: 'proxyRuntimeCode', + abi: this.contractAbi, + address: asAddress(this.contractAddress) + }) + ] } /** diff --git a/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.4.1/SafeProxyFactoryContract_v1_4_1.ts b/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.4.1/SafeProxyFactoryContract_v1_4_1.ts index e0a8eff0e..c1238c540 100644 --- a/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.4.1/SafeProxyFactoryContract_v1_4_1.ts +++ b/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.4.1/SafeProxyFactoryContract_v1_4_1.ts @@ -40,7 +40,7 @@ class SafeProxyFactoryContract_v1_4_1 safeProvider: SafeProvider, customContractAddress?: string, customContractAbi?: SafeProxyFactoryContract_v1_4_1_Abi, - runner?: PublicClient | null + runner?: PublicClient ) { const safeVersion = '1.4.1' const defaultAbi = safeProxyFactory_1_4_1_ContractArtifacts.abi @@ -63,7 +63,13 @@ class SafeProxyFactoryContract_v1_4_1 * @returns Array[chainId] */ getChainId: SafeProxyFactoryContract_v1_4_1_Function<'getChainId'> = async () => { - return [await this.contract.read.getChainId()] + return [ + await this.runner.readContract({ + functionName: 'getChainId', + abi: this.contractAbi, + address: asAddress(this.contractAddress) + }) + ] } /** @@ -71,7 +77,13 @@ class SafeProxyFactoryContract_v1_4_1 * @returns Array[creationCode] */ proxyCreationCode: SafeProxyFactoryContract_v1_4_1_Function<'proxyCreationCode'> = async () => { - return [await this.contract.read.proxyCreationCode()] + return [ + await this.runner.readContract({ + functionName: 'proxyCreationCode', + abi: this.contractAbi, + address: asAddress(this.contractAddress) + }) + ] } /** diff --git a/packages/protocol-kit/src/contracts/SignMessageLib/v1.3.0/SignMessageLibContract_v1_3_0.ts b/packages/protocol-kit/src/contracts/SignMessageLib/v1.3.0/SignMessageLibContract_v1_3_0.ts index 0c05575dc..8aa6b4125 100644 --- a/packages/protocol-kit/src/contracts/SignMessageLib/v1.3.0/SignMessageLibContract_v1_3_0.ts +++ b/packages/protocol-kit/src/contracts/SignMessageLib/v1.3.0/SignMessageLibContract_v1_3_0.ts @@ -9,6 +9,7 @@ import { SignMessageLibContract_v1_3_0_Function, signMessageLib_1_3_0_ContractArtifacts } from '@safe-global/safe-core-sdk-types' +import { asAddress } from '@safe-global/protocol-kit/utils/types' /** * SignMessageLibContract_v1_3_0 is the implementation specific to the SignMessageLib contract version 1.3.0. @@ -49,7 +50,14 @@ class SignMessageLibContract_v1_3_0 * @param args - Array[message] */ getMessageHash: SignMessageLibContract_v1_3_0_Function<'getMessageHash'> = async (args) => { - return [await this.contract.read.getMessageHash(args)] + return [ + await this.runner.readContract({ + functionName: 'getMessageHash', + abi: this.contractAbi, + address: asAddress(this.contractAddress), + args + }) + ] } /** diff --git a/packages/protocol-kit/src/contracts/SignMessageLib/v1.4.1/SignMessageLibContract_v1_4_1.ts b/packages/protocol-kit/src/contracts/SignMessageLib/v1.4.1/SignMessageLibContract_v1_4_1.ts index ec7a27d82..f307bd858 100644 --- a/packages/protocol-kit/src/contracts/SignMessageLib/v1.4.1/SignMessageLibContract_v1_4_1.ts +++ b/packages/protocol-kit/src/contracts/SignMessageLib/v1.4.1/SignMessageLibContract_v1_4_1.ts @@ -9,6 +9,7 @@ import { SignMessageLibContract_v1_4_1_Function, signMessageLib_1_4_1_ContractArtifacts } from '@safe-global/safe-core-sdk-types' +import { asAddress } from '@safe-global/protocol-kit/utils/types' /** * SignMessageLibContract_v1_4_1 is the implementation specific to the SignMessageLib contract version 1.4.1. @@ -50,7 +51,14 @@ class SignMessageLibContract_v1_4_1 * @param args - Array[message] */ getMessageHash: SignMessageLibContract_v1_4_1_Function<'getMessageHash'> = async (args) => { - return [await this.contract.read.getMessageHash(args)] + return [ + await this.runner.readContract({ + functionName: 'getMessageHash', + abi: this.contractAbi, + address: asAddress(this.contractAddress), + args + }) + ] } /** diff --git a/packages/protocol-kit/src/contracts/SimulateTxAccessor/SimulateTxAccessorBaseContract.ts b/packages/protocol-kit/src/contracts/SimulateTxAccessor/SimulateTxAccessorBaseContract.ts index 95dbc7042..ae85c2815 100644 --- a/packages/protocol-kit/src/contracts/SimulateTxAccessor/SimulateTxAccessorBaseContract.ts +++ b/packages/protocol-kit/src/contracts/SimulateTxAccessor/SimulateTxAccessorBaseContract.ts @@ -42,7 +42,7 @@ abstract class SimulateTxAccessorBaseContract< safeVersion: SafeVersion, customContractAddress?: string, customContractAbi?: SimulateTxAccessorContractAbiType, - runner?: PublicClient | null + runner?: PublicClient ) { const contractName = 'simulateTxAccessorVersion' diff --git a/packages/protocol-kit/src/utils/transactions/types.ts b/packages/protocol-kit/src/utils/transactions/types.ts index 19994fc52..054122077 100644 --- a/packages/protocol-kit/src/utils/transactions/types.ts +++ b/packages/protocol-kit/src/utils/transactions/types.ts @@ -1,5 +1,5 @@ import { SafeTransactionDataPartial } from '@safe-global/safe-core-sdk-types' -import { Chain, Address } from 'viem' +import { Chain, Address, Account } from 'viem' export type SafeTransactionOptionalProps = Pick< SafeTransactionDataPartial, @@ -8,7 +8,7 @@ export type SafeTransactionOptionalProps = Pick< export type WalletTransactionOptions = { chain: Chain - account: Address + account: Address | Account gas?: bigint maxFeePerGas?: bigint maxPriorityFeePerGas?: bigint @@ -17,7 +17,7 @@ export type WalletTransactionOptions = { export type WalletLegacyTransactionOptions = { chain: Chain - account: Address + account: Address | Account gas?: bigint gasPrice?: bigint nonce?: number diff --git a/playground/protocol-kit/deploy-safe.ts b/playground/protocol-kit/deploy-safe.ts index 867bebf29..4fa80b367 100644 --- a/playground/protocol-kit/deploy-safe.ts +++ b/playground/protocol-kit/deploy-safe.ts @@ -1,5 +1,6 @@ import { SafeAccountConfig, SafeFactory } from '@safe-global/protocol-kit' import { SafeVersion } from '@safe-global/safe-core-sdk-types' +import { privateKeyToAddress } from 'viem/accounts' // This file can be used to play around with the Safe Core SDK @@ -14,13 +15,15 @@ interface Config { } } +const privateKey = "0x943bb3afb48b023089757cb3317fba30bd9945edef44907103d3d432f972db90" // 0x2c101b1e0d4d60699e0da38d0630c51833159d4a16c70e29917402af147c6cef + const config: Config = { - RPC_URL: 'https://sepolia.gateway.tenderly.co', - DEPLOYER_ADDRESS_PRIVATE_KEY: '', + RPC_URL: 'https://rpc.sepolia.org', + DEPLOYER_ADDRESS_PRIVATE_KEY: privateKey, DEPLOY_SAFE: { - OWNERS: ['OWNER_ADDRESS'], + OWNERS: [privateKeyToAddress(privateKey)], THRESHOLD: 1, // - SALT_NONCE: '150000', + SALT_NONCE: '150002', SAFE_VERSION: '1.3.0' } } From 1a52333218df026e83232c7412b3c6badb44c709 Mon Sep 17 00:00:00 2001 From: leonardotc Date: Mon, 22 Jul 2024 15:12:04 +0200 Subject: [PATCH 55/85] Add chain to the external signer --- packages/protocol-kit/src/SafeProvider.ts | 17 ++++++++++++++--- .../protocol-kit/src/contracts/BaseContract.ts | 14 ++++++++------ .../src/utils/transactions/utils.ts | 2 +- packages/protocol-kit/src/utils/types.ts | 7 ++++++- packages/safe-kit/src/utils/sendTransaction.ts | 2 -- 5 files changed, 29 insertions(+), 13 deletions(-) diff --git a/packages/protocol-kit/src/SafeProvider.ts b/packages/protocol-kit/src/SafeProvider.ts index 7d48dd6ab..e59091ca7 100644 --- a/packages/protocol-kit/src/SafeProvider.ts +++ b/packages/protocol-kit/src/SafeProvider.ts @@ -25,7 +25,7 @@ import { SocketTransport, ExternalSigner } from '@safe-global/protocol-kit/types' -import { asAddress, asHash, asHex } from './utils/types' +import { asAddress, asHash, asHex, getChainById } from './utils/types' import { createPublicClient, createWalletClient, @@ -39,7 +39,8 @@ import { encodeAbiParameters, parseAbiParameters, toBytes, - BlockTag + BlockTag, + Chain } from 'viem' import { privateKeyToAccount } from 'viem/accounts' import { @@ -61,6 +62,7 @@ function blockTag(blockTag: any) { } class SafeProvider { + #chain?: Chain #externalProvider: PublicClient signer?: string provider: Eip1193Provider | HttpTransport | SocketTransport @@ -87,7 +89,8 @@ class SafeProvider { async getExternalSigner(): Promise { // If the signer is not an Ethereum address, it should be a private key - const { transport, chain } = this.getExternalProvider() + const { transport, chain = await this.#getChain() } = this.getExternalProvider() + if (this.signer && !this.isAddress(this.signer)) { const account = privateKeyToAccount(asHex(this.signer)) return createWalletClient({ @@ -370,6 +373,14 @@ class SafeProvider { decodeParameters(types: string, values: string): { [key: string]: any } { return decodeAbiParameters(parseAbiParameters(types), asHex(values)) } + + async #getChain(): Promise { + if (this.#chain) return this.#chain + const chain = getChainById(await this.getChainId()) + if (!chain) throw new Error('Invalid chainId') + this.#chain = chain + return this.#chain + } } export default SafeProvider diff --git a/packages/protocol-kit/src/contracts/BaseContract.ts b/packages/protocol-kit/src/contracts/BaseContract.ts index 59c8c034c..4729c50bb 100644 --- a/packages/protocol-kit/src/contracts/BaseContract.ts +++ b/packages/protocol-kit/src/contracts/BaseContract.ts @@ -11,7 +11,6 @@ import { } from 'viem' import { contractName, getContractDeployment } from '@safe-global/protocol-kit/contracts/config' import SafeProvider from '@safe-global/protocol-kit/SafeProvider' -import * as allChains from 'viem/chains' import { EncodeFunction, EstimateGasFunction, @@ -19,11 +18,11 @@ import { SafeVersion, TransactionOptions } from '@safe-global/safe-core-sdk-types' -import { asAddress } from '../utils/types' +import { asAddress, getChainById } from '../utils/types' import { WalletTransactionOptions, WalletLegacyTransactionOptions, - converTransactionOptions + convertTransactionOptions } from '@safe-global/protocol-kit/utils' /** @@ -117,15 +116,18 @@ class BaseContract { ): Promise { const chain = this.getChain() if (!chain) throw new Error('Invalid chainId') + const signerAddress = await this.safeProvider.getSignerAddress() const signer = this.wallet?.account - const account = signer || asAddress(signerAddress!) - const txOptions = await converTransactionOptions(options) + if (!signer || !signerAddress) throw new Error('Invalid signer') + + const account = signer || asAddress(signerAddress) + const txOptions = await convertTransactionOptions(options) return { chain, ...txOptions, account } // Needs to be in this order to override the `account` if necessary } getChain(): Chain | undefined { - return Object.values(allChains).find((chain) => chain.id === Number(this.chainId)) + return getChainById(this.chainId) } getAddress: GetAddressFunction = () => { diff --git a/packages/protocol-kit/src/utils/transactions/utils.ts b/packages/protocol-kit/src/utils/transactions/utils.ts index 2f1b67414..37660e71c 100644 --- a/packages/protocol-kit/src/utils/transactions/utils.ts +++ b/packages/protocol-kit/src/utils/transactions/utils.ts @@ -225,7 +225,7 @@ export function toCallGasParameters( return params } -export function converTransactionOptions( +export function convertTransactionOptions( options?: TransactionOptions ): Partial { return isLegacyTransaction(options) ? createLegacyTxOptions(options) : createTxOptions(options) diff --git a/packages/protocol-kit/src/utils/types.ts b/packages/protocol-kit/src/utils/types.ts index 74ec23392..9e6780169 100644 --- a/packages/protocol-kit/src/utils/types.ts +++ b/packages/protocol-kit/src/utils/types.ts @@ -1,5 +1,6 @@ import { SafeConfig, SafeConfigWithPredictedSafe } from '../types' -import { getAddress, Address, isHex, Hex, Hash } from 'viem' +import { getAddress, Address, isHex, Hex, Hash, Chain } from 'viem' +import * as allChains from 'viem/chains' export function isSafeConfigWithPredictedSafe( config: SafeConfig @@ -22,3 +23,7 @@ export function asHash(hash: string): Hash { export function asHex(hex?: string): Hex { return isHex(hex) ? (hex as Hex) : (`0x${hex}` as Hex) } + +export function getChainById(chainId: bigint): Chain | undefined { + return Object.values(allChains).find((chain) => chain.id === Number(chainId)) +} diff --git a/packages/safe-kit/src/utils/sendTransaction.ts b/packages/safe-kit/src/utils/sendTransaction.ts index 33f43bce8..1bae09c0d 100644 --- a/packages/safe-kit/src/utils/sendTransaction.ts +++ b/packages/safe-kit/src/utils/sendTransaction.ts @@ -21,11 +21,9 @@ export const sendTransaction = async ( > const client = await protocolKit.getSafeProvider().getExternalProvider() - const account = (await protocolKit.getSafeProvider().getSignerAddress()) || '0x' if (!signer) throw new Error('SafeProvider must be initialized with a signer to use this function') const hash = await signer.sendTransaction({ - account: account as Address, to: transaction.to as Address, data: transaction.data as Hex, value: BigInt(transaction.value), From e3ec4d8d44643d36aba0181f437c7c1770cd61d0 Mon Sep 17 00:00:00 2001 From: Tim Schwarz <4171783+tmjssz@users.noreply.github.com> Date: Mon, 22 Jul 2024 15:41:06 +0200 Subject: [PATCH 56/85] Fix parsing of SafeTxGas estimation from viem error object --- .../src/utils/transactions/gas.ts | 48 ++++++++++++------- playground/relay-kit/paid-transaction.ts | 5 +- playground/relay-kit/sponsored-transaction.ts | 12 +++-- .../usdc-transfer-4337-counterfactual.ts | 2 +- 4 files changed, 43 insertions(+), 24 deletions(-) diff --git a/packages/protocol-kit/src/utils/transactions/gas.ts b/packages/protocol-kit/src/utils/transactions/gas.ts index dafb12577..c9c6dd6a7 100644 --- a/packages/protocol-kit/src/utils/transactions/gas.ts +++ b/packages/protocol-kit/src/utils/transactions/gas.ts @@ -1,3 +1,4 @@ +import { BaseError, CallExecutionErrorType, RawContractErrorType } from 'viem' import { OperationType, SafeVersion, SafeTransaction } from '@safe-global/safe-core-sdk-types' import semverSatisfies from 'semver/functions/satisfies' import Safe from '@safe-global/protocol-kit/Safe' @@ -358,13 +359,24 @@ function decodeSafeTxGas(encodedDataResponse: string): string { type GnosisChainEstimationError = { info: { error: { data: string | { data: string } } } } type EthersEstimationError = { data: string } -type ViemEstimationError = { info: { error: { message: string } } } -type CallExecutionError = { details: string } -type EstimationError = Error & - EthersEstimationError & - GnosisChainEstimationError & - ViemEstimationError & - CallExecutionError +type ViemEstimationError = BaseError | CallExecutionErrorType +type EstimationError = + | Error + | EthersEstimationError + | GnosisChainEstimationError + | ViemEstimationError + +function isEthersError(error: EstimationError): error is EthersEstimationError { + return (error as EthersEstimationError).data != null +} + +function isViemError(error: EstimationError): error is ViemEstimationError { + return (error as ViemEstimationError).version.includes('viem') +} + +function isGnosisChainEstimationError(error: EstimationError): error is GnosisChainEstimationError { + return (error as GnosisChainEstimationError).info.error.data != null +} /** * Parses the SafeTxGas estimation response from different providers. @@ -376,21 +388,21 @@ type EstimationError = Error & */ function parseSafeTxGasErrorResponse(error: EstimationError) { // Ethers v6 - const ethersData = error?.data - if (ethersData) { - return decodeSafeTxGas(ethersData) + if (isEthersError(error)) { + return decodeSafeTxGas(error.data) } // viem - const viemError = error?.info?.error?.message || error?.details - if (viemError) { - return decodeSafeTxGas(viemError) + if (isViemError(error)) { + const cause = error.walk() as RawContractErrorType + if (typeof cause?.data === 'string') { + return decodeSafeTxGas(cause?.data) + } } // gnosis-chain - const gnosisChainProviderData = error?.info?.error?.data - - if (gnosisChainProviderData) { + if (isGnosisChainEstimationError(error)) { + const gnosisChainProviderData = error.info.error.data const isString = typeof gnosisChainProviderData === 'string' const encodedDataResponse = isString ? gnosisChainProviderData : gnosisChainProviderData.data @@ -398,10 +410,10 @@ function parseSafeTxGasErrorResponse(error: EstimationError) { } // Error message - const isEncodedDataPresent = error?.message?.includes('0x') + const isEncodedDataPresent = error.message.includes('0x') if (isEncodedDataPresent) { - return decodeSafeTxGas(error?.message) + return decodeSafeTxGas(error.message) } throw new Error('Could not parse SafeTxGas from Estimation response, Details: ' + error?.message) diff --git a/playground/relay-kit/paid-transaction.ts b/playground/relay-kit/paid-transaction.ts index 3739295b3..26c548b8a 100644 --- a/playground/relay-kit/paid-transaction.ts +++ b/playground/relay-kit/paid-transaction.ts @@ -21,7 +21,7 @@ const config = { SAFE_SIGNER_ADDRESS: '' } -const RPC_URL = 'https://sepolia.gateway.tenderly.co' +const RPC_URL = 'https://rpc.sepolia.org' const mockOnRampConfig = { ADDRESS: '
', @@ -130,6 +130,9 @@ async function main() { const response = await gelatoSafeClient.relayTransaction(safeTransactions, options) console.log({ GelatoTaskId: response }) + console.log( + `Check the status of the transaction at https://relay.gelato.digital/tasks/status/${response.taskId}` + ) } main() diff --git a/playground/relay-kit/sponsored-transaction.ts b/playground/relay-kit/sponsored-transaction.ts index 5c238afb3..31da0f5eb 100644 --- a/playground/relay-kit/sponsored-transaction.ts +++ b/playground/relay-kit/sponsored-transaction.ts @@ -1,5 +1,6 @@ import { Address, createWalletClient, custom, formatEther, Hex } from 'viem' import { privateKeyToAccount } from 'viem/accounts' +import { sepolia } from 'viem/chains' import { createSafeClient, SafeClient } from '@safe-global/safe-kit' import { GelatoRelayPack } from '@safe-global/relay-kit' import { @@ -24,7 +25,7 @@ const config = { RELAY_API_KEY: '' } -const RPC_URL = 'https://sepolia.gateway.tenderly.co' +const RPC_URL = 'https://rpc.sepolia.org' const mockOnRampConfig = { ADDRESS: '
', @@ -89,12 +90,12 @@ async function main() { if (safeBalance < BigInt(txConfig.VALUE)) { const fakeOnRampSigner = createWalletClient({ account: privateKeyToAccount(mockOnRampConfig.PRIVATE_KEY as Hex), - transport: custom(externalProvider) + transport: custom(externalProvider), + chain: sepolia }) const hash = await fakeOnRampSigner.sendTransaction({ to: predictedSafeAddress, - value: BigInt(txConfig.VALUE), - chain: undefined + value: BigInt(txConfig.VALUE) }) console.log(`Funding the Safe with ${formatEther(BigInt(txConfig.VALUE))} ETH`) await externalProvider.waitForTransactionReceipt({ hash }) @@ -119,6 +120,9 @@ async function main() { const response = await gelatoSafeClient.relayTransaction(safeTransactions, options) console.log({ GelatoTaskId: response }) + console.log( + `Check the status of the transaction at https://relay.gelato.digital/tasks/status/${response.taskId}` + ) } main() diff --git a/playground/relay-kit/usdc-transfer-4337-counterfactual.ts b/playground/relay-kit/usdc-transfer-4337-counterfactual.ts index dfea472a7..24b527f7b 100644 --- a/playground/relay-kit/usdc-transfer-4337-counterfactual.ts +++ b/playground/relay-kit/usdc-transfer-4337-counterfactual.ts @@ -12,7 +12,7 @@ const PIMLICO_API_KEY = '' const OWNER_ADDRESS = '' // RPC URL -const RPC_URL = 'https://sepolia.gateway.tenderly.co' // SEPOLIA +const RPC_URL = 'https://rpc.sepolia.org' // SEPOLIA // const RPC_URL = 'https://rpc.gnosischain.com/' // GNOSIS // CHAIN From a7c5bc1af9cc26653f49e5bd819ed2967b0c155c Mon Sep 17 00:00:00 2001 From: Tim Schwarz <4171783+tmjssz@users.noreply.github.com> Date: Mon, 22 Jul 2024 17:33:12 +0200 Subject: [PATCH 57/85] relay-kit: Fix getNonce call in Safe4337Pack --- .../src/packs/safe-4337/Safe4337Pack.test.ts | 13 ++++++------- .../relay-kit/src/packs/safe-4337/Safe4337Pack.ts | 6 ++++-- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.test.ts b/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.test.ts index 3b8ea6f92..5ecc051f2 100644 --- a/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.test.ts +++ b/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.test.ts @@ -29,14 +29,9 @@ const requestMock = jest.fn(async ({ method }: { method: keyof typeof requestRes return requestResponseMap[method] }) -const readContractMock = jest.fn().mockResolvedValue(1n) - jest.mock('./utils', () => ({ ...jest.requireActual('./utils'), - getEip4337BundlerProvider: jest.fn(() => ({ - request: requestMock, - readContract: readContractMock - })) + getEip4337BundlerProvider: jest.fn(() => ({ request: requestMock })) })) let safe4337ModuleAddress: viem.Hash @@ -652,11 +647,15 @@ describe('Safe4337Pack', () => { safeAddress: fixtures.SAFE_ADDRESS_v1_4_1 } }) + const readContractSpy = jest.spyOn( + safe4337Pack.protocolKit.getSafeProvider().getExternalProvider(), + 'readContract' + ) let safeOperation = await safe4337Pack.createTransaction({ transactions: [transferUSDC] }) - expect(readContractMock).toHaveBeenCalledWith({ + expect(readContractSpy).toHaveBeenCalledWith({ address: constants.ENTRYPOINT_ADDRESS_V06, abi: constants.ENTRYPOINT_ABI, functionName: 'getNonce', diff --git a/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.ts b/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.ts index 30d935602..d881fe48c 100644 --- a/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.ts +++ b/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.ts @@ -682,11 +682,13 @@ export class Safe4337Pack extends RelayKitBasePack<{ * @returns {Promise} The Promise object will resolve to the account nonce. */ async #getSafeNonceFromEntrypoint(safeAddress: string): Promise { - const newNonce = await this.#bundlerClient.readContract({ + const externalProvider = this.protocolKit.getSafeProvider().getExternalProvider() + + const newNonce = await externalProvider.readContract({ address: (this.#ENTRYPOINT_ADDRESS as Address) || '0x', abi: ENTRYPOINT_ABI, functionName: 'getNonce', - args: [safeAddress as Address, BigInt(0)] + args: [safeAddress as Address, 0n] }) return newNonce.toString() From 03907fd16ab8d2b73d7890b435b90c6c1da79292 Mon Sep 17 00:00:00 2001 From: Tim Schwarz <4171783+tmjssz@users.noreply.github.com> Date: Mon, 22 Jul 2024 18:03:00 +0200 Subject: [PATCH 58/85] Use different RPC endpoint --- playground/relay-kit/usdc-transfer-4337-erc20-counterfactual.ts | 2 +- playground/relay-kit/usdc-transfer-4337-erc20.ts | 2 +- .../relay-kit/usdc-transfer-4337-sponsored-counterfactual.ts | 2 +- playground/relay-kit/usdc-transfer-4337-sponsored.ts | 2 +- playground/relay-kit/usdc-transfer-4337.ts | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/playground/relay-kit/usdc-transfer-4337-erc20-counterfactual.ts b/playground/relay-kit/usdc-transfer-4337-erc20-counterfactual.ts index cb042e428..e19896f90 100644 --- a/playground/relay-kit/usdc-transfer-4337-erc20-counterfactual.ts +++ b/playground/relay-kit/usdc-transfer-4337-erc20-counterfactual.ts @@ -15,7 +15,7 @@ const CHAIN_NAME = 'sepolia' // const CHAIN_NAME = 'gnosis' // RPC URL -const RPC_URL = 'https://sepolia.gateway.tenderly.co' // SEPOLIA +const RPC_URL = 'https://rpc.sepolia.org' // SEPOLIA // const RPC_URL = 'https://rpc.gnosischain.com/' // GNOSIS // Bundler URL diff --git a/playground/relay-kit/usdc-transfer-4337-erc20.ts b/playground/relay-kit/usdc-transfer-4337-erc20.ts index 3424c2adc..b952f5cc0 100644 --- a/playground/relay-kit/usdc-transfer-4337-erc20.ts +++ b/playground/relay-kit/usdc-transfer-4337-erc20.ts @@ -15,7 +15,7 @@ const CHAIN_NAME = 'sepolia' // const CHAIN_NAME = 'gnosis' // RPC URL -const RPC_URL = 'https://sepolia.gateway.tenderly.co' // SEPOLIA +const RPC_URL = 'https://rpc.sepolia.org' // SEPOLIA // const RPC_URL = 'https://rpc.gnosischain.com/' // GNOSIS // Bundler URL diff --git a/playground/relay-kit/usdc-transfer-4337-sponsored-counterfactual.ts b/playground/relay-kit/usdc-transfer-4337-sponsored-counterfactual.ts index c85e5765f..e98d08fdb 100644 --- a/playground/relay-kit/usdc-transfer-4337-sponsored-counterfactual.ts +++ b/playground/relay-kit/usdc-transfer-4337-sponsored-counterfactual.ts @@ -18,7 +18,7 @@ const CHAIN_NAME = 'sepolia' // const CHAIN_NAME = 'gnosis' // RPC URL -const RPC_URL = 'https://sepolia.gateway.tenderly.co' // SEPOLIA +const RPC_URL = 'https://rpc.sepolia.org' // SEPOLIA // const RPC_URL = 'https://rpc.gnosischain.com/' // GNOSIS // Bundler URL diff --git a/playground/relay-kit/usdc-transfer-4337-sponsored.ts b/playground/relay-kit/usdc-transfer-4337-sponsored.ts index 40b352c78..93825ed23 100644 --- a/playground/relay-kit/usdc-transfer-4337-sponsored.ts +++ b/playground/relay-kit/usdc-transfer-4337-sponsored.ts @@ -18,7 +18,7 @@ const CHAIN_NAME = 'sepolia' // const CHAIN_NAME = 'gnosis' // RPC URL -const RPC_URL = 'https://sepolia.gateway.tenderly.co' // SEPOLIA +const RPC_URL = 'https://rpc.sepolia.org' // SEPOLIA // const RPC_URL = 'https://rpc.gnosischain.com/' // GNOSIS // Bundler URL diff --git a/playground/relay-kit/usdc-transfer-4337.ts b/playground/relay-kit/usdc-transfer-4337.ts index 022a818d9..df0e69722 100644 --- a/playground/relay-kit/usdc-transfer-4337.ts +++ b/playground/relay-kit/usdc-transfer-4337.ts @@ -14,7 +14,7 @@ const SAFE_ADDRESS = '' const BUNDLER_URL = `https://api.pimlico.io/v2/sepolia/rpc?apikey=${PIMLICO_API_KEY}` // PIMLICO // RPC URL -const RPC_URL = 'https://sepolia.gateway.tenderly.co' +const RPC_URL = 'https://rpc.sepolia.org' const CHAIN_NAME = 'sepolia' From cc6589cb4e124184c970f692b884f0de6eddf337 Mon Sep 17 00:00:00 2001 From: Tim Schwarz <4171783+tmjssz@users.noreply.github.com> Date: Mon, 22 Jul 2024 18:42:32 +0200 Subject: [PATCH 59/85] fix(api-kit): Fix confirmSafeOperation e2e test by making test transaction unique for each test run --- .../api-kit/tests/e2e/confirmSafeOperation.test.ts | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/packages/api-kit/tests/e2e/confirmSafeOperation.test.ts b/packages/api-kit/tests/e2e/confirmSafeOperation.test.ts index 9961d0515..d45e51986 100644 --- a/packages/api-kit/tests/e2e/confirmSafeOperation.test.ts +++ b/packages/api-kit/tests/e2e/confirmSafeOperation.test.ts @@ -10,7 +10,6 @@ import { SafeOperation } from '@safe-global/safe-core-sdk-types' import * as safe4337Utils from '@safe-global/relay-kit/dist/src/packs/safe-4337/utils' import { getApiKit, getEip1193Provider } from '../utils/setupKits' import { - ENTRYPOINT_ABI, ENTRYPOINT_ADDRESS_V06, RPC_4337_CALLS } from '@safe-global/relay-kit/packs/safe-4337/constants' @@ -34,7 +33,7 @@ describe('confirmSafeOperation', () => { const transferUSDC = { to: PAYMASTER_TOKEN_ADDRESS, data: generateTransferCallData(SAFE_ADDRESS, 100_000n), - value: '0', + value: Date.now().toString(), // Make sure that the transaction hash is unique operation: 0 } @@ -74,16 +73,7 @@ describe('confirmSafeOperation', () => { before(async () => { sinon.stub(safe4337Utils, 'getEip4337BundlerProvider').returns({ - request: requestStub, - readContract: sinon - .stub() - .withArgs({ - address: ENTRYPOINT_ADDRESS_V06, - abi: ENTRYPOINT_ABI, - functionName: 'getNonce', - args: [SAFE_ADDRESS, BigInt(0)] - }) - .resolves(BigInt(Date.now())) + request: requestStub } as unknown as BundlerClient) requestStub.withArgs({ method: RPC_4337_CALLS.CHAIN_ID }).resolves('0xaa36a7') From 360d997a94dc2ac982af220a6fcdcd7a5c07e589 Mon Sep 17 00:00:00 2001 From: leonardotc Date: Tue, 23 Jul 2024 11:20:00 +0200 Subject: [PATCH 60/85] remove public schema from bundler --- packages/relay-kit/src/packs/safe-4337/utils.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/relay-kit/src/packs/safe-4337/utils.ts b/packages/relay-kit/src/packs/safe-4337/utils.ts index 8b756447f..b9e1adb93 100644 --- a/packages/relay-kit/src/packs/safe-4337/utils.ts +++ b/packages/relay-kit/src/packs/safe-4337/utils.ts @@ -1,7 +1,6 @@ import { Address, Hex, - PublicRpcSchema, createPublicClient, encodeFunctionData, encodePacked, @@ -35,7 +34,7 @@ import { BundlerClient, PimlicoCustomRpcSchema } from './types' export function getEip4337BundlerProvider(bundlerUrl: string): BundlerClient { const provider = createPublicClient({ transport: http(bundlerUrl), - rpcSchema: rpcSchema<[...PimlicoCustomRpcSchema, ...PublicRpcSchema]>() + rpcSchema: rpcSchema<[...PimlicoCustomRpcSchema]>() }) return provider From 3795719a5511ee42a6e1769b53f52e1053ec3a92 Mon Sep 17 00:00:00 2001 From: Tim Schwarz <4171783+tmjssz@users.noreply.github.com> Date: Tue, 23 Jul 2024 13:01:30 +0200 Subject: [PATCH 61/85] refactor: Improve API Kit interoperability playground --- .../relay-kit/api-kit-interoperability.ts | 93 +++++++++---------- playground/utils.ts | 18 ---- 2 files changed, 46 insertions(+), 65 deletions(-) diff --git a/playground/relay-kit/api-kit-interoperability.ts b/playground/relay-kit/api-kit-interoperability.ts index 2745fdb0e..bb750820c 100644 --- a/playground/relay-kit/api-kit-interoperability.ts +++ b/playground/relay-kit/api-kit-interoperability.ts @@ -1,25 +1,25 @@ +import { Chain } from 'viem' +import { sepolia } from 'viem/chains' +import { privateKeyToAccount } from 'viem/accounts' import SafeApiKit from '@safe-global/api-kit' import { Safe4337Pack } from '@safe-global/relay-kit' -import { sortResultsByCreatedDateDesc, waitForOperationToFinish } from '../utils' +import { waitForOperationToFinish } from '../utils' // Variables const OWNER_1_PRIVATE_KEY = '' const OWNER_2_PRIVATE_KEY = '' const PIMLICO_API_KEY = '' const SAFE_ADDRESS = '' // Safe 2/N -const CHAIN_NAME = 'sepolia' +const CHAIN: Chain = sepolia // Constants -const BUNDLER_URL = `https://api.pimlico.io/v2/${CHAIN_NAME}/rpc?apikey=${PIMLICO_API_KEY}` -const PAYMASTER_URL = `https://api.pimlico.io/v2/${CHAIN_NAME}/rpc?apikey=${PIMLICO_API_KEY}` -const RPC_URL = 'https://sepolia.gateway.tenderly.co' -const PAYMASTER_ADDRESS = '0x0000000000325602a77416A16136FDafd04b299f' // SEPOLIA - -const CHAIN_ID = 11155111n +const BUNDLER_URL = `https://api.pimlico.io/v2/${CHAIN.name.toLowerCase()}/rpc?apikey=${PIMLICO_API_KEY}` +const PAYMASTER_URL = `https://api.pimlico.io/v2/${CHAIN.name.toLowerCase()}/rpc?apikey=${PIMLICO_API_KEY}` +const RPC_URL = 'https://rpc.sepolia.org' async function main() { const apiKit = new SafeApiKit({ - chainId: CHAIN_ID + chainId: BigInt(sepolia.id) }) let safe4337Pack = await Safe4337Pack.init({ @@ -42,54 +42,53 @@ async function main() { ] }) - let signedSafeOperation = await safe4337Pack.signSafeOperation(safeOperation) + const safeOperationHash = safeOperation.getHash() + console.log('SafeOperation hash =', safeOperationHash) - console.log('SafeOperation signature 1', signedSafeOperation) - await apiKit.addSafeOperation(signedSafeOperation) + const safeOpSignedByOwner1 = await safe4337Pack.signSafeOperation(safeOperation) + const signature1 = safeOpSignedByOwner1.getSignature( + privateKeyToAccount(OWNER_1_PRIVATE_KEY).address + )!.data - let safeOperations = await apiKit.getSafeOperationsByAddress({ - safeAddress: SAFE_ADDRESS, - ordering: '-created' - }) + console.log('Signed by first owner:', signature1) - if (safeOperations.results.length >= 0) { - safe4337Pack = await Safe4337Pack.init({ - provider: RPC_URL, - signer: OWNER_2_PRIVATE_KEY, - bundlerUrl: BUNDLER_URL, - paymasterOptions: { - isSponsored: true, - paymasterAddress: PAYMASTER_ADDRESS, - paymasterUrl: PAYMASTER_URL - }, - options: { - safeAddress: SAFE_ADDRESS - } - }) + await apiKit.addSafeOperation(safeOpSignedByOwner1) - signedSafeOperation = await safe4337Pack.signSafeOperation( - sortResultsByCreatedDateDesc(safeOperations).results[0] - ) + const addedSafeOperation = await apiKit.getSafeOperation(safeOperationHash) + console.log('Added to the Transaction service') - console.log('SafeOperation signature 2', signedSafeOperation) + safe4337Pack = await Safe4337Pack.init({ + provider: RPC_URL, + signer: OWNER_2_PRIVATE_KEY, + bundlerUrl: BUNDLER_URL, + paymasterOptions: { + isSponsored: true, + paymasterUrl: PAYMASTER_URL + }, + options: { + safeAddress: SAFE_ADDRESS + } + }) - // TODO. This should be the place to confirm the safe operation but the api endpoint is not available yet - // Update this once the new endpoint is released - await apiKit.addSafeOperation(signedSafeOperation) + const safeOpSignedByOwner2 = await safe4337Pack.signSafeOperation(addedSafeOperation) + const signature2 = safeOpSignedByOwner2.getSignature( + privateKeyToAccount(OWNER_2_PRIVATE_KEY).address + )!.data - safeOperations = await apiKit.getSafeOperationsByAddress({ - safeAddress: SAFE_ADDRESS, - ordering: '-created' - }) + console.log('Signed by second owner:', signature2) - console.log('SafeOperationList', safeOperations) + // Confirm the safe operation with the second owner + await apiKit.confirmSafeOperation(safeOperationHash, signature2) - const userOperationHash = await safe4337Pack.executeTransaction({ - executable: sortResultsByCreatedDateDesc(safeOperations).results[0] - }) + const confirmedSafeOperation = await apiKit.getSafeOperation(safeOperationHash) + console.log('Confirmed to the Transaction service') + + const userOperationHash = await safe4337Pack.executeTransaction({ + executable: confirmedSafeOperation + }) + console.log('Executing the SafeOperation...') - await waitForOperationToFinish(userOperationHash, CHAIN_NAME, safe4337Pack) - } + await waitForOperationToFinish(userOperationHash, CHAIN.name.toLowerCase(), safe4337Pack) } main() diff --git a/playground/utils.ts b/playground/utils.ts index 120cb5825..9cca0b8d1 100644 --- a/playground/utils.ts +++ b/playground/utils.ts @@ -1,6 +1,5 @@ import { Address, createPublicClient, custom, encodeFunctionData, parseAbi } from 'viem' import { Safe4337Pack } from '@safe-global/relay-kit' -import { GetSafeOperationListResponse } from '@safe-global/api-kit' import { ExternalSigner } from '@safe-global/protocol-kit' export const generateTransferCallData = (to: string, value: bigint) => { @@ -57,20 +56,3 @@ export async function transfer( return await publicClient.waitForTransactionReceipt({ hash }) } - -export function sortResultsByCreatedDateDesc( - data: GetSafeOperationListResponse -): GetSafeOperationListResponse { - if (!data || !Array.isArray(data.results)) { - throw new Error('The provided data is invalid or does not contain a results array.') - } - - data.results.sort((a, b) => { - const dateA = new Date(a.created).getTime() - const dateB = new Date(b.created).getTime() - - return dateB - dateA - }) - - return data -} From 90157d0133243583b2579012c6631d5ba4988c84 Mon Sep 17 00:00:00 2001 From: Tim Schwarz <4171783+tmjssz@users.noreply.github.com> Date: Tue, 23 Jul 2024 14:11:47 +0200 Subject: [PATCH 62/85] refactor: Improve relay-kit playground scripts --- .../relay-kit/api-kit-interoperability.ts | 23 +++++++++---------- playground/relay-kit/paid-transaction.ts | 7 +++--- playground/relay-kit/sponsored-transaction.ts | 7 +++--- 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/playground/relay-kit/api-kit-interoperability.ts b/playground/relay-kit/api-kit-interoperability.ts index bb750820c..28fecf4df 100644 --- a/playground/relay-kit/api-kit-interoperability.ts +++ b/playground/relay-kit/api-kit-interoperability.ts @@ -1,26 +1,25 @@ -import { Chain } from 'viem' -import { sepolia } from 'viem/chains' import { privateKeyToAccount } from 'viem/accounts' +import { sepolia } from 'viem/chains' import SafeApiKit from '@safe-global/api-kit' import { Safe4337Pack } from '@safe-global/relay-kit' import { waitForOperationToFinish } from '../utils' // Variables -const OWNER_1_PRIVATE_KEY = '' -const OWNER_2_PRIVATE_KEY = '' +const OWNER_1_PRIVATE_KEY = '0x' +const OWNER_2_PRIVATE_KEY = '0x' const PIMLICO_API_KEY = '' const SAFE_ADDRESS = '' // Safe 2/N -const CHAIN: Chain = sepolia + +const CHAIN_NAME = 'sepolia' +const CHAIN_ID = sepolia.id +const RPC_URL = sepolia.rpcUrls.default.http[0] // Constants -const BUNDLER_URL = `https://api.pimlico.io/v2/${CHAIN.name.toLowerCase()}/rpc?apikey=${PIMLICO_API_KEY}` -const PAYMASTER_URL = `https://api.pimlico.io/v2/${CHAIN.name.toLowerCase()}/rpc?apikey=${PIMLICO_API_KEY}` -const RPC_URL = 'https://rpc.sepolia.org' +const BUNDLER_URL = `https://api.pimlico.io/v2/${CHAIN_NAME}/rpc?apikey=${PIMLICO_API_KEY}` +const PAYMASTER_URL = `https://api.pimlico.io/v2/${CHAIN_NAME}/rpc?apikey=${PIMLICO_API_KEY}` async function main() { - const apiKit = new SafeApiKit({ - chainId: BigInt(sepolia.id) - }) + const apiKit = new SafeApiKit({ chainId: BigInt(CHAIN_ID) }) let safe4337Pack = await Safe4337Pack.init({ provider: RPC_URL, @@ -88,7 +87,7 @@ async function main() { }) console.log('Executing the SafeOperation...') - await waitForOperationToFinish(userOperationHash, CHAIN.name.toLowerCase(), safe4337Pack) + await waitForOperationToFinish(userOperationHash, CHAIN_NAME, safe4337Pack) } main() diff --git a/playground/relay-kit/paid-transaction.ts b/playground/relay-kit/paid-transaction.ts index 26c548b8a..28590c139 100644 --- a/playground/relay-kit/paid-transaction.ts +++ b/playground/relay-kit/paid-transaction.ts @@ -1,4 +1,4 @@ -import { Address, formatEther, createWalletClient, custom, Hex } from 'viem' +import { Address, Chain, formatEther, createWalletClient, custom, Hex } from 'viem' import { sepolia } from 'viem/chains' import { privateKeyToAccount } from 'viem/accounts' import { createSafeClient, SafeClient } from '@safe-global/safe-kit' @@ -21,7 +21,8 @@ const config = { SAFE_SIGNER_ADDRESS: '' } -const RPC_URL = 'https://rpc.sepolia.org' +const CHAIN: Chain = sepolia +const RPC_URL = CHAIN.rpcUrls.default.http[0] const mockOnRampConfig = { ADDRESS: '
', @@ -96,7 +97,7 @@ async function main() { const fakeOnRampSigner = createWalletClient({ account: privateKeyToAccount(mockOnRampConfig.PRIVATE_KEY as Hex), transport: custom(externalProvider), - chain: sepolia + chain: CHAIN }) const fundingAmount = safeBalance < relayFee ? relayFee - safeBalance : safeBalance - relayFee diff --git a/playground/relay-kit/sponsored-transaction.ts b/playground/relay-kit/sponsored-transaction.ts index 31da0f5eb..bbf8cb5de 100644 --- a/playground/relay-kit/sponsored-transaction.ts +++ b/playground/relay-kit/sponsored-transaction.ts @@ -1,4 +1,4 @@ -import { Address, createWalletClient, custom, formatEther, Hex } from 'viem' +import { Address, Chain, createWalletClient, custom, formatEther, Hex } from 'viem' import { privateKeyToAccount } from 'viem/accounts' import { sepolia } from 'viem/chains' import { createSafeClient, SafeClient } from '@safe-global/safe-kit' @@ -25,7 +25,8 @@ const config = { RELAY_API_KEY: '' } -const RPC_URL = 'https://rpc.sepolia.org' +const CHAIN: Chain = sepolia +const RPC_URL = CHAIN.rpcUrls.default.http[0] const mockOnRampConfig = { ADDRESS: '
', @@ -91,7 +92,7 @@ async function main() { const fakeOnRampSigner = createWalletClient({ account: privateKeyToAccount(mockOnRampConfig.PRIVATE_KEY as Hex), transport: custom(externalProvider), - chain: sepolia + chain: CHAIN }) const hash = await fakeOnRampSigner.sendTransaction({ to: predictedSafeAddress, From 300000305fecfedd79a62bf47ba61fe25ed14c01 Mon Sep 17 00:00:00 2001 From: Tim Schwarz <4171783+tmjssz@users.noreply.github.com> Date: Tue, 23 Jul 2024 14:47:22 +0200 Subject: [PATCH 63/85] refactor: Fix wait for transaction being executed in api-kit playground script Also update script configs to use viem Chain object --- playground/api-kit/confirm-transaction.ts | 12 ++++++------ playground/api-kit/execute-transaction.ts | 20 ++++++++++++-------- playground/api-kit/propose-transaction.ts | 12 ++++++------ 3 files changed, 24 insertions(+), 20 deletions(-) diff --git a/playground/api-kit/confirm-transaction.ts b/playground/api-kit/confirm-transaction.ts index 14a4fead3..876fd5845 100644 --- a/playground/api-kit/confirm-transaction.ts +++ b/playground/api-kit/confirm-transaction.ts @@ -1,19 +1,19 @@ +import { Chain } from 'viem' +import { sepolia } from 'viem/chains' import Safe from '@safe-global/protocol-kit' import SafeApiKit from '@safe-global/api-kit' // This file can be used to play around with the Safe Core SDK interface Config { - CHAIN_ID: bigint - RPC_URL: string + CHAIN: Chain SIGNER_ADDRESS_PRIVATE_KEY: string SAFE_ADDRESS: string SAFE_TX_HASH: string } const config: Config = { - CHAIN_ID: 11155111n, - RPC_URL: 'https://sepolia.gateway.tenderly.co', + CHAIN: sepolia, SIGNER_ADDRESS_PRIVATE_KEY: '', SAFE_ADDRESS: '', SAFE_TX_HASH: '' @@ -22,14 +22,14 @@ const config: Config = { async function main() { // Create Safe instance const protocolKit = await Safe.init({ - provider: config.RPC_URL, + provider: config.CHAIN.rpcUrls.default.http[0], signer: config.SIGNER_ADDRESS_PRIVATE_KEY, safeAddress: config.SAFE_ADDRESS }) // Create Safe API Kit instance const apiKit = new SafeApiKit({ - chainId: config.CHAIN_ID + chainId: BigInt(config.CHAIN.id) }) // Get the transaction diff --git a/playground/api-kit/execute-transaction.ts b/playground/api-kit/execute-transaction.ts index f6ec77c57..53f638333 100644 --- a/playground/api-kit/execute-transaction.ts +++ b/playground/api-kit/execute-transaction.ts @@ -1,19 +1,19 @@ +import { Chain, Hash } from 'viem' +import { sepolia } from 'viem/chains' import Safe from '@safe-global/protocol-kit' import SafeApiKit from '@safe-global/api-kit' // This file can be used to play around with the Safe Core SDK interface Config { - CHAIN_ID: bigint - RPC_URL: string + CHAIN: Chain SIGNER_ADDRESS_PRIVATE_KEY: string SAFE_ADDRESS: string SAFE_TX_HASH: string } const config: Config = { - CHAIN_ID: 11155111n, - RPC_URL: 'https://sepolia.gateway.tenderly.co', + CHAIN: sepolia, SIGNER_ADDRESS_PRIVATE_KEY: '', SAFE_ADDRESS: '', SAFE_TX_HASH: '' @@ -22,14 +22,14 @@ const config: Config = { async function main() { // Create Safe instance const protocolKit = await Safe.init({ - provider: config.RPC_URL, + provider: config.CHAIN.rpcUrls.default.http[0], signer: config.SIGNER_ADDRESS_PRIVATE_KEY, safeAddress: config.SAFE_ADDRESS }) // Create Safe API Kit instance const apiKit = new SafeApiKit({ - chainId: config.CHAIN_ID + chainId: BigInt(config.CHAIN.id) }) // Get the transaction @@ -39,10 +39,14 @@ async function main() { if (isTxExecutable) { // Execute the transaction const txResponse = await protocolKit.executeTransaction(safeTransaction) - const contractReceipt = await txResponse.transactionResponse?.wait() + + await protocolKit + .getSafeProvider() + .getExternalProvider() + .waitForTransactionReceipt({ hash: txResponse.hash as Hash }) console.log('Transaction executed.') - console.log('- Transaction hash:', contractReceipt?.hash) + console.log('- Transaction hash:', txResponse.hash) } else { console.log('Transaction invalid. Transaction was not executed.') } diff --git a/playground/api-kit/propose-transaction.ts b/playground/api-kit/propose-transaction.ts index f2f3ca7c5..8acb986eb 100644 --- a/playground/api-kit/propose-transaction.ts +++ b/playground/api-kit/propose-transaction.ts @@ -1,3 +1,5 @@ +import { Chain } from 'viem' +import { sepolia } from 'viem/chains' import Safe from '@safe-global/protocol-kit' import SafeApiKit from '@safe-global/api-kit' import { OperationType, SafeTransactionDataPartial } from '@safe-global/safe-core-sdk-types' @@ -5,15 +7,13 @@ import { OperationType, SafeTransactionDataPartial } from '@safe-global/safe-cor // This file can be used to play around with the Safe Core SDK interface Config { - CHAIN_ID: bigint - RPC_URL: string + CHAIN: Chain SIGNER_ADDRESS_PRIVATE_KEY: string SAFE_ADDRESS: string } const config: Config = { - CHAIN_ID: 11155111n, - RPC_URL: 'https://sepolia.gateway.tenderly.co', + CHAIN: sepolia, SIGNER_ADDRESS_PRIVATE_KEY: '', SAFE_ADDRESS: '' } @@ -21,14 +21,14 @@ const config: Config = { async function main() { // Create Safe instance const protocolKit = await Safe.init({ - provider: config.RPC_URL, + provider: config.CHAIN.rpcUrls.default.http[0], signer: config.SIGNER_ADDRESS_PRIVATE_KEY, safeAddress: config.SAFE_ADDRESS }) // Create Safe API Kit instance const apiKit = new SafeApiKit({ - chainId: config.CHAIN_ID + chainId: BigInt(config.CHAIN.id) }) // Create transaction From d20167c3abe6d6fef836759fdbe073935ce182c0 Mon Sep 17 00:00:00 2001 From: Tim Schwarz <4171783+tmjssz@users.noreply.github.com> Date: Tue, 23 Jul 2024 17:21:42 +0200 Subject: [PATCH 64/85] refactor: Update playground scripts to use viem/accounts for private key to address conversion --- playground/config/run.ts | 3 +++ .../relay-kit/api-kit-interoperability.ts | 6 ++--- playground/safe-kit/send-off-chain-message.ts | 19 +++++++------- playground/safe-kit/send-on-chain-message.ts | 19 +++++++------- playground/safe-kit/send-safe-operation.ts | 25 +++++++++++------- playground/safe-kit/send-transactions.ts | 26 +++++++++---------- 6 files changed, 53 insertions(+), 45 deletions(-) diff --git a/playground/config/run.ts b/playground/config/run.ts index 582ca0596..ae9129743 100644 --- a/playground/config/run.ts +++ b/playground/config/run.ts @@ -61,6 +61,9 @@ if (!path) { console.log('RELAY KIT') printPlaygrounds(playgroundRelayKitPaths) + console.log('SAFE KIT') + printPlaygrounds(playgroundSafeKitPaths) + process.exit() } diff --git a/playground/relay-kit/api-kit-interoperability.ts b/playground/relay-kit/api-kit-interoperability.ts index 28fecf4df..18f3350ab 100644 --- a/playground/relay-kit/api-kit-interoperability.ts +++ b/playground/relay-kit/api-kit-interoperability.ts @@ -1,4 +1,4 @@ -import { privateKeyToAccount } from 'viem/accounts' +import { privateKeyToAddress } from 'viem/accounts' import { sepolia } from 'viem/chains' import SafeApiKit from '@safe-global/api-kit' import { Safe4337Pack } from '@safe-global/relay-kit' @@ -46,7 +46,7 @@ async function main() { const safeOpSignedByOwner1 = await safe4337Pack.signSafeOperation(safeOperation) const signature1 = safeOpSignedByOwner1.getSignature( - privateKeyToAccount(OWNER_1_PRIVATE_KEY).address + privateKeyToAddress(OWNER_1_PRIVATE_KEY) )!.data console.log('Signed by first owner:', signature1) @@ -71,7 +71,7 @@ async function main() { const safeOpSignedByOwner2 = await safe4337Pack.signSafeOperation(addedSafeOperation) const signature2 = safeOpSignedByOwner2.getSignature( - privateKeyToAccount(OWNER_2_PRIVATE_KEY).address + privateKeyToAddress(OWNER_2_PRIVATE_KEY) )!.data console.log('Signed by second owner:', signature2) diff --git a/playground/safe-kit/send-off-chain-message.ts b/playground/safe-kit/send-off-chain-message.ts index 699115369..4ae497a50 100644 --- a/playground/safe-kit/send-off-chain-message.ts +++ b/playground/safe-kit/send-off-chain-message.ts @@ -1,17 +1,14 @@ +import { privateKeyToAddress } from 'viem/accounts' import { SafeClientResult, createSafeClient, offChainMessages } from '@safe-global/safe-kit' -const OWNER_1_PRIVATE_KEY = '' -const OWNER_2_PRIVATE_KEY = '' -const OWNER_3_PRIVATE_KEY = '' - -const OWNER_1_ADDRESS = '' -const OWNER_2_ADDRESS = '' -const OWNER_3_ADDRESS = '' +const OWNER_1_PRIVATE_KEY = '0x' +const OWNER_2_PRIVATE_KEY = '0x' +const OWNER_3_PRIVATE_KEY = '0x' const THRESHOLD = 3 const SALT_NONCE = '' -const RPC_URL = 'https://sepolia.gateway.tenderly.co' +const RPC_URL = 'https://rpc.sepolia.org' const MESSAGE = "I'm the owner of this Safe" // const MESSAGE = { @@ -62,11 +59,15 @@ const MESSAGE = "I'm the owner of this Safe" // } async function send(): Promise { + const owner1 = privateKeyToAddress(OWNER_1_PRIVATE_KEY) + const owner2 = privateKeyToAddress(OWNER_2_PRIVATE_KEY) + const owner3 = privateKeyToAddress(OWNER_3_PRIVATE_KEY) + const safeClient = await createSafeClient({ provider: RPC_URL, signer: OWNER_1_PRIVATE_KEY, safeOptions: { - owners: [OWNER_1_ADDRESS, OWNER_2_ADDRESS, OWNER_3_ADDRESS], + owners: [owner1, owner2, owner3], threshold: THRESHOLD, saltNonce: SALT_NONCE } diff --git a/playground/safe-kit/send-on-chain-message.ts b/playground/safe-kit/send-on-chain-message.ts index 8f8f0f79b..9c570045b 100644 --- a/playground/safe-kit/send-on-chain-message.ts +++ b/playground/safe-kit/send-on-chain-message.ts @@ -1,17 +1,14 @@ +import { privateKeyToAddress } from 'viem/accounts' import { SafeClientResult, createSafeClient, onChainMessages } from '@safe-global/safe-kit' -const OWNER_1_PRIVATE_KEY = '' -const OWNER_2_PRIVATE_KEY = '' -const OWNER_3_PRIVATE_KEY = '' - -const OWNER_1_ADDRESS = '' -const OWNER_2_ADDRESS = '' -const OWNER_3_ADDRESS = '' +const OWNER_1_PRIVATE_KEY = '0x' +const OWNER_2_PRIVATE_KEY = '0x' +const OWNER_3_PRIVATE_KEY = '0x' const THRESHOLD = 3 const SALT_NONCE = '' -const RPC_URL = 'https://sepolia.gateway.tenderly.co' +const RPC_URL = 'https://rpc.sepolia.org' const MESSAGE = "I'm the owner of this Safe" // const MESSAGE = { // types: { @@ -61,11 +58,15 @@ const MESSAGE = "I'm the owner of this Safe" // } async function send(): Promise { + const owner1 = privateKeyToAddress(OWNER_1_PRIVATE_KEY) + const owner2 = privateKeyToAddress(OWNER_2_PRIVATE_KEY) + const owner3 = privateKeyToAddress(OWNER_3_PRIVATE_KEY) + const safeClient = await createSafeClient({ provider: RPC_URL, signer: OWNER_1_PRIVATE_KEY, safeOptions: { - owners: [OWNER_1_ADDRESS, OWNER_2_ADDRESS, OWNER_3_ADDRESS], + owners: [owner1, owner2, owner3], threshold: THRESHOLD, saltNonce: SALT_NONCE } diff --git a/playground/safe-kit/send-safe-operation.ts b/playground/safe-kit/send-safe-operation.ts index 1e3f5cf21..c95969716 100644 --- a/playground/safe-kit/send-safe-operation.ts +++ b/playground/safe-kit/send-safe-operation.ts @@ -1,20 +1,17 @@ +import { privateKeyToAddress } from 'viem/accounts' import { createPublicClient, http } from 'viem' import { sepolia } from 'viem/chains' import { SafeClientResult, createSafeClient, safeOperations } from '@safe-global/safe-kit' import { generateTransferCallData } from '../utils' -const OWNER_1_PRIVATE_KEY = '' -const OWNER_2_PRIVATE_KEY = '' -const OWNER_3_PRIVATE_KEY = '' - -const OWNER_1_ADDRESS = '' -const OWNER_2_ADDRESS = '' -const OWNER_3_ADDRESS = '' +const OWNER_1_PRIVATE_KEY = '0x' +const OWNER_2_PRIVATE_KEY = '0x' +const OWNER_3_PRIVATE_KEY = '0x' const THRESHOLD = 3 const SALT_NONCE = '' -const RPC_URL = 'https://sepolia.gateway.tenderly.co' +const RPC_URL = 'https://rpc.sepolia.org' const usdcTokenAddress = '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238' // SEPOLIA const usdcAmount = 10_000n // 0.01 USDC @@ -24,11 +21,15 @@ const PAYMASTER_URL = `https://api.pimlico.io/v2/sepolia/rpc?apikey=${PIMLICO_AP const BUNDLER_URL = `https://api.pimlico.io/v2/sepolia/rpc?apikey=${PIMLICO_API_KEY}` async function send(): Promise { + const owner1 = privateKeyToAddress(OWNER_1_PRIVATE_KEY) + const owner2 = privateKeyToAddress(OWNER_2_PRIVATE_KEY) + const owner3 = privateKeyToAddress(OWNER_3_PRIVATE_KEY) + const safeClient = await createSafeClient({ provider: RPC_URL, signer: OWNER_1_PRIVATE_KEY, safeOptions: { - owners: [OWNER_1_ADDRESS, OWNER_2_ADDRESS, OWNER_3_ADDRESS], + owners: [owner1, owner2, owner3], threshold: THRESHOLD, saltNonce: SALT_NONCE } @@ -78,11 +79,15 @@ async function confirm(safeClientResult: SafeClientResult, pk: string) { return } + const owner1 = privateKeyToAddress(OWNER_1_PRIVATE_KEY) + const owner2 = privateKeyToAddress(OWNER_2_PRIVATE_KEY) + const owner3 = privateKeyToAddress(OWNER_3_PRIVATE_KEY) + const safeClient = await createSafeClient({ provider: RPC_URL, signer: pk, safeOptions: { - owners: [OWNER_1_ADDRESS, OWNER_2_ADDRESS, OWNER_3_ADDRESS], + owners: [owner1, owner2, owner3], threshold: THRESHOLD, saltNonce: SALT_NONCE } diff --git a/playground/safe-kit/send-transactions.ts b/playground/safe-kit/send-transactions.ts index b95715c08..493e2b255 100644 --- a/playground/safe-kit/send-transactions.ts +++ b/playground/safe-kit/send-transactions.ts @@ -1,27 +1,28 @@ +import { privateKeyToAddress } from 'viem/accounts' import { SafeClientResult, createSafeClient } from '@safe-global/safe-kit' import { generateTransferCallData } from '../utils' -const OWNER_1_PRIVATE_KEY = '' -const OWNER_2_PRIVATE_KEY = '' -const OWNER_3_PRIVATE_KEY = '' - -const OWNER_1_ADDRESS = '' -const OWNER_2_ADDRESS = '' -const OWNER_3_ADDRESS = '' +const OWNER_1_PRIVATE_KEY = '0x' +const OWNER_2_PRIVATE_KEY = '0x' +const OWNER_3_PRIVATE_KEY = '0x' const THRESHOLD = 3 const SALT_NONCE = '' -const RPC_URL = 'https://sepolia.gateway.tenderly.co' +const RPC_URL = 'https://rpc.sepolia.org' const usdcTokenAddress = '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238' // SEPOLIA const usdcAmount = 10_000n // 0.01 USDC async function send(): Promise { + const owner1 = privateKeyToAddress(OWNER_1_PRIVATE_KEY) + const owner2 = privateKeyToAddress(OWNER_2_PRIVATE_KEY) + const owner3 = privateKeyToAddress(OWNER_3_PRIVATE_KEY) + const safeClient = await createSafeClient({ provider: RPC_URL, signer: OWNER_1_PRIVATE_KEY, safeOptions: { - owners: [OWNER_1_ADDRESS, OWNER_2_ADDRESS, OWNER_3_ADDRESS], + owners: [owner1, owner2, owner3], threshold: THRESHOLD, saltNonce: SALT_NONCE } @@ -29,11 +30,8 @@ async function send(): Promise { const signerAddress = (await safeClient.protocolKit.getSafeProvider().getSignerAddress()) || '0x' - console.log( - '-Safe Address:', - await safeClient.protocolKit.getAddress(), - await safeClient.protocolKit.isSafeDeployed() - ) + console.log('-Safe Address:', await safeClient.protocolKit.getAddress()) + console.log('-Is deployed:', await safeClient.protocolKit.isSafeDeployed()) console.log('-Signer Address:', signerAddress) const transferUSDC = { From dd6e7756de0ae8dfc43e58a20e6bd91e608dc686 Mon Sep 17 00:00:00 2001 From: Tim Schwarz <4171783+tmjssz@users.noreply.github.com> Date: Wed, 24 Jul 2024 12:13:32 +0200 Subject: [PATCH 65/85] refactor: Use `Account` type instead of LocalAccount in api-kit --- .../src/types/safeTransactionServiceTypes.ts | 13 +++---------- packages/api-kit/src/utils/signDelegate.ts | 4 ++-- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/packages/api-kit/src/types/safeTransactionServiceTypes.ts b/packages/api-kit/src/types/safeTransactionServiceTypes.ts index 713791d53..71699e498 100644 --- a/packages/api-kit/src/types/safeTransactionServiceTypes.ts +++ b/packages/api-kit/src/types/safeTransactionServiceTypes.ts @@ -1,11 +1,4 @@ -import { - Chain, - LocalAccount, - Transport, - TypedDataDomain, - TypedDataParameter, - WalletClient -} from 'viem' +import { Account, Chain, Transport, TypedDataDomain, TypedDataParameter, WalletClient } from 'viem' import { SafeMultisigTransactionResponse, SafeTransactionData, @@ -84,14 +77,14 @@ export type AddSafeDelegateProps = { safeAddress?: string delegateAddress: string delegatorAddress: string - signer: WalletClient + signer: WalletClient label: string } export type DeleteSafeDelegateProps = { delegateAddress: string delegatorAddress: string - signer: WalletClient + signer: WalletClient } export type SafeDelegateResponse = { diff --git a/packages/api-kit/src/utils/signDelegate.ts b/packages/api-kit/src/utils/signDelegate.ts index 96d26ad1c..f52915bb9 100644 --- a/packages/api-kit/src/utils/signDelegate.ts +++ b/packages/api-kit/src/utils/signDelegate.ts @@ -1,7 +1,7 @@ -import { Chain, LocalAccount, Transport, WalletClient } from 'viem' +import { Chain, Account, Transport, WalletClient } from 'viem' export async function signDelegate( - walletClient: WalletClient, + walletClient: WalletClient, delegateAddress: string, chainId: bigint ) { From dca351a4c0f72edd9d4175f4c56812c7570a295d Mon Sep 17 00:00:00 2001 From: leonardotc Date: Wed, 24 Jul 2024 12:50:30 +0200 Subject: [PATCH 66/85] Revert protocol kit playground --- playground/protocol-kit/deploy-safe.ts | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/playground/protocol-kit/deploy-safe.ts b/playground/protocol-kit/deploy-safe.ts index 4fa80b367..867bebf29 100644 --- a/playground/protocol-kit/deploy-safe.ts +++ b/playground/protocol-kit/deploy-safe.ts @@ -1,6 +1,5 @@ import { SafeAccountConfig, SafeFactory } from '@safe-global/protocol-kit' import { SafeVersion } from '@safe-global/safe-core-sdk-types' -import { privateKeyToAddress } from 'viem/accounts' // This file can be used to play around with the Safe Core SDK @@ -15,15 +14,13 @@ interface Config { } } -const privateKey = "0x943bb3afb48b023089757cb3317fba30bd9945edef44907103d3d432f972db90" // 0x2c101b1e0d4d60699e0da38d0630c51833159d4a16c70e29917402af147c6cef - const config: Config = { - RPC_URL: 'https://rpc.sepolia.org', - DEPLOYER_ADDRESS_PRIVATE_KEY: privateKey, + RPC_URL: 'https://sepolia.gateway.tenderly.co', + DEPLOYER_ADDRESS_PRIVATE_KEY: '', DEPLOY_SAFE: { - OWNERS: [privateKeyToAddress(privateKey)], + OWNERS: ['OWNER_ADDRESS'], THRESHOLD: 1, // - SALT_NONCE: '150002', + SALT_NONCE: '150000', SAFE_VERSION: '1.3.0' } } From 124f9313a33e360ace296d3c82eb14af43febcf9 Mon Sep 17 00:00:00 2001 From: Tim Schwarz <4171783+tmjssz@users.noreply.github.com> Date: Wed, 24 Jul 2024 15:37:37 +0200 Subject: [PATCH 67/85] refactor: Use `(await signer.getAddresses())[0]` instead of `signer.account!.address` --- .../api-kit/tests/e2e/addSafeDelegate.test.ts | 20 +++++++------------ 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/packages/api-kit/tests/e2e/addSafeDelegate.test.ts b/packages/api-kit/tests/e2e/addSafeDelegate.test.ts index ec9873c5c..47ce2a34e 100644 --- a/packages/api-kit/tests/e2e/addSafeDelegate.test.ts +++ b/packages/api-kit/tests/e2e/addSafeDelegate.test.ts @@ -1,4 +1,4 @@ -import { createWalletClient, http } from 'viem' +import { Address, createWalletClient, http } from 'viem' import { privateKeyToAccount } from 'viem/accounts' import { sepolia } from 'viem/chains' import SafeApiKit, { AddSafeDelegateProps } from '@safe-global/api-kit/index' @@ -14,6 +14,7 @@ const PRIVATE_KEY_2 = '0xb0057716d5917badaf911b193b12b910811c1497b5bada8d7711f75 let safeApiKit: SafeApiKit let signer: AddSafeDelegateProps['signer'] +let delegatorAddress: Address describe('addSafeDelegate', () => { before(async () => { @@ -23,11 +24,11 @@ describe('addSafeDelegate', () => { transport: http(), account: privateKeyToAccount(PRIVATE_KEY_1) }) + delegatorAddress = (await signer.getAddresses())[0] }) it('should fail if Label is empty', async () => { const delegateAddress = '0x9cCBDE03eDd71074ea9c49e413FA9CDfF16D263B' - const delegatorAddress = signer.account!.address const delegateConfig: AddSafeDelegateProps = { delegateAddress, delegatorAddress, @@ -41,7 +42,6 @@ describe('addSafeDelegate', () => { it('should fail if Safe delegate address is empty', async () => { const delegateAddress = '' - const delegatorAddress = signer.account!.address const delegateConfig: AddSafeDelegateProps = { delegateAddress, delegatorAddress, @@ -70,7 +70,6 @@ describe('addSafeDelegate', () => { it('should fail if Safe address is not checksummed', async () => { const safeAddress = '0xF8ef84392f7542576F6b9d1b140334144930Ac78'.toLowerCase() const delegateAddress = '0x9cCBDE03eDd71074ea9c49e413FA9CDfF16D263B' - const delegatorAddress = signer.account!.address const delegateConfig: AddSafeDelegateProps = { safeAddress, delegateAddress, @@ -86,7 +85,6 @@ describe('addSafeDelegate', () => { it('should fail if Safe delegate address is not checksummed', async () => { const safeAddress = '0xF8ef84392f7542576F6b9d1b140334144930Ac78' const delegateAddress = '0x9cCBDE03eDd71074ea9c49e413FA9CDfF16D263B'.toLowerCase() - const delegatorAddress = signer.account!.address const delegateConfig: AddSafeDelegateProps = { safeAddress, delegateAddress, @@ -102,23 +100,22 @@ describe('addSafeDelegate', () => { it('should fail if Safe delegator address is not checksummed', async () => { const safeAddress = '0xF8ef84392f7542576F6b9d1b140334144930Ac78' const delegateAddress = '0x9cCBDE03eDd71074ea9c49e413FA9CDfF16D263B' - const delegatorAddress = signer.account!.address.toLocaleLowerCase() + const delegatorAddressLowerCase = delegatorAddress.toLocaleLowerCase() const delegateConfig: AddSafeDelegateProps = { safeAddress, delegateAddress, - delegatorAddress, + delegatorAddress: delegatorAddressLowerCase, signer, label: 'Label' } await chai .expect(safeApiKit.addSafeDelegate(delegateConfig)) - .to.be.rejectedWith(`Address ${delegatorAddress} is not checksumed`) + .to.be.rejectedWith(`Address ${delegatorAddressLowerCase} is not checksumed`) }) it('should fail if Safe does not exist', async () => { const safeAddress = '0x1dF62f291b2E969fB0849d99D9Ce41e2F137006e' const delegateAddress = '0x9cCBDE03eDd71074ea9c49e413FA9CDfF16D263B' - const delegatorAddress = signer.account!.address const delegateConfig: AddSafeDelegateProps = { safeAddress, delegateAddress, @@ -139,7 +136,7 @@ describe('addSafeDelegate', () => { transport: http(), account: privateKeyToAccount(PRIVATE_KEY_2) }) - const delegatorAddress = nonOwnerSigner.account!.address + const delegatorAddress = (await nonOwnerSigner.getAddresses())[0] const delegateConfig: AddSafeDelegateProps = { safeAddress, delegateAddress, @@ -157,7 +154,6 @@ describe('addSafeDelegate', () => { it('should add a new delegate', async () => { const safeAddress = '0xF8ef84392f7542576F6b9d1b140334144930Ac78' const delegateAddress = '0x9cCBDE03eDd71074ea9c49e413FA9CDfF16D263B' - const delegatorAddress = signer.account!.address const delegateConfig: AddSafeDelegateProps = { safeAddress, delegateAddress, @@ -180,7 +176,6 @@ describe('addSafeDelegate', () => { it('should add a new delegate without specifying a Safe', async () => { const delegateAddress = '0x9cCBDE03eDd71074ea9c49e413FA9CDfF16D263B' - const delegatorAddress = signer.account!.address const delegateConfig: AddSafeDelegateProps = { delegateAddress, delegatorAddress, @@ -210,7 +205,6 @@ describe('addSafeDelegate', () => { const eip3770SafeAddress = `${config.EIP_3770_PREFIX}:${safeAddress}` const delegateAddress = '0x9cCBDE03eDd71074ea9c49e413FA9CDfF16D263B' const eip3770DelegateAddress = `${config.EIP_3770_PREFIX}:${delegateAddress}` - const delegatorAddress = signer.account!.address const eip3770DelegatorAddress = `${config.EIP_3770_PREFIX}:${delegatorAddress}` const delegateConfig: AddSafeDelegateProps = { safeAddress: eip3770SafeAddress, From 403e842e12ff871e9429d5586f3d474c58d92243 Mon Sep 17 00:00:00 2001 From: leonardotc Date: Wed, 24 Jul 2024 16:05:18 +0200 Subject: [PATCH 68/85] Fix wait for receipt in transaction result --- packages/protocol-kit/src/contracts/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/protocol-kit/src/contracts/utils.ts b/packages/protocol-kit/src/contracts/utils.ts index 027c6869c..1ea5e1c70 100644 --- a/packages/protocol-kit/src/contracts/utils.ts +++ b/packages/protocol-kit/src/contracts/utils.ts @@ -378,7 +378,7 @@ export function toTxResult( options, transactionResponse: { wait: async () => { - return runner.getTransactionReceipt({ hash }) + return runner.waitForTransactionReceipt({ hash }) } } } From 1d58ce8c9baaf09e5c5d85397a3cf955a3f8b2fd Mon Sep 17 00:00:00 2001 From: Tim Schwarz <4171783+tmjssz@users.noreply.github.com> Date: Wed, 24 Jul 2024 17:45:23 +0200 Subject: [PATCH 69/85] Add comment for import from relay-kit dist folder --- packages/api-kit/tests/e2e/addSafeOperation.test.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/api-kit/tests/e2e/addSafeOperation.test.ts b/packages/api-kit/tests/e2e/addSafeOperation.test.ts index 04e174bed..09cb2f33d 100644 --- a/packages/api-kit/tests/e2e/addSafeOperation.test.ts +++ b/packages/api-kit/tests/e2e/addSafeOperation.test.ts @@ -12,6 +12,7 @@ import { ENTRYPOINT_ADDRESS_V06, RPC_4337_CALLS } from '@safe-global/relay-kit/packs/safe-4337/constants' +// Needs to be imported from dist folder in order to mock the getEip4337BundlerProvider function import * as safe4337Utils from '@safe-global/relay-kit/dist/src/packs/safe-4337/utils' import { getKits } from '../utils/setupKits' @@ -22,7 +23,7 @@ const SIGNER_PK = '0x83a415ca62e11f5fa5567e98450d0f82ae19ff36ef876c10a8d448c788a const SAFE_ADDRESS = '0x60C4Ab82D06Fd7dFE9517e17736C2Dcc77443EF0' // 1/2 Safe (v1.4.1) with signer above being an owner + 4337 module enabled const PAYMASTER_TOKEN_ADDRESS = '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238' const PAYMASTER_ADDRESS = '0x0000000000325602a77416A16136FDafd04b299f' -const BUNDLER_URL = `https://bundler.url` +const BUNDLER_URL = 'https://bundler.url' const TX_SERVICE_URL = 'https://safe-transaction-sepolia.staging.5afe.dev/api' let safeApiKit: SafeApiKit From 4f9400e548319aecc02608e96709c87c5e401ae0 Mon Sep 17 00:00:00 2001 From: Tim Schwarz <4171783+tmjssz@users.noreply.github.com> Date: Thu, 25 Jul 2024 11:32:29 +0200 Subject: [PATCH 70/85] refactor: Move `asBlockId` function to utils --- packages/protocol-kit/src/SafeProvider.ts | 14 +------------- packages/protocol-kit/src/utils/block.ts | 13 +++++++++++++ 2 files changed, 14 insertions(+), 13 deletions(-) create mode 100644 packages/protocol-kit/src/utils/block.ts diff --git a/packages/protocol-kit/src/SafeProvider.ts b/packages/protocol-kit/src/SafeProvider.ts index e59091ca7..ee1aa8a21 100644 --- a/packages/protocol-kit/src/SafeProvider.ts +++ b/packages/protocol-kit/src/SafeProvider.ts @@ -26,6 +26,7 @@ import { ExternalSigner } from '@safe-global/protocol-kit/types' import { asAddress, asHash, asHex, getChainById } from './utils/types' +import { asBlockId } from './utils/block' import { createPublicClient, createWalletClient, @@ -39,7 +40,6 @@ import { encodeAbiParameters, parseAbiParameters, toBytes, - BlockTag, Chain } from 'viem' import { privateKeyToAccount } from 'viem/accounts' @@ -49,18 +49,6 @@ import { sameString } from '@safe-global/protocol-kit/utils' -function asBlockId(blockId: number | string | undefined) { - return typeof blockId === 'number' ? blockNumber(blockId) : blockTag(blockId) -} - -function blockNumber(blockNumber: any) { - return { blockNumber: blockNumber.toNumber() } -} - -function blockTag(blockTag: any) { - return { blockTag: blockTag as BlockTag } -} - class SafeProvider { #chain?: Chain #externalProvider: PublicClient diff --git a/packages/protocol-kit/src/utils/block.ts b/packages/protocol-kit/src/utils/block.ts new file mode 100644 index 000000000..2e1f064e0 --- /dev/null +++ b/packages/protocol-kit/src/utils/block.ts @@ -0,0 +1,13 @@ +import { BlockTag } from 'viem' + +export function asBlockId(blockId: number | string | undefined) { + return typeof blockId === 'number' ? blockNumber(blockId) : blockTag(blockId) +} + +function blockNumber(blockNumber: any) { + return { blockNumber: blockNumber.toNumber() } +} + +function blockTag(blockTag: any) { + return { blockTag: blockTag as BlockTag } +} From 3648d946e78bd5114f7d106502be2fcb7c4a3d12 Mon Sep 17 00:00:00 2001 From: Tim Schwarz <4171783+tmjssz@users.noreply.github.com> Date: Thu, 25 Jul 2024 14:31:51 +0200 Subject: [PATCH 71/85] refactor: Simplify SafeProvider constructor logic --- packages/protocol-kit/src/SafeProvider.ts | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/packages/protocol-kit/src/SafeProvider.ts b/packages/protocol-kit/src/SafeProvider.ts index ee1aa8a21..155ec233e 100644 --- a/packages/protocol-kit/src/SafeProvider.ts +++ b/packages/protocol-kit/src/SafeProvider.ts @@ -56,16 +56,9 @@ class SafeProvider { provider: Eip1193Provider | HttpTransport | SocketTransport constructor({ provider, signer }: SafeProviderConfig) { - if (typeof provider === 'string') { - this.#externalProvider = createPublicClient({ - transport: http(provider) - }) - } else { - const client = createPublicClient({ - transport: custom(provider) - }) - this.#externalProvider = client - } + this.#externalProvider = createPublicClient({ + transport: typeof provider === 'string' ? http(provider) : custom(provider) + }) this.provider = provider this.signer = signer ? asHex(signer) : signer From 8e9391c1e986e9418b2521938318df537fadd07f Mon Sep 17 00:00:00 2001 From: leonardotc Date: Thu, 25 Jul 2024 17:25:39 +0200 Subject: [PATCH 72/85] Add explanation for conversion --- packages/protocol-kit/src/contracts/BaseContract.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/protocol-kit/src/contracts/BaseContract.ts b/packages/protocol-kit/src/contracts/BaseContract.ts index 4729c50bb..acede3acf 100644 --- a/packages/protocol-kit/src/contracts/BaseContract.ts +++ b/packages/protocol-kit/src/contracts/BaseContract.ts @@ -111,6 +111,14 @@ class BaseContract { return client?.getTransactionReceipt({ hash }) } + /** + * Converts a type of TransactionOptions to a viem transaction type. The viem transaction type creates a clear distinction between the multiple transaction objects (e.g., post-London hard fork) and doesn't allow a union of fields. + * See: https://github.com/wevm/viem/blob/viem%402.18.0/src/types/fee.ts and https://github.com/wevm/viem/blob/603227e2588366914fb79a902d23fd9afc353cc6/src/types/transaction.ts#L200 + * + * @param options - Transaction options as expected throughout safe sdk and propagated on the results. + * + * @returns Options object compatible with viem + */ async convertOptions( options?: TransactionOptions ): Promise { @@ -122,6 +130,7 @@ class BaseContract { if (!signer || !signerAddress) throw new Error('Invalid signer') const account = signer || asAddress(signerAddress) + this.wallet?.writeContract() const txOptions = await convertTransactionOptions(options) return { chain, ...txOptions, account } // Needs to be in this order to override the `account` if necessary } From 0b940bb1945061a5463ac22199f136c7377a57cf Mon Sep 17 00:00:00 2001 From: leonardotc Date: Fri, 26 Jul 2024 09:45:25 +0200 Subject: [PATCH 73/85] Remove residual code --- packages/protocol-kit/src/contracts/BaseContract.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/protocol-kit/src/contracts/BaseContract.ts b/packages/protocol-kit/src/contracts/BaseContract.ts index acede3acf..17f6f0e25 100644 --- a/packages/protocol-kit/src/contracts/BaseContract.ts +++ b/packages/protocol-kit/src/contracts/BaseContract.ts @@ -130,7 +130,6 @@ class BaseContract { if (!signer || !signerAddress) throw new Error('Invalid signer') const account = signer || asAddress(signerAddress) - this.wallet?.writeContract() const txOptions = await convertTransactionOptions(options) return { chain, ...txOptions, account } // Needs to be in this order to override the `account` if necessary } From 128987ff4fea3236c5a0d2b865f5b5b5cf1df4b1 Mon Sep 17 00:00:00 2001 From: leonardotc Date: Fri, 26 Jul 2024 09:55:13 +0200 Subject: [PATCH 74/85] Remove duplicate --- .../safe-kit/src/utils/sendTransaction.ts | 31 +------------------ 1 file changed, 1 insertion(+), 30 deletions(-) diff --git a/packages/safe-kit/src/utils/sendTransaction.ts b/packages/safe-kit/src/utils/sendTransaction.ts index f256026fc..969c65c26 100644 --- a/packages/safe-kit/src/utils/sendTransaction.ts +++ b/packages/safe-kit/src/utils/sendTransaction.ts @@ -1,6 +1,6 @@ import { Address, WalletClient, Transport, Chain, Hex, Account } from 'viem' import Safe from '@safe-global/protocol-kit' -import { Transaction, TransactionOptions } from '@safe-global/safe-core-sdk-types' +import { Transaction } from '@safe-global/safe-core-sdk-types' /** * Sends a transaction using the signer (owner) @@ -38,32 +38,3 @@ export const sendTransaction = async ({ return receipt.transactionHash } - -export function createLegacyTxOptions(options?: TransactionOptions) { - const converted: any = {} - if (options?.from) { - converted.account = options.from as Address - } - - if (options?.gasLimit) { - converted.gas = BigInt(options.gasLimit) - } - - if (options?.gasPrice) { - converted.gasPrice = BigInt(options.gasPrice) - } - - if (options?.nonce) { - converted.nonce = options.nonce - } - - if (options?.maxFeePerGas) { - converted.maxFeePerGas = BigInt(options.maxFeePerGas) - } - - if (options?.maxPriorityFeePerGas) { - converted.maxPriorityFeePerGas = BigInt(options.maxPriorityFeePerGas) - } - - return converted -} From 4475b880544a50a9a8b7c257b281214ea40e2849 Mon Sep 17 00:00:00 2001 From: leonardotc Date: Fri, 26 Jul 2024 10:24:46 +0200 Subject: [PATCH 75/85] Fix custom chain support --- .../e2e/getSafeOperationConfirmations.test.ts | 3 ++- packages/protocol-kit/src/utils/types.ts | 24 +++++++++++++++++-- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/packages/api-kit/tests/e2e/getSafeOperationConfirmations.test.ts b/packages/api-kit/tests/e2e/getSafeOperationConfirmations.test.ts index c6f747552..30c361233 100644 --- a/packages/api-kit/tests/e2e/getSafeOperationConfirmations.test.ts +++ b/packages/api-kit/tests/e2e/getSafeOperationConfirmations.test.ts @@ -2,6 +2,7 @@ import chai from 'chai' import chaiAsPromised from 'chai-as-promised' import SafeApiKit from '@safe-global/api-kit/index' import { getApiKit } from '../utils/setupKits' +import { zeroHash } from 'viem' chai.use(chaiAsPromised) @@ -40,7 +41,7 @@ describe('getSafeOperationConfirmations', () => { }) it('should return an empty array if the safeOperationHash is not found', async () => { - const safeOperationHash = '0x0000000000000000000000000000000000000000000000000000000000000000' + const safeOperationHash = zeroHash const safeOpConfirmations = await safeApiKit.getSafeOperationConfirmations(safeOperationHash) chai.expect(safeOpConfirmations.count).to.be.equal(0) chai.expect(safeOpConfirmations.results.length).to.be.equal(0) diff --git a/packages/protocol-kit/src/utils/types.ts b/packages/protocol-kit/src/utils/types.ts index 9e6780169..4b2f12fbe 100644 --- a/packages/protocol-kit/src/utils/types.ts +++ b/packages/protocol-kit/src/utils/types.ts @@ -1,5 +1,5 @@ import { SafeConfig, SafeConfigWithPredictedSafe } from '../types' -import { getAddress, Address, isHex, Hex, Hash, Chain } from 'viem' +import { getAddress, Address, isHex, Hex, Hash, Chain, defineChain, etherUnits } from 'viem' import * as allChains from 'viem/chains' export function isSafeConfigWithPredictedSafe( @@ -25,5 +25,25 @@ export function asHex(hex?: string): Hex { } export function getChainById(chainId: bigint): Chain | undefined { - return Object.values(allChains).find((chain) => chain.id === Number(chainId)) + const chain = Object.values(allChains).find((chain) => chain.id === Number(chainId)) + if (chain) { + return chain + } else { + // We assume an ethereum-based chain whose urls will be defined on the client. + return defineChain({ + id: Number(chainId), + name: 'Custom', + nativeCurrency: { + decimals: etherUnits.wei, + name: 'Ether', + symbol: 'ETH' + }, + rpcUrls: { + default: { + http: [], + webSocket: [] + } + } + }) + } } From 8cd7e96c56c3ab088e1758d1e4af61af5d913471 Mon Sep 17 00:00:00 2001 From: leonardotc Date: Fri, 26 Jul 2024 13:50:01 +0200 Subject: [PATCH 76/85] Depromisify getAddress --- .../packs/monerium/SafeMoneriumClient.test.ts | 6 +++--- .../src/packs/monerium/SafeMoneriumClient.ts | 2 +- packages/protocol-kit/src/Safe.ts | 18 +++++++++--------- packages/protocol-kit/src/SafeFactory.ts | 4 ++-- .../protocol-kit/src/contracts/BaseContract.ts | 2 +- .../src/contracts/safeDeploymentContracts.ts | 18 ++++++++---------- packages/protocol-kit/src/contracts/utils.ts | 10 +++++----- .../src/managers/fallbackHandlerManager.ts | 2 +- .../protocol-kit/src/managers/guardManager.ts | 2 +- .../protocol-kit/src/utils/transactions/gas.ts | 12 ++++++------ .../protocol-kit/tests/e2e/safeFactory.test.ts | 2 +- .../tests/e2e/safeProvider.test.ts | 18 +++++------------- .../src/packs/safe-4337/Safe4337Pack.ts | 2 +- .../src/contracts/common/BaseContract.ts | 2 +- .../src/extensions/messages/onChainMessages.ts | 2 +- 15 files changed, 46 insertions(+), 56 deletions(-) diff --git a/packages/onramp-kit/src/packs/monerium/SafeMoneriumClient.test.ts b/packages/onramp-kit/src/packs/monerium/SafeMoneriumClient.test.ts index e2a778a72..f4a99ad54 100644 --- a/packages/onramp-kit/src/packs/monerium/SafeMoneriumClient.test.ts +++ b/packages/onramp-kit/src/packs/monerium/SafeMoneriumClient.test.ts @@ -61,12 +61,12 @@ describe('SafeMoneriumClient', () => { }) it('should allow to get the Safe address', async () => { - protocolKit.getAddress = jest.fn(() => Promise.resolve('0xSafeAddress')) + protocolKit.getAddress = jest.fn(() => '0xSafeAddress') expect(await safeMoneriumClient.getSafeAddress()).toBe('0xSafeAddress') }) it('should allow to send tokens from then Safe to any IBAN', async () => { - protocolKit.getAddress = jest.fn(() => Promise.resolve('0xSafeAddress')) + protocolKit.getAddress = jest.fn(() => '0xSafeAddress') const placeOrderSpy = jest.spyOn(safeMoneriumClient, 'placeOrder') //@ts-expect-error - Not all values are mocked const signMessageSpy = jest.spyOn(safeMoneriumClient, 'signMessage').mockResolvedValueOnce({ @@ -96,7 +96,7 @@ describe('SafeMoneriumClient', () => { }) it('should throw if signing message fails', async () => { - protocolKit.getAddress = jest.fn(() => Promise.resolve('0xSafeAddress')) + protocolKit.getAddress = jest.fn(() => '0xSafeAddress') const placeOrderSpy = jest.spyOn(safeMoneriumClient, 'placeOrder') const signMessageSpy = jest .spyOn(safeMoneriumClient, 'signMessage') diff --git a/packages/onramp-kit/src/packs/monerium/SafeMoneriumClient.ts b/packages/onramp-kit/src/packs/monerium/SafeMoneriumClient.ts index f23d3b8b0..8bdce8b17 100644 --- a/packages/onramp-kit/src/packs/monerium/SafeMoneriumClient.ts +++ b/packages/onramp-kit/src/packs/monerium/SafeMoneriumClient.ts @@ -120,7 +120,7 @@ export class SafeMoneriumClient extends MoneriumClient { const txData = signMessageContract.encode('signMessage', [hashMessage(message)]) const safeTransactionData = { - to: await signMessageContract.getAddress(), + to: signMessageContract.getAddress(), value: '0', data: txData, operation: OperationType.DelegateCall diff --git a/packages/protocol-kit/src/Safe.ts b/packages/protocol-kit/src/Safe.ts index 5c889a7e5..d2a1cb50f 100644 --- a/packages/protocol-kit/src/Safe.ts +++ b/packages/protocol-kit/src/Safe.ts @@ -256,7 +256,7 @@ class Safe { throw new Error('Safe is not deployed') } - return await this.#contractManager.safeContract.getAddress() + return this.#contractManager.safeContract.getAddress() } /** @@ -282,8 +282,8 @@ class Safe { * * @returns The address of the MultiSend contract */ - async getMultiSendAddress(): Promise { - return await this.#contractManager.multiSendContract.getAddress() + getMultiSendAddress(): string { + return this.#contractManager.multiSendContract.getAddress() } /** @@ -291,8 +291,8 @@ class Safe { * * @returns The address of the MultiSendCallOnly contract */ - async getMultiSendCallOnlyAddress(): Promise { - return await this.#contractManager.multiSendCallOnlyContract.getAddress() + getMultiSendCallOnlyAddress(): string { + return this.#contractManager.multiSendCallOnlyContract.getAddress() } /** @@ -482,7 +482,7 @@ class Safe { const multiSendTransaction = { ...options, - to: await multiSendContract.getAddress(), + to: multiSendContract.getAddress(), value: '0', data: multiSendContract.encode('multiSend', [asHex(multiSendData)]), operation: OperationType.DelegateCall @@ -1401,11 +1401,11 @@ class Safe { const safeDeployTransactionData = { ...transactionOptions, // optional transaction options like from, gasLimit, gasPrice... - to: await safeProxyFactoryContract.getAddress(), + to: safeProxyFactoryContract.getAddress(), value: '0', // we use the createProxyWithNonce method to create the Safe in a deterministic address, see: https://github.com/safe-global/safe-contracts/blob/main/contracts/proxies/SafeProxyFactory.sol#L52 data: safeProxyFactoryContract.encode('createProxyWithNonce', [ - asAddress(await safeSingletonContract.getAddress()), + asAddress(safeSingletonContract.getAddress()), asHex(initializer), // call to the setup method to set the threshold & owners of the new Safe BigInt(saltNonce) ]) @@ -1445,7 +1445,7 @@ class Safe { const transactionBatch = { ...transactionOptions, // optional transaction options like from, gasLimit, gasPrice... - to: await multiSendCallOnlyContract.getAddress(), + to: multiSendCallOnlyContract.getAddress(), value: '0', data: batchData } diff --git a/packages/protocol-kit/src/SafeFactory.ts b/packages/protocol-kit/src/SafeFactory.ts index 180170e4f..822098237 100644 --- a/packages/protocol-kit/src/SafeFactory.ts +++ b/packages/protocol-kit/src/SafeFactory.ts @@ -89,7 +89,7 @@ class SafeFactory { return this.#safeVersion } - getAddress(): Promise { + getAddress(): string { return this.#safeProxyFactoryContract.getAddress() } @@ -144,7 +144,7 @@ class SafeFactory { }) const safeAddress = await this.#safeProxyFactoryContract.createProxyWithOptions({ - safeSingletonAddress: await this.#safeContract.getAddress(), + safeSingletonAddress: this.#safeContract.getAddress(), initializer, saltNonce: saltNonce || getChainSpecificDefaultSaltNonce(chainId), options: { diff --git a/packages/protocol-kit/src/contracts/BaseContract.ts b/packages/protocol-kit/src/contracts/BaseContract.ts index 17f6f0e25..de40003d2 100644 --- a/packages/protocol-kit/src/contracts/BaseContract.ts +++ b/packages/protocol-kit/src/contracts/BaseContract.ts @@ -139,7 +139,7 @@ class BaseContract { } getAddress: GetAddressFunction = () => { - return Promise.resolve(this.contract.address) + return this.contract.address } encode: EncodeFunction = (functionToEncode, args) => { diff --git a/packages/protocol-kit/src/contracts/safeDeploymentContracts.ts b/packages/protocol-kit/src/contracts/safeDeploymentContracts.ts index cc42e8a7f..2dcafe29b 100644 --- a/packages/protocol-kit/src/contracts/safeDeploymentContracts.ts +++ b/packages/protocol-kit/src/contracts/safeDeploymentContracts.ts @@ -36,7 +36,7 @@ export async function getSafeContract({ customContractAbi: customContracts?.safeSingletonAbi, isL1SafeSingleton }) - const isContractDeployed = await safeProvider.isContractDeployed(await safeContract.getAddress()) + const isContractDeployed = await safeProvider.isContractDeployed(safeContract.getAddress()) if (!isContractDeployed) { throw new Error('SafeProxy contract is not deployed on the current network') } @@ -54,7 +54,7 @@ export async function getProxyFactoryContract({ customContractAbi: customContracts?.safeProxyFactoryAbi }) const isContractDeployed = await safeProvider.isContractDeployed( - await safeProxyFactoryContract.getAddress() + safeProxyFactoryContract.getAddress() ) if (!isContractDeployed) { throw new Error('SafeProxyFactory contract is not deployed on the current network') @@ -73,7 +73,7 @@ export async function getCompatibilityFallbackHandlerContract({ customContractAbi: customContracts?.fallbackHandlerAbi }) const isContractDeployed = await safeProvider.isContractDeployed( - await fallbackHandlerContract.getAddress() + fallbackHandlerContract.getAddress() ) if (!isContractDeployed) { throw new Error('CompatibilityFallbackHandler contract is not deployed on the current network') @@ -91,7 +91,7 @@ export async function getMultiSendContract({ customContractAddress: customContracts?.multiSendAddress, customContractAbi: customContracts?.multiSendAbi }) - const address = await multiSendContract.getAddress() + const address = multiSendContract.getAddress() const isContractDeployed = await safeProvider.isContractDeployed(address) if (!isContractDeployed) { throw new Error('MultiSend contract is not deployed on the current network') @@ -110,7 +110,7 @@ export async function getMultiSendCallOnlyContract({ customContractAbi: customContracts?.multiSendCallOnlyAbi }) const isContractDeployed = await safeProvider.isContractDeployed( - await multiSendCallOnlyContract.getAddress() + multiSendCallOnlyContract.getAddress() ) if (!isContractDeployed) { throw new Error('MultiSendCallOnly contract is not deployed on the current network') @@ -129,7 +129,7 @@ export async function getSignMessageLibContract({ customContractAbi: customContracts?.signMessageLibAbi }) const isContractDeployed = await safeProvider.isContractDeployed( - await signMessageLibContract.getAddress() + signMessageLibContract.getAddress() ) if (!isContractDeployed) { throw new Error('SignMessageLib contract is not deployed on the current network') @@ -147,9 +147,7 @@ export async function getCreateCallContract({ customContractAddress: customContracts?.createCallAddress, customContractAbi: customContracts?.createCallAbi }) - const isContractDeployed = await safeProvider.isContractDeployed( - await createCallContract.getAddress() - ) + const isContractDeployed = await safeProvider.isContractDeployed(createCallContract.getAddress()) if (!isContractDeployed) { throw new Error('CreateCall contract is not deployed on the current network') } @@ -167,7 +165,7 @@ export async function getSimulateTxAccessorContract({ customContractAbi: customContracts?.simulateTxAccessorAbi }) const isContractDeployed = await safeProvider.isContractDeployed( - await simulateTxAccessorContract.getAddress() + simulateTxAccessorContract.getAddress() ) if (!isContractDeployed) { throw new Error('SimulateTxAccessor contract is not deployed on the current network') diff --git a/packages/protocol-kit/src/contracts/utils.ts b/packages/protocol-kit/src/contracts/utils.ts index 1ea5e1c70..d1dfc2c09 100644 --- a/packages/protocol-kit/src/contracts/utils.ts +++ b/packages/protocol-kit/src/contracts/utils.ts @@ -135,7 +135,7 @@ export async function encodeSetupCallData({ customContracts }) - fallbackHandlerAddress = await fallbackHandlerContract.getAddress() + fallbackHandlerAddress = fallbackHandlerContract.getAddress() } return safeContract.encode('setup', [ @@ -238,14 +238,14 @@ export async function getPredictedSafeAddressInitCode({ }) const encodedNonce = safeProvider.encodeParameters('uint256', [saltNonce]) - const safeSingletonAddress = await safeContract.getAddress() + const safeSingletonAddress = safeContract.getAddress() const initCodeCallData = encodeCreateProxyWithNonce( safeProxyFactoryContract, safeSingletonAddress, initializer, encodedNonce ) - const safeProxyFactoryAddress = await safeProxyFactoryContract.getAddress() + const safeProxyFactoryAddress = safeProxyFactoryContract.getAddress() const initCode = `0x${[safeProxyFactoryAddress, initCodeCallData].reduce( (acc, x) => acc + x.replace('0x', ''), '' @@ -305,9 +305,9 @@ export async function predictSafeAddress({ const salt = keccak256(concat([initializerHash, encodedNonce])) - const input = safeProvider.encodeParameters('address', [await safeContract.getAddress()]) + const input = safeProvider.encodeParameters('address', [safeContract.getAddress()]) - const from = asAddress(await safeProxyFactoryContract.getAddress()) + const from = asAddress(safeProxyFactoryContract.getAddress()) // On the zkSync Era chain, the counterfactual deployment address is calculated differently const isZkSyncEraChain = [ZKSYNC_MAINNET, ZKSYNC_TESTNET].includes(chainId) diff --git a/packages/protocol-kit/src/managers/fallbackHandlerManager.ts b/packages/protocol-kit/src/managers/fallbackHandlerManager.ts index c688c8555..3d476c3df 100644 --- a/packages/protocol-kit/src/managers/fallbackHandlerManager.ts +++ b/packages/protocol-kit/src/managers/fallbackHandlerManager.ts @@ -60,7 +60,7 @@ class FallbackHandlerManager { async getFallbackHandler(): Promise { const safeContract = await this.isFallbackHandlerCompatible() - return this.#safeProvider.getStorageAt(await safeContract.getAddress(), this.#slot) + return this.#safeProvider.getStorageAt(safeContract.getAddress(), this.#slot) } async encodeEnableFallbackHandlerData(fallbackHandlerAddress: string): Promise { diff --git a/packages/protocol-kit/src/managers/guardManager.ts b/packages/protocol-kit/src/managers/guardManager.ts index d05461348..7beabeec9 100644 --- a/packages/protocol-kit/src/managers/guardManager.ts +++ b/packages/protocol-kit/src/managers/guardManager.ts @@ -57,7 +57,7 @@ class GuardManager { async getGuard(): Promise { const safeContract = await this.isGuardCompatible() - return this.#safeProvider.getStorageAt(await safeContract.getAddress(), this.#slot) + return this.#safeProvider.getStorageAt(safeContract.getAddress(), this.#slot) } async encodeEnableGuardData(guardAddress: string): Promise { diff --git a/packages/protocol-kit/src/utils/transactions/gas.ts b/packages/protocol-kit/src/utils/transactions/gas.ts index c9c6dd6a7..0cef75951 100644 --- a/packages/protocol-kit/src/utils/transactions/gas.ts +++ b/packages/protocol-kit/src/utils/transactions/gas.ts @@ -91,9 +91,9 @@ export async function estimateGas( const safeFunctionToEstimate = safeContractContractCompatibleWithSimulateAndRevert.encode( 'simulateAndRevert', - [asAddress(await simulateTxAccessorContract.getAddress()), asHex(transactionDataToEstimate)] + [asAddress(simulateTxAccessorContract.getAddress()), asHex(transactionDataToEstimate)] ) - const safeAddress = await safeContract.getAddress() + const safeAddress = safeContract.getAddress() const transactionToEstimateGas = { to: safeAddress, value: '0', @@ -118,7 +118,7 @@ export async function estimateTxGas( data: string, operation: OperationType ): Promise { - const safeAddress = await safeContract.getAddress() + const safeAddress = safeContract.getAddress() try { const estimateGas = await safeProvider.estimateGas({ to, @@ -309,7 +309,7 @@ async function estimateSafeTxGasWithRequiredTxGas( ] ) - const to = isSafeDeployed ? safeAddress : await safeSingletonContract.getAddress() + const to = isSafeDeployed ? safeAddress : safeSingletonContract.getAddress() const transactionToEstimateGas = { to, @@ -464,14 +464,14 @@ async function estimateSafeTxGasWithSimulate( ]) // if the Safe is not deployed we can use the singleton address to simulate - const to = isSafeDeployed ? safeAddress : await safeSingletonContract.getAddress() + const to = isSafeDeployed ? safeAddress : safeSingletonContract.getAddress() const SafeContractCompatibleWithSimulateAndRevert = await isSafeContractCompatibleWithSimulateAndRevert(safeSingletonContract) const safeFunctionToEstimate: string = SafeContractCompatibleWithSimulateAndRevert.encode( 'simulateAndRevert', - [asAddress(await simulateTxAccessorContract.getAddress()), asHex(transactionDataToEstimate)] + [asAddress(simulateTxAccessorContract.getAddress()), asHex(transactionDataToEstimate)] ) const transactionToEstimateGas = { diff --git a/packages/protocol-kit/tests/e2e/safeFactory.test.ts b/packages/protocol-kit/tests/e2e/safeFactory.test.ts index 08cea2961..fd58c0a03 100644 --- a/packages/protocol-kit/tests/e2e/safeFactory.test.ts +++ b/packages/protocol-kit/tests/e2e/safeFactory.test.ts @@ -85,7 +85,7 @@ describe('SafeProxyFactory', () => { const safeFactory = await SafeFactory.init({ provider, contractNetworks }) const networkId = await safeProvider.getChainId() chai - .expect(await safeFactory.getAddress()) + .expect(safeFactory.getAddress()) .to.be.eq(contractNetworks[networkId.toString()].safeProxyFactoryAddress) }) }) diff --git a/packages/protocol-kit/tests/e2e/safeProvider.test.ts b/packages/protocol-kit/tests/e2e/safeProvider.test.ts index d4b141a28..b5cceb024 100644 --- a/packages/protocol-kit/tests/e2e/safeProvider.test.ts +++ b/packages/protocol-kit/tests/e2e/safeProvider.test.ts @@ -42,9 +42,7 @@ describe('Safe contracts', () => { const safeContract = await safeProvider.getSafeContract({ safeVersion }) - chai - .expect(await safeContract.getAddress()) - .to.be.eq('0xd9Db270c1B5E3Bd161E8c8503c55cEABeE709552') + chai.expect(safeContract.getAddress()).to.be.eq('0xd9Db270c1B5E3Bd161E8c8503c55cEABeE709552') }) it('should return an L2 Safe contract from safe-deployments', async () => { @@ -53,9 +51,7 @@ describe('Safe contracts', () => { const safeContract = await safeProvider.getSafeContract({ safeVersion }) - chai - .expect(await safeContract.getAddress()) - .to.be.eq('0x3E5c63644E683549055b9Be8653de26E0B4CD36E') + chai.expect(safeContract.getAddress()).to.be.eq('0x3E5c63644E683549055b9Be8653de26E0B4CD36E') }) it('should return an L1 Safe contract from safe-deployments using the L1 flag', async () => { @@ -66,9 +62,7 @@ describe('Safe contracts', () => { safeVersion, isL1SafeSingleton }) - chai - .expect(await safeContract.getAddress()) - .to.be.eq('0xd9Db270c1B5E3Bd161E8c8503c55cEABeE709552') + chai.expect(safeContract.getAddress()).to.be.eq('0xd9Db270c1B5E3Bd161E8c8503c55cEABeE709552') }) it('should return an L1 Safe contract from safe-deployments when the safeVersion is < 1.3.0', async () => { @@ -77,9 +71,7 @@ describe('Safe contracts', () => { const safeContract = await safeProvider.getSafeContract({ safeVersion }) - chai - .expect(await safeContract.getAddress()) - .to.be.eq('0x34CfAC646f301356fAa8B21e94227e3583Fe3F5F') + chai.expect(safeContract.getAddress()).to.be.eq('0x34CfAC646f301356fAa8B21e94227e3583Fe3F5F') }) it('should return a Safe contract from the custom addresses', async () => { @@ -93,7 +85,7 @@ describe('Safe contracts', () => { customContractAbi: customContract?.safeSingletonAbi }) chai - .expect(await safeContract.getAddress()) + .expect(safeContract.getAddress()) .to.be.eq(await (await getSafeSingleton()).contract.address) }) }) diff --git a/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.ts b/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.ts index d881fe48c..6a25fe724 100644 --- a/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.ts +++ b/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.ts @@ -250,7 +250,7 @@ export class Safe4337Pack extends RelayKitBasePack<{ safeVersion: options.safeVersion || DEFAULT_SAFE_VERSION }) - deploymentTo = (await multiSendContract.getAddress()) as Address + deploymentTo = multiSendContract.getAddress() as Address deploymentData = batchData } diff --git a/packages/safe-core-sdk-types/src/contracts/common/BaseContract.ts b/packages/safe-core-sdk-types/src/contracts/common/BaseContract.ts index a71fdb40b..0da3ac0e0 100644 --- a/packages/safe-core-sdk-types/src/contracts/common/BaseContract.ts +++ b/packages/safe-core-sdk-types/src/contracts/common/BaseContract.ts @@ -81,7 +81,7 @@ export type EstimateGasFunction< options?: TransactionOptions ) => Promise -export type GetAddressFunction = () => Promise +export type GetAddressFunction = () => string /** * Defines a function type for a contract, derived by the given function name from a given contract ABI. diff --git a/packages/safe-kit/src/extensions/messages/onChainMessages.ts b/packages/safe-kit/src/extensions/messages/onChainMessages.ts index ad0d554e4..764e1aee5 100644 --- a/packages/safe-kit/src/extensions/messages/onChainMessages.ts +++ b/packages/safe-kit/src/extensions/messages/onChainMessages.ts @@ -40,7 +40,7 @@ export function onChainMessages() { }) const transaction = { - to: await signMessageLibContract.getAddress(), + to: signMessageLibContract.getAddress(), value: '0', data: signMessageLibContract.encode('signMessage', [hashSafeMessage(message) as Hash]), operation: OperationType.DelegateCall From 658b9a8b6d8263aa34023542905de8a7a667929d Mon Sep 17 00:00:00 2001 From: leonardotc Date: Fri, 26 Jul 2024 14:28:41 +0200 Subject: [PATCH 77/85] Fix onramp --- .../src/packs/monerium/SafeMoneriumClient.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/onramp-kit/src/packs/monerium/SafeMoneriumClient.test.ts b/packages/onramp-kit/src/packs/monerium/SafeMoneriumClient.test.ts index f4a99ad54..e2a778a72 100644 --- a/packages/onramp-kit/src/packs/monerium/SafeMoneriumClient.test.ts +++ b/packages/onramp-kit/src/packs/monerium/SafeMoneriumClient.test.ts @@ -61,12 +61,12 @@ describe('SafeMoneriumClient', () => { }) it('should allow to get the Safe address', async () => { - protocolKit.getAddress = jest.fn(() => '0xSafeAddress') + protocolKit.getAddress = jest.fn(() => Promise.resolve('0xSafeAddress')) expect(await safeMoneriumClient.getSafeAddress()).toBe('0xSafeAddress') }) it('should allow to send tokens from then Safe to any IBAN', async () => { - protocolKit.getAddress = jest.fn(() => '0xSafeAddress') + protocolKit.getAddress = jest.fn(() => Promise.resolve('0xSafeAddress')) const placeOrderSpy = jest.spyOn(safeMoneriumClient, 'placeOrder') //@ts-expect-error - Not all values are mocked const signMessageSpy = jest.spyOn(safeMoneriumClient, 'signMessage').mockResolvedValueOnce({ @@ -96,7 +96,7 @@ describe('SafeMoneriumClient', () => { }) it('should throw if signing message fails', async () => { - protocolKit.getAddress = jest.fn(() => '0xSafeAddress') + protocolKit.getAddress = jest.fn(() => Promise.resolve('0xSafeAddress')) const placeOrderSpy = jest.spyOn(safeMoneriumClient, 'placeOrder') const signMessageSpy = jest .spyOn(safeMoneriumClient, 'signMessage') From 00a292ee7e406735c895bc8f2c5d4492c760054c Mon Sep 17 00:00:00 2001 From: Tim <4171783+tmjssz@users.noreply.github.com> Date: Tue, 30 Jul 2024 12:04:37 +0100 Subject: [PATCH 78/85] feat: Extend SafeProviders externalClient type (#928) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Extend SafeProvider's external client type to `PublicClient | WalletClient` * Introduce `ExternalClient` type alias and use it as type for `#externalProvider` in SafeProvider * With the extended type we need to use viem methods individually from `viem/actions` instead of calling them directly on the client itself * Extend SafeProvider by a `readContract` method to fix TS error in Safe4337Pack Also fix unit test for Safe4337Pack * Fix custom chain support --------- Co-authored-by: leonardotc --- .../packs/monerium/SafeMoneriumClient.test.ts | 14 +- packages/protocol-kit/src/SafeProvider.ts | 89 +++++--- .../src/contracts/BaseContract.ts | 69 ++++-- .../CreateCall/CreateCallBaseContract.ts | 4 +- .../v1.3.0/CreateCallContract_v1_3_0.ts | 14 +- .../v1.4.1/CreateCallContract_v1_4_1.ts | 14 +- .../Safe/v1.0.0/SafeContract_v1_0_0.ts | 207 ++++-------------- .../Safe/v1.1.1/SafeContract_v1_1_1.ts | 164 ++++---------- .../Safe/v1.2.0/SafeContract_v1_2_0.ts | 173 ++++----------- .../Safe/v1.3.0/SafeContract_v1_3_0.ts | 179 ++++----------- .../Safe/v1.4.1/SafeContract_v1_4_1.ts | 179 ++++----------- .../SafeProxyFactoryBaseContract.ts | 4 +- .../v1.0.0/SafeProxyFactoryContract_v1_0_0.ts | 41 ++-- .../v1.1.1/SafeProxyFactoryContract_v1_1_1.ts | 52 ++--- .../v1.3.0/SafeProxyFactoryContract_v1_3_0.ts | 52 ++--- .../v1.4.1/SafeProxyFactoryContract_v1_4_1.ts | 50 ++--- .../v1.3.0/SignMessageLibContract_v1_3_0.ts | 17 +- .../v1.4.1/SignMessageLibContract_v1_4_1.ts | 17 +- .../SimulateTxAccessorContract_v1_3_0.ts | 5 +- .../SimulateTxAccessorContract_v1_4_1.ts | 5 +- .../src/contracts/contractInstances.ts | 5 +- packages/protocol-kit/src/contracts/utils.ts | 9 +- .../protocol-kit/src/types/safeProvider.ts | 3 +- packages/protocol-kit/src/utils/provider.ts | 4 + .../src/utils/transactions/utils.ts | 11 +- .../src/packs/safe-4337/Safe4337Pack.test.ts | 5 +- .../src/packs/safe-4337/Safe4337Pack.ts | 4 +- .../src/contracts/common/BaseContract.ts | 2 +- .../safe-kit/src/utils/sendTransaction.ts | 3 +- playground/api-kit/execute-transaction.ts | 8 +- playground/relay-kit/paid-transaction.ts | 7 +- playground/relay-kit/sponsored-transaction.ts | 7 +- .../usdc-transfer-4337-counterfactual.ts | 5 +- ...usdc-transfer-4337-erc20-counterfactual.ts | 3 +- .../relay-kit/usdc-transfer-4337-erc20.ts | 3 +- ...-transfer-4337-sponsored-counterfactual.ts | 3 +- .../relay-kit/usdc-transfer-4337-sponsored.ts | 3 +- playground/relay-kit/usdc-transfer-4337.ts | 3 +- 38 files changed, 460 insertions(+), 977 deletions(-) create mode 100644 packages/protocol-kit/src/utils/provider.ts diff --git a/packages/onramp-kit/src/packs/monerium/SafeMoneriumClient.test.ts b/packages/onramp-kit/src/packs/monerium/SafeMoneriumClient.test.ts index e2a778a72..1482548d3 100644 --- a/packages/onramp-kit/src/packs/monerium/SafeMoneriumClient.test.ts +++ b/packages/onramp-kit/src/packs/monerium/SafeMoneriumClient.test.ts @@ -1,4 +1,4 @@ -import { createPublicClient, hashMessage, getContract, custom } from 'viem' +import { createPublicClient, hashMessage, custom } from 'viem' import { PaymentStandard } from '@monerium/sdk' import Safe, * as protocolKitPackage from '@safe-global/protocol-kit' import { @@ -225,17 +225,10 @@ describe('SafeMoneriumClient', () => { const contract = { safeVersion: '1.3.0', contractName: 'signMessageLibVersion', - contract: getContract({ - address: '0x0000000000000000000000000000000000000001', - abi: signMessageLib_1_4_1_ContractArtifacts.abi, - client: createPublicClient({ - transport: custom({ request: jest.fn() }) - }) - }), safeProvider: protocolKit.getSafeProvider() as protocolKitPackage.SafeProvider, encode: jest.fn(), contractAbi: signMessageLib_1_4_1_ContractArtifacts.abi, - contractAddress: '', + contractAddress: '0x0000000000000000000000000000000000000001', getAddress: jest.fn(), getMessageHash: jest.fn(), signMessage: jest.fn(), @@ -245,7 +238,10 @@ describe('SafeMoneriumClient', () => { transport: custom({ request: jest.fn() }) }), chainId: 1n, + read: jest.fn(), + write: jest.fn(), getChain: jest.fn(), + getWallet: jest.fn(), convertOptions: jest.fn(), getTransactionReceipt: jest.fn() } as SignMessageLibContractImplementationType diff --git a/packages/protocol-kit/src/SafeProvider.ts b/packages/protocol-kit/src/SafeProvider.ts index 155ec233e..2ca4c1997 100644 --- a/packages/protocol-kit/src/SafeProvider.ts +++ b/packages/protocol-kit/src/SafeProvider.ts @@ -20,17 +20,17 @@ import { SafeProviderTransaction, GetContractProps, SafeProviderConfig, + ExternalClient, + ExternalSigner, Eip1193Provider, HttpTransport, - SocketTransport, - ExternalSigner + SocketTransport } from '@safe-global/protocol-kit/types' import { asAddress, asHash, asHex, getChainById } from './utils/types' import { asBlockId } from './utils/block' import { createPublicClient, createWalletClient, - PublicClient, custom, http, getAddress, @@ -40,39 +40,62 @@ import { encodeAbiParameters, parseAbiParameters, toBytes, - Chain + Chain, + Abi, + ReadContractParameters, + ContractFunctionName, + ContractFunctionArgs, + walletActions, + publicActions, + createClient, + PublicRpcSchema, + WalletRpcSchema, + rpcSchema } from 'viem' import { privateKeyToAccount } from 'viem/accounts' +import { + call, + estimateGas, + getBalance, + getCode, + getTransaction, + getTransactionCount, + getStorageAt, + readContract +} from 'viem/actions' import { toEstimateGasParameters, toCallGasParameters, sameString } from '@safe-global/protocol-kit/utils' +import { isEip1193Provider, isPrivateKey } from './utils/provider' class SafeProvider { #chain?: Chain - #externalProvider: PublicClient + #externalProvider: ExternalClient signer?: string provider: Eip1193Provider | HttpTransport | SocketTransport constructor({ provider, signer }: SafeProviderConfig) { this.#externalProvider = createPublicClient({ - transport: typeof provider === 'string' ? http(provider) : custom(provider) + transport: isEip1193Provider(provider) + ? custom(provider as Eip1193Provider) + : http(provider as string) }) this.provider = provider this.signer = signer ? asHex(signer) : signer } - getExternalProvider(): PublicClient { + getExternalProvider(): ExternalClient { return this.#externalProvider } async getExternalSigner(): Promise { - // If the signer is not an Ethereum address, it should be a private key const { transport, chain = await this.#getChain() } = this.getExternalProvider() - if (this.signer && !this.isAddress(this.signer)) { + if (isPrivateKey(this.signer)) { + // This is a client with a local account, the account needs to be of type Accound as viem consider strings as 'json-rpc' (on parseAccount) const account = privateKeyToAccount(asHex(this.signer)) return createWalletClient({ account, @@ -82,7 +105,7 @@ class SafeProvider { } // If we have a signer and its not a pk, it might be a delegate on the rpc levels and this should work with eth_requestAcc - if (this.signer) { + if (this.signer && isAddress(this.signer)) { return createWalletClient({ account: asAddress(this.signer), chain, @@ -90,7 +113,7 @@ class SafeProvider { }) } - if (transport?.type === 'custom') { + try { // This behavior is a reproduction of JsonRpcApiProvider#getSigner (which is super of BrowserProvider). // it dispatches and eth_accounts and picks the index 0. https://github.com/ethers-io/ethers.js/blob/a4b1d1f43fca14f2e826e3c60e0d45f5b6ef3ec4/src.ts/providers/provider-jsonrpc.ts#L1119C24-L1119C37 const wallet = createWalletClient({ @@ -99,12 +122,18 @@ class SafeProvider { }) const [address] = await wallet.getAddresses() - return createWalletClient({ - account: address, - transport: custom(transport), - chain: wallet.chain - }) - } + if (address) { + const client = createClient({ + account: address, + transport: custom(transport), + chain: wallet.chain, + rpcSchema: rpcSchema() + }) + .extend(walletActions) + .extend(publicActions) + return client + } + } catch {} return undefined } @@ -119,14 +148,14 @@ class SafeProvider { } async getBalance(address: string, blockTag?: string | number): Promise { - return this.#externalProvider.getBalance({ + return getBalance(this.#externalProvider, { address: asAddress(address), ...asBlockId(blockTag) }) } async getNonce(address: string, blockTag?: string | number): Promise { - return this.#externalProvider.getTransactionCount({ + return getTransactionCount(this.#externalProvider, { address: asAddress(address), ...asBlockId(blockTag) }) @@ -245,7 +274,7 @@ class SafeProvider { } async getContractCode(address: string, blockTag?: string | number): Promise { - const res = await this.#externalProvider.getCode({ + const res = await getCode(this.#externalProvider, { address: asAddress(address), ...asBlockId(blockTag) }) @@ -254,7 +283,7 @@ class SafeProvider { } async isContractDeployed(address: string, blockTag?: string | number): Promise { - const contractCode = await this.#externalProvider.getCode({ + const contractCode = await getCode(this.#externalProvider, { address: asAddress(address), ...asBlockId(blockTag) }) @@ -263,7 +292,7 @@ class SafeProvider { } async getStorageAt(address: string, position: string): Promise { - const content = await this.#externalProvider.getStorageAt({ + const content = await getStorageAt(this.#externalProvider, { address: asAddress(address), slot: asHex(position) }) @@ -272,9 +301,9 @@ class SafeProvider { } async getTransaction(transactionHash: string): Promise { - return this.#externalProvider.getTransaction({ + return getTransaction(this.#externalProvider, { hash: asHash(transactionHash) - }) as Promise + }) // as Promise } async getSignerAddress(): Promise { @@ -334,18 +363,26 @@ class SafeProvider { async estimateGas(transaction: SafeProviderTransaction): Promise { const converted = toEstimateGasParameters(transaction) - return (await this.#externalProvider.estimateGas(converted)).toString() + return (await estimateGas(this.#externalProvider, converted)).toString() } async call(transaction: SafeProviderTransaction, blockTag?: string | number): Promise { const converted = toCallGasParameters(transaction) - const { data } = await this.#externalProvider.call({ + const { data } = await call(this.#externalProvider, { ...converted, ...asBlockId(blockTag) }) return data ?? '0x' } + async readContract< + const abi extends Abi | readonly unknown[], + functionName extends ContractFunctionName, + const args extends ContractFunctionArgs + >(args: ReadContractParameters) { + return readContract(this.#externalProvider, args) + } + // TODO: fix anys encodeParameters(types: string, values: any[]): string { return encodeAbiParameters(parseAbiParameters(types), values) diff --git a/packages/protocol-kit/src/contracts/BaseContract.ts b/packages/protocol-kit/src/contracts/BaseContract.ts index de40003d2..6693392d7 100644 --- a/packages/protocol-kit/src/contracts/BaseContract.ts +++ b/packages/protocol-kit/src/contracts/BaseContract.ts @@ -1,14 +1,6 @@ import { Abi } from 'abitype' -import { - PublicClient, - Transport, - encodeFunctionData, - GetContractReturnType, - WalletClient, - Hash, - Chain, - getContract -} from 'viem' +import { Transport, encodeFunctionData, WalletClient, Hash, Chain } from 'viem' +import { estimateContractGas, getTransactionReceipt } from 'viem/actions' import { contractName, getContractDeployment } from '@safe-global/protocol-kit/contracts/config' import SafeProvider from '@safe-global/protocol-kit/SafeProvider' import { @@ -24,6 +16,8 @@ import { WalletLegacyTransactionOptions, convertTransactionOptions } from '@safe-global/protocol-kit/utils' +import { ExternalClient } from '../types' +import { ContractFunctionName, ContractFunctionArgs } from 'viem' /** * Abstract class BaseContract @@ -47,8 +41,7 @@ class BaseContract { safeVersion: SafeVersion safeProvider: SafeProvider chainId: bigint - contract!: GetContractReturnType - runner: PublicClient + runner: ExternalClient wallet?: WalletClient /** @@ -71,7 +64,7 @@ class BaseContract { safeVersion: SafeVersion, customContractAddress?: string, customContractAbi?: ContractAbiType, - runner?: PublicClient + runner?: ExternalClient ) { const deployment = getContractDeployment(safeVersion, chainId, contractName) @@ -99,16 +92,10 @@ class BaseContract { async init() { this.wallet = await this.safeProvider.getExternalSigner() - this.contract = getContract({ - address: asAddress(this.contractAddress), - abi: this.contractAbi, - client: this.wallet || this.runner - }) } async getTransactionReceipt(hash: Hash) { - const client = this.runner - return client?.getTransactionReceipt({ hash }) + return getTransactionReceipt(this.runner, { hash }) } /** @@ -139,7 +126,7 @@ class BaseContract { } getAddress: GetAddressFunction = () => { - return this.contract.address + return this.contractAddress } encode: EncodeFunction = (functionToEncode, args) => { @@ -161,14 +148,50 @@ class BaseContract { const contractOptions = await this.convertOptions(options) const abi = this.contractAbi as Abi const params = args as unknown[] - return this.runner!.estimateContractGas({ + return estimateContractGas(this.runner, { abi, functionName: functionToEstimate, - address: this.contract.address, + address: asAddress(this.getAddress()), args: params, ...contractOptions }) } + + getWallet(): WalletClient { + if (!this.wallet) throw new Error('A signer must be set') + return this.wallet + } + + async write< + functionName extends ContractFunctionName, + functionArgs extends ContractFunctionArgs< + ContractAbiType, + 'payable' | 'nonpayable', + functionName + > + >(functionName: functionName, args: functionArgs, options?: TransactionOptions) { + const converted = (await this.convertOptions(options)) as any + + return await this.getWallet().writeContract({ + address: asAddress(this.contractAddress), + abi: this.contractAbi, + functionName, + args: args, + ...converted + }) + } + + async read< + functionName extends ContractFunctionName, + functionArgs extends ContractFunctionArgs + >(functionName: functionName, args?: functionArgs) { + return await this.runner.readContract({ + functionName, + abi: this.contractAbi, + address: asAddress(this.contractAddress), + args + }) + } } export default BaseContract diff --git a/packages/protocol-kit/src/contracts/CreateCall/CreateCallBaseContract.ts b/packages/protocol-kit/src/contracts/CreateCall/CreateCallBaseContract.ts index 3978797b5..efae0cd5d 100644 --- a/packages/protocol-kit/src/contracts/CreateCall/CreateCallBaseContract.ts +++ b/packages/protocol-kit/src/contracts/CreateCall/CreateCallBaseContract.ts @@ -1,10 +1,10 @@ import { Abi } from 'abitype' -import { PublicClient } from 'viem' import SafeProvider from '@safe-global/protocol-kit/SafeProvider' import BaseContract from '@safe-global/protocol-kit/contracts/BaseContract' import { SafeVersion } from '@safe-global/safe-core-sdk-types' import { contractName } from '@safe-global/protocol-kit/contracts/config' +import { ExternalClient } from '@safe-global/protocol-kit/types' /** * Abstract class CreateCallBaseContract extends BaseContract to specifically integrate with the CreateCall contract. @@ -42,7 +42,7 @@ abstract class CreateCallBaseContract< safeVersion: SafeVersion, customContractAddress?: string, customContractAbi?: CreateCallContractAbiType, - runner?: PublicClient + runner?: ExternalClient ) { const contractName = 'createCallVersion' diff --git a/packages/protocol-kit/src/contracts/CreateCall/v1.3.0/CreateCallContract_v1_3_0.ts b/packages/protocol-kit/src/contracts/CreateCall/v1.3.0/CreateCallContract_v1_3_0.ts index 43d97521e..e5c5e4076 100644 --- a/packages/protocol-kit/src/contracts/CreateCall/v1.3.0/CreateCallContract_v1_3_0.ts +++ b/packages/protocol-kit/src/contracts/CreateCall/v1.3.0/CreateCallContract_v1_3_0.ts @@ -59,11 +59,8 @@ class CreateCallContract_v1_3_0 await this.estimateGas('performCreate', [...args], { ...options }) ).toString() } - const txResponse = await this.contract.write.performCreate( - args, - await this.convertOptions(options) - ) - return toTxResult(this.runner!, txResponse, options) + + return toTxResult(this.runner!, await this.write('performCreate', args, options), options) } /** @@ -78,11 +75,8 @@ class CreateCallContract_v1_3_0 if (options && !options.gasLimit) { options.gasLimit = (await this.estimateGas('performCreate2', args, options)).toString() } - const txResponse = await this.contract.write.performCreate2( - args, - await this.convertOptions(options) - ) - return toTxResult(this.runner!, txResponse, options) + + return toTxResult(this.runner!, await this.write('performCreate2', args, options), options) } } diff --git a/packages/protocol-kit/src/contracts/CreateCall/v1.4.1/CreateCallContract_v1_4_1.ts b/packages/protocol-kit/src/contracts/CreateCall/v1.4.1/CreateCallContract_v1_4_1.ts index 50a194917..da54bf799 100644 --- a/packages/protocol-kit/src/contracts/CreateCall/v1.4.1/CreateCallContract_v1_4_1.ts +++ b/packages/protocol-kit/src/contracts/CreateCall/v1.4.1/CreateCallContract_v1_4_1.ts @@ -57,11 +57,8 @@ class CreateCallContract_v1_4_1 if (options && !options.gasLimit) { options.gasLimit = (await this.estimateGas('performCreate', args, options)).toString() } - const txResponse = await this.contract.write.performCreate( - args, - await this.convertOptions(options) - ) - return toTxResult(this.runner!, txResponse, options) + + return toTxResult(this.runner!, await this.write('performCreate', args, options), options) } /** @@ -78,11 +75,8 @@ class CreateCallContract_v1_4_1 await this.estimateGas('performCreate2', [...args], { ...options }) ).toString() } - const txResponse = await this.contract.write.performCreate2( - args, - await this.convertOptions(options) - ) - return toTxResult(this.runner!, txResponse, options) + + return toTxResult(this.runner!, await this.write('performCreate2', args, options), options) } } diff --git a/packages/protocol-kit/src/contracts/Safe/v1.0.0/SafeContract_v1_0_0.ts b/packages/protocol-kit/src/contracts/Safe/v1.0.0/SafeContract_v1_0_0.ts index 5acc7353f..bdc1b259d 100644 --- a/packages/protocol-kit/src/contracts/Safe/v1.0.0/SafeContract_v1_0_0.ts +++ b/packages/protocol-kit/src/contracts/Safe/v1.0.0/SafeContract_v1_0_0.ts @@ -1,3 +1,5 @@ +import { Address, ContractFunctionArgs } from 'viem' +import { simulateContract } from 'viem/actions' import SafeBaseContract from '@safe-global/protocol-kit/contracts/Safe/SafeBaseContract' import SafeProvider from '@safe-global/protocol-kit/SafeProvider' import { toTxResult } from '@safe-global/protocol-kit/contracts/utils' @@ -14,7 +16,6 @@ import { } from '@safe-global/safe-core-sdk-types' import { SENTINEL_ADDRESS } from '@safe-global/protocol-kit/utils/constants' import { asAddress, asHash, asHex } from '@safe-global/protocol-kit/utils/types' -import { Address } from 'viem' /** * SafeContract_v1_0_0 is the implementation specific to the Safe contract version 1.0.0. @@ -65,53 +66,23 @@ class SafeContract_v1_0_0 /* ----- Specific v1.0.0 properties ----- */ DOMAIN_SEPARATOR_TYPEHASH: SafeContract_v1_0_0_Function<'DOMAIN_SEPARATOR_TYPEHASH'> = async () => { - return [ - await this.runner.readContract({ - functionName: 'DOMAIN_SEPARATOR_TYPEHASH', - abi: this.contractAbi, - address: asAddress(this.contractAddress) - }) - ] + return [await this.read('DOMAIN_SEPARATOR_TYPEHASH')] } SENTINEL_MODULES: SafeContract_v1_0_0_Function<'SENTINEL_MODULES'> = async () => { - return [ - await this.runner.readContract({ - functionName: 'SENTINEL_MODULES', - abi: this.contractAbi, - address: asAddress(this.contractAddress) - }) - ] + return [await this.read('SENTINEL_MODULES')] } SENTINEL_OWNERS: SafeContract_v1_0_0_Function<'SENTINEL_OWNERS'> = async () => { - return [ - await this.runner.readContract({ - functionName: 'SENTINEL_OWNERS', - abi: this.contractAbi, - address: asAddress(this.contractAddress) - }) - ] + return [await this.read('SENTINEL_OWNERS')] } SAFE_MSG_TYPEHASH: SafeContract_v1_0_0_Function<'SAFE_MSG_TYPEHASH'> = async () => { - return [ - await this.runner.readContract({ - functionName: 'SAFE_MSG_TYPEHASH', - abi: this.contractAbi, - address: asAddress(this.contractAddress) - }) - ] + return [await this.read('SAFE_MSG_TYPEHASH')] } SAFE_TX_TYPEHASH: SafeContract_v1_0_0_Function<'SAFE_TX_TYPEHASH'> = async () => { - return [ - await this.runner.readContract({ - functionName: 'SAFE_TX_TYPEHASH', - abi: this.contractAbi, - address: asAddress(this.contractAddress) - }) - ] + return [await this.read('SAFE_TX_TYPEHASH')] } /* ----- End of specific v1.0.0 properties ----- */ @@ -119,26 +90,14 @@ class SafeContract_v1_0_0 * @returns Array[contractName] */ NAME: SafeContract_v1_0_0_Function<'NAME'> = async () => { - return [ - await this.runner.readContract({ - functionName: 'NAME', - abi: this.contractAbi, - address: asAddress(this.contractAddress) - }) - ] + return [await this.read('NAME')] } /** * @returns Array[safeContractVersion] */ VERSION: SafeContract_v1_0_0_Function<'VERSION'> = async () => { - return [ - await this.runner.readContract({ - functionName: 'VERSION', - abi: this.contractAbi, - address: asAddress(this.contractAddress) - }) - ] + return [await this.read('VERSION')] } /** @@ -146,27 +105,14 @@ class SafeContract_v1_0_0 * @returns Array[approvedHashes] */ approvedHashes: SafeContract_v1_0_0_Function<'approvedHashes'> = async (args) => { - return [ - await this.runner.readContract({ - functionName: 'approvedHashes', - abi: this.contractAbi, - address: asAddress(this.contractAddress), - args - }) - ] + return [await this.read('approvedHashes', args)] } /** * @returns Array[domainSeparator] */ domainSeparator: SafeContract_v1_0_0_Function<'domainSeparator'> = async () => { - return [ - await this.runner.readContract({ - functionName: 'domainSeparator', - abi: this.contractAbi, - address: asAddress(this.contractAddress) - }) - ] + return [await this.read('domainSeparator')] } /** @@ -174,13 +120,7 @@ class SafeContract_v1_0_0 * @returns Array[Array[modules]] */ getModules: SafeContract_v1_0_0_Function<'getModules'> = async () => { - return [ - await this.runner.readContract({ - functionName: 'getModules', - abi: this.contractAbi, - address: asAddress(this.contractAddress) - }) - ] + return [await this.read('getModules')] } /** @@ -188,13 +128,7 @@ class SafeContract_v1_0_0 * @returns Array[Array[owners]] */ getOwners: SafeContract_v1_0_0_Function<'getOwners'> = async () => { - return [ - await this.runner.readContract({ - functionName: 'getOwners', - abi: this.contractAbi, - address: asAddress(this.contractAddress) - }) - ] + return [await this.read('getOwners')] } /** @@ -202,13 +136,7 @@ class SafeContract_v1_0_0 * @returns Array[threshold] */ getThreshold: SafeContract_v1_0_0_Function<'getThreshold'> = async () => { - return [ - await this.runner.readContract({ - functionName: 'getThreshold', - abi: this.contractAbi, - address: asAddress(this.contractAddress) - }) - ] + return [await this.read('getThreshold')] } /** @@ -217,14 +145,7 @@ class SafeContract_v1_0_0 * @returns Array[isOwner] */ isOwner: SafeContract_v1_0_0_Function<'isOwner'> = async (args) => { - return [ - await this.runner.readContract({ - functionName: 'isOwner', - abi: this.contractAbi, - address: asAddress(this.contractAddress), - args - }) - ] + return [await this.read('isOwner', args)] } /** @@ -232,13 +153,7 @@ class SafeContract_v1_0_0 * @returns Array[nonce] */ nonce: SafeContract_v1_0_0_Function<'nonce'> = async () => { - return [ - await this.runner.readContract({ - functionName: 'nonce', - abi: this.contractAbi, - address: asAddress(this.contractAddress) - }) - ] + return [await this.read('nonce')] } /** @@ -246,14 +161,7 @@ class SafeContract_v1_0_0 * @returns Array[signedMessages] */ signedMessages: SafeContract_v1_0_0_Function<'signedMessages'> = async (args) => { - return [ - await this.runner.readContract({ - functionName: 'signedMessages', - abi: this.contractAbi, - address: asAddress(this.contractAddress), - args - }) - ] + return [await this.read('signedMessages', args)] } /** @@ -262,14 +170,7 @@ class SafeContract_v1_0_0 * @returns Array[messageHash] */ getMessageHash: SafeContract_v1_0_0_Function<'getMessageHash'> = async (args) => { - return [ - await this.runner.readContract({ - functionName: 'getMessageHash', - abi: this.contractAbi, - address: asAddress(this.contractAddress), - args - }) - ] + return [await this.read('getMessageHash', args)] } /** @@ -278,14 +179,7 @@ class SafeContract_v1_0_0 * @returns Array[encodedData] */ encodeTransactionData: SafeContract_v1_0_0_Function<'encodeTransactionData'> = async (args) => { - return [ - await this.runner.readContract({ - functionName: 'encodeTransactionData', - abi: this.contractAbi, - address: asAddress(this.contractAddress), - args - }) - ] + return [await this.read('encodeTransactionData', args)] } /** @@ -294,14 +188,7 @@ class SafeContract_v1_0_0 * @returns Array[transactionHash] */ getTransactionHash: SafeContract_v1_0_0_Function<'getTransactionHash'> = async (args) => { - return [ - await this.runner.readContract({ - functionName: 'getTransactionHash', - abi: this.contractAbi, - address: asAddress(this.contractAddress), - args - }) - ] + return [await this.read('getTransactionHash', args)] } /** @@ -315,20 +202,11 @@ class SafeContract_v1_0_0 const gasLimit = options?.gasLimit || (await this.estimateGas('approveHash', [asHash(hash)], options)) - const converted = await this.convertOptions({ - ...options, - gasLimit - }) - - const txResponse = await this.wallet?.writeContract({ - functionName: 'approveHash', - address: asAddress(this.contractAddress), - abi: this.contractAbi, - args: [asHash(hash)], - ...converted - }) - - return toTxResult(this.runner!, txResponse, options) + return toTxResult( + this.runner!, + await this.write('approveHash', [asHash(hash)], { ...options, gasLimit }), + options + ) } /** @@ -360,23 +238,24 @@ class SafeContract_v1_0_0 options )) - const txResponse = await this.contract.write.execTransaction( - [ - asAddress(safeTransaction.data.to), - BigInt(safeTransaction.data.value), - asHex(safeTransaction.data.data), - safeTransaction.data.operation, - BigInt(safeTransaction.data.safeTxGas), - BigInt(safeTransaction.data.baseGas), - BigInt(safeTransaction.data.gasPrice), - asAddress(safeTransaction.data.gasToken), - asAddress(safeTransaction.data.refundReceiver), - asHex(safeTransaction.encodedSignatures()) - ], - await this.convertOptions({ ...options, gasLimit }) - ) + const args: ContractFunctionArgs = [ + asAddress(safeTransaction.data.to), + BigInt(safeTransaction.data.value), + asHex(safeTransaction.data.data), + safeTransaction.data.operation, + BigInt(safeTransaction.data.safeTxGas), + BigInt(safeTransaction.data.baseGas), + BigInt(safeTransaction.data.gasPrice), + asAddress(safeTransaction.data.gasToken), + asAddress(safeTransaction.data.refundReceiver), + asHex(safeTransaction.encodedSignatures()) + ] - return toTxResult(this.runner!, txResponse, options) + return toTxResult( + this.runner!, + await this.write('execTransaction', args, { ...options, gasLimit }), + options + ) } async getModulesPaginated([start, pageSize]: [Address, bigint]): Promise<[string[], string]> { @@ -445,7 +324,7 @@ class SafeContract_v1_0_0 )) const converted = await this.convertOptions({ ...options, gasLimit }) - const txResult = await this.runner.simulateContract({ + const txResult = await simulateContract(this.runner, { address: asAddress(this.contractAddress), functionName: 'execTransaction', abi: this.contractAbi, diff --git a/packages/protocol-kit/src/contracts/Safe/v1.1.1/SafeContract_v1_1_1.ts b/packages/protocol-kit/src/contracts/Safe/v1.1.1/SafeContract_v1_1_1.ts index e00c31d1a..cd7ac401d 100644 --- a/packages/protocol-kit/src/contracts/Safe/v1.1.1/SafeContract_v1_1_1.ts +++ b/packages/protocol-kit/src/contracts/Safe/v1.1.1/SafeContract_v1_1_1.ts @@ -1,3 +1,4 @@ +import { simulateContract } from 'viem/actions' import SafeBaseContract from '@safe-global/protocol-kit/contracts/Safe/SafeBaseContract' import SafeProvider from '@safe-global/protocol-kit/SafeProvider' import { toTxResult } from '@safe-global/protocol-kit/contracts/utils' @@ -13,6 +14,7 @@ import { TransactionResult } from '@safe-global/safe-core-sdk-types' import { asAddress, asHash, asHex } from '@safe-global/protocol-kit/utils/types' +import { ContractFunctionArgs } from 'viem' /** * SafeContract_v1_1_1 is the implementation specific to the Safe contract version 1.1.1. @@ -64,26 +66,14 @@ class SafeContract_v1_1_1 * @returns Array[contractName] */ NAME: SafeContract_v1_1_1_Function<'NAME'> = async () => { - return [ - await this.runner.readContract({ - functionName: 'NAME', - abi: this.contractAbi, - address: asAddress(this.contractAddress) - }) - ] + return [await this.read('NAME')] } /** * @returns Array[safeContractVersion] */ VERSION: SafeContract_v1_1_1_Function<'VERSION'> = async () => { - return [ - await this.runner.readContract({ - functionName: 'VERSION', - abi: this.contractAbi, - address: asAddress(this.contractAddress) - }) - ] + return [await this.read('VERSION')] } /** @@ -91,27 +81,14 @@ class SafeContract_v1_1_1 * @returns Array[approvedHashes] */ approvedHashes: SafeContract_v1_1_1_Function<'approvedHashes'> = async (args) => { - return [ - await this.runner.readContract({ - functionName: 'approvedHashes', - abi: this.contractAbi, - address: asAddress(this.contractAddress), - args - }) - ] + return [await this.read('approvedHashes', args)] } /** * @returns Array[domainSeparator] */ domainSeparator: SafeContract_v1_1_1_Function<'domainSeparator'> = async () => { - return [ - await this.runner.readContract({ - functionName: 'domainSeparator', - abi: this.contractAbi, - address: asAddress(this.contractAddress) - }) - ] + return [await this.read('domainSeparator')] } /** @@ -119,13 +96,7 @@ class SafeContract_v1_1_1 * @returns Array[Array[modules]] */ getModules: SafeContract_v1_1_1_Function<'getModules'> = async () => { - return [ - await this.runner.readContract({ - functionName: 'getModules', - abi: this.contractAbi, - address: asAddress(this.contractAddress) - }) - ] + return [await this.read('getModules')] } /** @@ -134,12 +105,7 @@ class SafeContract_v1_1_1 * @returns Array[Array[modules], next] */ getModulesPaginated: SafeContract_v1_1_1_Function<'getModulesPaginated'> = async (args) => { - const [array, next] = await this.runner.readContract({ - functionName: 'getModulesPaginated', - abi: this.contractAbi, - address: asAddress(this.contractAddress), - args - }) + const [array, next] = await this.read('getModulesPaginated', args) return [array, next] } @@ -148,13 +114,7 @@ class SafeContract_v1_1_1 * @returns Array[Array[owners]] */ getOwners: SafeContract_v1_1_1_Function<'getOwners'> = async () => { - return [ - await this.runner.readContract({ - functionName: 'getOwners', - abi: this.contractAbi, - address: asAddress(this.contractAddress) - }) - ] + return [await this.read('getOwners')] } /** @@ -162,13 +122,7 @@ class SafeContract_v1_1_1 * @returns Array[threshold] */ getThreshold: SafeContract_v1_1_1_Function<'getThreshold'> = async () => { - return [ - await this.runner.readContract({ - functionName: 'getThreshold', - abi: this.contractAbi, - address: asAddress(this.contractAddress) - }) - ] + return [await this.read('getThreshold')] } /** @@ -177,14 +131,7 @@ class SafeContract_v1_1_1 * @returns Array[isOwner] */ isOwner: SafeContract_v1_1_1_Function<'isOwner'> = async (args) => { - return [ - await this.runner.readContract({ - functionName: 'isOwner', - abi: this.contractAbi, - address: asAddress(this.contractAddress), - args - }) - ] + return [await this.read('isOwner', args)] } /** @@ -192,13 +139,7 @@ class SafeContract_v1_1_1 * @returns Array[nonce] */ nonce: SafeContract_v1_1_1_Function<'nonce'> = async () => { - return [ - await this.runner.readContract({ - functionName: 'nonce', - abi: this.contractAbi, - address: asAddress(this.contractAddress) - }) - ] + return [await this.read('nonce')] } /** @@ -206,14 +147,7 @@ class SafeContract_v1_1_1 * @returns Array[signedMessages] */ signedMessages: SafeContract_v1_1_1_Function<'signedMessages'> = async (args) => { - return [ - await this.runner.readContract({ - functionName: 'signedMessages', - abi: this.contractAbi, - address: asAddress(this.contractAddress), - args - }) - ] + return [await this.read('signedMessages', args)] } /** @@ -222,14 +156,7 @@ class SafeContract_v1_1_1 * @returns Array[messageHash] */ getMessageHash: SafeContract_v1_1_1_Function<'getMessageHash'> = async (args) => { - return [ - await this.runner.readContract({ - functionName: 'getMessageHash', - abi: this.contractAbi, - address: asAddress(this.contractAddress), - args - }) - ] + return [await this.read('getMessageHash', args)] } /** @@ -238,14 +165,7 @@ class SafeContract_v1_1_1 * @returns Array[encodedData] */ encodeTransactionData: SafeContract_v1_1_1_Function<'encodeTransactionData'> = async (args) => { - return [ - await this.runner.readContract({ - functionName: 'encodeTransactionData', - abi: this.contractAbi, - address: asAddress(this.contractAddress), - args - }) - ] + return [await this.read('encodeTransactionData', args)] } /** @@ -254,14 +174,7 @@ class SafeContract_v1_1_1 * @returns Array[transactionHash] */ getTransactionHash: SafeContract_v1_1_1_Function<'getTransactionHash'> = async (args) => { - return [ - await this.runner.readContract({ - functionName: 'getTransactionHash', - abi: this.contractAbi, - address: asAddress(this.contractAddress), - args - }) - ] + return [await this.read('getTransactionHash', args)] } /** @@ -273,12 +186,12 @@ class SafeContract_v1_1_1 async approveHash(hash: string, options?: TransactionOptions): Promise { const gasLimit = options?.gasLimit || (await this.estimateGas('approveHash', [asHash(hash)], options)) - const txResponse = await this.contract.write.approveHash( - [asHash(hash)], - await this.convertOptions({ ...options, gasLimit }) - ) - return toTxResult(this.runner!, txResponse, options) + return toTxResult( + this.runner!, + await this.write('approveHash', [asHash(hash)], { ...options, gasLimit }), + options + ) } /** @@ -310,23 +223,24 @@ class SafeContract_v1_1_1 options )) - const txResponse = await this.contract.write.execTransaction( - [ - asAddress(safeTransaction.data.to), - BigInt(safeTransaction.data.value), - asHex(safeTransaction.data.data), - safeTransaction.data.operation, - BigInt(safeTransaction.data.safeTxGas), - BigInt(safeTransaction.data.baseGas), - BigInt(safeTransaction.data.gasPrice), - asAddress(safeTransaction.data.gasToken), - asAddress(safeTransaction.data.refundReceiver), - asHex(safeTransaction.encodedSignatures()) - ], - await this.convertOptions({ ...options, gasLimit }) - ) + const args: ContractFunctionArgs = [ + asAddress(safeTransaction.data.to), + BigInt(safeTransaction.data.value), + asHex(safeTransaction.data.data), + safeTransaction.data.operation, + BigInt(safeTransaction.data.safeTxGas), + BigInt(safeTransaction.data.baseGas), + BigInt(safeTransaction.data.gasPrice), + asAddress(safeTransaction.data.gasToken), + asAddress(safeTransaction.data.refundReceiver), + asHex(safeTransaction.encodedSignatures()) + ] - return toTxResult(this.runner!, txResponse, options) + return toTxResult( + this.runner!, + await this.write('execTransaction', args, { ...options, gasLimit }), + options + ) } /** @@ -373,7 +287,7 @@ class SafeContract_v1_1_1 )) const converted = await this.convertOptions({ ...options, gasLimit }) - const txResult = await this.runner.simulateContract({ + const txResult = await simulateContract(this.runner, { address: asAddress(this.contractAddress), functionName: 'execTransaction', abi: this.contractAbi, diff --git a/packages/protocol-kit/src/contracts/Safe/v1.2.0/SafeContract_v1_2_0.ts b/packages/protocol-kit/src/contracts/Safe/v1.2.0/SafeContract_v1_2_0.ts index d867ec218..4cebfc2b8 100644 --- a/packages/protocol-kit/src/contracts/Safe/v1.2.0/SafeContract_v1_2_0.ts +++ b/packages/protocol-kit/src/contracts/Safe/v1.2.0/SafeContract_v1_2_0.ts @@ -1,3 +1,4 @@ +import { simulateContract } from 'viem/actions' import SafeBaseContract from '@safe-global/protocol-kit/contracts/Safe/SafeBaseContract' import SafeProvider from '@safe-global/protocol-kit/SafeProvider' import { toTxResult } from '@safe-global/protocol-kit/contracts/utils' @@ -12,6 +13,7 @@ import { TransactionResult } from '@safe-global/safe-core-sdk-types' import { asAddress, asHash, asHex } from '@safe-global/protocol-kit/utils/types' +import { ContractFunctionArgs } from 'viem' /** * SafeContract_v1_2_0 is the implementation specific to the Safe contract version 1.2.0. @@ -63,26 +65,14 @@ class SafeContract_v1_2_0 * @returns Array[contractName] */ NAME: SafeContract_v1_2_0_Function<'NAME'> = async () => { - return [ - await this.runner.readContract({ - functionName: 'NAME', - abi: this.contractAbi, - address: asAddress(this.contractAddress) - }) - ] + return [await this.read('NAME')] } /** * @returns Array[safeContractVersion] */ VERSION: SafeContract_v1_2_0_Function<'VERSION'> = async () => { - return [ - await this.runner.readContract({ - functionName: 'VERSION', - abi: this.contractAbi, - address: asAddress(this.contractAddress) - }) - ] + return [await this.read('VERSION')] } /** @@ -90,27 +80,14 @@ class SafeContract_v1_2_0 * @returns Array[approvedHashes] */ approvedHashes: SafeContract_v1_2_0_Function<'approvedHashes'> = async (args) => { - return [ - await this.runner.readContract({ - functionName: 'approvedHashes', - abi: this.contractAbi, - address: asAddress(this.contractAddress), - args - }) - ] + return [await this.read('approvedHashes', args)] } /** * @returns Array[domainSeparator] */ domainSeparator: SafeContract_v1_2_0_Function<'domainSeparator'> = async () => { - return [ - await this.runner.readContract({ - functionName: 'domainSeparator', - abi: this.contractAbi, - address: asAddress(this.contractAddress) - }) - ] + return [await this.read('domainSeparator')] } /** @@ -118,13 +95,7 @@ class SafeContract_v1_2_0 * @returns Array[Array[modules]] */ getModules: SafeContract_v1_2_0_Function<'getModules'> = async () => { - return [ - await this.runner.readContract({ - functionName: 'getModules', - abi: this.contractAbi, - address: asAddress(this.contractAddress) - }) - ] + return [await this.read('getModules')] } /** @@ -133,12 +104,7 @@ class SafeContract_v1_2_0 * @returns Array[Array[modules], next] */ getModulesPaginated: SafeContract_v1_2_0_Function<'getModulesPaginated'> = async (args) => { - const [array, next] = await this.runner.readContract({ - functionName: 'getModulesPaginated', - abi: this.contractAbi, - address: asAddress(this.contractAddress), - args - }) + const [array, next] = await this.read('getModulesPaginated', args) return [array, next] } @@ -147,13 +113,7 @@ class SafeContract_v1_2_0 * @returns Array[Array[owners]] */ getOwners: SafeContract_v1_2_0_Function<'getOwners'> = async () => { - return [ - await this.runner.readContract({ - functionName: 'getOwners', - abi: this.contractAbi, - address: asAddress(this.contractAddress) - }) - ] + return [await this.read('getOwners')] } /** @@ -161,13 +121,7 @@ class SafeContract_v1_2_0 * @returns Array[threshold] */ getThreshold: SafeContract_v1_2_0_Function<'getThreshold'> = async () => { - return [ - await this.runner.readContract({ - functionName: 'getThreshold', - abi: this.contractAbi, - address: asAddress(this.contractAddress) - }) - ] + return [await this.read('getThreshold')] } /** @@ -176,14 +130,7 @@ class SafeContract_v1_2_0 * @returns Array[isEnabled] */ isModuleEnabled: SafeContract_v1_2_0_Function<'isModuleEnabled'> = async (args) => { - return [ - await this.runner.readContract({ - functionName: 'isModuleEnabled', - abi: this.contractAbi, - address: asAddress(this.contractAddress), - args - }) - ] + return [await this.read('isModuleEnabled', args)] } /** @@ -192,14 +139,7 @@ class SafeContract_v1_2_0 * @returns Array[isOwner] */ isOwner: SafeContract_v1_2_0_Function<'isOwner'> = async (args) => { - return [ - await this.runner.readContract({ - functionName: 'isOwner', - abi: this.contractAbi, - address: asAddress(this.contractAddress), - args - }) - ] + return [await this.read('isOwner', args)] } /** @@ -207,13 +147,7 @@ class SafeContract_v1_2_0 * @returns Array[nonce] */ nonce: SafeContract_v1_2_0_Function<'nonce'> = async () => { - return [ - await this.runner.readContract({ - functionName: 'nonce', - abi: this.contractAbi, - address: asAddress(this.contractAddress) - }) - ] + return [await this.read('nonce')] } /** @@ -221,14 +155,7 @@ class SafeContract_v1_2_0 * @returns Array[signedMessages] */ signedMessages: SafeContract_v1_2_0_Function<'signedMessages'> = async (args) => { - return [ - await this.runner.readContract({ - functionName: 'signedMessages', - abi: this.contractAbi, - address: asAddress(this.contractAddress), - args - }) - ] + return [await this.read('signedMessages', args)] } /** @@ -236,14 +163,7 @@ class SafeContract_v1_2_0 * @returns Array[messageHash] */ getMessageHash: SafeContract_v1_2_0_Function<'getMessageHash'> = async (args) => { - return [ - await this.runner.readContract({ - functionName: 'getMessageHash', - abi: this.contractAbi, - address: asAddress(this.contractAddress), - args - }) - ] + return [await this.read('getMessageHash', args)] } /** @@ -253,14 +173,7 @@ class SafeContract_v1_2_0 * @returns Array[encodedData] */ encodeTransactionData: SafeContract_v1_2_0_Function<'encodeTransactionData'> = async (args) => { - return [ - await this.runner.readContract({ - functionName: 'encodeTransactionData', - abi: this.contractAbi, - address: asAddress(this.contractAddress), - args - }) - ] + return [await this.read('encodeTransactionData', args)] } /** @@ -270,14 +183,7 @@ class SafeContract_v1_2_0 * @returns Array[transactionHash] */ getTransactionHash: SafeContract_v1_2_0_Function<'getTransactionHash'> = async (args) => { - return [ - await this.runner.readContract({ - functionName: 'getTransactionHash', - abi: this.contractAbi, - address: asAddress(this.contractAddress), - args - }) - ] + return [await this.read('getTransactionHash', args)] } /** @@ -289,12 +195,12 @@ class SafeContract_v1_2_0 async approveHash(hash: string, options?: TransactionOptions): Promise { const gasLimit = options?.gasLimit || (await this.estimateGas('approveHash', [asHash(hash)], options)) - const txResponse = await this.contract.write.approveHash( - [asHash(hash)], - await this.convertOptions({ ...options, gasLimit }) - ) - return toTxResult(this.runner!, txResponse, options) + return toTxResult( + this.runner!, + await this.write('approveHash', [asHash(hash)], { ...options, gasLimit }), + options + ) } /** @@ -326,23 +232,24 @@ class SafeContract_v1_2_0 options )) - const txResponse = await this.contract.write.execTransaction( - [ - asAddress(safeTransaction.data.to), - BigInt(safeTransaction.data.value), - asHex(safeTransaction.data.data), - safeTransaction.data.operation, - BigInt(safeTransaction.data.safeTxGas), - BigInt(safeTransaction.data.baseGas), - BigInt(safeTransaction.data.gasPrice), - asAddress(safeTransaction.data.gasToken), - asAddress(safeTransaction.data.refundReceiver), - asHex(safeTransaction.encodedSignatures()) - ], - await this.convertOptions({ ...options, gasLimit }) - ) + const args: ContractFunctionArgs = [ + asAddress(safeTransaction.data.to), + BigInt(safeTransaction.data.value), + asHex(safeTransaction.data.data), + safeTransaction.data.operation, + BigInt(safeTransaction.data.safeTxGas), + BigInt(safeTransaction.data.baseGas), + BigInt(safeTransaction.data.gasPrice), + asAddress(safeTransaction.data.gasToken), + asAddress(safeTransaction.data.refundReceiver), + asHex(safeTransaction.encodedSignatures()) + ] - return toTxResult(this.runner!, txResponse, options) + return toTxResult( + this.runner!, + await this.write('execTransaction', args, { ...options, gasLimit }), + options + ) } /** @@ -382,7 +289,7 @@ class SafeContract_v1_2_0 )) const converted = await this.convertOptions({ ...options, gasLimit }) - const txResult = await this.runner.simulateContract({ + const txResult = await simulateContract(this.runner, { address: asAddress(this.contractAddress), functionName: 'execTransaction', abi: this.contractAbi, diff --git a/packages/protocol-kit/src/contracts/Safe/v1.3.0/SafeContract_v1_3_0.ts b/packages/protocol-kit/src/contracts/Safe/v1.3.0/SafeContract_v1_3_0.ts index 1b089a48e..915501e91 100644 --- a/packages/protocol-kit/src/contracts/Safe/v1.3.0/SafeContract_v1_3_0.ts +++ b/packages/protocol-kit/src/contracts/Safe/v1.3.0/SafeContract_v1_3_0.ts @@ -1,3 +1,4 @@ +import { simulateContract } from 'viem/actions' import SafeBaseContract from '@safe-global/protocol-kit/contracts/Safe/SafeBaseContract' import SafeProvider from '@safe-global/protocol-kit/SafeProvider' import { toTxResult } from '@safe-global/protocol-kit/contracts/utils' @@ -13,6 +14,7 @@ import { TransactionResult } from '@safe-global/safe-core-sdk-types' import { asAddress, asHash, asHex } from '@safe-global/protocol-kit/utils/types' +import { ContractFunctionArgs } from 'viem' /** * SafeContract_v1_3_0 is the implementation specific to the Safe contract version 1.3.0. @@ -64,13 +66,7 @@ class SafeContract_v1_3_0 * @returns Array[safeContractVersion] */ VERSION: SafeContract_v1_3_0_Function<'VERSION'> = async () => { - return [ - await this.runner.readContract({ - functionName: 'VERSION', - abi: this.contractAbi, - address: asAddress(this.contractAddress) - }) - ] + return [await this.read('VERSION')] } /** @@ -78,14 +74,7 @@ class SafeContract_v1_3_0 * @returns Array[approvedHashes] */ approvedHashes: SafeContract_v1_3_0_Function<'approvedHashes'> = async (args) => { - return [ - await this.runner.readContract({ - functionName: 'approvedHashes', - abi: this.contractAbi, - address: asAddress(this.contractAddress), - args - }) - ] + return [await this.read('approvedHashes', args)] } /** @@ -95,12 +84,7 @@ class SafeContract_v1_3_0 * @returns Empty array */ checkNSignatures: SafeContract_v1_3_0_Function<'checkNSignatures'> = async (args) => { - await this.runner.readContract({ - functionName: 'checkNSignatures', - abi: this.contractAbi, - address: asAddress(this.contractAddress), - args - }) + await this.read('checkNSignatures', args) return [] } @@ -110,12 +94,7 @@ class SafeContract_v1_3_0 * @returns Empty array */ checkSignatures: SafeContract_v1_3_0_Function<'checkSignatures'> = async (args) => { - await this.runner.readContract({ - functionName: 'checkSignatures', - abi: this.contractAbi, - address: asAddress(this.contractAddress), - args - }) + await this.read('checkSignatures', args) return [] } @@ -123,13 +102,7 @@ class SafeContract_v1_3_0 * @returns Array[domainSeparator] */ domainSeparator: SafeContract_v1_3_0_Function<'domainSeparator'> = async () => { - return [ - await this.runner.readContract({ - functionName: 'domainSeparator', - abi: this.contractAbi, - address: asAddress(this.contractAddress) - }) - ] + return [await this.read('domainSeparator')] } /** @@ -138,14 +111,7 @@ class SafeContract_v1_3_0 * @returns Array[encodedData] */ encodeTransactionData: SafeContract_v1_3_0_Function<'encodeTransactionData'> = async (args) => { - return [ - await this.runner.readContract({ - functionName: 'encodeTransactionData', - abi: this.contractAbi, - address: asAddress(this.contractAddress), - args - }) - ] + return [await this.read('encodeTransactionData', args)] } /** @@ -154,12 +120,7 @@ class SafeContract_v1_3_0 * @returns Array[Array[modules], next] */ getModulesPaginated: SafeContract_v1_3_0_Function<'getModulesPaginated'> = async (args) => { - const [array, next] = await this.runner.readContract({ - functionName: 'getModulesPaginated', - abi: this.contractAbi, - address: asAddress(this.contractAddress), - args - }) + const [array, next] = await this.read('getModulesPaginated', args) return [array, next] } @@ -168,13 +129,7 @@ class SafeContract_v1_3_0 * @returns Array[Array[owners]] */ getOwners: SafeContract_v1_3_0_Function<'getOwners'> = async () => { - return [ - await this.runner.readContract({ - functionName: 'getOwners', - abi: this.contractAbi, - address: asAddress(this.contractAddress) - }) - ] + return [await this.read('getOwners')] } /** @@ -183,14 +138,7 @@ class SafeContract_v1_3_0 * @returns Array[storage] */ getStorageAt: SafeContract_v1_3_0_Function<'getStorageAt'> = async (args) => { - return [ - await this.runner.readContract({ - functionName: 'getStorageAt', - abi: this.contractAbi, - address: asAddress(this.contractAddress), - args - }) - ] + return [await this.read('getStorageAt', args)] } /** @@ -198,13 +146,7 @@ class SafeContract_v1_3_0 * @returns Array[threshold] */ getThreshold: SafeContract_v1_3_0_Function<'getThreshold'> = async () => { - return [ - await this.runner.readContract({ - functionName: 'getThreshold', - abi: this.contractAbi, - address: asAddress(this.contractAddress) - }) - ] + return [await this.read('getThreshold')] } /** @@ -213,14 +155,7 @@ class SafeContract_v1_3_0 * @returns Array[transactionHash] */ getTransactionHash: SafeContract_v1_3_0_Function<'getTransactionHash'> = async (args) => { - return [ - await this.runner.readContract({ - functionName: 'getTransactionHash', - abi: this.contractAbi, - address: asAddress(this.contractAddress), - args - }) - ] + return [await this.read('getTransactionHash', args)] } /** @@ -229,14 +164,7 @@ class SafeContract_v1_3_0 * @returns Array[isEnabled] */ isModuleEnabled: SafeContract_v1_3_0_Function<'isModuleEnabled'> = async (args) => { - return [ - await this.runner.readContract({ - functionName: 'isModuleEnabled', - abi: this.contractAbi, - address: asAddress(this.contractAddress), - args - }) - ] + return [await this.read('isModuleEnabled', args)] } /** @@ -245,14 +173,7 @@ class SafeContract_v1_3_0 * @returns Array[isOwner] */ isOwner: SafeContract_v1_3_0_Function<'isOwner'> = async (args) => { - return [ - await this.runner.readContract({ - functionName: 'isOwner', - abi: this.contractAbi, - address: asAddress(this.contractAddress), - args - }) - ] + return [await this.read('isOwner', args)] } /** @@ -260,13 +181,7 @@ class SafeContract_v1_3_0 * @returns Array[nonce] */ nonce: SafeContract_v1_3_0_Function<'nonce'> = async () => { - return [ - await this.runner.readContract({ - functionName: 'nonce', - abi: this.contractAbi, - address: asAddress(this.contractAddress) - }) - ] + return [await this.read('nonce')] } /** @@ -274,14 +189,7 @@ class SafeContract_v1_3_0 * @returns Array[signedMessages] */ signedMessages: SafeContract_v1_3_0_Function<'signedMessages'> = async (args) => { - return [ - await this.runner.readContract({ - functionName: 'signedMessages', - abi: this.contractAbi, - address: asAddress(this.contractAddress), - args - }) - ] + return [await this.read('signedMessages', args)] } /** @@ -312,7 +220,7 @@ class SafeContract_v1_3_0 )) const converted = await this.convertOptions({ ...options, gasLimit }) - const txResult = await this.runner.simulateContract({ + const txResult = await simulateContract(this.runner, { address: asAddress(this.contractAddress), functionName: 'execTransaction', abi: this.contractAbi, @@ -366,23 +274,24 @@ class SafeContract_v1_3_0 options )) - const txResponse = await this.contract.write.execTransaction( - [ - asAddress(safeTransaction.data.to), - BigInt(safeTransaction.data.value), - asHex(safeTransaction.data.data), - safeTransaction.data.operation, - BigInt(safeTransaction.data.safeTxGas), - BigInt(safeTransaction.data.baseGas), - BigInt(safeTransaction.data.gasPrice), - asAddress(safeTransaction.data.gasToken), - asAddress(safeTransaction.data.refundReceiver), - asHex(safeTransaction.encodedSignatures()) - ], - await this.convertOptions({ ...options, gasLimit }) - ) + const args: ContractFunctionArgs = [ + asAddress(safeTransaction.data.to), + BigInt(safeTransaction.data.value), + asHex(safeTransaction.data.data), + safeTransaction.data.operation, + BigInt(safeTransaction.data.safeTxGas), + BigInt(safeTransaction.data.baseGas), + BigInt(safeTransaction.data.gasPrice), + asAddress(safeTransaction.data.gasToken), + asAddress(safeTransaction.data.refundReceiver), + asHex(safeTransaction.encodedSignatures()) + ] - return toTxResult(this.runner!, txResponse, options) + return toTxResult( + this.runner!, + await this.write('execTransaction', args, { ...options, gasLimit }), + options + ) } /** @@ -403,12 +312,12 @@ class SafeContract_v1_3_0 async approveHash(hash: string, options?: TransactionOptions): Promise { const gasLimit = options?.gasLimit || (await this.estimateGas('approveHash', [asHash(hash)], options)) - const txResponse = await this.contract.write.approveHash( - [asHash(hash)], - await this.convertOptions({ ...options, gasLimit }) - ) - return toTxResult(this.runner!, txResponse, options) + return toTxResult( + this.runner!, + await this.write('approveHash', [asHash(hash)], { ...options, gasLimit }), + options + ) } /** @@ -416,13 +325,7 @@ class SafeContract_v1_3_0 * @returns Array[chainId] */ async getChainId(): Promise<[bigint]> { - return [ - await this.runner.readContract({ - functionName: 'getChainId', - abi: this.contractAbi, - address: asAddress(this.contractAddress) - }) - ] + return [await this.read('getChainId')] } /** diff --git a/packages/protocol-kit/src/contracts/Safe/v1.4.1/SafeContract_v1_4_1.ts b/packages/protocol-kit/src/contracts/Safe/v1.4.1/SafeContract_v1_4_1.ts index 3f596378f..55e8555b8 100644 --- a/packages/protocol-kit/src/contracts/Safe/v1.4.1/SafeContract_v1_4_1.ts +++ b/packages/protocol-kit/src/contracts/Safe/v1.4.1/SafeContract_v1_4_1.ts @@ -1,3 +1,4 @@ +import { simulateContract } from 'viem/actions' import SafeBaseContract from '@safe-global/protocol-kit/contracts/Safe/SafeBaseContract' import SafeProvider from '@safe-global/protocol-kit/SafeProvider' import { toTxResult } from '@safe-global/protocol-kit/contracts/utils' @@ -13,6 +14,7 @@ import { TransactionResult } from '@safe-global/safe-core-sdk-types' import { asHash, asHex, asAddress } from '@safe-global/protocol-kit/utils/types' +import { ContractFunctionArgs } from 'viem' /** * SafeContract_v1_4_1 is the implementation specific to the Safe contract version 1.4.1. @@ -64,13 +66,7 @@ class SafeContract_v1_4_1 * @returns Array[safeContractVersion] */ VERSION: SafeContract_v1_4_1_Function<'VERSION'> = async () => { - return [ - await this.runner.readContract({ - functionName: 'VERSION', - abi: this.contractAbi, - address: asAddress(this.contractAddress) - }) - ] + return [await this.read('VERSION')] } /** @@ -78,14 +74,7 @@ class SafeContract_v1_4_1 * @returns Array[approvedHashes] */ approvedHashes: SafeContract_v1_4_1_Function<'approvedHashes'> = async (args) => { - return [ - await this.runner.readContract({ - functionName: 'approvedHashes', - abi: this.contractAbi, - address: asAddress(this.contractAddress), - args - }) - ] + return [await this.read('approvedHashes', args)] } /** @@ -95,12 +84,7 @@ class SafeContract_v1_4_1 * @returns Empty array */ checkNSignatures: SafeContract_v1_4_1_Function<'checkNSignatures'> = async (args) => { - await this.runner.readContract({ - functionName: 'checkNSignatures', - abi: this.contractAbi, - address: asAddress(this.contractAddress), - args - }) + await this.read('checkNSignatures', args) return [] } @@ -110,12 +94,7 @@ class SafeContract_v1_4_1 * @returns Empty array */ checkSignatures: SafeContract_v1_4_1_Function<'checkSignatures'> = async (args) => { - await this.runner.readContract({ - functionName: 'checkSignatures', - abi: this.contractAbi, - address: asAddress(this.contractAddress), - args - }) + await this.read('checkSignatures', args) return [] } @@ -123,13 +102,7 @@ class SafeContract_v1_4_1 * @returns Array[domainSeparator] */ domainSeparator: SafeContract_v1_4_1_Function<'domainSeparator'> = async () => { - return [ - await this.runner.readContract({ - functionName: 'domainSeparator', - abi: this.contractAbi, - address: asAddress(this.contractAddress) - }) - ] + return [await this.read('domainSeparator')] } /** @@ -138,14 +111,7 @@ class SafeContract_v1_4_1 * @returns Array[encodedData] */ encodeTransactionData: SafeContract_v1_4_1_Function<'encodeTransactionData'> = async (args) => { - return [ - await this.runner.readContract({ - functionName: 'encodeTransactionData', - abi: this.contractAbi, - address: asAddress(this.contractAddress), - args - }) - ] + return [await this.read('encodeTransactionData', args)] } /** @@ -154,12 +120,7 @@ class SafeContract_v1_4_1 * @returns Array[Array[modules], next] */ getModulesPaginated: SafeContract_v1_4_1_Function<'getModulesPaginated'> = async (args) => { - const [array, next] = await this.runner.readContract({ - functionName: 'getModulesPaginated', - abi: this.contractAbi, - address: asAddress(this.contractAddress), - args - }) + const [array, next] = await this.read('getModulesPaginated', args) return [array, next] } @@ -168,13 +129,7 @@ class SafeContract_v1_4_1 * @returns Array[Array[owners]] */ getOwners: SafeContract_v1_4_1_Function<'getOwners'> = async () => { - return [ - await this.runner.readContract({ - functionName: 'getOwners', - abi: this.contractAbi, - address: asAddress(this.contractAddress) - }) - ] + return [await this.read('getOwners')] } /** @@ -183,14 +138,7 @@ class SafeContract_v1_4_1 * @returns Array[storage] */ getStorageAt: SafeContract_v1_4_1_Function<'getStorageAt'> = async (args) => { - return [ - await this.runner.readContract({ - functionName: 'getStorageAt', - abi: this.contractAbi, - address: asAddress(this.contractAddress), - args - }) - ] + return [await this.read('getStorageAt', args)] } /** @@ -198,13 +146,7 @@ class SafeContract_v1_4_1 * @returns Array[threshold] */ getThreshold: SafeContract_v1_4_1_Function<'getThreshold'> = async () => { - return [ - await this.runner.readContract({ - functionName: 'getThreshold', - abi: this.contractAbi, - address: asAddress(this.contractAddress) - }) - ] + return [await this.read('getThreshold')] } /** @@ -213,14 +155,7 @@ class SafeContract_v1_4_1 * @returns Array[transactionHash] */ getTransactionHash: SafeContract_v1_4_1_Function<'getTransactionHash'> = async (args) => { - return [ - await this.runner.readContract({ - functionName: 'getTransactionHash', - abi: this.contractAbi, - address: asAddress(this.contractAddress), - args - }) - ] + return [await this.read('getTransactionHash', args)] } /** @@ -229,14 +164,7 @@ class SafeContract_v1_4_1 * @returns Array[isEnabled] */ isModuleEnabled: SafeContract_v1_4_1_Function<'isModuleEnabled'> = async (args) => { - return [ - await this.runner.readContract({ - functionName: 'isModuleEnabled', - abi: this.contractAbi, - address: asAddress(this.contractAddress), - args - }) - ] + return [await this.read('isModuleEnabled', args)] } /** @@ -245,14 +173,7 @@ class SafeContract_v1_4_1 * @returns Array[isOwner] */ isOwner: SafeContract_v1_4_1_Function<'isOwner'> = async (args) => { - return [ - await this.runner.readContract({ - functionName: 'isOwner', - abi: this.contractAbi, - address: asAddress(this.contractAddress), - args - }) - ] + return [await this.read('isOwner', args)] } /** @@ -260,13 +181,7 @@ class SafeContract_v1_4_1 * @returns Array[nonce] */ nonce: SafeContract_v1_4_1_Function<'nonce'> = async () => { - return [ - await this.runner.readContract({ - functionName: 'nonce', - abi: this.contractAbi, - address: asAddress(this.contractAddress) - }) - ] + return [await this.read('nonce')] } /** @@ -274,14 +189,7 @@ class SafeContract_v1_4_1 * @returns Array[signedMessages] */ signedMessages: SafeContract_v1_4_1_Function<'signedMessages'> = async (args) => { - return [ - await this.runner.readContract({ - functionName: 'signedMessages', - abi: this.contractAbi, - address: asAddress(this.contractAddress), - args - }) - ] + return [await this.read('signedMessages', args)] } /** @@ -312,7 +220,7 @@ class SafeContract_v1_4_1 )) const converted = await this.convertOptions({ ...options, gasLimit }) - const txResult = await this.runner.simulateContract({ + const txResult = await simulateContract(this.runner, { address: asAddress(this.contractAddress), functionName: 'execTransaction', abi: this.contractAbi, @@ -366,23 +274,24 @@ class SafeContract_v1_4_1 options )) - const txResponse = await this.contract.write.execTransaction( - [ - asAddress(safeTransaction.data.to), - BigInt(safeTransaction.data.value), - asHex(safeTransaction.data.data), - safeTransaction.data.operation, - BigInt(safeTransaction.data.safeTxGas), - BigInt(safeTransaction.data.baseGas), - BigInt(safeTransaction.data.gasPrice), - asAddress(safeTransaction.data.gasToken), - asAddress(safeTransaction.data.refundReceiver), - asHex(safeTransaction.encodedSignatures()) - ], - await this.convertOptions({ ...options, gasLimit }) - ) + const args: ContractFunctionArgs = [ + asAddress(safeTransaction.data.to), + BigInt(safeTransaction.data.value), + asHex(safeTransaction.data.data), + safeTransaction.data.operation, + BigInt(safeTransaction.data.safeTxGas), + BigInt(safeTransaction.data.baseGas), + BigInt(safeTransaction.data.gasPrice), + asAddress(safeTransaction.data.gasToken), + asAddress(safeTransaction.data.refundReceiver), + asHex(safeTransaction.encodedSignatures()) + ] - return toTxResult(this.runner!, txResponse, options) + return toTxResult( + this.runner!, + await this.write('execTransaction', args, { ...options, gasLimit }), + options + ) } /** @@ -403,12 +312,12 @@ class SafeContract_v1_4_1 async approveHash(hash: string, options?: TransactionOptions): Promise { const gasLimit = options?.gasLimit || (await this.estimateGas('approveHash', [asHash(hash)], options)) - const txResponse = await this.contract.write.approveHash( - [asHash(hash)], - await this.convertOptions({ ...options, gasLimit }) - ) - return toTxResult(this.runner!, txResponse, options) + return toTxResult( + this.runner!, + await this.write('approveHash', [asHash(hash)], { ...options, gasLimit }), + options + ) } /** @@ -416,13 +325,7 @@ class SafeContract_v1_4_1 * @returns Array[chainId] */ async getChainId(): Promise<[bigint]> { - return [ - await this.runner.readContract({ - functionName: 'getChainId', - abi: this.contractAbi, - address: asAddress(this.contractAddress) - }) - ] + return [await this.read('getChainId')] } /** diff --git a/packages/protocol-kit/src/contracts/SafeProxyFactory/SafeProxyFactoryBaseContract.ts b/packages/protocol-kit/src/contracts/SafeProxyFactory/SafeProxyFactoryBaseContract.ts index 1c7416a7a..ddd29ff4d 100644 --- a/packages/protocol-kit/src/contracts/SafeProxyFactory/SafeProxyFactoryBaseContract.ts +++ b/packages/protocol-kit/src/contracts/SafeProxyFactory/SafeProxyFactoryBaseContract.ts @@ -1,5 +1,4 @@ import { Abi } from 'abitype' -import { PublicClient } from 'viem' import SafeProvider from '@safe-global/protocol-kit/SafeProvider' import BaseContract from '@safe-global/protocol-kit/contracts/BaseContract' import { @@ -8,6 +7,7 @@ import { CreateProxyProps as CreateProxyPropsGeneral } from '@safe-global/safe-core-sdk-types' import { contractName } from '@safe-global/protocol-kit/contracts/config' +import { ExternalClient } from '@safe-global/protocol-kit/types' export interface CreateProxyProps extends CreateProxyPropsGeneral { options?: TransactionOptions @@ -52,7 +52,7 @@ abstract class SafeProxyFactoryBaseContract< safeVersion: SafeVersion, customContractAddress?: string, customContractAbi?: SafeProxyFactoryContractAbiType, - runner?: PublicClient + runner?: ExternalClient ) { const contractName = 'safeProxyFactoryVersion' diff --git a/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.0.0/SafeProxyFactoryContract_v1_0_0.ts b/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.0.0/SafeProxyFactoryContract_v1_0_0.ts index c8dd82983..250f2619a 100644 --- a/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.0.0/SafeProxyFactoryContract_v1_0_0.ts +++ b/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.0.0/SafeProxyFactoryContract_v1_0_0.ts @@ -1,4 +1,4 @@ -import { PublicClient, parseEventLogs } from 'viem' +import { parseEventLogs } from 'viem' import SafeProxyFactoryBaseContract, { CreateProxyProps } from '@safe-global/protocol-kit/contracts/SafeProxyFactory/SafeProxyFactoryBaseContract' @@ -12,6 +12,7 @@ import { } from '@safe-global/safe-core-sdk-types' import { waitForTransactionReceipt } from '@safe-global/protocol-kit/utils' import { asAddress, asHex } from '@safe-global/protocol-kit/utils/types' +import { ExternalClient } from '@safe-global/protocol-kit/types' /** * SafeProxyFactoryContract_v1_0_0 is the implementation specific to the Safe Proxy Factory contract version 1.0.0. @@ -40,7 +41,7 @@ class SafeProxyFactoryContract_v1_0_0 safeProvider: SafeProvider, customContractAddress?: string, customContractAbi?: SafeProxyFactoryContract_v1_0_0_Abi, - runner?: PublicClient + runner?: ExternalClient ) { const safeVersion = '1.0.0' const defaultAbi = safeProxyFactory_1_0_0_ContractArtifacts.abi @@ -63,13 +64,7 @@ class SafeProxyFactoryContract_v1_0_0 * @returns Array[creationCode] */ proxyCreationCode: SafeProxyFactoryContract_v1_0_0_Function<'proxyCreationCode'> = async () => { - return [ - await this.runner.readContract({ - functionName: 'proxyCreationCode', - abi: this.contractAbi, - address: asAddress(this.contractAddress) - }) - ] + return [await this.read('proxyCreationCode')] } /** @@ -77,13 +72,7 @@ class SafeProxyFactoryContract_v1_0_0 * @returns Array[runtimeCode] */ proxyRuntimeCode: SafeProxyFactoryContract_v1_0_0_Function<'proxyRuntimeCode'> = async () => { - return [ - await this.runner.readContract({ - functionName: 'proxyRuntimeCode', - abi: this.contractAbi, - address: asAddress(this.contractAddress) - }) - ] + return [await this.read('proxyRuntimeCode')] } /** @@ -92,7 +81,7 @@ class SafeProxyFactoryContract_v1_0_0 * @returns Array[proxyAddress] */ createProxy: SafeProxyFactoryContract_v1_0_0_Function<'createProxy'> = async (args) => { - return [await this.contract.write.createProxy(args, await this.convertOptions({}))] + return [await this.write('createProxy', args)] } /** @@ -103,7 +92,7 @@ class SafeProxyFactoryContract_v1_0_0 createProxyWithNonce: SafeProxyFactoryContract_v1_0_0_Function<'createProxyWithNonce'> = async ( args ) => { - return [await this.contract.write.createProxyWithNonce(args, await this.convertOptions({}))] + return [await this.write('createProxyWithNonce', args)] } /** @@ -132,16 +121,20 @@ class SafeProxyFactoryContract_v1_0_0 ).toString() } - const proxyAddress = await this.contract.write - .createProxyWithNonce( - [asAddress(safeSingletonAddress), asHex(initializer), saltNonceBigInt], - await this.convertOptions(options) - ) + const coverted = await this.convertOptions(options) + const proxyAddress = await this.getWallet() + .writeContract({ + address: asAddress(this.contractAddress), + abi: this.contractAbi, + functionName: 'createProxyWithNonce', + args: [asAddress(safeSingletonAddress), asHex(initializer), saltNonceBigInt], + ...coverted + }) .then(async (hash) => { if (callback) { callback(hash) } - const { logs } = await waitForTransactionReceipt(this.runner!, hash) + const { logs } = await waitForTransactionReceipt(this.runner, hash) const events = parseEventLogs({ logs, abi: this.contractAbi }) const proxyCreationEvent = events.find((event) => event?.eventName === 'ProxyCreation') if (!proxyCreationEvent || !proxyCreationEvent.args) { diff --git a/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.1.1/SafeProxyFactoryContract_v1_1_1.ts b/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.1.1/SafeProxyFactoryContract_v1_1_1.ts index 19d02c0d1..dddec5875 100644 --- a/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.1.1/SafeProxyFactoryContract_v1_1_1.ts +++ b/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.1.1/SafeProxyFactoryContract_v1_1_1.ts @@ -1,4 +1,4 @@ -import { parseEventLogs, PublicClient } from 'viem' +import { parseEventLogs } from 'viem' import SafeProxyFactoryBaseContract, { CreateProxyProps } from '@safe-global/protocol-kit/contracts/SafeProxyFactory/SafeProxyFactoryBaseContract' @@ -12,6 +12,7 @@ import { } from '@safe-global/safe-core-sdk-types' import { waitForTransactionReceipt } from '@safe-global/protocol-kit/utils' import { asHex, asAddress } from '@safe-global/protocol-kit/utils/types' +import { ExternalClient } from '@safe-global/protocol-kit/types' /** * SafeProxyFactoryContract_v1_1_1 is the implementation specific to the Safe Proxy Factory contract version 1.1.1. @@ -40,7 +41,7 @@ class SafeProxyFactoryContract_v1_1_1 safeProvider: SafeProvider, customContractAddress?: string, customContractAbi?: SafeProxyFactoryContract_v1_1_1_Abi, - runner?: PublicClient + runner?: ExternalClient ) { const safeVersion = '1.1.1' const defaultAbi = safeProxyFactory_1_1_1_ContractArtifacts.abi @@ -63,13 +64,7 @@ class SafeProxyFactoryContract_v1_1_1 * @returns Array[creationCode] */ proxyCreationCode: SafeProxyFactoryContract_v1_1_1_Function<'proxyCreationCode'> = async () => { - return [ - await this.runner.readContract({ - functionName: 'proxyCreationCode', - abi: this.contractAbi, - address: asAddress(this.contractAddress) - }) - ] + return [await this.read('proxyCreationCode')] } /** @@ -77,13 +72,7 @@ class SafeProxyFactoryContract_v1_1_1 * @returns Array[runtimeCode] */ proxyRuntimeCode: SafeProxyFactoryContract_v1_1_1_Function<'proxyRuntimeCode'> = async () => { - return [ - await this.runner.readContract({ - functionName: 'proxyRuntimeCode', - abi: this.contractAbi, - address: asAddress(this.contractAddress) - }) - ] + return [await this.read('proxyRuntimeCode')] } /** @@ -93,12 +82,7 @@ class SafeProxyFactoryContract_v1_1_1 */ calculateCreateProxyWithNonceAddress: SafeProxyFactoryContract_v1_1_1_Function<'calculateCreateProxyWithNonceAddress'> = async (args) => { - return [ - await this.contract.write.calculateCreateProxyWithNonceAddress( - args, - await this.convertOptions({}) - ) - ] + return [await this.write('calculateCreateProxyWithNonceAddress', args)] } /** @@ -107,7 +91,7 @@ class SafeProxyFactoryContract_v1_1_1 * @returns Array[proxyAddress] */ createProxy: SafeProxyFactoryContract_v1_1_1_Function<'createProxy'> = async (args) => { - return [await this.contract.write.createProxy(args, await this.convertOptions({}))] + return [await this.write('createProxy', args)] } /** @@ -117,9 +101,7 @@ class SafeProxyFactoryContract_v1_1_1 */ createProxyWithCallback: SafeProxyFactoryContract_v1_1_1_Function<'createProxyWithCallback'> = async (args) => { - return [ - await this.contract.write.createProxyWithCallback(args, await this.convertOptions({})) - ] + return [await this.write('createProxyWithCallback', args)] } /** @@ -130,7 +112,7 @@ class SafeProxyFactoryContract_v1_1_1 createProxyWithNonce: SafeProxyFactoryContract_v1_1_1_Function<'createProxyWithNonce'> = async ( args ) => { - return [await this.contract.write.createProxyWithNonce(args, await this.convertOptions({}))] + return [await this.write('createProxyWithNonce', args)] } /** @@ -159,16 +141,20 @@ class SafeProxyFactoryContract_v1_1_1 ).toString() } - const proxyAddress = this.contract.write - .createProxyWithNonce( - [asAddress(safeSingletonAddress), asHex(initializer), saltNonceBigInt], - await this.convertOptions(options) - ) + const coverted = await this.convertOptions(options) + const proxyAddress = await this.getWallet() + .writeContract({ + address: asAddress(this.contractAddress), + abi: this.contractAbi, + functionName: 'createProxyWithNonce', + args: [asAddress(safeSingletonAddress), asHex(initializer), saltNonceBigInt], + ...coverted + }) .then(async (hash) => { if (callback) { callback(hash) } - const { logs } = await waitForTransactionReceipt(this.runner!, hash) + const { logs } = await waitForTransactionReceipt(this.runner, hash) const events = parseEventLogs({ logs, abi: this.contractAbi }) const proxyCreationEvent = events.find((event) => event?.eventName === 'ProxyCreation') if (!proxyCreationEvent || !proxyCreationEvent.args) { diff --git a/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.3.0/SafeProxyFactoryContract_v1_3_0.ts b/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.3.0/SafeProxyFactoryContract_v1_3_0.ts index 78aee1bfa..ec608aac6 100644 --- a/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.3.0/SafeProxyFactoryContract_v1_3_0.ts +++ b/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.3.0/SafeProxyFactoryContract_v1_3_0.ts @@ -1,4 +1,4 @@ -import { parseEventLogs, PublicClient } from 'viem' +import { parseEventLogs } from 'viem' import SafeProxyFactoryBaseContract, { CreateProxyProps } from '@safe-global/protocol-kit/contracts/SafeProxyFactory/SafeProxyFactoryBaseContract' @@ -12,6 +12,7 @@ import { } from '@safe-global/safe-core-sdk-types' import { waitForTransactionReceipt } from '@safe-global/protocol-kit/utils' import { asAddress, asHex } from '@safe-global/protocol-kit/utils/types' +import { ExternalClient } from '@safe-global/protocol-kit/types' /** * SafeProxyFactoryContract_v1_3_0 is the implementation specific to the Safe Proxy Factory contract version 1.3.0. @@ -40,7 +41,7 @@ class SafeProxyFactoryContract_v1_3_0 safeProvider: SafeProvider, customContractAddress?: string, customContractAbi?: SafeProxyFactoryContract_v1_3_0_Abi, - runner?: PublicClient + runner?: ExternalClient ) { const safeVersion = '1.3.0' const defaultAbi = safeProxyFactory_1_3_0_ContractArtifacts.abi @@ -63,13 +64,7 @@ class SafeProxyFactoryContract_v1_3_0 * @returns Array[creationCode] */ proxyCreationCode: SafeProxyFactoryContract_v1_3_0_Function<'proxyCreationCode'> = async () => { - return [ - await this.runner.readContract({ - functionName: 'proxyCreationCode', - abi: this.contractAbi, - address: asAddress(this.contractAddress) - }) - ] + return [await this.read('proxyCreationCode')] } /** @@ -77,13 +72,7 @@ class SafeProxyFactoryContract_v1_3_0 * @returns Array[runtimeCode] */ proxyRuntimeCode: SafeProxyFactoryContract_v1_3_0_Function<'proxyRuntimeCode'> = async () => { - return [ - await this.runner.readContract({ - functionName: 'proxyRuntimeCode', - abi: this.contractAbi, - address: asAddress(this.contractAddress) - }) - ] + return [await this.read('proxyRuntimeCode')] } /** @@ -93,12 +82,7 @@ class SafeProxyFactoryContract_v1_3_0 */ calculateCreateProxyWithNonceAddress: SafeProxyFactoryContract_v1_3_0_Function<'calculateCreateProxyWithNonceAddress'> = async (args) => { - return [ - await this.contract.write.calculateCreateProxyWithNonceAddress( - args, - await this.convertOptions({}) - ) - ] + return [await this.write('calculateCreateProxyWithNonceAddress', args)] } /** @@ -107,7 +91,7 @@ class SafeProxyFactoryContract_v1_3_0 * @returns Array[proxyAddress] */ createProxy: SafeProxyFactoryContract_v1_3_0_Function<'createProxy'> = async (args) => { - return [await this.contract.write.createProxy(args, await this.convertOptions({}))] + return [await this.write('createProxy', args)] } /** @@ -117,9 +101,7 @@ class SafeProxyFactoryContract_v1_3_0 */ createProxyWithCallback: SafeProxyFactoryContract_v1_3_0_Function<'createProxyWithCallback'> = async (args) => { - return [ - await this.contract.write.createProxyWithCallback(args, await this.convertOptions({})) - ] + return [await this.write('createProxyWithCallback', args)] } /** @@ -130,7 +112,7 @@ class SafeProxyFactoryContract_v1_3_0 createProxyWithNonce: SafeProxyFactoryContract_v1_3_0_Function<'createProxyWithNonce'> = async ( args ) => { - return [await this.contract.write.createProxyWithNonce(args, await this.convertOptions({}))] + return [await this.write('createProxyWithNonce', args)] } /** @@ -159,16 +141,20 @@ class SafeProxyFactoryContract_v1_3_0 ).toString() } - const proxyAddress = this.contract.write - .createProxyWithNonce( - [asAddress(safeSingletonAddress), asHex(initializer), saltNonceBigInt], - await this.convertOptions(options) - ) + const coverted = await this.convertOptions(options) + const proxyAddress = await this.getWallet() + .writeContract({ + address: asAddress(this.contractAddress), + abi: this.contractAbi, + functionName: 'createProxyWithNonce', + args: [asAddress(safeSingletonAddress), asHex(initializer), saltNonceBigInt], + ...coverted + }) .then(async (hash) => { if (callback) { callback(hash) } - const { logs } = await waitForTransactionReceipt(this.runner!, hash) + const { logs } = await waitForTransactionReceipt(this.runner, hash) const events = parseEventLogs({ logs, abi: this.contractAbi }) const proxyCreationEvent = events.find((event) => event?.eventName === 'ProxyCreation') if (!proxyCreationEvent || !proxyCreationEvent.args) { diff --git a/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.4.1/SafeProxyFactoryContract_v1_4_1.ts b/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.4.1/SafeProxyFactoryContract_v1_4_1.ts index c1238c540..48560f73b 100644 --- a/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.4.1/SafeProxyFactoryContract_v1_4_1.ts +++ b/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.4.1/SafeProxyFactoryContract_v1_4_1.ts @@ -1,4 +1,4 @@ -import { parseEventLogs, PublicClient } from 'viem' +import { parseEventLogs } from 'viem' import SafeProxyFactoryBaseContract, { CreateProxyProps } from '@safe-global/protocol-kit/contracts/SafeProxyFactory/SafeProxyFactoryBaseContract' @@ -12,6 +12,7 @@ import { import SafeProvider from '@safe-global/protocol-kit/SafeProvider' import { waitForTransactionReceipt } from '@safe-global/protocol-kit/utils' import { asAddress, asHex } from '@safe-global/protocol-kit/utils/types' +import { ExternalClient } from '@safe-global/protocol-kit/types' /** * SafeProxyFactoryContract_v1_4_1 is the implementation specific to the Safe Proxy Factory contract version 1.4.1. @@ -40,7 +41,7 @@ class SafeProxyFactoryContract_v1_4_1 safeProvider: SafeProvider, customContractAddress?: string, customContractAbi?: SafeProxyFactoryContract_v1_4_1_Abi, - runner?: PublicClient + runner?: ExternalClient ) { const safeVersion = '1.4.1' const defaultAbi = safeProxyFactory_1_4_1_ContractArtifacts.abi @@ -63,13 +64,7 @@ class SafeProxyFactoryContract_v1_4_1 * @returns Array[chainId] */ getChainId: SafeProxyFactoryContract_v1_4_1_Function<'getChainId'> = async () => { - return [ - await this.runner.readContract({ - functionName: 'getChainId', - abi: this.contractAbi, - address: asAddress(this.contractAddress) - }) - ] + return [await this.read('getChainId')] } /** @@ -77,13 +72,7 @@ class SafeProxyFactoryContract_v1_4_1 * @returns Array[creationCode] */ proxyCreationCode: SafeProxyFactoryContract_v1_4_1_Function<'proxyCreationCode'> = async () => { - return [ - await this.runner.readContract({ - functionName: 'proxyCreationCode', - abi: this.contractAbi, - address: asAddress(this.contractAddress) - }) - ] + return [await this.read('proxyCreationCode')] } /** @@ -93,12 +82,7 @@ class SafeProxyFactoryContract_v1_4_1 */ createChainSpecificProxyWithNonce: SafeProxyFactoryContract_v1_4_1_Function<'createChainSpecificProxyWithNonce'> = async (args) => { - return [ - await this.contract.write.createChainSpecificProxyWithNonce( - args, - await this.convertOptions({}) - ) - ] + return [await this.write('createChainSpecificProxyWithNonce', args)] } /** @@ -109,9 +93,7 @@ class SafeProxyFactoryContract_v1_4_1 */ createProxyWithCallback: SafeProxyFactoryContract_v1_4_1_Function<'createProxyWithCallback'> = async (args) => { - return [ - await this.contract.write.createProxyWithCallback(args, await this.convertOptions({})) - ] + return [await this.write('createProxyWithCallback', args)] } /** @@ -122,7 +104,7 @@ class SafeProxyFactoryContract_v1_4_1 createProxyWithNonce: SafeProxyFactoryContract_v1_4_1_Function<'createProxyWithNonce'> = async ( args ) => { - return [await this.contract.write.createProxyWithNonce(args, await this.convertOptions({}))] + return [await this.write('createProxyWithNonce', args)] } /** @@ -151,16 +133,20 @@ class SafeProxyFactoryContract_v1_4_1 ).toString() } - const proxyAddress = this.contract.write - .createProxyWithNonce( - [asAddress(safeSingletonAddress), asHex(initializer), saltNonceBigInt], - await this.convertOptions(options) - ) + const coverted = await this.convertOptions(options) + const proxyAddress = await this.getWallet() + .writeContract({ + address: asAddress(this.contractAddress), + abi: this.contractAbi, + functionName: 'createProxyWithNonce', + args: [asAddress(safeSingletonAddress), asHex(initializer), saltNonceBigInt], + ...coverted + }) .then(async (hash) => { if (callback) { callback(hash) } - const { logs } = await waitForTransactionReceipt(this.runner!, hash) + const { logs } = await waitForTransactionReceipt(this.runner, hash) const events = parseEventLogs({ logs, abi: this.contractAbi }) const proxyCreationEvent = events.find((event) => event?.eventName === 'ProxyCreation') if (!proxyCreationEvent || !proxyCreationEvent.args) { diff --git a/packages/protocol-kit/src/contracts/SignMessageLib/v1.3.0/SignMessageLibContract_v1_3_0.ts b/packages/protocol-kit/src/contracts/SignMessageLib/v1.3.0/SignMessageLibContract_v1_3_0.ts index 8aa6b4125..dec0de630 100644 --- a/packages/protocol-kit/src/contracts/SignMessageLib/v1.3.0/SignMessageLibContract_v1_3_0.ts +++ b/packages/protocol-kit/src/contracts/SignMessageLib/v1.3.0/SignMessageLibContract_v1_3_0.ts @@ -9,7 +9,6 @@ import { SignMessageLibContract_v1_3_0_Function, signMessageLib_1_3_0_ContractArtifacts } from '@safe-global/safe-core-sdk-types' -import { asAddress } from '@safe-global/protocol-kit/utils/types' /** * SignMessageLibContract_v1_3_0 is the implementation specific to the SignMessageLib contract version 1.3.0. @@ -50,14 +49,7 @@ class SignMessageLibContract_v1_3_0 * @param args - Array[message] */ getMessageHash: SignMessageLibContract_v1_3_0_Function<'getMessageHash'> = async (args) => { - return [ - await this.runner.readContract({ - functionName: 'getMessageHash', - abi: this.contractAbi, - address: asAddress(this.contractAddress), - args - }) - ] + return [await this.read('getMessageHash', args)] } /** @@ -71,12 +63,7 @@ class SignMessageLibContract_v1_3_0 options.gasLimit = Number(await this.estimateGas('signMessage', data, { ...options })) } - const txResponse = await this.contract.write.signMessage( - data, - await this.convertOptions(options) - ) - - return toTxResult(this.runner!, txResponse, options) + return toTxResult(this.runner!, await this.write('signMessage', data, options), options) } } diff --git a/packages/protocol-kit/src/contracts/SignMessageLib/v1.4.1/SignMessageLibContract_v1_4_1.ts b/packages/protocol-kit/src/contracts/SignMessageLib/v1.4.1/SignMessageLibContract_v1_4_1.ts index f307bd858..01a85ebf7 100644 --- a/packages/protocol-kit/src/contracts/SignMessageLib/v1.4.1/SignMessageLibContract_v1_4_1.ts +++ b/packages/protocol-kit/src/contracts/SignMessageLib/v1.4.1/SignMessageLibContract_v1_4_1.ts @@ -9,7 +9,6 @@ import { SignMessageLibContract_v1_4_1_Function, signMessageLib_1_4_1_ContractArtifacts } from '@safe-global/safe-core-sdk-types' -import { asAddress } from '@safe-global/protocol-kit/utils/types' /** * SignMessageLibContract_v1_4_1 is the implementation specific to the SignMessageLib contract version 1.4.1. @@ -51,14 +50,7 @@ class SignMessageLibContract_v1_4_1 * @param args - Array[message] */ getMessageHash: SignMessageLibContract_v1_4_1_Function<'getMessageHash'> = async (args) => { - return [ - await this.runner.readContract({ - functionName: 'getMessageHash', - abi: this.contractAbi, - address: asAddress(this.contractAddress), - args - }) - ] + return [await this.read('getMessageHash', args)] } /** @@ -72,12 +64,7 @@ class SignMessageLibContract_v1_4_1 options.gasLimit = Number(await this.estimateGas('signMessage', data, { ...options })) } - const txResponse = await this.contract.write.signMessage( - data, - await this.convertOptions(options) - ) - - return toTxResult(this.runner!, txResponse, options) + return toTxResult(this.runner!, await this.write('signMessage', data, options), options) } } diff --git a/packages/protocol-kit/src/contracts/SimulateTxAccessor/v1.3.0/SimulateTxAccessorContract_v1_3_0.ts b/packages/protocol-kit/src/contracts/SimulateTxAccessor/v1.3.0/SimulateTxAccessorContract_v1_3_0.ts index 9f660d5bc..d4bc87412 100644 --- a/packages/protocol-kit/src/contracts/SimulateTxAccessor/v1.3.0/SimulateTxAccessorContract_v1_3_0.ts +++ b/packages/protocol-kit/src/contracts/SimulateTxAccessor/v1.3.0/SimulateTxAccessorContract_v1_3_0.ts @@ -51,10 +51,7 @@ class SimulateTxAccessorContract_v1_3_0 * @returns Array[estimate, success, returnData] */ simulate: SimulateTxAccessorContract_v1_3_0_Function<'simulate'> = async (args) => { - const [estimate, success, returnData] = await this.contract.write.simulate( - args, - await this.convertOptions({}) - ) + const [estimate, success, returnData] = await this.write('simulate', args) return [BigInt(estimate), !!success, asHex(returnData)] } } diff --git a/packages/protocol-kit/src/contracts/SimulateTxAccessor/v1.4.1/SimulateTxAccessorContract_v1_4_1.ts b/packages/protocol-kit/src/contracts/SimulateTxAccessor/v1.4.1/SimulateTxAccessorContract_v1_4_1.ts index 5936b2fb7..1786d3498 100644 --- a/packages/protocol-kit/src/contracts/SimulateTxAccessor/v1.4.1/SimulateTxAccessorContract_v1_4_1.ts +++ b/packages/protocol-kit/src/contracts/SimulateTxAccessor/v1.4.1/SimulateTxAccessorContract_v1_4_1.ts @@ -49,10 +49,7 @@ class SimulateTxAccessorContract_v1_4_1 * @returns Array[estimate, success, returnData] */ simulate: SimulateTxAccessorContract_v1_4_1_Function<'simulate'> = async (args) => { - const [estimate, success, returnData] = await this.contract.write.simulate( - args, - await this.convertOptions({}) - ) + const [estimate, success, returnData] = await this.write('simulate', args) return [BigInt(estimate), !!success, asHex(returnData)] } } diff --git a/packages/protocol-kit/src/contracts/contractInstances.ts b/packages/protocol-kit/src/contracts/contractInstances.ts index 3f5e09705..86412f518 100644 --- a/packages/protocol-kit/src/contracts/contractInstances.ts +++ b/packages/protocol-kit/src/contracts/contractInstances.ts @@ -1,4 +1,4 @@ -import { PublicClient, Abi } from 'viem' +import { Abi } from 'viem' import { SafeVersion, SafeContract_v1_3_0_Abi, @@ -47,6 +47,7 @@ import SimulateTxAccessorContract_v1_4_1 from './SimulateTxAccessor/v1.4.1/Simul import CompatibilityFallbackHandlerContract_v1_3_0 from './CompatibilityFallbackHandler/v1.3.0/CompatibilityFallbackHandlerContract_v1_3_0' import CompatibilityFallbackHandlerContract_v1_4_1 from './CompatibilityFallbackHandler/v1.4.1/CompatibilityFallbackHandlerContract_v1_4_1' import SafeProvider from '../SafeProvider' +import { ExternalClient } from '../types' export async function getSafeContractInstance( safeVersion: SafeVersion, @@ -245,7 +246,7 @@ export async function getSafeProxyFactoryContractInstance( safeVersion: SafeVersion, safeProvider: SafeProvider, // TODO: remove this ?? - signerOrProvider: PublicClient, + signerOrProvider: ExternalClient, contractAddress?: string, customContractAbi?: Abi ): Promise< diff --git a/packages/protocol-kit/src/contracts/utils.ts b/packages/protocol-kit/src/contracts/utils.ts index d1dfc2c09..eb475403a 100644 --- a/packages/protocol-kit/src/contracts/utils.ts +++ b/packages/protocol-kit/src/contracts/utils.ts @@ -5,10 +5,10 @@ import { isAddress, keccak256, pad, - PublicClient, toHex, WalletClient } from 'viem' +import { waitForTransactionReceipt } from 'viem/actions' import { DEFAULT_SAFE_VERSION } from '@safe-global/protocol-kit/contracts/config' import { EMPTY_DATA, ZERO_ADDRESS } from '@safe-global/protocol-kit/utils/constants' import { createMemoizedFunction } from '@safe-global/protocol-kit/utils/memoized' @@ -29,6 +29,7 @@ import { } from '../contracts/safeDeploymentContracts' import { ContractNetworkConfig, + ExternalClient, SafeAccountConfig, SafeContractImplementationType, SafeDeploymentConfig @@ -369,7 +370,7 @@ export function zkSyncEraCreate2Address( } export function toTxResult( - runner: PublicClient, + runner: ExternalClient, hash: Hash, options?: TransactionOptions ): TransactionResult { @@ -377,9 +378,7 @@ export function toTxResult( hash, options, transactionResponse: { - wait: async () => { - return runner.waitForTransactionReceipt({ hash }) - } + wait: async () => waitForTransactionReceipt(runner, { hash }) } } } diff --git a/packages/protocol-kit/src/types/safeProvider.ts b/packages/protocol-kit/src/types/safeProvider.ts index d2e5047bb..6ebf359cd 100644 --- a/packages/protocol-kit/src/types/safeProvider.ts +++ b/packages/protocol-kit/src/types/safeProvider.ts @@ -1,4 +1,4 @@ -import { Account, Chain, Transport, WalletClient } from 'viem' +import { Account, Chain, PublicClient, Transport, WalletClient } from 'viem' export type RequestArguments = { readonly method: string @@ -10,6 +10,7 @@ export type Eip1193Provider = { } export type ExternalSigner = WalletClient +export type ExternalClient = PublicClient | (ExternalSigner & PublicClient) export type HexAddress = string export type PrivateKey = string diff --git a/packages/protocol-kit/src/utils/provider.ts b/packages/protocol-kit/src/utils/provider.ts new file mode 100644 index 000000000..ad30a817e --- /dev/null +++ b/packages/protocol-kit/src/utils/provider.ts @@ -0,0 +1,4 @@ +import { isAddress } from 'viem' + +export const isEip1193Provider = (provider: any): boolean => typeof provider !== 'string' +export const isPrivateKey = (signer?: string): boolean => !!signer && !isAddress(signer) diff --git a/packages/protocol-kit/src/utils/transactions/utils.ts b/packages/protocol-kit/src/utils/transactions/utils.ts index 37660e71c..a003b3eb7 100644 --- a/packages/protocol-kit/src/utils/transactions/utils.ts +++ b/packages/protocol-kit/src/utils/transactions/utils.ts @@ -1,6 +1,9 @@ import SafeProvider from '@safe-global/protocol-kit/SafeProvider' import { DEFAULT_SAFE_VERSION } from '@safe-global/protocol-kit/contracts/config' -import { StandardizeSafeTransactionDataProps } from '@safe-global/protocol-kit/types' +import { + ExternalClient, + StandardizeSafeTransactionDataProps +} from '@safe-global/protocol-kit/types' import { hasSafeFeature, SAFE_FEATURES } from '@safe-global/protocol-kit/utils' import { ZERO_ADDRESS } from '@safe-global/protocol-kit/utils/constants' import { asAddress, asHex } from '../types' @@ -17,7 +20,6 @@ import { import semverSatisfies from 'semver/functions/satisfies' import { estimateGas, estimateTxGas } from './gas' import { - PublicClient, Hash, EstimateGasParameters, TransactionRequest, @@ -29,6 +31,7 @@ import { decodeFunctionData, parseAbi } from 'viem' +import { waitForTransactionReceipt as waitForTransactionReceiptViem } from 'viem/actions' import { SafeProviderTransaction } from '@safe-global/protocol-kit/types' import { WalletLegacyTransactionOptions, WalletTransactionOptions } from './types' @@ -42,8 +45,8 @@ export function standardizeMetaTransactionData( return standardizedTxs } -export function waitForTransactionReceipt(client: PublicClient, hash: Hash) { - return client.waitForTransactionReceipt({ hash }) +export function waitForTransactionReceipt(client: ExternalClient, hash: Hash) { + return waitForTransactionReceiptViem(client, { hash }) } export async function standardizeSafeTransactionData({ diff --git a/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.test.ts b/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.test.ts index 5ecc051f2..89d4e9354 100644 --- a/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.test.ts +++ b/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.test.ts @@ -647,10 +647,7 @@ describe('Safe4337Pack', () => { safeAddress: fixtures.SAFE_ADDRESS_v1_4_1 } }) - const readContractSpy = jest.spyOn( - safe4337Pack.protocolKit.getSafeProvider().getExternalProvider(), - 'readContract' - ) + const readContractSpy = jest.spyOn(safe4337Pack.protocolKit.getSafeProvider(), 'readContract') let safeOperation = await safe4337Pack.createTransaction({ transactions: [transferUSDC] diff --git a/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.ts b/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.ts index 6a25fe724..fc272c2ac 100644 --- a/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.ts +++ b/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.ts @@ -682,9 +682,9 @@ export class Safe4337Pack extends RelayKitBasePack<{ * @returns {Promise} The Promise object will resolve to the account nonce. */ async #getSafeNonceFromEntrypoint(safeAddress: string): Promise { - const externalProvider = this.protocolKit.getSafeProvider().getExternalProvider() + const safeProvider = this.protocolKit.getSafeProvider() - const newNonce = await externalProvider.readContract({ + const newNonce = await safeProvider.readContract({ address: (this.#ENTRYPOINT_ADDRESS as Address) || '0x', abi: ENTRYPOINT_ABI, functionName: 'getNonce', diff --git a/packages/safe-core-sdk-types/src/contracts/common/BaseContract.ts b/packages/safe-core-sdk-types/src/contracts/common/BaseContract.ts index 0da3ac0e0..75001ef9f 100644 --- a/packages/safe-core-sdk-types/src/contracts/common/BaseContract.ts +++ b/packages/safe-core-sdk-types/src/contracts/common/BaseContract.ts @@ -40,7 +40,7 @@ export type ContractWriteFunctionNames = ExtractAbiFunc * @template ArgType - The type of arguments to extract, either 'inputs' or 'outputs'. (default: 'inputs') * @type {ExtractFunctionArgs} */ -type ExtractFunctionArgs< +export type ExtractFunctionArgs< ContractAbi extends Abi, ContractFunctionName extends ExtractAbiFunctionNames = ExtractAbiFunctionNames, diff --git a/packages/safe-kit/src/utils/sendTransaction.ts b/packages/safe-kit/src/utils/sendTransaction.ts index 969c65c26..b8da14400 100644 --- a/packages/safe-kit/src/utils/sendTransaction.ts +++ b/packages/safe-kit/src/utils/sendTransaction.ts @@ -1,4 +1,5 @@ import { Address, WalletClient, Transport, Chain, Hex, Account } from 'viem' +import { waitForTransactionReceipt } from 'viem/actions' import Safe from '@safe-global/protocol-kit' import { Transaction } from '@safe-global/safe-core-sdk-types' @@ -34,7 +35,7 @@ export const sendTransaction = async ({ account: signer.account }) - const receipt = await client.waitForTransactionReceipt({ hash }) + const receipt = await waitForTransactionReceipt(client, { hash }) return receipt.transactionHash } diff --git a/playground/api-kit/execute-transaction.ts b/playground/api-kit/execute-transaction.ts index 53f638333..9ed1c78c8 100644 --- a/playground/api-kit/execute-transaction.ts +++ b/playground/api-kit/execute-transaction.ts @@ -1,4 +1,5 @@ import { Chain, Hash } from 'viem' +import { waitForTransactionReceipt } from 'viem/actions' import { sepolia } from 'viem/chains' import Safe from '@safe-global/protocol-kit' import SafeApiKit from '@safe-global/api-kit' @@ -40,10 +41,9 @@ async function main() { // Execute the transaction const txResponse = await protocolKit.executeTransaction(safeTransaction) - await protocolKit - .getSafeProvider() - .getExternalProvider() - .waitForTransactionReceipt({ hash: txResponse.hash as Hash }) + await waitForTransactionReceipt(protocolKit.getSafeProvider().getExternalProvider(), { + hash: txResponse.hash as Hash + }) console.log('Transaction executed.') console.log('- Transaction hash:', txResponse.hash) diff --git a/playground/relay-kit/paid-transaction.ts b/playground/relay-kit/paid-transaction.ts index 28590c139..f7a170087 100644 --- a/playground/relay-kit/paid-transaction.ts +++ b/playground/relay-kit/paid-transaction.ts @@ -1,5 +1,6 @@ import { Address, Chain, formatEther, createWalletClient, custom, Hex } from 'viem' import { sepolia } from 'viem/chains' +import { getBalance, waitForTransactionReceipt } from 'viem/actions' import { privateKeyToAccount } from 'viem/accounts' import { createSafeClient, SafeClient } from '@safe-global/safe-kit' import { GelatoRelayPack } from '@safe-global/relay-kit' @@ -89,7 +90,7 @@ async function main() { const relayFee = BigInt( await gelatoSafeClient.getEstimateFee(BigInt(chainId), txConfig.GAS_LIMIT, txConfig.GAS_TOKEN) ) - const safeBalance = await externalProvider.getBalance({ address: predictedSafeAddress }) + const safeBalance = await getBalance(externalProvider, { address: predictedSafeAddress }) console.log({ minSafeBalance: formatEther(relayFee) }) console.log({ safeBalance: formatEther(safeBalance) }) @@ -108,9 +109,9 @@ async function main() { }) console.log(`Funding the Safe with ${formatEther(fundingAmount)} ETH`) - await externalProvider.waitForTransactionReceipt({ hash }) + await waitForTransactionReceipt(externalProvider, { hash }) - const safeBalanceAfter = await externalProvider.getBalance({ address: predictedSafeAddress }) + const safeBalanceAfter = await getBalance(externalProvider, { address: predictedSafeAddress }) console.log({ safeBalance: formatEther(safeBalanceAfter) }) } diff --git a/playground/relay-kit/sponsored-transaction.ts b/playground/relay-kit/sponsored-transaction.ts index bbf8cb5de..4d0093fb1 100644 --- a/playground/relay-kit/sponsored-transaction.ts +++ b/playground/relay-kit/sponsored-transaction.ts @@ -1,5 +1,6 @@ import { Address, Chain, createWalletClient, custom, formatEther, Hex } from 'viem' import { privateKeyToAccount } from 'viem/accounts' +import { getBalance, waitForTransactionReceipt } from 'viem/actions' import { sepolia } from 'viem/chains' import { createSafeClient, SafeClient } from '@safe-global/safe-kit' import { GelatoRelayPack } from '@safe-global/relay-kit' @@ -86,7 +87,7 @@ async function main() { // Fake on-ramp to fund the Safe const externalProvider = gelatoSafeClient.protocolKit.getSafeProvider().getExternalProvider() - const safeBalance = await externalProvider.getBalance({ address: predictedSafeAddress }) + const safeBalance = await getBalance(externalProvider, { address: predictedSafeAddress }) console.log({ safeBalance: formatEther(safeBalance) }) if (safeBalance < BigInt(txConfig.VALUE)) { const fakeOnRampSigner = createWalletClient({ @@ -99,9 +100,9 @@ async function main() { value: BigInt(txConfig.VALUE) }) console.log(`Funding the Safe with ${formatEther(BigInt(txConfig.VALUE))} ETH`) - await externalProvider.waitForTransactionReceipt({ hash }) + await waitForTransactionReceipt(externalProvider, { hash }) - const safeBalanceAfter = await externalProvider.getBalance({ address: predictedSafeAddress }) + const safeBalanceAfter = await getBalance(externalProvider, { address: predictedSafeAddress }) console.log({ safeBalance: formatEther(safeBalanceAfter) }) } diff --git a/playground/relay-kit/usdc-transfer-4337-counterfactual.ts b/playground/relay-kit/usdc-transfer-4337-counterfactual.ts index 24b527f7b..ec9ea5cca 100644 --- a/playground/relay-kit/usdc-transfer-4337-counterfactual.ts +++ b/playground/relay-kit/usdc-transfer-4337-counterfactual.ts @@ -1,4 +1,5 @@ import { parseEther, Address } from 'viem' +import { getBlock, waitForTransactionReceipt } from 'viem/actions' import { sepolia } from 'viem/chains' import { Safe4337Pack } from '@safe-global/relay-kit' import { waitForOperationToFinish, transfer, generateTransferCallData } from '../utils' @@ -72,7 +73,7 @@ async function main() { const hash = await externalSigner?.sendTransaction(fundingSafe) - await externalProvider.waitForTransactionReceipt({ hash }) + await waitForTransactionReceipt(externalProvider, { hash }) // Create transaction batch with two 0.1 USDC transfers @@ -92,7 +93,7 @@ async function main() { } const transactions = [transferUSDC, transferUSDC] - const timestamp = (await externalProvider.getBlock())?.timestamp || 0n + const timestamp = (await getBlock(externalProvider))?.timestamp || 0n // 2) Create transaction batch const safeOperation = await safe4337Pack.createTransaction({ diff --git a/playground/relay-kit/usdc-transfer-4337-erc20-counterfactual.ts b/playground/relay-kit/usdc-transfer-4337-erc20-counterfactual.ts index e19896f90..1da2ab133 100644 --- a/playground/relay-kit/usdc-transfer-4337-erc20-counterfactual.ts +++ b/playground/relay-kit/usdc-transfer-4337-erc20-counterfactual.ts @@ -1,4 +1,5 @@ import { Address } from 'viem' +import { getBlock } from 'viem/actions' import { Safe4337Pack } from '@safe-global/relay-kit' import { waitForOperationToFinish, transfer, generateTransferCallData } from '../utils' @@ -81,7 +82,7 @@ async function main() { value: '0' } const transactions = [transferUSDC, transferUSDC] - const timestamp = (await externalProvider.getBlock())?.timestamp || 0n + const timestamp = (await getBlock(externalProvider))?.timestamp || 0n // 2) Create transaction batch const safeOperation = await safe4337Pack.createTransaction({ diff --git a/playground/relay-kit/usdc-transfer-4337-erc20.ts b/playground/relay-kit/usdc-transfer-4337-erc20.ts index b952f5cc0..648e69e2d 100644 --- a/playground/relay-kit/usdc-transfer-4337-erc20.ts +++ b/playground/relay-kit/usdc-transfer-4337-erc20.ts @@ -1,4 +1,5 @@ import { Address } from 'viem' +import { getBlock } from 'viem/actions' import { Safe4337Pack } from '@safe-global/relay-kit' import { waitForOperationToFinish, transfer, generateTransferCallData } from '../utils' @@ -75,7 +76,7 @@ async function main() { value: '0' } const transactions = [transferUSDC, transferUSDC] - const timestamp = (await externalProvider.getBlock())?.timestamp || 0n + const timestamp = (await getBlock(externalProvider))?.timestamp || 0n // 2) Create transaction batch const safeOperation = await safe4337Pack.createTransaction({ diff --git a/playground/relay-kit/usdc-transfer-4337-sponsored-counterfactual.ts b/playground/relay-kit/usdc-transfer-4337-sponsored-counterfactual.ts index e98d08fdb..4f27fd912 100644 --- a/playground/relay-kit/usdc-transfer-4337-sponsored-counterfactual.ts +++ b/playground/relay-kit/usdc-transfer-4337-sponsored-counterfactual.ts @@ -1,4 +1,5 @@ import { Address } from 'viem' +import { getBlock } from 'viem/actions' import { Safe4337Pack } from '@safe-global/relay-kit' import { waitForOperationToFinish, transfer, generateTransferCallData } from '../utils' @@ -88,7 +89,7 @@ async function main() { value: '0' } const transactions = [transferUSDC, transferUSDC] - const timestamp = (await externalProvider.getBlock())?.timestamp || 0n + const timestamp = (await getBlock(externalProvider))?.timestamp || 0n // 2) Create transaction batch const safeOperation = await safe4337Pack.createTransaction({ diff --git a/playground/relay-kit/usdc-transfer-4337-sponsored.ts b/playground/relay-kit/usdc-transfer-4337-sponsored.ts index 93825ed23..4672f4e7a 100644 --- a/playground/relay-kit/usdc-transfer-4337-sponsored.ts +++ b/playground/relay-kit/usdc-transfer-4337-sponsored.ts @@ -1,4 +1,5 @@ import { Address } from 'viem' +import { getBlock } from 'viem/actions' import { Safe4337Pack } from '@safe-global/relay-kit' import { generateTransferCallData, waitForOperationToFinish } from '../utils' @@ -69,7 +70,7 @@ async function main() { } const transactions = [transferUSDC, transferUSDC] const externalProvider = safe4337Pack.protocolKit.getSafeProvider().getExternalProvider() - const timestamp = (await externalProvider.getBlock())?.timestamp || 0n + const timestamp = (await getBlock(externalProvider))?.timestamp || 0n // 2) Create transaction batch const safeOperation = await safe4337Pack.createTransaction({ diff --git a/playground/relay-kit/usdc-transfer-4337.ts b/playground/relay-kit/usdc-transfer-4337.ts index df0e69722..6809358e8 100644 --- a/playground/relay-kit/usdc-transfer-4337.ts +++ b/playground/relay-kit/usdc-transfer-4337.ts @@ -1,4 +1,5 @@ import { Address } from 'viem' +import { getBlock } from 'viem/actions' import { Safe4337Pack } from '@safe-global/relay-kit' import { generateTransferCallData, waitForOperationToFinish } from '../utils' @@ -50,7 +51,7 @@ async function main() { } const transactions = [transferUSDC, transferUSDC] const externalProvider = safe4337Pack.protocolKit.getSafeProvider().getExternalProvider() - const timestamp = (await externalProvider.getBlock())?.timestamp || 0n + const timestamp = (await getBlock(externalProvider))?.timestamp || 0n // 2) Create transaction batch const safeOperation = await safe4337Pack.createTransaction({ From 9853b121b95c52a32359e4523941c31f23b49f76 Mon Sep 17 00:00:00 2001 From: Daniel <25051234+dasanra@users.noreply.github.com> Date: Thu, 1 Aug 2024 10:44:17 +0200 Subject: [PATCH 79/85] chore: align api-kit tests --- packages/api-kit/tests/e2e/addSafeDelegate.test.ts | 4 ++-- .../api-kit/tests/e2e/confirmSafeOperation.test.ts | 3 ++- packages/api-kit/tests/e2e/getSafeDelegates.test.ts | 7 +++---- .../api-kit/tests/e2e/removeSafeDelegate.test.ts | 13 +++++-------- packages/api-kit/tests/endpoint/index.test.ts | 8 ++++---- packages/safe-kit/src/utils/sendTransaction.ts | 2 +- 6 files changed, 17 insertions(+), 20 deletions(-) diff --git a/packages/api-kit/tests/e2e/addSafeDelegate.test.ts b/packages/api-kit/tests/e2e/addSafeDelegate.test.ts index 47ce2a34e..2f9a31561 100644 --- a/packages/api-kit/tests/e2e/addSafeDelegate.test.ts +++ b/packages/api-kit/tests/e2e/addSafeDelegate.test.ts @@ -24,7 +24,7 @@ describe('addSafeDelegate', () => { transport: http(), account: privateKeyToAccount(PRIVATE_KEY_1) }) - delegatorAddress = (await signer.getAddresses())[0] + delegatorAddress = signer.account.address }) it('should fail if Label is empty', async () => { @@ -100,7 +100,7 @@ describe('addSafeDelegate', () => { it('should fail if Safe delegator address is not checksummed', async () => { const safeAddress = '0xF8ef84392f7542576F6b9d1b140334144930Ac78' const delegateAddress = '0x9cCBDE03eDd71074ea9c49e413FA9CDfF16D263B' - const delegatorAddressLowerCase = delegatorAddress.toLocaleLowerCase() + const delegatorAddressLowerCase = delegatorAddress.toLowerCase() const delegateConfig: AddSafeDelegateProps = { safeAddress, delegateAddress, diff --git a/packages/api-kit/tests/e2e/confirmSafeOperation.test.ts b/packages/api-kit/tests/e2e/confirmSafeOperation.test.ts index d45e51986..9f1e51146 100644 --- a/packages/api-kit/tests/e2e/confirmSafeOperation.test.ts +++ b/packages/api-kit/tests/e2e/confirmSafeOperation.test.ts @@ -7,6 +7,7 @@ import { generateTransferCallData } from '@safe-global/relay-kit/packs/safe-4337 import SafeApiKit from '@safe-global/api-kit/index' import { getAddSafeOperationProps } from '@safe-global/api-kit/utils/safeOperation' import { SafeOperation } from '@safe-global/safe-core-sdk-types' +// Needs to be imported from dist folder in order to mock the getEip4337BundlerProvider function import * as safe4337Utils from '@safe-global/relay-kit/dist/src/packs/safe-4337/utils' import { getApiKit, getEip1193Provider } from '../utils/setupKits' import { @@ -89,7 +90,7 @@ describe('confirmSafeOperation', () => { // Submit a new Safe operation to the transaction service safeOperation = await addSafeOperation() - safeOpHash = await safeOperation.getHash() + safeOpHash = safeOperation.getHash() }) after(() => { diff --git a/packages/api-kit/tests/e2e/getSafeDelegates.test.ts b/packages/api-kit/tests/e2e/getSafeDelegates.test.ts index cd689e616..a4a4d4c19 100644 --- a/packages/api-kit/tests/e2e/getSafeDelegates.test.ts +++ b/packages/api-kit/tests/e2e/getSafeDelegates.test.ts @@ -1,4 +1,4 @@ -import { createWalletClient, http } from 'viem' +import { Address, createWalletClient, http } from 'viem' import { sepolia } from 'viem/chains' import { privateKeyToAccount } from 'viem/accounts' import SafeApiKit, { @@ -16,6 +16,7 @@ const PRIVATE_KEY = '0x83a415ca62e11f5fa5567e98450d0f82ae19ff36ef876c10a8d448c78 let safeApiKit: SafeApiKit let signer: DeleteSafeDelegateProps['signer'] +let delegatorAddress: Address describe('getSafeDelegates', () => { const safeAddress = '0xF8ef84392f7542576F6b9d1b140334144930Ac78' @@ -27,6 +28,7 @@ describe('getSafeDelegates', () => { transport: http(), account: privateKeyToAccount(PRIVATE_KEY) }) + delegatorAddress = signer.account.address }) it('should fail if Safe address is empty', async () => { @@ -50,13 +52,11 @@ describe('getSafeDelegates', () => { }) describe('for valid parameters', () => { - let delegatorAddress: string let delegateConfig1: DeleteSafeDelegateProps let delegateConfig2: DeleteSafeDelegateProps let delegatesResponse: SafeDelegateResponse[] before(async () => { - delegatorAddress = signer.account!.address delegateConfig1 = { delegateAddress: '0x9cCBDE03eDd71074ea9c49e413FA9CDfF16D263B', delegatorAddress, @@ -129,7 +129,6 @@ describe('getSafeDelegates', () => { it('should return an array of delegates EIP-3770', async () => { const safeAddress = '0xF8ef84392f7542576F6b9d1b140334144930Ac78' const eip3770SafeAddress = `${config.EIP_3770_PREFIX}:${safeAddress}` - const delegatorAddress = signer.account!.address const delegateConfig1: DeleteSafeDelegateProps = { delegateAddress: `${config.EIP_3770_PREFIX}:0x9cCBDE03eDd71074ea9c49e413FA9CDfF16D263B`, delegatorAddress, diff --git a/packages/api-kit/tests/e2e/removeSafeDelegate.test.ts b/packages/api-kit/tests/e2e/removeSafeDelegate.test.ts index 29af873ae..328ece7a0 100644 --- a/packages/api-kit/tests/e2e/removeSafeDelegate.test.ts +++ b/packages/api-kit/tests/e2e/removeSafeDelegate.test.ts @@ -1,4 +1,4 @@ -import { createWalletClient, http } from 'viem' +import { Address, createWalletClient, http } from 'viem' import { sepolia } from 'viem/chains' import { privateKeyToAccount } from 'viem/accounts' import SafeApiKit, { DeleteSafeDelegateProps } from '@safe-global/api-kit/index' @@ -13,6 +13,7 @@ const PRIVATE_KEY = '0x83a415ca62e11f5fa5567e98450d0f82ae19ff36ef876c10a8d448c78 let safeApiKit: SafeApiKit let signer: DeleteSafeDelegateProps['signer'] +let delegatorAddress: Address describe('removeSafeDelegate', () => { before(async () => { @@ -22,11 +23,11 @@ describe('removeSafeDelegate', () => { transport: http(), account: privateKeyToAccount(PRIVATE_KEY) }) + delegatorAddress = signer.account.address }) it('should fail if Safe delegate address is empty', async () => { const delegateAddress = '' - const delegatorAddress = signer.account!.address const delegateConfig: DeleteSafeDelegateProps = { delegateAddress, delegatorAddress, @@ -52,7 +53,6 @@ describe('removeSafeDelegate', () => { it('should fail if Safe delegate address is not checksummed', async () => { const delegateAddress = '0x9cCBDE03eDd71074ea9c49e413FA9CDfF16D263B'.toLowerCase() - const delegatorAddress = signer.account!.address const delegateConfig: DeleteSafeDelegateProps = { delegateAddress, delegatorAddress, @@ -65,10 +65,10 @@ describe('removeSafeDelegate', () => { it('should fail if Safe delegator address is not checksummed', async () => { const delegateAddress = '0x9cCBDE03eDd71074ea9c49e413FA9CDfF16D263B' - const delegatorAddress = signer.account!.address.toLowerCase() + const delegatorAddressLowerCase = delegatorAddress.toLowerCase() const delegateConfig: DeleteSafeDelegateProps = { delegateAddress, - delegatorAddress, + delegatorAddress: delegatorAddressLowerCase, signer } await chai @@ -78,7 +78,6 @@ describe('removeSafeDelegate', () => { it('should fail if the delegate to remove is not a delegate', async () => { const delegateAddress = '0x1dF62f291b2E969fB0849d99D9Ce41e2F137006e' - const delegatorAddress = signer.account!.address const delegateConfig: DeleteSafeDelegateProps = { delegateAddress, delegatorAddress, @@ -89,7 +88,6 @@ describe('removeSafeDelegate', () => { it('should remove a delegate', async () => { const delegateAddress = '0x9cCBDE03eDd71074ea9c49e413FA9CDfF16D263B' - const delegatorAddress = signer.account!.address const delegateConfig: DeleteSafeDelegateProps = { delegateAddress, delegatorAddress, @@ -112,7 +110,6 @@ describe('removeSafeDelegate', () => { it('should remove a delegate EIP-3770', async () => { const delegateAddress = '0x9cCBDE03eDd71074ea9c49e413FA9CDfF16D263B' const eip3770DelegateAddress = `${config.EIP_3770_PREFIX}:${delegateAddress}` - const delegatorAddress = signer.account!.address const eip3770DelegatorAddress = `${config.EIP_3770_PREFIX}:${delegatorAddress}` const delegateConfig: DeleteSafeDelegateProps = { delegateAddress: eip3770DelegateAddress, diff --git a/packages/api-kit/tests/endpoint/index.test.ts b/packages/api-kit/tests/endpoint/index.test.ts index 5cdb94dba..e72b5c536 100644 --- a/packages/api-kit/tests/endpoint/index.test.ts +++ b/packages/api-kit/tests/endpoint/index.test.ts @@ -690,11 +690,11 @@ describe('Endpoint tests', () => { const entryPoint = '0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789' - const ethersProvider = protocolKit.getSafeProvider().getExternalProvider() - const timestamp = (await ethersProvider.getBlock())?.timestamp || 0n + const externalProvider = protocolKit.getSafeProvider().getExternalProvider() + const timestamp = Number((await externalProvider.getBlock())?.timestamp) || 0 - const validAfter = Number(timestamp - 60_000n) - const validUntil = Number(timestamp + 60_000n) + const validAfter = timestamp - 60_000 + const validUntil = timestamp + 60_000 const options = { validAfter, validUntil } await chai diff --git a/packages/safe-kit/src/utils/sendTransaction.ts b/packages/safe-kit/src/utils/sendTransaction.ts index b8da14400..d8aede050 100644 --- a/packages/safe-kit/src/utils/sendTransaction.ts +++ b/packages/safe-kit/src/utils/sendTransaction.ts @@ -23,7 +23,7 @@ export const sendTransaction = async ({ Chain, Account > - const client = await protocolKit.getSafeProvider().getExternalProvider() + const client = protocolKit.getSafeProvider().getExternalProvider() if (!signer) throw new Error('SafeProvider must be initialized with a signer to use this function') From 48d4902e4f5f001ce93d71171e7b192eb7a7a073 Mon Sep 17 00:00:00 2001 From: Daniel <25051234+dasanra@users.noreply.github.com> Date: Thu, 1 Aug 2024 10:49:32 +0200 Subject: [PATCH 80/85] fix: delegator address not checksummed --- packages/api-kit/tests/e2e/removeSafeDelegate.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/api-kit/tests/e2e/removeSafeDelegate.test.ts b/packages/api-kit/tests/e2e/removeSafeDelegate.test.ts index 328ece7a0..6f848d91e 100644 --- a/packages/api-kit/tests/e2e/removeSafeDelegate.test.ts +++ b/packages/api-kit/tests/e2e/removeSafeDelegate.test.ts @@ -73,7 +73,7 @@ describe('removeSafeDelegate', () => { } await chai .expect(safeApiKit.removeSafeDelegate(delegateConfig)) - .to.be.rejectedWith(`Address ${delegatorAddress} is not checksumed`) + .to.be.rejectedWith(`Address ${delegatorAddressLowerCase} is not checksumed`) }) it('should fail if the delegate to remove is not a delegate', async () => { From 19d7910578469abd1e0ddef159c8ed2475a171d0 Mon Sep 17 00:00:00 2001 From: leonardotc Date: Fri, 2 Aug 2024 09:07:06 +0200 Subject: [PATCH 81/85] Add further comments --- packages/protocol-kit/src/utils/eip-712/encode.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/protocol-kit/src/utils/eip-712/encode.ts b/packages/protocol-kit/src/utils/eip-712/encode.ts index ae94dd069..635fa890d 100644 --- a/packages/protocol-kit/src/utils/eip-712/encode.ts +++ b/packages/protocol-kit/src/utils/eip-712/encode.ts @@ -13,7 +13,10 @@ import { } from 'viem' import { asHex } from '../types' -// This whole file was copied (and softly adapted) from viem in order to expose the function that provides just the encoding. +/* + * This whole file was copied (and softly adapted) from viem in order to expose the function that provides just the encoding. The purpose is to expose `encodeTypedData` (viem only exports the hashTypedData) + * That function are used by preimageSafeTransactionHash, preimageSafeMessageHash. + */ function encodeField({ types, name, From 86871bdffc771d30b53e6a19941efd3d0624e1c9 Mon Sep 17 00:00:00 2001 From: leonardotc Date: Thu, 8 Aug 2024 10:17:27 +0200 Subject: [PATCH 82/85] Change base address type --- packages/api-kit/package.json | 2 +- packages/auth-kit/package.json | 2 +- packages/onramp-kit/package.json | 2 +- packages/protocol-kit/package.json | 4 +- packages/protocol-kit/src/Safe.ts | 6 +- packages/protocol-kit/src/SafeProvider.ts | 18 ++--- .../src/contracts/BaseContract.ts | 10 +-- .../Safe/v1.0.0/SafeContract_v1_0_0.ts | 28 +++---- .../Safe/v1.1.1/SafeContract_v1_1_1.ts | 28 +++---- .../Safe/v1.2.0/SafeContract_v1_2_0.ts | 28 +++---- .../Safe/v1.3.0/SafeContract_v1_3_0.ts | 28 +++---- .../Safe/v1.4.1/SafeContract_v1_4_1.ts | 28 +++---- .../v1.0.0/SafeProxyFactoryContract_v1_0_0.ts | 8 +- .../v1.1.1/SafeProxyFactoryContract_v1_1_1.ts | 8 +- .../v1.3.0/SafeProxyFactoryContract_v1_3_0.ts | 8 +- .../v1.4.1/SafeProxyFactoryContract_v1_4_1.ts | 8 +- packages/protocol-kit/src/contracts/utils.ts | 18 ++--- .../src/managers/fallbackHandlerManager.ts | 3 +- .../protocol-kit/src/managers/guardManager.ts | 3 +- .../src/managers/moduleManager.ts | 8 +- .../protocol-kit/src/managers/ownerManager.ts | 3 +- .../src/utils/transactions/gas.ts | 14 ++-- .../src/utils/transactions/utils.ts | 12 +-- packages/protocol-kit/src/utils/types.ts | 10 +-- packages/protocol-kit/tests/e2e/core.test.ts | 3 +- .../tests/e2e/utils/setupContracts.ts | 39 +++++---- .../tests/e2e/utils/transactions.ts | 3 +- packages/relay-kit/package.json | 2 +- .../src/packs/safe-4337/Safe4337Pack.ts | 32 ++++---- .../src/packs/safe-4337/SafeOperation.ts | 4 +- .../packs/safe-4337/testing-utils/helpers.ts | 4 +- .../relay-kit/src/packs/safe-4337/utils.ts | 5 +- .../src/packs/safe-4337/utils/entrypoint.ts | 5 +- packages/safe-core-sdk-types/package.json | 3 +- packages/safe-core-sdk-types/src/index.ts | 18 +++++ packages/safe-core-sdk-types/src/types.ts | 2 + packages/safe-kit/package.json | 2 +- .../safe-kit/src/utils/sendTransaction.ts | 4 +- playground/relay-kit/paid-transaction.ts | 2 +- playground/relay-kit/sponsored-transaction.ts | 2 +- .../usdc-transfer-4337-counterfactual.ts | 2 +- ...usdc-transfer-4337-erc20-counterfactual.ts | 2 +- .../relay-kit/usdc-transfer-4337-erc20.ts | 2 +- ...-transfer-4337-sponsored-counterfactual.ts | 2 +- .../relay-kit/usdc-transfer-4337-sponsored.ts | 2 +- playground/relay-kit/usdc-transfer-4337.ts | 2 +- playground/utils.ts | 2 +- yarn.lock | 79 ++++++------------- 48 files changed, 239 insertions(+), 271 deletions(-) diff --git a/packages/api-kit/package.json b/packages/api-kit/package.json index 9274fbcfe..36472471d 100644 --- a/packages/api-kit/package.json +++ b/packages/api-kit/package.json @@ -64,6 +64,6 @@ "@safe-global/protocol-kit": "^4.0.3", "@safe-global/safe-core-sdk-types": "^5.0.3", "node-fetch": "^2.7.0", - "viem": "^2.15.1" + "viem": "^2.19.0" } } diff --git a/packages/auth-kit/package.json b/packages/auth-kit/package.json index cab60c04c..ece380088 100644 --- a/packages/auth-kit/package.json +++ b/packages/auth-kit/package.json @@ -42,6 +42,6 @@ "@safe-global/api-kit": "^2.4.3", "@safe-global/protocol-kit": "^4.0.3", "@web3auth/safeauth-embed": "^0.0.0", - "viem": "^2.17.0" + "viem": "^2.19.0" } } diff --git a/packages/onramp-kit/package.json b/packages/onramp-kit/package.json index c44a61c66..cc6d98bd6 100644 --- a/packages/onramp-kit/package.json +++ b/packages/onramp-kit/package.json @@ -41,7 +41,7 @@ "@safe-global/safe-core-sdk-types": "^5.0.3", "@stripe/crypto": "^0.0.4", "@stripe/stripe-js": "^1.54.2", - "viem": "^2.17.0" + "viem": "^2.19.0" }, "devDependencies": { "events": "^3.3.0", diff --git a/packages/protocol-kit/package.json b/packages/protocol-kit/package.json index 50a2d2462..d009f2dc4 100644 --- a/packages/protocol-kit/package.json +++ b/packages/protocol-kit/package.json @@ -33,7 +33,7 @@ "format:check": "prettier --check \"*/**/*.{js,json,md,ts}\"", "format": "prettier --write \"*/**/*.{js,json,md,ts}\"", "unbuild": "rimraf dist artifacts deployments cache .nyc_output *.tsbuildinfo", - "build": "yarn unbuild && hardhat compile && yarn safe-deployments && tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json" + "build": "yarn unbuild && hardhat compile && yarn safe-deployments && NODE_OPTIONS=--max-old-space-size=8192 tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json" }, "repository": { "type": "git", @@ -75,6 +75,6 @@ "@safe-global/safe-deployments": "^1.37.1", "abitype": "^1.0.2", "semver": "^7.6.2", - "viem": "^2.15.1" + "viem": "^2.19.0" } } diff --git a/packages/protocol-kit/src/Safe.ts b/packages/protocol-kit/src/Safe.ts index d2a1cb50f..4b347dc31 100644 --- a/packages/protocol-kit/src/Safe.ts +++ b/packages/protocol-kit/src/Safe.ts @@ -72,7 +72,7 @@ import { import SafeMessage from './utils/messages/SafeMessage' import semverSatisfies from 'semver/functions/satisfies' import SafeProvider from './SafeProvider' -import { asAddress, asHash, asHex } from './utils/types' +import { asHash, asHex } from './utils/types' import { Hash, Hex } from 'viem' const EQ_OR_GT_1_4_1 = '>=1.4.1' @@ -842,7 +842,7 @@ class Safe { const ownersWhoApproved: string[] = [] for (const owner of owners) { const [approved] = await this.#contractManager.safeContract.approvedHashes([ - asAddress(owner), + owner, asHash(txHash) ]) if (approved > 0) { @@ -1405,7 +1405,7 @@ class Safe { value: '0', // we use the createProxyWithNonce method to create the Safe in a deterministic address, see: https://github.com/safe-global/safe-contracts/blob/main/contracts/proxies/SafeProxyFactory.sol#L52 data: safeProxyFactoryContract.encode('createProxyWithNonce', [ - asAddress(safeSingletonContract.getAddress()), + safeSingletonContract.getAddress(), asHex(initializer), // call to the setup method to set the threshold & owners of the new Safe BigInt(saltNonce) ]) diff --git a/packages/protocol-kit/src/SafeProvider.ts b/packages/protocol-kit/src/SafeProvider.ts index 2ca4c1997..e61cf43f1 100644 --- a/packages/protocol-kit/src/SafeProvider.ts +++ b/packages/protocol-kit/src/SafeProvider.ts @@ -26,7 +26,7 @@ import { HttpTransport, SocketTransport } from '@safe-global/protocol-kit/types' -import { asAddress, asHash, asHex, getChainById } from './utils/types' +import { asHash, asHex, getChainById } from './utils/types' import { asBlockId } from './utils/block' import { createPublicClient, @@ -107,7 +107,7 @@ class SafeProvider { // If we have a signer and its not a pk, it might be a delegate on the rpc levels and this should work with eth_requestAcc if (this.signer && isAddress(this.signer)) { return createWalletClient({ - account: asAddress(this.signer), + account: this.signer, chain, transport: custom(transport) }) @@ -149,14 +149,14 @@ class SafeProvider { async getBalance(address: string, blockTag?: string | number): Promise { return getBalance(this.#externalProvider, { - address: asAddress(address), + address, ...asBlockId(blockTag) }) } async getNonce(address: string, blockTag?: string | number): Promise { return getTransactionCount(this.#externalProvider, { - address: asAddress(address), + address, ...asBlockId(blockTag) }) } @@ -275,7 +275,7 @@ class SafeProvider { async getContractCode(address: string, blockTag?: string | number): Promise { const res = await getCode(this.#externalProvider, { - address: asAddress(address), + address, ...asBlockId(blockTag) }) @@ -284,7 +284,7 @@ class SafeProvider { async isContractDeployed(address: string, blockTag?: string | number): Promise { const contractCode = await getCode(this.#externalProvider, { - address: asAddress(address), + address, ...asBlockId(blockTag) }) // https://github.com/wevm/viem/blob/963877cd43083260a4399d6f0bbf142ccede53b4/src/actions/public/getCode.ts#L71 @@ -293,7 +293,7 @@ class SafeProvider { async getStorageAt(address: string, position: string): Promise { const content = await getStorageAt(this.#externalProvider, { - address: asAddress(address), + address, slot: asHex(position) }) const decodedContent = this.decodeParameters('address', asHex(content)) @@ -327,7 +327,7 @@ class SafeProvider { }) } else { return await signer?.signMessage!({ - account: asAddress(account), + account: account, message: { raw: toBytes(message) } }) } @@ -344,7 +344,7 @@ class SafeProvider { const typedData = generateTypedData(safeEIP712Args) const { chainId, verifyingContract } = typedData.domain const chain = chainId ? Number(chainId) : undefined // ensure empty string becomes undefined - const domain = { verifyingContract: asAddress(verifyingContract), chainId: chain } + const domain = { verifyingContract: verifyingContract, chainId: chain } const signature = await signer.signTypedData({ domain, diff --git a/packages/protocol-kit/src/contracts/BaseContract.ts b/packages/protocol-kit/src/contracts/BaseContract.ts index 6693392d7..6d8becd26 100644 --- a/packages/protocol-kit/src/contracts/BaseContract.ts +++ b/packages/protocol-kit/src/contracts/BaseContract.ts @@ -10,7 +10,7 @@ import { SafeVersion, TransactionOptions } from '@safe-global/safe-core-sdk-types' -import { asAddress, getChainById } from '../utils/types' +import { getChainById } from '../utils/types' import { WalletTransactionOptions, WalletLegacyTransactionOptions, @@ -116,7 +116,7 @@ class BaseContract { const signer = this.wallet?.account if (!signer || !signerAddress) throw new Error('Invalid signer') - const account = signer || asAddress(signerAddress) + const account = signer || signerAddress const txOptions = await convertTransactionOptions(options) return { chain, ...txOptions, account } // Needs to be in this order to override the `account` if necessary } @@ -151,7 +151,7 @@ class BaseContract { return estimateContractGas(this.runner, { abi, functionName: functionToEstimate, - address: asAddress(this.getAddress()), + address: this.getAddress(), args: params, ...contractOptions }) @@ -173,7 +173,7 @@ class BaseContract { const converted = (await this.convertOptions(options)) as any return await this.getWallet().writeContract({ - address: asAddress(this.contractAddress), + address: this.contractAddress, abi: this.contractAbi, functionName, args: args, @@ -188,7 +188,7 @@ class BaseContract { return await this.runner.readContract({ functionName, abi: this.contractAbi, - address: asAddress(this.contractAddress), + address: this.contractAddress, args }) } diff --git a/packages/protocol-kit/src/contracts/Safe/v1.0.0/SafeContract_v1_0_0.ts b/packages/protocol-kit/src/contracts/Safe/v1.0.0/SafeContract_v1_0_0.ts index bdc1b259d..44554231c 100644 --- a/packages/protocol-kit/src/contracts/Safe/v1.0.0/SafeContract_v1_0_0.ts +++ b/packages/protocol-kit/src/contracts/Safe/v1.0.0/SafeContract_v1_0_0.ts @@ -15,7 +15,7 @@ import { TransactionResult } from '@safe-global/safe-core-sdk-types' import { SENTINEL_ADDRESS } from '@safe-global/protocol-kit/utils/constants' -import { asAddress, asHash, asHex } from '@safe-global/protocol-kit/utils/types' +import { asHash, asHex } from '@safe-global/protocol-kit/utils/types' /** * SafeContract_v1_0_0 is the implementation specific to the Safe contract version 1.0.0. @@ -224,30 +224,30 @@ class SafeContract_v1_0_0 (await this.estimateGas( 'execTransaction', [ - asAddress(safeTransaction.data.to), + safeTransaction.data.to, BigInt(safeTransaction.data.value), asHex(safeTransaction.data.data), safeTransaction.data.operation, BigInt(safeTransaction.data.safeTxGas), BigInt(safeTransaction.data.baseGas), BigInt(safeTransaction.data.gasPrice), - asAddress(safeTransaction.data.gasToken), - asAddress(safeTransaction.data.refundReceiver), + safeTransaction.data.gasToken, + safeTransaction.data.refundReceiver, asHex(safeTransaction.encodedSignatures()) ], options )) const args: ContractFunctionArgs = [ - asAddress(safeTransaction.data.to), + safeTransaction.data.to, BigInt(safeTransaction.data.value), asHex(safeTransaction.data.data), safeTransaction.data.operation, BigInt(safeTransaction.data.safeTxGas), BigInt(safeTransaction.data.baseGas), BigInt(safeTransaction.data.gasPrice), - asAddress(safeTransaction.data.gasToken), - asAddress(safeTransaction.data.refundReceiver), + safeTransaction.data.gasToken, + safeTransaction.data.refundReceiver, asHex(safeTransaction.encodedSignatures()) ] @@ -309,15 +309,15 @@ class SafeContract_v1_0_0 (await this.estimateGas( 'execTransaction', [ - asAddress(safeTransaction.data.to), + safeTransaction.data.to, BigInt(safeTransaction.data.value), asHex(safeTransaction.data.data), safeTransaction.data.operation, BigInt(safeTransaction.data.safeTxGas), BigInt(safeTransaction.data.baseGas), BigInt(safeTransaction.data.gasPrice), - asAddress(safeTransaction.data.gasToken), - asAddress(safeTransaction.data.refundReceiver), + safeTransaction.data.gasToken, + safeTransaction.data.refundReceiver, asHex(safeTransaction.encodedSignatures()) ], options @@ -325,19 +325,19 @@ class SafeContract_v1_0_0 const converted = await this.convertOptions({ ...options, gasLimit }) const txResult = await simulateContract(this.runner, { - address: asAddress(this.contractAddress), + address: this.contractAddress, functionName: 'execTransaction', abi: this.contractAbi, args: [ - asAddress(safeTransaction.data.to), + safeTransaction.data.to, BigInt(safeTransaction.data.value), asHex(safeTransaction.data.data), safeTransaction.data.operation, BigInt(safeTransaction.data.safeTxGas), BigInt(safeTransaction.data.baseGas), BigInt(safeTransaction.data.gasPrice), - asAddress(safeTransaction.data.gasToken), - asAddress(safeTransaction.data.refundReceiver), + safeTransaction.data.gasToken, + safeTransaction.data.refundReceiver, asHex(safeTransaction.encodedSignatures()) ], ...converted diff --git a/packages/protocol-kit/src/contracts/Safe/v1.1.1/SafeContract_v1_1_1.ts b/packages/protocol-kit/src/contracts/Safe/v1.1.1/SafeContract_v1_1_1.ts index cd7ac401d..8b25aa2d2 100644 --- a/packages/protocol-kit/src/contracts/Safe/v1.1.1/SafeContract_v1_1_1.ts +++ b/packages/protocol-kit/src/contracts/Safe/v1.1.1/SafeContract_v1_1_1.ts @@ -13,7 +13,7 @@ import { TransactionOptions, TransactionResult } from '@safe-global/safe-core-sdk-types' -import { asAddress, asHash, asHex } from '@safe-global/protocol-kit/utils/types' +import { asHash, asHex } from '@safe-global/protocol-kit/utils/types' import { ContractFunctionArgs } from 'viem' /** @@ -209,30 +209,30 @@ class SafeContract_v1_1_1 (await this.estimateGas( 'execTransaction', [ - asAddress(safeTransaction.data.to), + safeTransaction.data.to, BigInt(safeTransaction.data.value), asHex(safeTransaction.data.data), safeTransaction.data.operation, BigInt(safeTransaction.data.safeTxGas), BigInt(safeTransaction.data.baseGas), BigInt(safeTransaction.data.gasPrice), - asAddress(safeTransaction.data.gasToken), - asAddress(safeTransaction.data.refundReceiver), + safeTransaction.data.gasToken, + safeTransaction.data.refundReceiver, asHex(safeTransaction.encodedSignatures()) ], options )) const args: ContractFunctionArgs = [ - asAddress(safeTransaction.data.to), + safeTransaction.data.to, BigInt(safeTransaction.data.value), asHex(safeTransaction.data.data), safeTransaction.data.operation, BigInt(safeTransaction.data.safeTxGas), BigInt(safeTransaction.data.baseGas), BigInt(safeTransaction.data.gasPrice), - asAddress(safeTransaction.data.gasToken), - asAddress(safeTransaction.data.refundReceiver), + safeTransaction.data.gasToken, + safeTransaction.data.refundReceiver, asHex(safeTransaction.encodedSignatures()) ] @@ -272,15 +272,15 @@ class SafeContract_v1_1_1 (await this.estimateGas( 'execTransaction', [ - asAddress(safeTransaction.data.to), + safeTransaction.data.to, BigInt(safeTransaction.data.value), asHex(safeTransaction.data.data), safeTransaction.data.operation, BigInt(safeTransaction.data.safeTxGas), BigInt(safeTransaction.data.baseGas), BigInt(safeTransaction.data.gasPrice), - asAddress(safeTransaction.data.gasToken), - asAddress(safeTransaction.data.refundReceiver), + safeTransaction.data.gasToken, + safeTransaction.data.refundReceiver, asHex(safeTransaction.encodedSignatures()) ], options @@ -288,19 +288,19 @@ class SafeContract_v1_1_1 const converted = await this.convertOptions({ ...options, gasLimit }) const txResult = await simulateContract(this.runner, { - address: asAddress(this.contractAddress), + address: this.contractAddress, functionName: 'execTransaction', abi: this.contractAbi, args: [ - asAddress(safeTransaction.data.to), + safeTransaction.data.to, BigInt(safeTransaction.data.value), asHex(safeTransaction.data.data), safeTransaction.data.operation, BigInt(safeTransaction.data.safeTxGas), BigInt(safeTransaction.data.baseGas), BigInt(safeTransaction.data.gasPrice), - asAddress(safeTransaction.data.gasToken), - asAddress(safeTransaction.data.refundReceiver), + safeTransaction.data.gasToken, + safeTransaction.data.refundReceiver, asHex(safeTransaction.encodedSignatures()) ], ...converted diff --git a/packages/protocol-kit/src/contracts/Safe/v1.2.0/SafeContract_v1_2_0.ts b/packages/protocol-kit/src/contracts/Safe/v1.2.0/SafeContract_v1_2_0.ts index 4cebfc2b8..18d2b131c 100644 --- a/packages/protocol-kit/src/contracts/Safe/v1.2.0/SafeContract_v1_2_0.ts +++ b/packages/protocol-kit/src/contracts/Safe/v1.2.0/SafeContract_v1_2_0.ts @@ -12,7 +12,7 @@ import { TransactionOptions, TransactionResult } from '@safe-global/safe-core-sdk-types' -import { asAddress, asHash, asHex } from '@safe-global/protocol-kit/utils/types' +import { asHash, asHex } from '@safe-global/protocol-kit/utils/types' import { ContractFunctionArgs } from 'viem' /** @@ -218,30 +218,30 @@ class SafeContract_v1_2_0 (await this.estimateGas( 'execTransaction', [ - asAddress(safeTransaction.data.to), + safeTransaction.data.to, BigInt(safeTransaction.data.value), asHex(safeTransaction.data.data), safeTransaction.data.operation, BigInt(safeTransaction.data.safeTxGas), BigInt(safeTransaction.data.baseGas), BigInt(safeTransaction.data.gasPrice), - asAddress(safeTransaction.data.gasToken), - asAddress(safeTransaction.data.refundReceiver), + safeTransaction.data.gasToken, + safeTransaction.data.refundReceiver, asHex(safeTransaction.encodedSignatures()) ], options )) const args: ContractFunctionArgs = [ - asAddress(safeTransaction.data.to), + safeTransaction.data.to, BigInt(safeTransaction.data.value), asHex(safeTransaction.data.data), safeTransaction.data.operation, BigInt(safeTransaction.data.safeTxGas), BigInt(safeTransaction.data.baseGas), BigInt(safeTransaction.data.gasPrice), - asAddress(safeTransaction.data.gasToken), - asAddress(safeTransaction.data.refundReceiver), + safeTransaction.data.gasToken, + safeTransaction.data.refundReceiver, asHex(safeTransaction.encodedSignatures()) ] @@ -274,15 +274,15 @@ class SafeContract_v1_2_0 (await this.estimateGas( 'execTransaction', [ - asAddress(safeTransaction.data.to), + safeTransaction.data.to, BigInt(safeTransaction.data.value), asHex(safeTransaction.data.data), safeTransaction.data.operation, BigInt(safeTransaction.data.safeTxGas), BigInt(safeTransaction.data.baseGas), BigInt(safeTransaction.data.gasPrice), - asAddress(safeTransaction.data.gasToken), - asAddress(safeTransaction.data.refundReceiver), + safeTransaction.data.gasToken, + safeTransaction.data.refundReceiver, asHex(safeTransaction.encodedSignatures()) ], options @@ -290,19 +290,19 @@ class SafeContract_v1_2_0 const converted = await this.convertOptions({ ...options, gasLimit }) const txResult = await simulateContract(this.runner, { - address: asAddress(this.contractAddress), + address: this.contractAddress, functionName: 'execTransaction', abi: this.contractAbi, args: [ - asAddress(safeTransaction.data.to), + safeTransaction.data.to, BigInt(safeTransaction.data.value), asHex(safeTransaction.data.data), safeTransaction.data.operation, BigInt(safeTransaction.data.safeTxGas), BigInt(safeTransaction.data.baseGas), BigInt(safeTransaction.data.gasPrice), - asAddress(safeTransaction.data.gasToken), - asAddress(safeTransaction.data.refundReceiver), + safeTransaction.data.gasToken, + safeTransaction.data.refundReceiver, asHex(safeTransaction.encodedSignatures()) ], ...converted diff --git a/packages/protocol-kit/src/contracts/Safe/v1.3.0/SafeContract_v1_3_0.ts b/packages/protocol-kit/src/contracts/Safe/v1.3.0/SafeContract_v1_3_0.ts index 915501e91..abb71d16e 100644 --- a/packages/protocol-kit/src/contracts/Safe/v1.3.0/SafeContract_v1_3_0.ts +++ b/packages/protocol-kit/src/contracts/Safe/v1.3.0/SafeContract_v1_3_0.ts @@ -13,7 +13,7 @@ import { TransactionOptions, TransactionResult } from '@safe-global/safe-core-sdk-types' -import { asAddress, asHash, asHex } from '@safe-global/protocol-kit/utils/types' +import { asHash, asHex } from '@safe-global/protocol-kit/utils/types' import { ContractFunctionArgs } from 'viem' /** @@ -205,15 +205,15 @@ class SafeContract_v1_3_0 (await this.estimateGas( 'execTransaction', [ - asAddress(safeTransaction.data.to), + safeTransaction.data.to, BigInt(safeTransaction.data.value), asHex(safeTransaction.data.data), safeTransaction.data.operation, BigInt(safeTransaction.data.safeTxGas), BigInt(safeTransaction.data.baseGas), BigInt(safeTransaction.data.gasPrice), - asAddress(safeTransaction.data.gasToken), - asAddress(safeTransaction.data.refundReceiver), + safeTransaction.data.gasToken, + safeTransaction.data.refundReceiver, asHex(safeTransaction.encodedSignatures()) ], options @@ -221,19 +221,19 @@ class SafeContract_v1_3_0 const converted = await this.convertOptions({ ...options, gasLimit }) const txResult = await simulateContract(this.runner, { - address: asAddress(this.contractAddress), + address: this.contractAddress, functionName: 'execTransaction', abi: this.contractAbi, args: [ - asAddress(safeTransaction.data.to), + safeTransaction.data.to, BigInt(safeTransaction.data.value), asHex(safeTransaction.data.data), safeTransaction.data.operation, BigInt(safeTransaction.data.safeTxGas), BigInt(safeTransaction.data.baseGas), BigInt(safeTransaction.data.gasPrice), - asAddress(safeTransaction.data.gasToken), - asAddress(safeTransaction.data.refundReceiver), + safeTransaction.data.gasToken, + safeTransaction.data.refundReceiver, asHex(safeTransaction.encodedSignatures()) ], ...converted @@ -260,30 +260,30 @@ class SafeContract_v1_3_0 (await this.estimateGas( 'execTransaction', [ - asAddress(safeTransaction.data.to), + safeTransaction.data.to, BigInt(safeTransaction.data.value), asHex(safeTransaction.data.data), safeTransaction.data.operation, BigInt(safeTransaction.data.safeTxGas), BigInt(safeTransaction.data.baseGas), BigInt(safeTransaction.data.gasPrice), - asAddress(safeTransaction.data.gasToken), - asAddress(safeTransaction.data.refundReceiver), + safeTransaction.data.gasToken, + safeTransaction.data.refundReceiver, asHex(safeTransaction.encodedSignatures()) ], options )) const args: ContractFunctionArgs = [ - asAddress(safeTransaction.data.to), + safeTransaction.data.to, BigInt(safeTransaction.data.value), asHex(safeTransaction.data.data), safeTransaction.data.operation, BigInt(safeTransaction.data.safeTxGas), BigInt(safeTransaction.data.baseGas), BigInt(safeTransaction.data.gasPrice), - asAddress(safeTransaction.data.gasToken), - asAddress(safeTransaction.data.refundReceiver), + safeTransaction.data.gasToken, + safeTransaction.data.refundReceiver, asHex(safeTransaction.encodedSignatures()) ] diff --git a/packages/protocol-kit/src/contracts/Safe/v1.4.1/SafeContract_v1_4_1.ts b/packages/protocol-kit/src/contracts/Safe/v1.4.1/SafeContract_v1_4_1.ts index 55e8555b8..0fe749408 100644 --- a/packages/protocol-kit/src/contracts/Safe/v1.4.1/SafeContract_v1_4_1.ts +++ b/packages/protocol-kit/src/contracts/Safe/v1.4.1/SafeContract_v1_4_1.ts @@ -13,7 +13,7 @@ import { TransactionOptions, TransactionResult } from '@safe-global/safe-core-sdk-types' -import { asHash, asHex, asAddress } from '@safe-global/protocol-kit/utils/types' +import { asHash, asHex } from '@safe-global/protocol-kit/utils/types' import { ContractFunctionArgs } from 'viem' /** @@ -205,15 +205,15 @@ class SafeContract_v1_4_1 (await this.estimateGas( 'execTransaction', [ - asAddress(safeTransaction.data.to), + safeTransaction.data.to, BigInt(safeTransaction.data.value), asHex(safeTransaction.data.data), safeTransaction.data.operation, BigInt(safeTransaction.data.safeTxGas), BigInt(safeTransaction.data.baseGas), BigInt(safeTransaction.data.gasPrice), - asAddress(safeTransaction.data.gasToken), - asAddress(safeTransaction.data.refundReceiver), + safeTransaction.data.gasToken, + safeTransaction.data.refundReceiver, asHex(safeTransaction.encodedSignatures()) ], options @@ -221,19 +221,19 @@ class SafeContract_v1_4_1 const converted = await this.convertOptions({ ...options, gasLimit }) const txResult = await simulateContract(this.runner, { - address: asAddress(this.contractAddress), + address: this.contractAddress, functionName: 'execTransaction', abi: this.contractAbi, args: [ - asAddress(safeTransaction.data.to), + safeTransaction.data.to, BigInt(safeTransaction.data.value), asHex(safeTransaction.data.data), safeTransaction.data.operation, BigInt(safeTransaction.data.safeTxGas), BigInt(safeTransaction.data.baseGas), BigInt(safeTransaction.data.gasPrice), - asAddress(safeTransaction.data.gasToken), - asAddress(safeTransaction.data.refundReceiver), + safeTransaction.data.gasToken, + safeTransaction.data.refundReceiver, asHex(safeTransaction.encodedSignatures()) ], ...converted @@ -260,30 +260,30 @@ class SafeContract_v1_4_1 (await this.estimateGas( 'execTransaction', [ - asAddress(safeTransaction.data.to), + safeTransaction.data.to, BigInt(safeTransaction.data.value), asHex(safeTransaction.data.data), safeTransaction.data.operation, BigInt(safeTransaction.data.safeTxGas), BigInt(safeTransaction.data.baseGas), BigInt(safeTransaction.data.gasPrice), - asAddress(safeTransaction.data.gasToken), - asAddress(safeTransaction.data.refundReceiver), + safeTransaction.data.gasToken, + safeTransaction.data.refundReceiver, asHex(safeTransaction.encodedSignatures()) ], options )) const args: ContractFunctionArgs = [ - asAddress(safeTransaction.data.to), + safeTransaction.data.to, BigInt(safeTransaction.data.value), asHex(safeTransaction.data.data), safeTransaction.data.operation, BigInt(safeTransaction.data.safeTxGas), BigInt(safeTransaction.data.baseGas), BigInt(safeTransaction.data.gasPrice), - asAddress(safeTransaction.data.gasToken), - asAddress(safeTransaction.data.refundReceiver), + safeTransaction.data.gasToken, + safeTransaction.data.refundReceiver, asHex(safeTransaction.encodedSignatures()) ] diff --git a/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.0.0/SafeProxyFactoryContract_v1_0_0.ts b/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.0.0/SafeProxyFactoryContract_v1_0_0.ts index 250f2619a..6a78eafd8 100644 --- a/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.0.0/SafeProxyFactoryContract_v1_0_0.ts +++ b/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.0.0/SafeProxyFactoryContract_v1_0_0.ts @@ -11,7 +11,7 @@ import { safeProxyFactory_1_0_0_ContractArtifacts } from '@safe-global/safe-core-sdk-types' import { waitForTransactionReceipt } from '@safe-global/protocol-kit/utils' -import { asAddress, asHex } from '@safe-global/protocol-kit/utils/types' +import { asHex } from '@safe-global/protocol-kit/utils/types' import { ExternalClient } from '@safe-global/protocol-kit/types' /** @@ -115,7 +115,7 @@ class SafeProxyFactoryContract_v1_0_0 options.gasLimit = ( await this.estimateGas( 'createProxyWithNonce', - [asAddress(safeSingletonAddress), asHex(initializer), saltNonceBigInt], + [safeSingletonAddress, asHex(initializer), saltNonceBigInt], { ...options } ) ).toString() @@ -124,10 +124,10 @@ class SafeProxyFactoryContract_v1_0_0 const coverted = await this.convertOptions(options) const proxyAddress = await this.getWallet() .writeContract({ - address: asAddress(this.contractAddress), + address: this.contractAddress, abi: this.contractAbi, functionName: 'createProxyWithNonce', - args: [asAddress(safeSingletonAddress), asHex(initializer), saltNonceBigInt], + args: [safeSingletonAddress, asHex(initializer), saltNonceBigInt], ...coverted }) .then(async (hash) => { diff --git a/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.1.1/SafeProxyFactoryContract_v1_1_1.ts b/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.1.1/SafeProxyFactoryContract_v1_1_1.ts index dddec5875..936d3fb19 100644 --- a/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.1.1/SafeProxyFactoryContract_v1_1_1.ts +++ b/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.1.1/SafeProxyFactoryContract_v1_1_1.ts @@ -11,7 +11,7 @@ import { safeProxyFactory_1_1_1_ContractArtifacts } from '@safe-global/safe-core-sdk-types' import { waitForTransactionReceipt } from '@safe-global/protocol-kit/utils' -import { asHex, asAddress } from '@safe-global/protocol-kit/utils/types' +import { asHex } from '@safe-global/protocol-kit/utils/types' import { ExternalClient } from '@safe-global/protocol-kit/types' /** @@ -135,7 +135,7 @@ class SafeProxyFactoryContract_v1_1_1 options.gasLimit = ( await this.estimateGas( 'createProxyWithNonce', - [asAddress(safeSingletonAddress), asHex(initializer), saltNonceBigInt], + [safeSingletonAddress, asHex(initializer), saltNonceBigInt], { ...options } ) ).toString() @@ -144,10 +144,10 @@ class SafeProxyFactoryContract_v1_1_1 const coverted = await this.convertOptions(options) const proxyAddress = await this.getWallet() .writeContract({ - address: asAddress(this.contractAddress), + address: this.contractAddress, abi: this.contractAbi, functionName: 'createProxyWithNonce', - args: [asAddress(safeSingletonAddress), asHex(initializer), saltNonceBigInt], + args: [safeSingletonAddress, asHex(initializer), saltNonceBigInt], ...coverted }) .then(async (hash) => { diff --git a/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.3.0/SafeProxyFactoryContract_v1_3_0.ts b/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.3.0/SafeProxyFactoryContract_v1_3_0.ts index ec608aac6..f7ec52d3a 100644 --- a/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.3.0/SafeProxyFactoryContract_v1_3_0.ts +++ b/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.3.0/SafeProxyFactoryContract_v1_3_0.ts @@ -11,7 +11,7 @@ import { safeProxyFactory_1_3_0_ContractArtifacts } from '@safe-global/safe-core-sdk-types' import { waitForTransactionReceipt } from '@safe-global/protocol-kit/utils' -import { asAddress, asHex } from '@safe-global/protocol-kit/utils/types' +import { asHex } from '@safe-global/protocol-kit/utils/types' import { ExternalClient } from '@safe-global/protocol-kit/types' /** @@ -135,7 +135,7 @@ class SafeProxyFactoryContract_v1_3_0 options.gasLimit = ( await this.estimateGas( 'createProxyWithNonce', - [asAddress(safeSingletonAddress), asHex(initializer), saltNonceBigInt], + [safeSingletonAddress, asHex(initializer), saltNonceBigInt], { ...options } ) ).toString() @@ -144,10 +144,10 @@ class SafeProxyFactoryContract_v1_3_0 const coverted = await this.convertOptions(options) const proxyAddress = await this.getWallet() .writeContract({ - address: asAddress(this.contractAddress), + address: this.contractAddress, abi: this.contractAbi, functionName: 'createProxyWithNonce', - args: [asAddress(safeSingletonAddress), asHex(initializer), saltNonceBigInt], + args: [safeSingletonAddress, asHex(initializer), saltNonceBigInt], ...coverted }) .then(async (hash) => { diff --git a/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.4.1/SafeProxyFactoryContract_v1_4_1.ts b/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.4.1/SafeProxyFactoryContract_v1_4_1.ts index 48560f73b..ea33a43ec 100644 --- a/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.4.1/SafeProxyFactoryContract_v1_4_1.ts +++ b/packages/protocol-kit/src/contracts/SafeProxyFactory/v1.4.1/SafeProxyFactoryContract_v1_4_1.ts @@ -11,7 +11,7 @@ import { } from '@safe-global/safe-core-sdk-types' import SafeProvider from '@safe-global/protocol-kit/SafeProvider' import { waitForTransactionReceipt } from '@safe-global/protocol-kit/utils' -import { asAddress, asHex } from '@safe-global/protocol-kit/utils/types' +import { asHex } from '@safe-global/protocol-kit/utils/types' import { ExternalClient } from '@safe-global/protocol-kit/types' /** @@ -127,7 +127,7 @@ class SafeProxyFactoryContract_v1_4_1 options.gasLimit = ( await this.estimateGas( 'createProxyWithNonce', - [asAddress(safeSingletonAddress), asHex(initializer), saltNonceBigInt], + [safeSingletonAddress, asHex(initializer), saltNonceBigInt], { ...options } ) ).toString() @@ -136,10 +136,10 @@ class SafeProxyFactoryContract_v1_4_1 const coverted = await this.convertOptions(options) const proxyAddress = await this.getWallet() .writeContract({ - address: asAddress(this.contractAddress), + address: this.contractAddress, abi: this.contractAbi, functionName: 'createProxyWithNonce', - args: [asAddress(safeSingletonAddress), asHex(initializer), saltNonceBigInt], + args: [safeSingletonAddress, asHex(initializer), saltNonceBigInt], ...coverted }) .then(async (hash) => { diff --git a/packages/protocol-kit/src/contracts/utils.ts b/packages/protocol-kit/src/contracts/utils.ts index eb475403a..5170ce48a 100644 --- a/packages/protocol-kit/src/contracts/utils.ts +++ b/packages/protocol-kit/src/contracts/utils.ts @@ -19,7 +19,7 @@ import { TransactionResult } from '@safe-global/safe-core-sdk-types' import semverSatisfies from 'semver/functions/satisfies' -import { asAddress, asHex } from '../utils/types' +import { asHex } from '../utils/types' import { GetContractInstanceProps, GetSafeContractInstanceProps, @@ -85,7 +85,7 @@ export function encodeCreateProxyWithNonce( salt?: string ) { return safeProxyFactoryContract.encode('createProxyWithNonce', [ - asAddress(safeSingletonAddress), + safeSingletonAddress, asHex(initializer), BigInt(salt || PREDETERMINED_SALT_NONCE) ]) @@ -119,11 +119,11 @@ export async function encodeSetupCallData({ return safeContract.encode('setup', [ owners, threshold, - asAddress(to), + to, asHex(data), - asAddress(paymentToken), + paymentToken, payment, - asAddress(paymentReceiver) + paymentReceiver ]) } @@ -308,7 +308,7 @@ export async function predictSafeAddress({ const input = safeProvider.encodeParameters('address', [safeContract.getAddress()]) - const from = asAddress(safeProxyFactoryContract.getAddress()) + const from = safeProxyFactoryContract.getAddress() // On the zkSync Era chain, the counterfactual deployment address is calculated differently const isZkSyncEraChain = [ZKSYNC_MAINNET, ZKSYNC_TESTNET].includes(chainId) @@ -346,7 +346,7 @@ export const validateSafeDeploymentConfig = ({ saltNonce }: SafeDeploymentConfig * Generates a zkSync Era address. zkSync Era uses a distinct address derivation method compared to Ethereum * see: https://docs.zksync.io/build/developer-reference/ethereum-differences/evm-instructions/#address-derivation * - * @param {`0x${string}`} from - The sender's address. + * @param {`string`} from - The sender's address. * @param {SafeVersion} safeVersion - The version of the safe. * @param {`0x${string}`} salt - The salt used for address derivation. * @param {`0x${string}`} input - Additional input data for the derivation. @@ -354,7 +354,7 @@ export const validateSafeDeploymentConfig = ({ saltNonce }: SafeDeploymentConfig * @returns {string} The derived zkSync Era address. */ export function zkSyncEraCreate2Address( - from: `0x${string}`, + from: string, safeVersion: SafeVersion, salt: `0x${string}`, input: `0x${string}` @@ -363,7 +363,7 @@ export function zkSyncEraCreate2Address( const inputHash = keccak256(input) const addressBytes = keccak256( - concat([ZKSYNC_CREATE2_PREFIX, pad(from), salt, bytecodeHash, inputHash]) + concat([ZKSYNC_CREATE2_PREFIX, pad(asHex(from)), salt, bytecodeHash, inputHash]) ).slice(26) return addressBytes diff --git a/packages/protocol-kit/src/managers/fallbackHandlerManager.ts b/packages/protocol-kit/src/managers/fallbackHandlerManager.ts index 3d476c3df..d2107148d 100644 --- a/packages/protocol-kit/src/managers/fallbackHandlerManager.ts +++ b/packages/protocol-kit/src/managers/fallbackHandlerManager.ts @@ -8,7 +8,6 @@ import { import { ZERO_ADDRESS } from '@safe-global/protocol-kit/utils/constants' import { SafeContractImplementationType } from '@safe-global/protocol-kit/types' import SafeProvider from '../SafeProvider' -import { asAddress } from '../utils/types' class FallbackHandlerManager { #safeProvider: SafeProvider @@ -70,7 +69,7 @@ class FallbackHandlerManager { const currentFallbackHandler = await this.getFallbackHandler() this.validateFallbackHandlerIsNotEnabled(currentFallbackHandler, fallbackHandlerAddress) - return safeContract.encode('setFallbackHandler', [asAddress(fallbackHandlerAddress)]) + return safeContract.encode('setFallbackHandler', [fallbackHandlerAddress]) } async encodeDisableFallbackHandlerData(): Promise { diff --git a/packages/protocol-kit/src/managers/guardManager.ts b/packages/protocol-kit/src/managers/guardManager.ts index 7beabeec9..fbb8b5c6b 100644 --- a/packages/protocol-kit/src/managers/guardManager.ts +++ b/packages/protocol-kit/src/managers/guardManager.ts @@ -8,7 +8,6 @@ import { import { ZERO_ADDRESS } from '@safe-global/protocol-kit/utils/constants' import { SafeContractImplementationType } from '@safe-global/protocol-kit/types' import SafeProvider from '../SafeProvider' -import { asAddress } from '../utils/types' class GuardManager { #safeProvider: SafeProvider @@ -66,7 +65,7 @@ class GuardManager { this.validateGuardAddress(guardAddress) const currentGuard = await this.getGuard() this.validateGuardIsNotEnabled(currentGuard, guardAddress) - return safeContract.encode('setGuard', [asAddress(guardAddress)]) + return safeContract.encode('setGuard', [guardAddress]) } async encodeDisableGuardData(): Promise { diff --git a/packages/protocol-kit/src/managers/moduleManager.ts b/packages/protocol-kit/src/managers/moduleManager.ts index c7150254f..f90d626fc 100644 --- a/packages/protocol-kit/src/managers/moduleManager.ts +++ b/packages/protocol-kit/src/managers/moduleManager.ts @@ -5,7 +5,6 @@ import { SafeModulesPaginated } from '@safe-global/protocol-kit/types' import SafeProvider from '../SafeProvider' -import { asAddress } from '../utils/types' class ModuleManager { #safeProvider: SafeProvider @@ -55,10 +54,7 @@ class ModuleManager { throw new Error('Safe is not deployed') } - const [modules, next] = await this.#safeContract.getModulesPaginated([ - asAddress(start), - BigInt(pageSize) - ]) + const [modules, next] = await this.#safeContract.getModulesPaginated([start, BigInt(pageSize)]) return { modules: modules as string[], next } } @@ -67,7 +63,7 @@ class ModuleManager { throw new Error('Safe is not deployed') } - const [isModuleEnabled] = await this.#safeContract.isModuleEnabled([asAddress(moduleAddress)]) + const [isModuleEnabled] = await this.#safeContract.isModuleEnabled([moduleAddress]) return isModuleEnabled } diff --git a/packages/protocol-kit/src/managers/ownerManager.ts b/packages/protocol-kit/src/managers/ownerManager.ts index 6cb1aa424..6ede3460b 100644 --- a/packages/protocol-kit/src/managers/ownerManager.ts +++ b/packages/protocol-kit/src/managers/ownerManager.ts @@ -2,7 +2,6 @@ import { isRestrictedAddress, sameString } from '@safe-global/protocol-kit/utils import { SENTINEL_ADDRESS } from '@safe-global/protocol-kit/utils/constants' import { SafeContractImplementationType } from '../types' import SafeProvider from '../SafeProvider' -import { asAddress } from '../utils/types' class OwnerManager { #safeProvider: SafeProvider @@ -77,7 +76,7 @@ class OwnerManager { throw new Error('Safe is not deployed') } - const [isOwner] = await this.#safeContract.isOwner([asAddress(ownerAddress)]) + const [isOwner] = await this.#safeContract.isOwner([ownerAddress]) return isOwner } diff --git a/packages/protocol-kit/src/utils/transactions/gas.ts b/packages/protocol-kit/src/utils/transactions/gas.ts index 0cef75951..87b74ac70 100644 --- a/packages/protocol-kit/src/utils/transactions/gas.ts +++ b/packages/protocol-kit/src/utils/transactions/gas.ts @@ -16,7 +16,7 @@ import { isSafeContractCompatibleWithRequiredTxGas, isSafeContractCompatibleWithSimulateAndRevert } from '../safeVersions' -import { asAddress, asHex } from '../types' +import { asHex } from '../types' // Every byte == 00 -> 4 Gas cost const CALL_DATA_ZERO_BYTE_GAS_COST = 4 @@ -80,7 +80,7 @@ export async function estimateGas( }) const transactionDataToEstimate = simulateTxAccessorContract.encode('simulate', [ - asAddress(to), + to, BigInt(valueInWei), asHex(data), operation @@ -91,7 +91,7 @@ export async function estimateGas( const safeFunctionToEstimate = safeContractContractCompatibleWithSimulateAndRevert.encode( 'simulateAndRevert', - [asAddress(simulateTxAccessorContract.getAddress()), asHex(transactionDataToEstimate)] + [simulateTxAccessorContract.getAddress(), asHex(transactionDataToEstimate)] ) const safeAddress = safeContract.getAddress() const transactionToEstimateGas = { @@ -302,7 +302,7 @@ async function estimateSafeTxGasWithRequiredTxGas( const transactionDataToEstimate: string = safeContractCompatibleWithRequiredTxGas.encode( 'requiredTxGas', [ - asAddress(safeTransaction.data.to), + safeTransaction.data.to, BigInt(safeTransaction.data.value), asHex(safeTransaction.data.data), safeTransaction.data.operation @@ -371,7 +371,7 @@ function isEthersError(error: EstimationError): error is EthersEstimationError { } function isViemError(error: EstimationError): error is ViemEstimationError { - return (error as ViemEstimationError).version.includes('viem') + return error instanceof BaseError } function isGnosisChainEstimationError(error: EstimationError): error is GnosisChainEstimationError { @@ -457,7 +457,7 @@ async function estimateSafeTxGasWithSimulate( }) const transactionDataToEstimate: string = simulateTxAccessorContract.encode('simulate', [ - asAddress(safeTransaction.data.to), + safeTransaction.data.to, BigInt(safeTransaction.data.value), asHex(safeTransaction.data.data), safeTransaction.data.operation @@ -471,7 +471,7 @@ async function estimateSafeTxGasWithSimulate( const safeFunctionToEstimate: string = SafeContractCompatibleWithSimulateAndRevert.encode( 'simulateAndRevert', - [asAddress(simulateTxAccessorContract.getAddress()), asHex(transactionDataToEstimate)] + [simulateTxAccessorContract.getAddress(), asHex(transactionDataToEstimate)] ) const transactionToEstimateGas = { diff --git a/packages/protocol-kit/src/utils/transactions/utils.ts b/packages/protocol-kit/src/utils/transactions/utils.ts index a003b3eb7..c45c13a8a 100644 --- a/packages/protocol-kit/src/utils/transactions/utils.ts +++ b/packages/protocol-kit/src/utils/transactions/utils.ts @@ -6,7 +6,7 @@ import { } from '@safe-global/protocol-kit/types' import { hasSafeFeature, SAFE_FEATURES } from '@safe-global/protocol-kit/utils' import { ZERO_ADDRESS } from '@safe-global/protocol-kit/utils/constants' -import { asAddress, asHex } from '../types' +import { asHex } from '../types' import { MetaTransactionData, OperationType, @@ -136,7 +136,7 @@ function encodeMetaTransaction(tx: MetaTransactionData): string { ['uint8', 'address', 'uint256', 'uint256', 'bytes'], [ tx.operation ?? OperationType.Call, - asAddress(tx.to), + tx.to, BigInt(tx.value), BigInt(data.length), bytesToHex(data) @@ -200,7 +200,7 @@ export function toEstimateGasParameters(tx: SafeProviderTransaction): EstimateGa } if (tx.to) { - params.to = asAddress(tx.to) + params.to = tx.to } if (tx.data) { @@ -218,7 +218,7 @@ export function toCallGasParameters( : createTxOptions(tx) if (tx.to) { - params.to = asAddress(tx.to) + params.to = tx.to } if (tx.data) { @@ -243,7 +243,7 @@ export function createLegacyTxOptions( ): Partial { const converted: Partial = {} if (options?.from) { - converted.account = asAddress(options.from) + converted.account = options.from } if (options?.gasLimit) { @@ -264,7 +264,7 @@ export function createLegacyTxOptions( export function createTxOptions(options?: TransactionOptions): Partial { const converted: Partial = {} if (options?.from) { - converted.account = asAddress(options.from) + converted.account = options.from } if (options?.gasLimit) { diff --git a/packages/protocol-kit/src/utils/types.ts b/packages/protocol-kit/src/utils/types.ts index 4b2f12fbe..f939c0b22 100644 --- a/packages/protocol-kit/src/utils/types.ts +++ b/packages/protocol-kit/src/utils/types.ts @@ -1,5 +1,5 @@ import { SafeConfig, SafeConfigWithPredictedSafe } from '../types' -import { getAddress, Address, isHex, Hex, Hash, Chain, defineChain, etherUnits } from 'viem' +import { isHex, Hex, Hash, Chain, defineChain, etherUnits } from 'viem' import * as allChains from 'viem/chains' export function isSafeConfigWithPredictedSafe( @@ -8,14 +8,6 @@ export function isSafeConfigWithPredictedSafe( return (config as unknown as SafeConfigWithPredictedSafe).predictedSafe !== undefined } -export function asAddresses(addresses: string[]): Address[] { - return addresses.map(asAddress) -} - -export function asAddress(address: string): Address { - return getAddress(address) -} - export function asHash(hash: string): Hash { return hash as Hash } diff --git a/packages/protocol-kit/tests/e2e/core.test.ts b/packages/protocol-kit/tests/e2e/core.test.ts index 975fadca1..d1bd27877 100644 --- a/packages/protocol-kit/tests/e2e/core.test.ts +++ b/packages/protocol-kit/tests/e2e/core.test.ts @@ -10,7 +10,6 @@ import { getSafeWithOwners } from './utils/setupContracts' import { getEip1193Provider } from './utils/setupProvider' import { getAccounts } from './utils/setupTestNetwork' import { waitSafeTxReceipt } from './utils/transactions' -import { asAddress } from '@safe-global/protocol-kit/utils/types' import { waitTransactionReceipt } from './utils/transactions' import { sameString } from '@safe-global/protocol-kit/utils' @@ -331,7 +330,7 @@ describe('Safe Info', () => { chai.expect(await safeSdk.getBalance()).to.be.eq(0n) const hash = await account1.signer.sendTransaction({ - to: asAddress(await safeSdk.getAddress()), + to: await safeSdk.getAddress(), value: BigInt(`${1e18}`) }) await waitTransactionReceipt(hash) diff --git a/packages/protocol-kit/tests/e2e/utils/setupContracts.ts b/packages/protocol-kit/tests/e2e/utils/setupContracts.ts index 76051bd08..669da0752 100644 --- a/packages/protocol-kit/tests/e2e/utils/setupContracts.ts +++ b/packages/protocol-kit/tests/e2e/utils/setupContracts.ts @@ -1,5 +1,5 @@ import { ZERO_ADDRESS } from '@safe-global/protocol-kit/utils/constants' -import { Address, GetContractReturnType, Abi, WalletClient } from 'viem' +import { GetContractReturnType, Abi, WalletClient } from 'viem' import { compatibilityFallbackHandlerDeployed, createCallDeployed, @@ -14,7 +14,6 @@ import { import { deployments, viem } from 'hardhat' import semverSatisfies from 'semver/functions/satisfies' import { getDeployer, waitTransactionReceipt } from './transactions' -import { asAddress } from '@safe-global/protocol-kit/utils/types' // TODO: changue contract por abitype objts export const getSafeSingleton = async (): Promise<{ @@ -22,7 +21,7 @@ export const getSafeSingleton = async (): Promise<{ abi: Abi }> => { const safeDeployment = await deployments.get(safeDeployed.name) - const contract = await viem.getContractAt(safeDeployed.name, asAddress(safeDeployment.address)) + const contract = await viem.getContractAt(safeDeployed.name, safeDeployment.address) return { contract, abi: safeDeployment.abi @@ -34,8 +33,8 @@ export const getFactory = async (): Promise<{ abi: Abi }> => { const factoryDeployment = await deployments.get(proxyFactoryDeployed.name) - const factoryAddress = asAddress(factoryDeployment.address) - const contract = await viem.getContractAt(proxyFactoryDeployed.name, asAddress(factoryAddress), { + const factoryAddress = factoryDeployment.address + const contract = await viem.getContractAt(proxyFactoryDeployed.name, factoryAddress, { client: { wallet: await getDeployer() } }) return { @@ -57,7 +56,7 @@ export const getSafeTemplate = async (): Promise => { const multiSendDeployment = await deployments.get(multiSendDeployed.name) - const multiSendAddress = asAddress(multiSendDeployment.address) + const multiSendAddress = multiSendDeployment.address const contract = await viem.getContractAt(multiSendDeployed.name, multiSendAddress) return { contract, @@ -129,7 +128,7 @@ export const getMultiSendCallOnly = async (): Promise<{ abi: Abi }> => { const multiSendCallOnlyDeployment = await deployments.get(multiSendCallOnlyDeployed.name) - const multiSendAddress = asAddress(multiSendCallOnlyDeployment.address) + const multiSendAddress = multiSendCallOnlyDeployment.address const contract = await viem.getContractAt(multiSendCallOnlyDeployed.name, multiSendAddress) return { contract, @@ -142,7 +141,7 @@ export const getSignMessageLib = async (): Promise<{ abi: Abi }> => { const signMessageLibDeployment = await deployments.get(signMessageLibDeployed.name) - const signMessageLibAddress = asAddress(signMessageLibDeployment.address) + const signMessageLibAddress = signMessageLibDeployment.address const contract = await viem.getContractAt(signMessageLibDeployed.name, signMessageLibAddress) return { contract, @@ -155,7 +154,7 @@ export const getCreateCall = async (): Promise<{ abi: Abi }> => { const createCallDeployment = await deployments.get(createCallDeployed.name) - const createCallAddress = asAddress(createCallDeployment.address) + const createCallAddress = createCallDeployment.address const contract = await viem.getContractAt(createCallDeployed.name, createCallAddress) return { contract, @@ -168,7 +167,7 @@ export const getSimulateTxAccessor = async (): Promise<{ abi: Abi }> => { const simulateTxAccessorDeployment = await deployments.get(simulateTxAccessorDeployed.name) - const simulateTxAccessorAddress = asAddress(simulateTxAccessorDeployment.address) + const simulateTxAccessorAddress = simulateTxAccessorDeployment.address const contract = await viem.getContractAt( simulateTxAccessorDeployed.name, simulateTxAccessorAddress @@ -181,31 +180,31 @@ export const getSimulateTxAccessor = async (): Promise<{ export const getDailyLimitModule = async (): Promise> => { const dailyLimitModuleDeployment = await deployments.get('DailyLimitModule') - const dailyLimitModuleAddress = asAddress(dailyLimitModuleDeployment.address) + const dailyLimitModuleAddress = dailyLimitModuleDeployment.address return await viem.getContractAt('DailyLimitModule', dailyLimitModuleAddress) } export const getSocialRecoveryModule = async (): Promise> => { const socialRecoveryModuleDeployment = await deployments.get('SocialRecoveryModule') - const socialRecoveryModuleAddress = asAddress(socialRecoveryModuleDeployment.address) + const socialRecoveryModuleAddress = socialRecoveryModuleDeployment.address return await viem.getContractAt('SocialRecoveryModule', socialRecoveryModuleAddress) } export const getStateChannelModule = async (): Promise> => { const stateChannelModuleDeployment = await deployments.get('StateChannelModule') - const stateChannelModuleAddress = asAddress(stateChannelModuleDeployment.address) + const stateChannelModuleAddress = stateChannelModuleDeployment.address return await viem.getContractAt('StateChannelModule', stateChannelModuleAddress) } export const getWhiteListModule = async (): Promise> => { const whiteListModuleDeployment = await deployments.get('WhitelistModule') - const whiteListModuleAddress = asAddress(whiteListModuleDeployment.address) + const whiteListModuleAddress = whiteListModuleDeployment.address return await viem.getContractAt('WhitelistModule', whiteListModuleAddress) } export const getERC20Mintable = async (): Promise> => { const eRC20MintableDeployment = await deployments.get('ERC20Mintable') - const eRC20MintableAddress = asAddress(eRC20MintableDeployment.address) + const eRC20MintableAddress = eRC20MintableDeployment.address return await viem.getContractAt('ERC20Mintable', eRC20MintableAddress, { client: { wallet: await getDeployer() } }) @@ -216,7 +215,7 @@ export const getDebugTransactionGuard = async (): Promise> { const { deployer } = await hre.getNamedAccounts() - return viem.getWalletClient(asAddress(deployer)) + return viem.getWalletClient(deployer) } diff --git a/packages/relay-kit/package.json b/packages/relay-kit/package.json index 8e956c081..f54f8c4fc 100644 --- a/packages/relay-kit/package.json +++ b/packages/relay-kit/package.json @@ -42,6 +42,6 @@ "@safe-global/protocol-kit": "^4.0.3", "@safe-global/safe-core-sdk-types": "^5.0.3", "@safe-global/safe-modules-deployments": "^2.1.1", - "viem": "^2.16.1" + "viem": "^2.19.0" } } diff --git a/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.ts b/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.ts index fc272c2ac..f11c52181 100644 --- a/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.ts +++ b/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.ts @@ -1,4 +1,3 @@ -import { Address, Hash, encodeFunctionData, zeroAddress, Hex, concat } from 'viem' import semverSatisfies from 'semver/functions/satisfies' import Safe, { EthSafeSignature, @@ -21,6 +20,7 @@ import { getAddModulesLibDeployment, getSafe4337ModuleDeployment } from '@safe-global/safe-modules-deployments' +import { Hash, encodeFunctionData, zeroAddress, Hex, concat } from 'viem' import EthSafeOperation from './SafeOperation' import { EstimateFeeProps, @@ -141,7 +141,7 @@ export class Safe4337Pack extends RelayKitBasePack<{ version: safeModulesVersion, network }) - addModulesLibAddress = addModulesDeployment?.networkAddresses[network] as Address | undefined + addModulesLibAddress = addModulesDeployment?.networkAddresses[network] as string | undefined } let safe4337ModuleAddress = customContracts?.safe4337ModuleAddress @@ -204,7 +204,7 @@ export class Safe4337Pack extends RelayKitBasePack<{ let deploymentData = encodeFunctionData({ abi: ABI, functionName: 'enableModules', - args: [[safe4337ModuleAddress as Address]] + args: [[safe4337ModuleAddress]] }) const isApproveTransactionRequired = @@ -221,7 +221,7 @@ export class Safe4337Pack extends RelayKitBasePack<{ data: encodeFunctionData({ abi: ABI, functionName: 'enableModules', - args: [[safe4337ModuleAddress as Address]] + args: [[safe4337ModuleAddress]] }), operation: OperationType.DelegateCall // DelegateCall required for enabling the 4337 module } @@ -231,7 +231,7 @@ export class Safe4337Pack extends RelayKitBasePack<{ data: encodeFunctionData({ abi: ABI, functionName: 'approve', - args: [paymasterAddress as Address, amountToApprove] + args: [paymasterAddress, amountToApprove] }), value: '0', operation: OperationType.Call // Call for approve @@ -250,7 +250,7 @@ export class Safe4337Pack extends RelayKitBasePack<{ safeVersion: options.safeVersion || DEFAULT_SAFE_VERSION }) - deploymentTo = multiSendContract.getAddress() as Address + deploymentTo = multiSendContract.getAddress() deploymentData = batchData } @@ -279,9 +279,7 @@ export class Safe4337Pack extends RelayKitBasePack<{ let selectedEntryPoint if (customContracts?.entryPointAddress) { - const requiredSafeModulesVersion = entryPointToSafeModules( - customContracts?.entryPointAddress as Address - ) + const requiredSafeModulesVersion = entryPointToSafeModules(customContracts?.entryPointAddress) if (!semverSatisfies(safeModulesVersion, requiredSafeModulesVersion)) throw new Error( `The selected entrypoint ${customContracts?.entryPointAddress} is not compatible with version ${safeModulesVersion} of Safe modules` @@ -405,7 +403,7 @@ export class Safe4337Pack extends RelayKitBasePack<{ transactions, options = {} }: Safe4337CreateTransactionProps): Promise { - const safeAddress = (await this.protocolKit.getAddress()) as Address + const safeAddress = await this.protocolKit.getAddress() const nonce = await this.#getSafeNonceFromEntrypoint(safeAddress) const { amountToApprove, validUntil, validAfter, feeEstimator } = options @@ -421,7 +419,7 @@ export class Safe4337Pack extends RelayKitBasePack<{ data: encodeFunctionData({ abi: ABI, functionName: 'approve', - args: [paymasterOptions.paymasterAddress as Address, amountToApprove] + args: [paymasterOptions.paymasterAddress, amountToApprove] }), value: '0', operation: OperationType.Call // Call for approve @@ -490,8 +488,8 @@ export class Safe4337Pack extends RelayKitBasePack<{ #toSafeOperation(safeOperationResponse: SafeOperationResponse): EthSafeOperation { const { validUntil, validAfter, userOperation } = safeOperationResponse - const paymaster = userOperation?.paymaster || '0x' - const paymasterData = userOperation?.paymasterData || '0x' + const paymaster = (userOperation?.paymaster as Hex) || '0x' + const paymasterData = (userOperation?.paymasterData as Hex) || '0x' const safeOperation = new EthSafeOperation( { sender: userOperation?.sender || '0x', @@ -503,7 +501,7 @@ export class Safe4337Pack extends RelayKitBasePack<{ preVerificationGas: BigInt(userOperation?.preVerificationGas || 0), maxFeePerGas: BigInt(userOperation?.maxFeePerGas || 0), maxPriorityFeePerGas: BigInt(userOperation?.maxPriorityFeePerGas || 0), - paymasterAndData: concat([paymaster as Address, paymasterData as Hex]), + paymasterAndData: concat([paymaster, paymasterData]), signature: safeOperationResponse.preparedSignature || '0x' }, { @@ -685,10 +683,10 @@ export class Safe4337Pack extends RelayKitBasePack<{ const safeProvider = this.protocolKit.getSafeProvider() const newNonce = await safeProvider.readContract({ - address: (this.#ENTRYPOINT_ADDRESS as Address) || '0x', + address: this.#ENTRYPOINT_ADDRESS || '0x', abi: ENTRYPOINT_ABI, functionName: 'getNonce', - args: [safeAddress as Address, 0n] + args: [safeAddress, 0n] }) return newNonce.toString() @@ -705,7 +703,7 @@ export class Safe4337Pack extends RelayKitBasePack<{ abi: ABI, functionName: 'executeUserOp', args: [ - transaction.to as Address, + transaction.to, BigInt(transaction.value), transaction.data as Hex, transaction.operation || OperationType.Call diff --git a/packages/relay-kit/src/packs/safe-4337/SafeOperation.ts b/packages/relay-kit/src/packs/safe-4337/SafeOperation.ts index eaec3b908..aba890116 100644 --- a/packages/relay-kit/src/packs/safe-4337/SafeOperation.ts +++ b/packages/relay-kit/src/packs/safe-4337/SafeOperation.ts @@ -1,4 +1,4 @@ -import { Address, Hex, encodePacked, toHex } from 'viem' +import { Hex, encodePacked, toHex } from 'viem' import { EstimateGasData, SafeOperation, @@ -92,7 +92,7 @@ class EthSafeOperation implements SafeOperation { } getHash(): string { - return calculateSafeUserOperationHash(this.data, this.chainId, this.moduleAddress as Address) + return calculateSafeUserOperationHash(this.data, this.chainId, this.moduleAddress) } } diff --git a/packages/relay-kit/src/packs/safe-4337/testing-utils/helpers.ts b/packages/relay-kit/src/packs/safe-4337/testing-utils/helpers.ts index e44addd04..15f7d29f6 100644 --- a/packages/relay-kit/src/packs/safe-4337/testing-utils/helpers.ts +++ b/packages/relay-kit/src/packs/safe-4337/testing-utils/helpers.ts @@ -1,4 +1,4 @@ -import { Address, encodeFunctionData, parseAbi } from 'viem' +import { encodeFunctionData, parseAbi } from 'viem' import { Safe4337InitOptions } from '../types' import { Safe4337Pack } from '../Safe4337Pack' import * as fixtures from './fixtures' @@ -9,7 +9,7 @@ export const generateTransferCallData = (to: string, value: bigint) => { return encodeFunctionData({ abi: functionAbi, functionName: 'transfer', - args: [to as Address, value] + args: [to, value] }) } diff --git a/packages/relay-kit/src/packs/safe-4337/utils.ts b/packages/relay-kit/src/packs/safe-4337/utils.ts index b9e1adb93..de86dc8ef 100644 --- a/packages/relay-kit/src/packs/safe-4337/utils.ts +++ b/packages/relay-kit/src/packs/safe-4337/utils.ts @@ -1,5 +1,4 @@ import { - Address, Hex, createPublicClient, encodeFunctionData, @@ -64,7 +63,7 @@ export async function signSafeOp( const signature = await signer.signTypedData({ domain: { chainId: Number(chainId), - verifyingContract: safe4337ModuleAddress as Address + verifyingContract: safe4337ModuleAddress }, types: EIP712_SAFE_OPERATION_TYPE, message: { @@ -115,7 +114,7 @@ export function calculateSafeUserOperationHash( return hashTypedData({ domain: { chainId: Number(chainId), - verifyingContract: safe4337ModuleAddress as Address + verifyingContract: safe4337ModuleAddress }, types: EIP712_SAFE_OPERATION_TYPE, primaryType: 'SafeOp', diff --git a/packages/relay-kit/src/packs/safe-4337/utils/entrypoint.ts b/packages/relay-kit/src/packs/safe-4337/utils/entrypoint.ts index e3d472504..3626f3859 100644 --- a/packages/relay-kit/src/packs/safe-4337/utils/entrypoint.ts +++ b/packages/relay-kit/src/packs/safe-4337/utils/entrypoint.ts @@ -1,4 +1,3 @@ -import { Address } from 'viem' import { ENTRYPOINT_ADDRESS_V06, ENTRYPOINT_ADDRESS_V07 } from '../constants' const EQ_0_2_0 = '0.2.0' @@ -9,8 +8,8 @@ export function sameString(str1: string, str2: string): boolean { return str1.toLowerCase() === str2.toLowerCase() } -export function entryPointToSafeModules(entryPoint: Address) { - const moduleVersionToEntryPoint: Record = { +export function entryPointToSafeModules(entryPoint: string) { + const moduleVersionToEntryPoint: Record = { [ENTRYPOINT_ADDRESS_V06]: EQ_0_2_0, [ENTRYPOINT_ADDRESS_V07]: EQ_OR_GT_0_3_0 } diff --git a/packages/safe-core-sdk-types/package.json b/packages/safe-core-sdk-types/package.json index 3fbae77f2..93cfeb836 100644 --- a/packages/safe-core-sdk-types/package.json +++ b/packages/safe-core-sdk-types/package.json @@ -31,6 +31,7 @@ ], "homepage": "https://github.com/safe-global/safe-core-sdk#readme", "dependencies": { - "abitype": "^1.0.2" + "abitype": "^1.0.2", + "viem": "^2.19.0" } } diff --git a/packages/safe-core-sdk-types/src/index.ts b/packages/safe-core-sdk-types/src/index.ts index b24debaf7..e7cc0555c 100644 --- a/packages/safe-core-sdk-types/src/index.ts +++ b/packages/safe-core-sdk-types/src/index.ts @@ -8,3 +8,21 @@ export * from './contracts/SimulateTxAccessor' export * from './contracts/common/BaseContract' export * from './contracts/assets' export * from './types' + +// see docs: https://abitype.dev/config +declare module 'abitype' { + export interface Register { + // AddressType: `0x${string}` + // BytesType: { + // inputs: `0x${string}` | Uint8Array + // outputs: `0x${string}` + // } + AddressType: string + } +} + +declare module 'viem/node_modules/abitype' { + export interface Register { + AddressType: string + } +} diff --git a/packages/safe-core-sdk-types/src/types.ts b/packages/safe-core-sdk-types/src/types.ts index 6e7361731..7405d0ca7 100644 --- a/packages/safe-core-sdk-types/src/types.ts +++ b/packages/safe-core-sdk-types/src/types.ts @@ -1,3 +1,5 @@ +export { type Hex } from 'viem' + export type SafeVersion = '1.4.1' | '1.3.0' | '1.2.0' | '1.1.1' | '1.0.0' export enum OperationType { diff --git a/packages/safe-kit/package.json b/packages/safe-kit/package.json index e91368ba0..18c18259a 100644 --- a/packages/safe-kit/package.json +++ b/packages/safe-kit/package.json @@ -38,6 +38,6 @@ "@safe-global/protocol-kit": "^4.0.3", "@safe-global/relay-kit": "^3.0.3", "@safe-global/safe-core-sdk-types": "^5.0.3", - "viem": "^2.15.1" + "viem": "^2.19.0" } } diff --git a/packages/safe-kit/src/utils/sendTransaction.ts b/packages/safe-kit/src/utils/sendTransaction.ts index d8aede050..f4992c2ec 100644 --- a/packages/safe-kit/src/utils/sendTransaction.ts +++ b/packages/safe-kit/src/utils/sendTransaction.ts @@ -1,4 +1,4 @@ -import { Address, WalletClient, Transport, Chain, Hex, Account } from 'viem' +import { WalletClient, Transport, Chain, Hex, Account } from 'viem' import { waitForTransactionReceipt } from 'viem/actions' import Safe from '@safe-global/protocol-kit' import { Transaction } from '@safe-global/safe-core-sdk-types' @@ -29,7 +29,7 @@ export const sendTransaction = async ({ throw new Error('SafeProvider must be initialized with a signer to use this function') const hash = await signer.sendTransaction({ - to: transaction.to as Address, + to: transaction.to, data: transaction.data as Hex, value: BigInt(transaction.value), account: signer.account diff --git a/playground/relay-kit/paid-transaction.ts b/playground/relay-kit/paid-transaction.ts index f7a170087..210c1f518 100644 --- a/playground/relay-kit/paid-transaction.ts +++ b/playground/relay-kit/paid-transaction.ts @@ -76,7 +76,7 @@ async function main() { }) // Calculate Safe address - const predictedSafeAddress = (await gelatoSafeClient.protocolKit.getAddress()) as Address + const predictedSafeAddress = (await gelatoSafeClient.protocolKit.getAddress()) console.log({ predictedSafeAddress }) const isSafeDeployed = await gelatoSafeClient.protocolKit.isSafeDeployed() diff --git a/playground/relay-kit/sponsored-transaction.ts b/playground/relay-kit/sponsored-transaction.ts index 4d0093fb1..469fa7510 100644 --- a/playground/relay-kit/sponsored-transaction.ts +++ b/playground/relay-kit/sponsored-transaction.ts @@ -78,7 +78,7 @@ async function main() { // Calculate Safe address - const predictedSafeAddress = (await gelatoSafeClient.protocolKit.getAddress()) as Address + const predictedSafeAddress = (await gelatoSafeClient.protocolKit.getAddress()) console.log({ predictedSafeAddress }) const isSafeDeployed = await gelatoSafeClient.protocolKit.isSafeDeployed() diff --git a/playground/relay-kit/usdc-transfer-4337-counterfactual.ts b/playground/relay-kit/usdc-transfer-4337-counterfactual.ts index ec9ea5cca..32df5af15 100644 --- a/playground/relay-kit/usdc-transfer-4337-counterfactual.ts +++ b/playground/relay-kit/usdc-transfer-4337-counterfactual.ts @@ -45,7 +45,7 @@ async function main() { console.log('Supported Entry Points', await safe4337Pack.getSupportedEntryPoints()) console.log('Chain Id', await safe4337Pack.getChainId()) - const senderAddress = (await safe4337Pack.protocolKit.getAddress()) as Address + const senderAddress = (await safe4337Pack.protocolKit.getAddress()) console.log('senderAddress: ', senderAddress) diff --git a/playground/relay-kit/usdc-transfer-4337-erc20-counterfactual.ts b/playground/relay-kit/usdc-transfer-4337-erc20-counterfactual.ts index 1da2ab133..82a6fe59f 100644 --- a/playground/relay-kit/usdc-transfer-4337-erc20-counterfactual.ts +++ b/playground/relay-kit/usdc-transfer-4337-erc20-counterfactual.ts @@ -54,7 +54,7 @@ async function main() { console.log('Chain Id', await safe4337Pack.getChainId()) // Create transaction batch with two 0.1 USDC transfers - const senderAddress = (await safe4337Pack.protocolKit.getAddress()) as Address + const senderAddress = (await safe4337Pack.protocolKit.getAddress()) console.log('senderAddress: ', senderAddress) diff --git a/playground/relay-kit/usdc-transfer-4337-erc20.ts b/playground/relay-kit/usdc-transfer-4337-erc20.ts index 648e69e2d..104312d17 100644 --- a/playground/relay-kit/usdc-transfer-4337-erc20.ts +++ b/playground/relay-kit/usdc-transfer-4337-erc20.ts @@ -52,7 +52,7 @@ async function main() { console.log('Chain Id', await safe4337Pack.getChainId()) // Create transaction batch with two 0.1 USDC transfers - const senderAddress = (await safe4337Pack.protocolKit.getAddress()) as Address + const senderAddress = (await safe4337Pack.protocolKit.getAddress()) const usdcAmount = 100_000n // 0.1 USDC diff --git a/playground/relay-kit/usdc-transfer-4337-sponsored-counterfactual.ts b/playground/relay-kit/usdc-transfer-4337-sponsored-counterfactual.ts index 4f27fd912..de1477784 100644 --- a/playground/relay-kit/usdc-transfer-4337-sponsored-counterfactual.ts +++ b/playground/relay-kit/usdc-transfer-4337-sponsored-counterfactual.ts @@ -61,7 +61,7 @@ async function main() { console.log('Chain Id', await safe4337Pack.getChainId()) // Create transaction batch with two 0.1 USDC transfers - const senderAddress = (await safe4337Pack.protocolKit.getAddress()) as Address + const senderAddress = (await safe4337Pack.protocolKit.getAddress()) console.log('senderAddress: ', senderAddress) diff --git a/playground/relay-kit/usdc-transfer-4337-sponsored.ts b/playground/relay-kit/usdc-transfer-4337-sponsored.ts index 4672f4e7a..df02d80a6 100644 --- a/playground/relay-kit/usdc-transfer-4337-sponsored.ts +++ b/playground/relay-kit/usdc-transfer-4337-sponsored.ts @@ -59,7 +59,7 @@ async function main() { console.log('Chain Id', await safe4337Pack.getChainId()) // Create transaction batch with two 0.1 USDC transfers - const senderAddress = (await safe4337Pack.protocolKit.getAddress()) as Address + const senderAddress = (await safe4337Pack.protocolKit.getAddress()) const usdcAmount = 100_000n // 0.1 USDC diff --git a/playground/relay-kit/usdc-transfer-4337.ts b/playground/relay-kit/usdc-transfer-4337.ts index 6809358e8..fb6b6bda4 100644 --- a/playground/relay-kit/usdc-transfer-4337.ts +++ b/playground/relay-kit/usdc-transfer-4337.ts @@ -39,7 +39,7 @@ async function main() { console.log('Chain Id', await safe4337Pack.getChainId()) // Create transaction batch with two 0.1 USDC transfers - const senderAddress = (await safe4337Pack.protocolKit.getAddress()) as Address + const senderAddress = (await safe4337Pack.protocolKit.getAddress()) const usdcAmount = 100_000n // 0.1 USDC diff --git a/playground/utils.ts b/playground/utils.ts index 9cca0b8d1..461eeaf34 100644 --- a/playground/utils.ts +++ b/playground/utils.ts @@ -8,7 +8,7 @@ export const generateTransferCallData = (to: string, value: bigint) => { return encodeFunctionData({ abi: functionAbi, functionName: 'transfer', - args: [to as Address, value] + args: [to, value] }) } diff --git a/yarn.lock b/yarn.lock index 1ca69e5bb..0128cd829 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1249,7 +1249,7 @@ dependencies: "@noble/hashes" "1.3.1" -"@noble/curves@1.2.0", "@noble/curves@~1.2.0": +"@noble/curves@1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.2.0.tgz#92d7e12e4e49b23105a2555c6984d41733d65c35" integrity sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw== @@ -1263,6 +1263,13 @@ dependencies: "@noble/hashes" "1.4.0" +"@noble/curves@^1.4.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.5.0.tgz#7a9b9b507065d516e6dce275a1e31db8d2a100dd" + integrity sha512-J5EKamIHnKPyClwVrzmaf5wSdQXgdHcPZIZLu3bwnbeCx8/7NPK5q2ZBWF+5FvYGByjiQQsJYX6jfgB2wDPn3A== + dependencies: + "@noble/hashes" "1.4.0" + "@noble/curves@~1.4.0": version "1.4.2" resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.4.2.tgz#40309198c76ed71bc6dbf7ba24e81ceb4d0d1fe9" @@ -1290,12 +1297,12 @@ resolved "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz" integrity sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ== -"@noble/hashes@1.4.0", "@noble/hashes@~1.4.0": +"@noble/hashes@1.4.0", "@noble/hashes@^1.4.0", "@noble/hashes@~1.4.0": version "1.4.0" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.4.0.tgz#45814aa329f30e4fe0ba49426f49dfccdd066426" integrity sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg== -"@noble/hashes@^1.3.1", "@noble/hashes@~1.3.0", "@noble/hashes@~1.3.1", "@noble/hashes@~1.3.2": +"@noble/hashes@^1.3.1", "@noble/hashes@~1.3.0", "@noble/hashes@~1.3.1": version "1.3.3" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.3.tgz#39908da56a4adc270147bb07968bf3b16cfe1699" integrity sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA== @@ -1856,7 +1863,7 @@ resolved "https://registry.yarnpkg.com/@safe-global/safe-modules-deployments/-/safe-modules-deployments-2.1.1.tgz#ee887d7349dc6b8e9caa944cd612e71a73b5c8ac" integrity sha512-Tfiv+qYGEJM7idF8Ee1Gu8thg3qkCONBlOQxjS45kTAWn2VfnaPgIH2aMguiXbhkU8LgbNTzWtmmib+dR7KGpQ== -"@scure/base@^1.1.3", "@scure/base@~1.1.0", "@scure/base@~1.1.2": +"@scure/base@^1.1.3", "@scure/base@~1.1.0": version "1.1.6" resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.6.tgz#8ce5d304b436e4c84f896e0550c83e4d88cb917d" integrity sha512-ok9AWwhcgYuGG3Zfhyqg+zwl+Wn5uE+dwC0NV/2qQkx4dABbb/bx96vWu8NSj+BNjjSjno+JRYRjle1jV08k3g== @@ -1884,15 +1891,6 @@ "@noble/hashes" "~1.3.1" "@scure/base" "~1.1.0" -"@scure/bip32@1.3.2": - version "1.3.2" - resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.3.2.tgz#90e78c027d5e30f0b22c1f8d50ff12f3fb7559f8" - integrity sha512-N1ZhksgwD3OBlwTv3R6KFEcPojl/W4ElJOeCZdi+vuI5QmTFwLq3OFf2zd2ROpKvxFdgZ6hUpb0dx9bVNEwYCA== - dependencies: - "@noble/curves" "~1.2.0" - "@noble/hashes" "~1.3.2" - "@scure/base" "~1.1.2" - "@scure/bip32@1.4.0": version "1.4.0" resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.4.0.tgz#4e1f1e196abedcef395b33b9674a042524e20d67" @@ -2677,16 +2675,6 @@ abitype@0.7.1: resolved "https://registry.yarnpkg.com/abitype/-/abitype-0.7.1.tgz#16db20abe67de80f6183cf75f3de1ff86453b745" integrity sha512-VBkRHTDZf9Myaek/dO3yMmOzB/y2s3Zo6nVU7yaw1G+TvCHAjwaJzNGN9yo4K5D8bU/VZXKP1EJpRhFr862PlQ== -abitype@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/abitype/-/abitype-1.0.0.tgz#237176dace81d90d018bebf3a45cb42f2a2d9e97" - integrity sha512-NMeMah//6bJ56H5XRj8QCV4AwuW6hB6zqz2LnhhLdcWVQOsXki6/Pn3APeqxCma62nXIcmZWdu1DlHWS74umVQ== - -abitype@1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/abitype/-/abitype-1.0.4.tgz#a817ff44860e8a84e9a37ed22aa9b738dbb51dba" - integrity sha512-UivtYZOGJGE8rsrM/N5vdRkUpqEZVmuTumfTuolm7m/6O09wprd958rx8kUBwVAAAhQDveGAgD0GJdBuR8s6tw== - abitype@1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/abitype/-/abitype-1.0.5.tgz#29d0daa3eea867ca90f7e4123144c1d1270774b6" @@ -9521,38 +9509,10 @@ validate-npm-package-name@^3.0.0: dependencies: builtins "^1.0.3" -viem@^2.15.1: - version "2.15.1" - resolved "https://registry.yarnpkg.com/viem/-/viem-2.15.1.tgz#05a9ef5fd74661bd77d865c334477a900e59b436" - integrity sha512-Vrveen3vDOJyPf8Q8TDyWePG2pTdK6IpSi4P6qlvAP+rXkAeqRvwYBy9AmGm+BeYpCETAyTT0SrCP6458XSt+w== - dependencies: - "@adraffy/ens-normalize" "1.10.0" - "@noble/curves" "1.2.0" - "@noble/hashes" "1.3.2" - "@scure/bip32" "1.3.2" - "@scure/bip39" "1.2.1" - abitype "1.0.0" - isows "1.0.4" - ws "8.17.1" - -viem@^2.16.1: - version "2.16.1" - resolved "https://registry.yarnpkg.com/viem/-/viem-2.16.1.tgz#6be85ab69e2948d878d7b42f5d0e22333a8f6b33" - integrity sha512-rmgXcxif740m2ARqPFoiXRHkljXhsruCZgRXf6XuS6n+Lymy7X2ma5vuzBw3mDKiA2BmxjbyJC4Wxi7kaIwHhw== - dependencies: - "@adraffy/ens-normalize" "1.10.0" - "@noble/curves" "1.2.0" - "@noble/hashes" "1.3.2" - "@scure/bip32" "1.3.2" - "@scure/bip39" "1.2.1" - abitype "1.0.4" - isows "1.0.4" - ws "8.17.1" - -viem@^2.17.0: - version "2.17.1" - resolved "https://registry.yarnpkg.com/viem/-/viem-2.17.1.tgz#33447c1ab1b0875a0ab7276139400c4fd6b1ed0d" - integrity sha512-iLwFAfn7aWfvc1KY176YNTJQpPdepRhvaltae6TomZ+DU5M7LdASP2ywdAHw/rezdEmrH/ytwG2WWnjWioE0fA== +viem@^2.19.0: + version "2.19.2" + resolved "https://registry.yarnpkg.com/viem/-/viem-2.19.2.tgz#11f03621fd0d0d742f04e3da30fa49093a3cf612" + integrity sha512-BrR7fEEpuu9Om7obQGThb4BEu00PPHPKaUx+snB/F6yBZtr34FdXCPnphr+S73W2iIu/mt3yaRkfkLlD6a1R5g== dependencies: "@adraffy/ens-normalize" "1.10.0" "@noble/curves" "1.4.0" @@ -9561,6 +9521,7 @@ viem@^2.17.0: "@scure/bip39" "1.3.0" abitype "1.0.5" isows "1.0.4" + webauthn-p256 "0.0.5" ws "8.17.1" w3c-xmlserializer@^4.0.0: @@ -9797,6 +9758,14 @@ web3@^4.7.0: web3-utils "^4.2.3" web3-validator "^2.0.5" +webauthn-p256@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/webauthn-p256/-/webauthn-p256-0.0.5.tgz#0baebd2ba8a414b21cc09c0d40f9dd0be96a06bd" + integrity sha512-drMGNWKdaixZNobeORVIqq7k5DsRC9FnG201K2QjeOoQLmtSDaSsVZdkg6n5jUALJKcAG++zBPJXmv6hy0nWFg== + dependencies: + "@noble/curves" "^1.4.0" + "@noble/hashes" "^1.4.0" + webidl-conversions@^3.0.0: version "3.0.1" resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz" From eeeeb84a5540c00712d43f7e0789df5392945d38 Mon Sep 17 00:00:00 2001 From: Daniel <25051234+dasanra@users.noreply.github.com> Date: Thu, 8 Aug 2024 13:53:41 +0200 Subject: [PATCH 83/85] remove Viem dependency from @safe-global/safe-core-sdk-types --- packages/api-kit/src/index.ts | 6 ++++++ packages/protocol-kit/src/index.ts | 6 ++++++ packages/relay-kit/src/index.ts | 6 ++++++ packages/safe-core-sdk-types/package.json | 3 +-- packages/safe-core-sdk-types/src/index.ts | 6 ------ 5 files changed, 19 insertions(+), 8 deletions(-) diff --git a/packages/api-kit/src/index.ts b/packages/api-kit/src/index.ts index 9ca1211a5..6067338bb 100644 --- a/packages/api-kit/src/index.ts +++ b/packages/api-kit/src/index.ts @@ -3,3 +3,9 @@ import SafeApiKit, { SafeApiKitConfig } from './SafeApiKit' export * from './types/safeTransactionServiceTypes' export { SafeApiKitConfig } export default SafeApiKit + +declare module 'viem/node_modules/abitype' { + export interface Register { + AddressType: string + } +} diff --git a/packages/protocol-kit/src/index.ts b/packages/protocol-kit/src/index.ts index 53a3dc80d..daa7adb4a 100644 --- a/packages/protocol-kit/src/index.ts +++ b/packages/protocol-kit/src/index.ts @@ -115,3 +115,9 @@ export { export * from './types' export default Safe + +declare module 'viem/node_modules/abitype' { + export interface Register { + AddressType: string + } +} diff --git a/packages/relay-kit/src/index.ts b/packages/relay-kit/src/index.ts index 2139b10da..9a8b21952 100644 --- a/packages/relay-kit/src/index.ts +++ b/packages/relay-kit/src/index.ts @@ -10,3 +10,9 @@ export * from './packs/safe-4337/estimators' export * from './packs/safe-4337/types' export * from './RelayKitBasePack' + +declare module 'viem/node_modules/abitype' { + export interface Register { + AddressType: string + } +} diff --git a/packages/safe-core-sdk-types/package.json b/packages/safe-core-sdk-types/package.json index 93cfeb836..3fbae77f2 100644 --- a/packages/safe-core-sdk-types/package.json +++ b/packages/safe-core-sdk-types/package.json @@ -31,7 +31,6 @@ ], "homepage": "https://github.com/safe-global/safe-core-sdk#readme", "dependencies": { - "abitype": "^1.0.2", - "viem": "^2.19.0" + "abitype": "^1.0.2" } } diff --git a/packages/safe-core-sdk-types/src/index.ts b/packages/safe-core-sdk-types/src/index.ts index e7cc0555c..b69eab47c 100644 --- a/packages/safe-core-sdk-types/src/index.ts +++ b/packages/safe-core-sdk-types/src/index.ts @@ -20,9 +20,3 @@ declare module 'abitype' { AddressType: string } } - -declare module 'viem/node_modules/abitype' { - export interface Register { - AddressType: string - } -} From 4dc89f1f84e57d7e1c77db2d96b7d180d3a91a66 Mon Sep 17 00:00:00 2001 From: Daniel <25051234+dasanra@users.noreply.github.com> Date: Thu, 8 Aug 2024 16:49:35 +0200 Subject: [PATCH 84/85] revert unnecessary Viem changes in api-kit playground --- playground/api-kit/confirm-transaction.ts | 12 ++++++------ playground/api-kit/execute-transaction.ts | 13 +++++++------ playground/api-kit/propose-transaction.ts | 12 ++++++------ playground/relay-kit/paid-transaction.ts | 4 ++-- playground/relay-kit/sponsored-transaction.ts | 4 ++-- .../relay-kit/usdc-transfer-4337-counterfactual.ts | 4 ++-- .../usdc-transfer-4337-erc20-counterfactual.ts | 3 +-- playground/relay-kit/usdc-transfer-4337-erc20.ts | 3 +-- .../usdc-transfer-4337-sponsored-counterfactual.ts | 8 +------- .../relay-kit/usdc-transfer-4337-sponsored.ts | 8 +------- playground/relay-kit/usdc-transfer-4337.ts | 3 +-- 11 files changed, 30 insertions(+), 44 deletions(-) diff --git a/playground/api-kit/confirm-transaction.ts b/playground/api-kit/confirm-transaction.ts index 876fd5845..14a4fead3 100644 --- a/playground/api-kit/confirm-transaction.ts +++ b/playground/api-kit/confirm-transaction.ts @@ -1,19 +1,19 @@ -import { Chain } from 'viem' -import { sepolia } from 'viem/chains' import Safe from '@safe-global/protocol-kit' import SafeApiKit from '@safe-global/api-kit' // This file can be used to play around with the Safe Core SDK interface Config { - CHAIN: Chain + CHAIN_ID: bigint + RPC_URL: string SIGNER_ADDRESS_PRIVATE_KEY: string SAFE_ADDRESS: string SAFE_TX_HASH: string } const config: Config = { - CHAIN: sepolia, + CHAIN_ID: 11155111n, + RPC_URL: 'https://sepolia.gateway.tenderly.co', SIGNER_ADDRESS_PRIVATE_KEY: '', SAFE_ADDRESS: '', SAFE_TX_HASH: '' @@ -22,14 +22,14 @@ const config: Config = { async function main() { // Create Safe instance const protocolKit = await Safe.init({ - provider: config.CHAIN.rpcUrls.default.http[0], + provider: config.RPC_URL, signer: config.SIGNER_ADDRESS_PRIVATE_KEY, safeAddress: config.SAFE_ADDRESS }) // Create Safe API Kit instance const apiKit = new SafeApiKit({ - chainId: BigInt(config.CHAIN.id) + chainId: config.CHAIN_ID }) // Get the transaction diff --git a/playground/api-kit/execute-transaction.ts b/playground/api-kit/execute-transaction.ts index 9ed1c78c8..ace08f7d4 100644 --- a/playground/api-kit/execute-transaction.ts +++ b/playground/api-kit/execute-transaction.ts @@ -1,20 +1,21 @@ -import { Chain, Hash } from 'viem' +import { Hash } from 'viem' import { waitForTransactionReceipt } from 'viem/actions' -import { sepolia } from 'viem/chains' import Safe from '@safe-global/protocol-kit' import SafeApiKit from '@safe-global/api-kit' // This file can be used to play around with the Safe Core SDK interface Config { - CHAIN: Chain + CHAIN_ID: bigint + RPC_URL: string SIGNER_ADDRESS_PRIVATE_KEY: string SAFE_ADDRESS: string SAFE_TX_HASH: string } const config: Config = { - CHAIN: sepolia, + CHAIN_ID: 11155111n, + RPC_URL: 'https://sepolia.gateway.tenderly.co', SIGNER_ADDRESS_PRIVATE_KEY: '', SAFE_ADDRESS: '', SAFE_TX_HASH: '' @@ -23,14 +24,14 @@ const config: Config = { async function main() { // Create Safe instance const protocolKit = await Safe.init({ - provider: config.CHAIN.rpcUrls.default.http[0], + provider: config.RPC_URL, signer: config.SIGNER_ADDRESS_PRIVATE_KEY, safeAddress: config.SAFE_ADDRESS }) // Create Safe API Kit instance const apiKit = new SafeApiKit({ - chainId: BigInt(config.CHAIN.id) + chainId: config.CHAIN_ID }) // Get the transaction diff --git a/playground/api-kit/propose-transaction.ts b/playground/api-kit/propose-transaction.ts index 8acb986eb..f2f3ca7c5 100644 --- a/playground/api-kit/propose-transaction.ts +++ b/playground/api-kit/propose-transaction.ts @@ -1,5 +1,3 @@ -import { Chain } from 'viem' -import { sepolia } from 'viem/chains' import Safe from '@safe-global/protocol-kit' import SafeApiKit from '@safe-global/api-kit' import { OperationType, SafeTransactionDataPartial } from '@safe-global/safe-core-sdk-types' @@ -7,13 +5,15 @@ import { OperationType, SafeTransactionDataPartial } from '@safe-global/safe-cor // This file can be used to play around with the Safe Core SDK interface Config { - CHAIN: Chain + CHAIN_ID: bigint + RPC_URL: string SIGNER_ADDRESS_PRIVATE_KEY: string SAFE_ADDRESS: string } const config: Config = { - CHAIN: sepolia, + CHAIN_ID: 11155111n, + RPC_URL: 'https://sepolia.gateway.tenderly.co', SIGNER_ADDRESS_PRIVATE_KEY: '', SAFE_ADDRESS: '' } @@ -21,14 +21,14 @@ const config: Config = { async function main() { // Create Safe instance const protocolKit = await Safe.init({ - provider: config.CHAIN.rpcUrls.default.http[0], + provider: config.RPC_URL, signer: config.SIGNER_ADDRESS_PRIVATE_KEY, safeAddress: config.SAFE_ADDRESS }) // Create Safe API Kit instance const apiKit = new SafeApiKit({ - chainId: BigInt(config.CHAIN.id) + chainId: config.CHAIN_ID }) // Create transaction diff --git a/playground/relay-kit/paid-transaction.ts b/playground/relay-kit/paid-transaction.ts index 210c1f518..bb28861c1 100644 --- a/playground/relay-kit/paid-transaction.ts +++ b/playground/relay-kit/paid-transaction.ts @@ -1,4 +1,4 @@ -import { Address, Chain, formatEther, createWalletClient, custom, Hex } from 'viem' +import { Chain, formatEther, createWalletClient, custom, Hex } from 'viem' import { sepolia } from 'viem/chains' import { getBalance, waitForTransactionReceipt } from 'viem/actions' import { privateKeyToAccount } from 'viem/accounts' @@ -76,7 +76,7 @@ async function main() { }) // Calculate Safe address - const predictedSafeAddress = (await gelatoSafeClient.protocolKit.getAddress()) + const predictedSafeAddress = await gelatoSafeClient.protocolKit.getAddress() console.log({ predictedSafeAddress }) const isSafeDeployed = await gelatoSafeClient.protocolKit.isSafeDeployed() diff --git a/playground/relay-kit/sponsored-transaction.ts b/playground/relay-kit/sponsored-transaction.ts index 469fa7510..4573aafb2 100644 --- a/playground/relay-kit/sponsored-transaction.ts +++ b/playground/relay-kit/sponsored-transaction.ts @@ -1,4 +1,4 @@ -import { Address, Chain, createWalletClient, custom, formatEther, Hex } from 'viem' +import { Chain, createWalletClient, custom, formatEther, Hex } from 'viem' import { privateKeyToAccount } from 'viem/accounts' import { getBalance, waitForTransactionReceipt } from 'viem/actions' import { sepolia } from 'viem/chains' @@ -78,7 +78,7 @@ async function main() { // Calculate Safe address - const predictedSafeAddress = (await gelatoSafeClient.protocolKit.getAddress()) + const predictedSafeAddress = await gelatoSafeClient.protocolKit.getAddress() console.log({ predictedSafeAddress }) const isSafeDeployed = await gelatoSafeClient.protocolKit.isSafeDeployed() diff --git a/playground/relay-kit/usdc-transfer-4337-counterfactual.ts b/playground/relay-kit/usdc-transfer-4337-counterfactual.ts index 32df5af15..28bcd026f 100644 --- a/playground/relay-kit/usdc-transfer-4337-counterfactual.ts +++ b/playground/relay-kit/usdc-transfer-4337-counterfactual.ts @@ -1,4 +1,4 @@ -import { parseEther, Address } from 'viem' +import { parseEther } from 'viem' import { getBlock, waitForTransactionReceipt } from 'viem/actions' import { sepolia } from 'viem/chains' import { Safe4337Pack } from '@safe-global/relay-kit' @@ -45,7 +45,7 @@ async function main() { console.log('Supported Entry Points', await safe4337Pack.getSupportedEntryPoints()) console.log('Chain Id', await safe4337Pack.getChainId()) - const senderAddress = (await safe4337Pack.protocolKit.getAddress()) + const senderAddress = await safe4337Pack.protocolKit.getAddress() console.log('senderAddress: ', senderAddress) diff --git a/playground/relay-kit/usdc-transfer-4337-erc20-counterfactual.ts b/playground/relay-kit/usdc-transfer-4337-erc20-counterfactual.ts index 82a6fe59f..974f4eff8 100644 --- a/playground/relay-kit/usdc-transfer-4337-erc20-counterfactual.ts +++ b/playground/relay-kit/usdc-transfer-4337-erc20-counterfactual.ts @@ -1,4 +1,3 @@ -import { Address } from 'viem' import { getBlock } from 'viem/actions' import { Safe4337Pack } from '@safe-global/relay-kit' import { waitForOperationToFinish, transfer, generateTransferCallData } from '../utils' @@ -54,7 +53,7 @@ async function main() { console.log('Chain Id', await safe4337Pack.getChainId()) // Create transaction batch with two 0.1 USDC transfers - const senderAddress = (await safe4337Pack.protocolKit.getAddress()) + const senderAddress = await safe4337Pack.protocolKit.getAddress() console.log('senderAddress: ', senderAddress) diff --git a/playground/relay-kit/usdc-transfer-4337-erc20.ts b/playground/relay-kit/usdc-transfer-4337-erc20.ts index 104312d17..5f54a2db0 100644 --- a/playground/relay-kit/usdc-transfer-4337-erc20.ts +++ b/playground/relay-kit/usdc-transfer-4337-erc20.ts @@ -1,4 +1,3 @@ -import { Address } from 'viem' import { getBlock } from 'viem/actions' import { Safe4337Pack } from '@safe-global/relay-kit' import { waitForOperationToFinish, transfer, generateTransferCallData } from '../utils' @@ -52,7 +51,7 @@ async function main() { console.log('Chain Id', await safe4337Pack.getChainId()) // Create transaction batch with two 0.1 USDC transfers - const senderAddress = (await safe4337Pack.protocolKit.getAddress()) + const senderAddress = await safe4337Pack.protocolKit.getAddress() const usdcAmount = 100_000n // 0.1 USDC diff --git a/playground/relay-kit/usdc-transfer-4337-sponsored-counterfactual.ts b/playground/relay-kit/usdc-transfer-4337-sponsored-counterfactual.ts index de1477784..abf437791 100644 --- a/playground/relay-kit/usdc-transfer-4337-sponsored-counterfactual.ts +++ b/playground/relay-kit/usdc-transfer-4337-sponsored-counterfactual.ts @@ -1,4 +1,3 @@ -import { Address } from 'viem' import { getBlock } from 'viem/actions' import { Safe4337Pack } from '@safe-global/relay-kit' import { waitForOperationToFinish, transfer, generateTransferCallData } from '../utils' @@ -28,10 +27,6 @@ const BUNDLER_URL = `https://api.pimlico.io/v2/${CHAIN_NAME}/rpc?apikey=${PIMLIC // Paymaster URL const PAYMASTER_URL = `https://api.pimlico.io/v2/${CHAIN_NAME}/rpc?apikey=${PIMLICO_API_KEY}` // PIMLICO -// PAYMASTER ADDRESS -const paymasterAddress = '0x0000000000325602a77416A16136FDafd04b299f' // SEPOLIA -// const paymasterAddress = '0x000000000034B78bfe02Be30AE4D324c8702803d' // GNOSIS - // USDC CONTRACT ADDRESS IN SEPOLIA // faucet: https://faucet.circle.com/ const usdcTokenAddress = '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238' // SEPOLIA @@ -46,7 +41,6 @@ async function main() { paymasterOptions: { isSponsored: true, sponsorshipPolicyId: POLICY_ID, - paymasterAddress, paymasterUrl: PAYMASTER_URL }, options: { @@ -61,7 +55,7 @@ async function main() { console.log('Chain Id', await safe4337Pack.getChainId()) // Create transaction batch with two 0.1 USDC transfers - const senderAddress = (await safe4337Pack.protocolKit.getAddress()) + const senderAddress = await safe4337Pack.protocolKit.getAddress() console.log('senderAddress: ', senderAddress) diff --git a/playground/relay-kit/usdc-transfer-4337-sponsored.ts b/playground/relay-kit/usdc-transfer-4337-sponsored.ts index df02d80a6..82c1b6298 100644 --- a/playground/relay-kit/usdc-transfer-4337-sponsored.ts +++ b/playground/relay-kit/usdc-transfer-4337-sponsored.ts @@ -1,4 +1,3 @@ -import { Address } from 'viem' import { getBlock } from 'viem/actions' import { Safe4337Pack } from '@safe-global/relay-kit' import { generateTransferCallData, waitForOperationToFinish } from '../utils' @@ -28,10 +27,6 @@ const BUNDLER_URL = `https://api.pimlico.io/v2/${CHAIN_NAME}/rpc?apikey=${PIMLIC // Paymaster URL const PAYMASTER_URL = `https://api.pimlico.io/v2/${CHAIN_NAME}/rpc?apikey=${PIMLICO_API_KEY}` // PIMLICO -// PAYMASTER ADDRESS -const paymasterAddress = '0x0000000000325602a77416A16136FDafd04b299f' // SEPOLIA -// const paymasterAddress = '0x000000000034B78bfe02Be30AE4D324c8702803d' // GNOSIS - // USDC CONTRACT ADDRESS IN SEPOLIA // faucet: https://faucet.circle.com/ const usdcTokenAddress = '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238' // SEPOLIA @@ -46,7 +41,6 @@ async function main() { paymasterOptions: { isSponsored: true, paymasterUrl: PAYMASTER_URL, - paymasterAddress, sponsorshipPolicyId: POLICY_ID }, options: { @@ -59,7 +53,7 @@ async function main() { console.log('Chain Id', await safe4337Pack.getChainId()) // Create transaction batch with two 0.1 USDC transfers - const senderAddress = (await safe4337Pack.protocolKit.getAddress()) + const senderAddress = await safe4337Pack.protocolKit.getAddress() const usdcAmount = 100_000n // 0.1 USDC diff --git a/playground/relay-kit/usdc-transfer-4337.ts b/playground/relay-kit/usdc-transfer-4337.ts index fb6b6bda4..3b56e313e 100644 --- a/playground/relay-kit/usdc-transfer-4337.ts +++ b/playground/relay-kit/usdc-transfer-4337.ts @@ -1,4 +1,3 @@ -import { Address } from 'viem' import { getBlock } from 'viem/actions' import { Safe4337Pack } from '@safe-global/relay-kit' import { generateTransferCallData, waitForOperationToFinish } from '../utils' @@ -39,7 +38,7 @@ async function main() { console.log('Chain Id', await safe4337Pack.getChainId()) // Create transaction batch with two 0.1 USDC transfers - const senderAddress = (await safe4337Pack.protocolKit.getAddress()) + const senderAddress = await safe4337Pack.protocolKit.getAddress() const usdcAmount = 100_000n // 0.1 USDC From 9d92313c384b6e59613a2b14fac89a1756cc0900 Mon Sep 17 00:00:00 2001 From: Daniel <25051234+dasanra@users.noreply.github.com> Date: Fri, 9 Aug 2024 09:51:45 +0200 Subject: [PATCH 85/85] fix: types in tests --- packages/protocol-kit/tests/unit/eip-3770.test.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/protocol-kit/tests/unit/eip-3770.test.ts b/packages/protocol-kit/tests/unit/eip-3770.test.ts index 671943a33..a0927defc 100644 --- a/packages/protocol-kit/tests/unit/eip-3770.test.ts +++ b/packages/protocol-kit/tests/unit/eip-3770.test.ts @@ -8,6 +8,12 @@ import { validateEthereumAddress } from '@safe-global/protocol-kit/utils' +declare module 'viem/node_modules/abitype' { + export interface Register { + AddressType: string + } +} + describe('EIP-3770 chain-specific addresses', () => { describe('parseEip3770Address', async () => { it('should parse an empty full address', async () => {