diff --git a/packages/protocol-kit/scripts/generateTypechainFiles.ts b/packages/protocol-kit/scripts/generateTypechainFiles.ts index ba995980f..0e5b2cad2 100644 --- a/packages/protocol-kit/scripts/generateTypechainFiles.ts +++ b/packages/protocol-kit/scripts/generateTypechainFiles.ts @@ -37,7 +37,7 @@ const safeContracts_V1_3_0 = [ ].join(' ') const safeContracts_V1_2_0 = [`${safeContractsPath}/v1.2.0/gnosis_safe.json`].join(' ') const safeContracts_V1_1_1 = [ - `${safeContractsPath}/v1.1.1/gnosis_safe.json`, + // `${safeContractsPath}/v1.1.1/gnosis_safe.json`, // Remove contract 1.1.1 from typechain as it's migrated to Abitype, `${safeContractsPath}/v1.1.1/proxy_factory.json`, `${safeContractsPath}/v1.1.1/multi_send.json` ].join(' ') diff --git a/packages/protocol-kit/src/adapters/ethers/contracts/Safe/SafeContractEthers.ts b/packages/protocol-kit/src/adapters/ethers/contracts/Safe/SafeContractEthers.ts index e07bef0d1..de781faa1 100644 --- a/packages/protocol-kit/src/adapters/ethers/contracts/Safe/SafeContractEthers.ts +++ b/packages/protocol-kit/src/adapters/ethers/contracts/Safe/SafeContractEthers.ts @@ -4,7 +4,6 @@ import { } from '@safe-global/protocol-kit/adapters/ethers/types' import { toTxResult } from '@safe-global/protocol-kit/adapters/ethers/utils' import { Gnosis_safe as Safe_V1_0_0 } from '@safe-global/protocol-kit/typechain/src/ethers-v6/v1.0.0/Gnosis_safe' -import { Gnosis_safe as Safe_V1_1_1 } from '@safe-global/protocol-kit/typechain/src/ethers-v6/v1.1.1/Gnosis_safe' import { Gnosis_safe as Safe_V1_2_0 } from '@safe-global/protocol-kit/typechain/src/ethers-v6/v1.2.0/Gnosis_safe' import { SafeContract, @@ -15,7 +14,7 @@ import { } from '@safe-global/safe-core-sdk-types' abstract class SafeContractEthers implements SafeContract { - constructor(public contract: Safe_V1_2_0 | Safe_V1_1_1 | Safe_V1_0_0) {} + constructor(public contract: Safe_V1_2_0 | Safe_V1_0_0) {} abstract setup( setupConfig: SafeSetupConfig, diff --git a/packages/protocol-kit/src/adapters/ethers/contracts/Safe/v1.1.1/SafeContract_V1_1_1_Ethers.ts b/packages/protocol-kit/src/adapters/ethers/contracts/Safe/v1.1.1/SafeContract_V1_1_1_Ethers.ts deleted file mode 100644 index 57b3d67f5..000000000 --- a/packages/protocol-kit/src/adapters/ethers/contracts/Safe/v1.1.1/SafeContract_V1_1_1_Ethers.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { - EthersTransactionOptions, - EthersTransactionResult -} from '@safe-global/protocol-kit/adapters/ethers/types' -import { sameString, toTxResult } from '@safe-global/protocol-kit/adapters/ethers/utils' -import { EMPTY_DATA, ZERO_ADDRESS } from '@safe-global/protocol-kit/adapters/ethers/utils/constants' -import { Gnosis_safe as Safe } from '@safe-global/protocol-kit/typechain/src/ethers-v6/v1.1.1/Gnosis_safe' -import { SafeSetupConfig } from '@safe-global/safe-core-sdk-types' -import SafeContractEthers from '../SafeContractEthers' - -class SafeContract_V1_1_1_Ethers extends SafeContractEthers { - constructor(public contract: Safe) { - super(contract) - } - - async setup( - setupConfig: SafeSetupConfig, - options?: EthersTransactionOptions - ): Promise { - const { - owners, - threshold, - to = ZERO_ADDRESS, - data = EMPTY_DATA, - fallbackHandler = ZERO_ADDRESS, - paymentToken = ZERO_ADDRESS, - payment = 0, - paymentReceiver = ZERO_ADDRESS - } = setupConfig - - if (options && !options.gasLimit) { - options.gasLimit = await this.estimateGas( - 'setup', - [owners, threshold, to, data, fallbackHandler, paymentToken, payment, paymentReceiver], - { - ...options - } - ) - } - const txResponse = await this.contract.setup( - owners, - threshold, - to, - data, - fallbackHandler, - paymentToken, - payment, - paymentReceiver, - { ...options } - ) - - return toTxResult(txResponse, options) - } - - async getModules(): Promise { - return this.contract.getModules() - } - - async isModuleEnabled(moduleAddress: string): Promise { - const modules = await this.getModules() - const isModuleEnabled = modules.some((enabledModuleAddress: string) => - sameString(enabledModuleAddress, moduleAddress) - ) - return isModuleEnabled - } -} - -export default SafeContract_V1_1_1_Ethers diff --git a/packages/protocol-kit/src/adapters/ethers/contracts/Safe/v1.1.1/SafeContract_v1_1_1_Ethers.ts b/packages/protocol-kit/src/adapters/ethers/contracts/Safe/v1.1.1/SafeContract_v1_1_1_Ethers.ts new file mode 100644 index 000000000..56f53ee64 --- /dev/null +++ b/packages/protocol-kit/src/adapters/ethers/contracts/Safe/v1.1.1/SafeContract_v1_1_1_Ethers.ts @@ -0,0 +1,330 @@ +import SafeBaseContractEthers from '@safe-global/protocol-kit/adapters/ethers/contracts/Safe/SafeBaseContractEthers' +import EthersAdapter from '@safe-global/protocol-kit/adapters/ethers/EthersAdapter' +import { + EthersTransactionOptions, + EthersTransactionResult +} from '@safe-global/protocol-kit/adapters/ethers/types' +import SafeContract_v1_1_1_Contract, { + SafeContract_v1_1_1_Abi +} from '@safe-global/protocol-kit/contracts/AbiType/Safe/v1.1.1/SafeContract_v1_1_1' +import { toTxResult } from '@safe-global/protocol-kit/adapters/ethers/utils' +import safe_1_1_1_ContractArtifacts from '@safe-global/protocol-kit/contracts/AbiType/assets/Safe/v1.1.1/gnosis_safe' +import { + EncodeSafeFunction, + EstimateGasSafeFunction +} from '@safe-global/protocol-kit/contracts/AbiType/Safe/SafeBaseContract' +import { sameString } from '@safe-global/protocol-kit/utils' +import { SafeTransaction, SafeTransactionData, SafeVersion } from '@safe-global/safe-core-sdk-types' + +/** + * SafeContract_v1_1_1_Ethers is the implementation specific to the Safe contract version 1.1.1. + * + * This class specializes in handling interactions with the Safe contract version 1.1.1 using Ethers.js v6. + * + * @extends SafeBaseContractEthers - Inherits from SafeBaseContractEthers with ABI specific to Safe contract version 1.1.1. + * @implements SafeContract_v1_1_1_Contract - Implements the interface specific to Safe contract version 1.1.1. + */ +class SafeContract_v1_1_1_Ethers + extends SafeBaseContractEthers + implements SafeContract_v1_1_1_Contract +{ + safeVersion: SafeVersion + + /** + * Constructs an instance of SafeContract_v1_1_1_Ethers + * + * @param chainId - The chain ID where the contract resides. + * @param ethersAdapter - An instance of EthersAdapter. + * @param isL1SafeSingleton - A flag indicating if the contract is a L1 Safe Singleton. + * @param customContractAddress - Optional custom address for the contract. If not provided, the address is derived from the Safe deployments based on the chainId and safeVersion. + * @param customContractAbi - Optional custom ABI for the contract. If not provided, the default ABI for version 1.1.1 is used. + */ + constructor( + chainId: bigint, + ethersAdapter: EthersAdapter, + isL1SafeSingleton = false, + customContractAddress?: string, + customContractAbi?: SafeContract_v1_1_1_Abi + ) { + const safeVersion = '1.1.1' + const defaultAbi = safe_1_1_1_ContractArtifacts.abi + + super( + chainId, + ethersAdapter, + defaultAbi, + safeVersion, + isL1SafeSingleton, + customContractAddress, + customContractAbi + ) + + this.safeVersion = safeVersion + } + + async NAME(): Promise<[string]> { + return [await this.contract.NAME()] + } + + async VERSION(): Promise<[SafeVersion]> { + return [await this.contract.VERSION()] + } + + async approvedHashes([owner, txHash]: readonly [string, string]): Promise<[bigint]> { + return [await this.contract.approvedHashes(owner, txHash)] + } + + async domainSeparator(): Promise<[string]> { + return [await this.contract.domainSeparator()] + } + + async getModules(): Promise<[string[]]> { + return [await this.contract.getModules()] + } + + async getModulesPaginated( + args: readonly [start: string, pageSize: bigint] + ): Promise<[modules: string[], next: string]> { + const res = await this.contract.getModulesPaginated(...args) + return [res.array, res.next] + } + + async getOwners(): Promise<[string[]]> { + return [await this.contract.getOwners()] + } + + async getThreshold(): Promise<[bigint]> { + return [await this.contract.getThreshold()] + } + + async isOwner(args: readonly [address: string]): Promise<[boolean]> { + return [await this.contract.isOwner(...args)] + } + + async nonce(): Promise<[bigint]> { + return [await this.contract.nonce()] + } + + async signedMessages(args: readonly [messageHash: string]): Promise<[bigint]> { + return [await this.contract.signedMessages(...args)] + } + + async getMessageHash(args: readonly [message: string]): Promise<[string]> { + return [await this.contract.getMessageHash(...args)] + } + + async encodeTransactionData( + args: readonly [ + to: string, + value: bigint, + data: string, + operation: number, + safeTxGas: bigint, + baseGas: bigint, + gasPrice: bigint, + gasToken: string, + refundReceiver: string, + _nonce: bigint + ] + ): Promise<[string]> { + return [await this.contract.encodeTransactionData(...args)] + } + + async getTransactionHash( + args: readonly [ + to: string, + value: bigint, + data: string, + operation: number, + safeTxGas: bigint, + baseGas: bigint, + gasPrice: bigint, + gasToken: string, + refundReceiver: string, + _nonce: bigint + ] + ): Promise<[string]> { + return [await this.contract.getTransactionHash(...args)] + } + + encode: EncodeSafeFunction = (functionToEncode, args) => { + return this.contract.interface.encodeFunctionData(functionToEncode, args) + } + + estimateGas: EstimateGasSafeFunction = ( + functionToEstimate, + args, + options = {} + ) => { + return this.contract.getFunction(functionToEstimate).estimateGas(...args, options) + } + + // Custom method (not defined in the Safe Contract) + async approveHash( + hash: string, + options?: EthersTransactionOptions + ): Promise { + const gasLimit = options?.gasLimit || (await this.estimateGas('approveHash', [hash], options)) + const txResponse = await this.contract.approveHash(hash, { ...options, gasLimit }) + + return toTxResult(txResponse, options) + } + + // Custom method (not defined in the Safe Contract) + getAddress(): Promise { + return this.contract.getAddress() + } + + // Custom method (not defined in the Safe Contract) + async execTransaction( + safeTransaction: SafeTransaction, + options?: EthersTransactionOptions + ): Promise { + const gasLimit = + options?.gasLimit || + (await this.estimateGas( + 'execTransaction', + [ + 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 + )) + + 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 } + ) + + return toTxResult(txResponse, options) + } + + // Custom method (not defined in the Safe Contract) + async isModuleEnabled(moduleAddress: string): Promise { + const [modules] = await this.getModules() + const isModuleEnabled = modules.some((enabledModuleAddress: string) => + sameString(enabledModuleAddress, moduleAddress) + ) + return isModuleEnabled + } + + // Custom method (not defined in the Safe Contract) + async isValidTransaction( + safeTransaction: SafeTransaction, + options: EthersTransactionOptions = {} + ): Promise { + try { + const gasLimit = + options?.gasLimit || + (await this.estimateGas( + 'execTransaction', + [ + 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 + )) + + 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 } + ) + } catch (error) { + return false + } + } + + // TODO: Remove this mapper after remove Typechain + mapToTypechainContract(): any { + return { + contract: this.contract, + + setup: (): any => { + // setup function is labelled as `external` on the contract code, but not present on type SafeContract_v1_1_1_Contract + return + }, + + getModules: async () => (await this.getModules())[0], + + isModuleEnabled: this.isModuleEnabled.bind(this), + + getVersion: async () => (await this.VERSION())[0], + + getAddress: this.getAddress.bind(this), + + getNonce: async () => Number((await this.nonce())[0]), + + getThreshold: async () => Number((await this.getThreshold())[0]), + + getOwners: async () => (await this.getOwners())[0], + + isOwner: async (address: string) => (await this.isOwner([address]))[0], + + getTransactionHash: async (safeTransactionData: SafeTransactionData) => { + return ( + await this.getTransactionHash([ + safeTransactionData.to, + BigInt(safeTransactionData.value), + safeTransactionData.data, + safeTransactionData.operation, + BigInt(safeTransactionData.safeTxGas), + BigInt(safeTransactionData.baseGas), + BigInt(safeTransactionData.gasPrice), + safeTransactionData.gasToken, + safeTransactionData.refundReceiver, + BigInt(safeTransactionData.nonce) + ]) + )[0] + }, + + approvedHashes: async (ownerAddress: string, hash: string) => + (await this.approvedHashes([ownerAddress, hash]))[0], + + approveHash: this.approveHash.bind(this), + + isValidTransaction: this.isValidTransaction.bind(this), + + execTransaction: this.execTransaction.bind(this), + + encode: this.encode.bind(this), + + estimateGas: this.estimateGas.bind(this) + } + } +} + +export default SafeContract_v1_1_1_Ethers diff --git a/packages/protocol-kit/src/adapters/ethers/contracts/contractInstancesEthers.ts b/packages/protocol-kit/src/adapters/ethers/contracts/contractInstancesEthers.ts index 0510cab70..7d63f8740 100644 --- a/packages/protocol-kit/src/adapters/ethers/contracts/contractInstancesEthers.ts +++ b/packages/protocol-kit/src/adapters/ethers/contracts/contractInstancesEthers.ts @@ -2,7 +2,6 @@ import { AbstractSigner, Provider } from 'ethers' import { AbiItem } from 'web3-utils' import { Gnosis_safe__factory as SafeSingleton_V1_0_0 } from '@safe-global/protocol-kit/typechain/src/ethers-v6/v1.0.0/factories/Gnosis_safe__factory' import { Proxy_factory__factory as SafeProxyFactory_V1_0_0 } from '@safe-global/protocol-kit/typechain/src/ethers-v6/v1.0.0/factories/Proxy_factory__factory' -import { Gnosis_safe__factory as SafeSingleton_V1_1_1 } from '@safe-global/protocol-kit/typechain/src/ethers-v6/v1.1.1/factories/Gnosis_safe__factory' import { Multi_send__factory as MultiSend_V1_1_1 } from '@safe-global/protocol-kit/typechain/src/ethers-v6/v1.1.1/factories/Multi_send__factory' import { Proxy_factory__factory as SafeProxyFactory_V1_1_1 } from '@safe-global/protocol-kit/typechain/src/ethers-v6/v1.1.1/factories/Proxy_factory__factory' import { Compatibility_fallback_handler__factory as CompatibilityFallbackHandler_V1_3_0 } from '@safe-global/protocol-kit/typechain/src/ethers-v6/v1.3.0/factories/Compatibility_fallback_handler__factory' @@ -30,7 +29,6 @@ import MultiSendContract_V1_4_1_Ethers from './MultiSend/v1.4.1/MultiSendContrac import MultiSendCallOnlyContract_V1_3_0_Ethers from './MultiSendCallOnly/v1.3.0/MultiSendCallOnlyContract_V1_3_0_Ethers' import MultiSendCallOnlyContract_V1_4_1_Ethers from './MultiSendCallOnly/v1.4.1/MultiSendCallOnlyContract_V1_4_1_Ethers' import SafeContract_V1_0_0_Ethers from './Safe/v1.0.0/SafeContract_V1_0_0_Ethers' -import SafeContract_V1_1_1_Ethers from './Safe/v1.1.1/SafeContract_V1_1_1_Ethers' import SafeProxyFactoryContract_V1_0_0_Ethers from './SafeProxyFactory/v1.0.0/SafeProxyFactoryContract_V1_0_0_Ethers' import SafeProxyFactoryContract_V1_1_1_Ethers from './SafeProxyFactory/v1.1.1/SafeProxyFactoryContract_V1_1_1_Ethers' import SafeProxyFactoryContract_V1_3_0_Ethers from './SafeProxyFactory/v1.3.0/SafeProxyFactoryContract_V1_3_0_Ethers' @@ -39,10 +37,12 @@ import SignMessageLibContract_V1_3_0_Ethers from './SignMessageLib/v1.3.0/SignMe import SignMessageLibContract_V1_4_1_Ethers from './SignMessageLib/v1.4.1/SignMessageLibContract_V1_4_1_Ethers' import SimulateTxAccessorContract_V1_3_0_Ethers from './SimulateTxAccessor/v1.3.0/SimulateTxAccessorContract_V1_3_0_Ethers' import SimulateTxAccessorContract_V1_4_1_Ethers from './SimulateTxAccessor/v1.4.1/SimulateTxAccessorContract_V1_4_1_Ethers' +import SafeContract_v1_1_1_Ethers from '@safe-global/protocol-kit/adapters/ethers/contracts/Safe/v1.1.1/SafeContract_v1_1_1_Ethers' import SafeContract_v1_2_0_Ethers from '@safe-global/protocol-kit/adapters/ethers/contracts/Safe/v1.2.0/SafeContract_v1_2_0_Ethers' import SafeContract_v1_3_0_Ethers from '@safe-global/protocol-kit/adapters/ethers/contracts/Safe/v1.3.0/SafeContract_v1_3_0_Ethers' import SafeContract_v1_4_1_Ethers from '@safe-global/protocol-kit/adapters/ethers/contracts/Safe/v1.4.1/SafeContract_v1_4_1_Ethers' import EthersAdapter from '../EthersAdapter' +import { SafeContract_v1_1_1_Abi } from '@safe-global/protocol-kit/contracts/AbiType/Safe/v1.1.1/SafeContract_v1_1_1' import { SafeContract_v1_2_0_Abi } from '@safe-global/protocol-kit/contracts/AbiType/Safe/v1.2.0/SafeContract_v1_2_0' import { SafeContract_v1_3_0_Abi } from '@safe-global/protocol-kit/contracts/AbiType/Safe/v1.3.0/SafeContract_v1_3_0' import { SafeContract_v1_4_1_Abi } from '@safe-global/protocol-kit/contracts/AbiType/Safe/v1.4.1/SafeContract_v1_4_1' @@ -54,7 +54,7 @@ export async function getSafeContractInstance( ethersAdapter: EthersAdapter, customContractAbi?: AbiItem | AbiItem[] | undefined, isL1SafeSingleton?: boolean -): Promise { +): Promise { const chainId = await ethersAdapter.getChainId() let safeContract switch (safeVersion) { @@ -89,8 +89,15 @@ export async function getSafeContractInstance( ) return mapToTypechainContract(safeContract) // remove this mapper after remove typechain case '1.1.1': - safeContract = SafeSingleton_V1_1_1.connect(contractAddress, signerOrProvider) - return new SafeContract_V1_1_1_Ethers(safeContract) + safeContract = new SafeContract_v1_1_1_Ethers( + chainId, + ethersAdapter, + isL1SafeSingleton, + contractAddress, + // TODO: Remove this unknown after remove Typechain + customContractAbi as unknown as SafeContract_v1_1_1_Abi + ) + return safeContract.mapToTypechainContract() case '1.0.0': safeContract = SafeSingleton_V1_0_0.connect(contractAddress, signerOrProvider) return new SafeContract_V1_0_0_Ethers(safeContract) diff --git a/packages/protocol-kit/src/adapters/web3/contracts/Safe/SafeContractWeb3.ts b/packages/protocol-kit/src/adapters/web3/contracts/Safe/SafeContractWeb3.ts index b2008069c..10cb6e36d 100644 --- a/packages/protocol-kit/src/adapters/web3/contracts/Safe/SafeContractWeb3.ts +++ b/packages/protocol-kit/src/adapters/web3/contracts/Safe/SafeContractWeb3.ts @@ -4,7 +4,6 @@ import { } from '@safe-global/protocol-kit/adapters/web3/types' import { toTxResult } from '@safe-global/protocol-kit/adapters/web3/utils' import { Gnosis_safe as Safe_V1_0_0 } from '@safe-global/protocol-kit/typechain/src/web3-v1/v1.0.0/Gnosis_safe' -import { Gnosis_safe as Safe_V1_1_1 } from '@safe-global/protocol-kit/typechain/src/web3-v1/v1.1.1/Gnosis_safe' import { Gnosis_safe as Safe_V1_2_0 } from '@safe-global/protocol-kit/typechain/src/web3-v1/v1.2.0/Gnosis_safe' import { SafeContract, @@ -15,7 +14,7 @@ import { } from '@safe-global/safe-core-sdk-types' abstract class SafeContractWeb3 implements SafeContract { - constructor(public contract: Safe_V1_2_0 | Safe_V1_1_1 | Safe_V1_0_0) {} + constructor(public contract: Safe_V1_2_0 | Safe_V1_0_0) {} abstract setup( setupConfig: SafeSetupConfig, diff --git a/packages/protocol-kit/src/adapters/web3/contracts/Safe/v1.1.1/SafeContract_V1_1_1_Web3.ts b/packages/protocol-kit/src/adapters/web3/contracts/Safe/v1.1.1/SafeContract_V1_1_1_Web3.ts deleted file mode 100644 index 5af219ac0..000000000 --- a/packages/protocol-kit/src/adapters/web3/contracts/Safe/v1.1.1/SafeContract_V1_1_1_Web3.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { - Web3TransactionOptions, - Web3TransactionResult -} from '@safe-global/protocol-kit/adapters/web3/types' -import { sameString, toTxResult } from '@safe-global/protocol-kit/adapters/web3/utils' -import { EMPTY_DATA, ZERO_ADDRESS } from '@safe-global/protocol-kit/adapters/web3/utils/constants' -import { Gnosis_safe as Safe } from '@safe-global/protocol-kit/typechain/src/web3-v1/v1.1.1/Gnosis_safe' -import { SafeSetupConfig } from '@safe-global/safe-core-sdk-types' -import SafeContractWeb3 from '../SafeContractWeb3' - -class SafeContract_V1_1_1_Web3 extends SafeContractWeb3 { - constructor(public contract: Safe) { - super(contract) - } - - async setup( - setupConfig: SafeSetupConfig, - options?: Web3TransactionOptions - ): Promise { - const { - owners, - threshold, - to = ZERO_ADDRESS, - data = EMPTY_DATA, - fallbackHandler = ZERO_ADDRESS, - paymentToken = ZERO_ADDRESS, - payment = 0, - paymentReceiver = ZERO_ADDRESS - } = setupConfig - - if (options && !options.gas) { - options.gas = await this.estimateGas( - 'setup', - [owners, threshold, to, data, fallbackHandler, paymentToken, payment, paymentReceiver], - { - ...options - } - ) - } - const txResponse = this.contract.methods - .setup(owners, threshold, to, data, fallbackHandler, paymentToken, payment, paymentReceiver) - .send(options) - - return toTxResult(txResponse, options) - } - - async getModules(): Promise { - return this.contract.methods.getModules().call() - } - - async isModuleEnabled(moduleAddress: string): Promise { - const modules = await this.getModules() - const isModuleEnabled = modules.some((enabledModuleAddress: string) => - sameString(enabledModuleAddress, moduleAddress) - ) - return isModuleEnabled - } -} - -export default SafeContract_V1_1_1_Web3 diff --git a/packages/protocol-kit/src/adapters/web3/contracts/Safe/v1.1.1/SafeContract_v1_1_1_Web3.ts b/packages/protocol-kit/src/adapters/web3/contracts/Safe/v1.1.1/SafeContract_v1_1_1_Web3.ts new file mode 100644 index 000000000..0a8832396 --- /dev/null +++ b/packages/protocol-kit/src/adapters/web3/contracts/Safe/v1.1.1/SafeContract_v1_1_1_Web3.ts @@ -0,0 +1,341 @@ +import SafeBaseContractWeb3 from '@safe-global/protocol-kit/adapters/web3/contracts/Safe/SafeBaseContractWeb3' +import { + DeepWriteable, + Web3TransactionOptions, + Web3TransactionResult +} from '@safe-global/protocol-kit/adapters/web3/types' +import { toTxResult } from '@safe-global/protocol-kit/adapters/web3/utils' +import Web3Adapter from '@safe-global/protocol-kit/adapters/web3/Web3Adapter' +import safe_1_1_1_ContractArtifacts from '@safe-global/protocol-kit/contracts/AbiType/assets/Safe/v1.1.1/gnosis_safe' +import { + EncodeSafeFunction, + EstimateGasSafeFunction +} from '@safe-global/protocol-kit/contracts/AbiType/Safe/SafeBaseContract' +import SafeContract_v1_1_1_Contract, { + SafeContract_v1_1_1_Abi as SafeContract_v1_1_1_Abi_Readonly +} from '@safe-global/protocol-kit/contracts/AbiType/Safe/v1.1.1/SafeContract_v1_1_1' +import { sameString } from '@safe-global/protocol-kit/utils' +import { SafeTransaction, SafeTransactionData, SafeVersion } from '@safe-global/safe-core-sdk-types' + +// Remove all nested `readonly` modifiers from the ABI type +type SafeContract_v1_1_1_Abi = DeepWriteable + +/** + * SafeContract_v1_1_1_Web3 is the implementation specific to the Safe contract version 1.1.1. + * + * This class specializes in handling interactions with the Safe contract version 1.1.1 using Web3.js. + * + * @extends SafeBaseContractWeb3 - Inherits from SafeBaseContractWeb3 with ABI specific to Safe contract version 1.1.1. + * @implements SafeContract_v1_1_1_Contract - Implements the interface specific to Safe contract version 1.1.1. + */ +class SafeContract_v1_1_1_Web3 + extends SafeBaseContractWeb3> + implements SafeContract_v1_1_1_Contract +{ + safeVersion: SafeVersion + + /** + * Constructs an instance of SafeContract_v1_1_1_Web3 + * + * @param chainId - The chain ID where the contract resides. + * @param web3Adapter - An instance of Web3Adapter. + * @param isL1SafeSingleton - A flag indicating if the contract is a L1 Safe Singleton. + * @param customContractAddress - Optional custom address for the contract. If not provided, the address is derived from the Safe deployments based on the chainId and safeVersion. + * @param customContractAbi - Optional custom ABI for the contract. If not provided, the default ABI for version 1.1.1 is used. + */ + constructor( + chainId: bigint, + web3Adapter: Web3Adapter, + isL1SafeSingleton = false, + customContractAddress?: string, + customContractAbi?: SafeContract_v1_1_1_Abi_Readonly + ) { + const safeVersion = '1.1.1' + const defaultAbi = safe_1_1_1_ContractArtifacts.abi as DeepWriteable + + super( + chainId, + web3Adapter, + defaultAbi, + safeVersion, + isL1SafeSingleton, + customContractAddress, + customContractAbi as DeepWriteable + ) + + this.safeVersion = safeVersion + } + + async NAME(): Promise<[string]> { + return [await this.contract.methods.NAME().call()] + } + + async VERSION(): Promise<[SafeVersion]> { + return [await this.contract.methods.VERSION().call()] + } + + async approvedHashes(args: readonly [owner: string, txHash: string]): Promise<[bigint]> { + return [await this.contract.methods.approvedHashes(...args).call()] + } + + async domainSeparator(): Promise<[string]> { + return [await this.contract.methods.domainSeparator().call()] + } + + async getModules(): Promise<[string[]]> { + return [await this.contract.methods.getModules().call()] + } + + async getModulesPaginated( + args: readonly [start: string, pageSize: bigint] + ): Promise<[modules: string[], next: string]> { + const res = await this.contract.methods.getModulesPaginated(...args).call() + return [res.array, res.next] + } + + async getOwners(): Promise { + return [await this.contract.methods.getOwners().call()] + } + + async getThreshold(): Promise<[bigint]> { + return [await this.contract.methods.getThreshold().call()] + } + + async isOwner(args: readonly [address: string]): Promise<[boolean]> { + return [await this.contract.methods.isOwner(...args).call()] + } + + async nonce(): Promise<[bigint]> { + return [await this.contract.methods.nonce().call()] + } + + async signedMessages(args: readonly [messageHash: string]): Promise<[bigint]> { + return [await this.contract.methods.signedMessages(...args).call()] + } + + async getMessageHash(args: readonly [message: string]): Promise<[string]> { + return [await this.contract.methods.getMessageHash(...args).call()] + } + + async encodeTransactionData( + args: readonly [ + to: string, + value: bigint, + data: string, + operation: number, + safeTxGas: bigint, + baseGas: bigint, + gasPrice: bigint, + gasToken: string, + refundReceiver: string, + _nonce: bigint + ] + ): Promise<[string]> { + return [await this.contract.methods.encodeTransactionData(...args).call()] + } + + async getTransactionHash( + args: readonly [ + to: string, + value: bigint, + data: string, + operation: number, + safeTxGas: bigint, + baseGas: bigint, + gasPrice: bigint, + gasToken: string, + refundReceiver: string, + _nonce: bigint + ] + ): Promise<[string]> { + return [await this.contract.methods.getTransactionHash(...args).call()] + } + + encode: EncodeSafeFunction = (functionToEncode, args) => { + return this.contract.methods[functionToEncode](...args).encodeABI() + } + + estimateGas: EstimateGasSafeFunction = ( + functionToEstimate, + args, + options = {} + ) => { + return this.contract.methods[functionToEstimate](...args) + .estimateGas(options) + .then(BigInt) + } + + // Custom method (not defined in the Safe Contract) + getAddress(): Promise { + return Promise.resolve(this.contract.options.address) + } + + // Custom method (not defined in the Safe Contract) + async execTransaction( + safeTransaction: SafeTransaction, + options?: Web3TransactionOptions + ): Promise { + if (options && !options.gas) { + options.gas = ( + await this.estimateGas( + 'execTransaction', + [ + 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 + ) + ).toString() + } + const txResponse = this.contract.methods + .execTransaction( + 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() + ) + .send(options) + + return toTxResult(txResponse, options) + } + + // Custom method (not defined in the Safe Contract) + async isModuleEnabled(moduleAddress: string): Promise { + const [modules] = await this.getModules() + const isModuleEnabled = modules.some((enabledModuleAddress: string) => + sameString(enabledModuleAddress, moduleAddress) + ) + return isModuleEnabled + } + + // Custom method (not defined in the Safe Contract) + async isValidTransaction( + safeTransaction: SafeTransaction, + options?: Web3TransactionOptions + ): Promise { + let isTxValid = false + try { + if (options && !options.gas) { + options.gas = ( + await this.estimateGas( + 'execTransaction', + [ + 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 + ) + ).toString() + } + isTxValid = await this.contract.methods + .execTransaction( + 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() + ) + .call(options) + } catch {} + return isTxValid + } + + // Custom method (not defined in the Safe Contract) + async approveHash( + hash: string, + options?: Web3TransactionOptions + ): Promise { + if (options && !options.gas) { + options.gas = (await this.estimateGas('approveHash', [hash], { ...options })).toString() + } + const txResponse = this.contract.methods.approveHash(hash).send(options) + return toTxResult(txResponse, options) + } + + // TODO: Remove this mapper after remove Typechain + mapToTypechainContract(): any { + return { + contract: this.contract, + + setup: (): any => { + // setup function is labelled as `external` on the contract code, but not present on type SafeContract_v1_1_1_Contract + return + }, + + getModules: async () => (await this.getModules())[0], + + isModuleEnabled: this.isModuleEnabled.bind(this), + + getVersion: async () => (await this.VERSION())[0], + + getAddress: this.getAddress.bind(this), + + getNonce: async () => Number((await this.nonce())[0]), + + getThreshold: async () => Number((await this.getThreshold())[0]), + + getOwners: async () => (await this.getOwners())[0], + + isOwner: async (address: string) => (await this.isOwner([address]))[0], + + getTransactionHash: async (safeTransactionData: SafeTransactionData) => { + return ( + await this.getTransactionHash([ + safeTransactionData.to, + BigInt(safeTransactionData.value), + safeTransactionData.data, + safeTransactionData.operation, + BigInt(safeTransactionData.safeTxGas), + BigInt(safeTransactionData.baseGas), + BigInt(safeTransactionData.gasPrice), + safeTransactionData.gasToken, + safeTransactionData.refundReceiver, + BigInt(safeTransactionData.nonce) + ]) + )[0] + }, + + approvedHashes: async (ownerAddress: string, hash: string) => + (await this.approvedHashes([ownerAddress, hash]))[0], + + approveHash: this.approveHash.bind(this), + + isValidTransaction: this.isValidTransaction.bind(this), + + execTransaction: this.execTransaction.bind(this), + + encode: this.encode.bind(this), + + estimateGas: this.estimateGas.bind(this) + } + } +} + +export default SafeContract_v1_1_1_Web3 diff --git a/packages/protocol-kit/src/adapters/web3/contracts/contractInstancesWeb3.ts b/packages/protocol-kit/src/adapters/web3/contracts/contractInstancesWeb3.ts index d2ade6b40..d4bf5d52a 100644 --- a/packages/protocol-kit/src/adapters/web3/contracts/contractInstancesWeb3.ts +++ b/packages/protocol-kit/src/adapters/web3/contracts/contractInstancesWeb3.ts @@ -1,12 +1,13 @@ import { AbiItem } from 'web3-utils' +import SafeContract_v1_1_1_Web3 from '@safe-global/protocol-kit/adapters/web3/contracts/Safe/v1.1.1/SafeContract_v1_1_1_Web3' import SafeContract_v1_3_0_Web3 from '@safe-global/protocol-kit/adapters/web3/contracts/Safe/v1.3.0/SafeContract_v1_3_0_Web3' import SafeContract_v1_4_1_Web3 from '@safe-global/protocol-kit/adapters/web3/contracts/Safe/v1.4.1/SafeContract_v1_4_1_Web3' import Web3Adapter from '@safe-global/protocol-kit/adapters/web3/Web3Adapter' +import { SafeContract_v1_1_1_Abi } from '@safe-global/protocol-kit/contracts/AbiType/Safe/v1.1.1/SafeContract_v1_1_1' import { SafeContract_v1_3_0_Abi } from '@safe-global/protocol-kit/contracts/AbiType/Safe/v1.3.0/SafeContract_v1_3_0' import { SafeContract_v1_4_1_Abi } from '@safe-global/protocol-kit/contracts/AbiType/Safe/v1.4.1/SafeContract_v1_4_1' import { Gnosis_safe as SafeSingleton_V1_0_0 } from '@safe-global/protocol-kit/typechain/src/web3-v1/v1.0.0/Gnosis_safe' import { Proxy_factory as SafeProxyFactory_V1_0_0 } from '@safe-global/protocol-kit/typechain/src/web3-v1/v1.0.0/Proxy_factory' -import { Gnosis_safe as SafeSingleton_V1_1_1 } from '@safe-global/protocol-kit/typechain/src/web3-v1/v1.1.1/Gnosis_safe' import { Multi_send as MultiSend_V1_1_1 } from '@safe-global/protocol-kit/typechain/src/web3-v1/v1.1.1/Multi_send' import { Proxy_factory as SafeProxyFactory_V1_1_1 } from '@safe-global/protocol-kit/typechain/src/web3-v1/v1.1.1/Proxy_factory' import { Gnosis_safe as SafeSingleton_V1_2_0 } from '@safe-global/protocol-kit/typechain/src/web3-v1/v1.2.0/Gnosis_safe' @@ -35,7 +36,6 @@ import MultiSendContract_V1_4_1_Web3 from './MultiSend/v1.4.1/MultiSendContract_ import MultiSendCallOnlyContract_V1_3_0_Web3 from './MultiSendCallOnly/v1.3.0/MultiSendCallOnlyContract_V1_3_0_Web3' import MultiSendCallOnlyContract_V1_4_1_Web3 from './MultiSendCallOnly/v1.4.1/MultiSendCallOnlyContract_V1_4_1_Web3' import SafeContract_V1_0_0_Web3 from './Safe/v1.0.0/SafeContract_V1_0_0_Web3' -import SafeContract_V1_1_1_Web3 from './Safe/v1.1.1/SafeContract_V1_1_1_Web3' import SafeContract_V1_2_0_Web3 from './Safe/v1.2.0/SafeContract_V1_2_0_Web3' import SafeProxyFactoryContract_V1_0_0_Web3 from './SafeProxyFactory/v1.0.0/SafeProxyFactoryContract_V1_0_0_Web3' import SafeProxyFactoryContract_V1_1_1_Web3 from './SafeProxyFactory/v1.1.1/SafeProxyFactoryContract_V1_1_1_Web3' @@ -48,12 +48,12 @@ import SimulateTxAccessorContract_V1_4_1_Web3 from './SimulateTxAccessor/v1.4.1/ export async function getSafeContractInstance( safeVersion: SafeVersion, - safeSingletonContract: SafeSingleton_V1_2_0 | SafeSingleton_V1_1_1 | SafeSingleton_V1_0_0, + safeSingletonContract: SafeSingleton_V1_2_0 | SafeSingleton_V1_0_0, contractAddress: string, web3Adapter: Web3Adapter, customContractAbi?: AbiItem | AbiItem[] | undefined, isL1SafeSingleton?: boolean -): Promise { +): Promise { const chainId = await web3Adapter.getChainId() let safeContract switch (safeVersion) { @@ -82,7 +82,16 @@ export async function getSafeContractInstance( case '1.2.0': return new SafeContract_V1_2_0_Web3(safeSingletonContract as SafeSingleton_V1_2_0) case '1.1.1': - return new SafeContract_V1_1_1_Web3(safeSingletonContract as SafeSingleton_V1_1_1) + safeContract = new SafeContract_v1_1_1_Web3( + chainId, + web3Adapter, + isL1SafeSingleton, + contractAddress, + // TODO: Remove this unknown after remove Typechain + customContractAbi as unknown as SafeContract_v1_1_1_Abi + ) + // TODO: Remove this mapper after remove typechain + return safeContract.mapToTypechainContract() case '1.0.0': return new SafeContract_V1_0_0_Web3(safeSingletonContract as SafeSingleton_V1_0_0) default: diff --git a/packages/protocol-kit/src/contracts/AbiType/Safe/v1.1.1/SafeContract_v1_1_1.ts b/packages/protocol-kit/src/contracts/AbiType/Safe/v1.1.1/SafeContract_v1_1_1.ts new file mode 100644 index 000000000..fe9d10124 --- /dev/null +++ b/packages/protocol-kit/src/contracts/AbiType/Safe/v1.1.1/SafeContract_v1_1_1.ts @@ -0,0 +1,39 @@ +import { narrow } from 'abitype' +import safe_1_1_1_ContractArtifacts from '@safe-global/protocol-kit/contracts/AbiType/assets/Safe/v1.1.1/gnosis_safe' +import SafeBaseContract, { + SafeContractReadFunctions, + SafeContractWriteFunctions +} from '../SafeBaseContract' + +const safeContract_v1_1_1_AbiTypes = narrow(safe_1_1_1_ContractArtifacts.abi) + +/** + * Represents the ABI of the Safe contract version 1.1.1. + * + * @type {SafeContract_v1_1_1_Abi} + */ +export type SafeContract_v1_1_1_Abi = typeof safeContract_v1_1_1_AbiTypes + +/** + * Extracts the names of read-only functions (view or pure) specific to the Safe contract version 1.1.1. + * + * @type {Safe_v1_1_1_Read_Functions} + */ +export type Safe_v1_1_1_Read_Functions = SafeContractReadFunctions + +/** + * Extracts the names of write functions (nonpayable or payable) specific to the Safe contract version 1.1.1. + * + * @type {Safe_v1_1_1_Write_Functions} + */ +export type Safe_v1_1_1_Write_Functions = SafeContractWriteFunctions + +/** + * Represents the contract type for a Safe contract version 1.1.1, defining read and write methods. + * Utilizes the generic SafeBaseContract with the ABI specific to version 1.1.1. + * + * @type {SafeContract_v1_1_1_Contract} + */ +type SafeContract_v1_1_1_Contract = SafeBaseContract + +export default SafeContract_v1_1_1_Contract diff --git a/packages/protocol-kit/src/contracts/AbiType/assets/Safe/v1.1.1/gnosis_safe.ts b/packages/protocol-kit/src/contracts/AbiType/assets/Safe/v1.1.1/gnosis_safe.ts new file mode 100644 index 000000000..f22985fbe --- /dev/null +++ b/packages/protocol-kit/src/contracts/AbiType/assets/Safe/v1.1.1/gnosis_safe.ts @@ -0,0 +1,996 @@ +// Source: https://github.com/safe-global/safe-deployments/blob/main/src/assets/v1.1.1/gnosis_safe.json +export default { + defaultAddress: '0x34CfAC646f301356fAa8B21e94227e3583Fe3F5F', + released: true, + contractName: 'GnosisSafe', + version: '1.1.1', + networkAddresses: { + '1': '0x34CfAC646f301356fAa8B21e94227e3583Fe3F5F', + '4': '0x34CfAC646f301356fAa8B21e94227e3583Fe3F5F', + '5': '0x34CfAC646f301356fAa8B21e94227e3583Fe3F5F', + '42': '0x34CfAC646f301356fAa8B21e94227e3583Fe3F5F', + '88': '0x34CfAC646f301356fAa8B21e94227e3583Fe3F5F', + '100': '0x34CfAC646f301356fAa8B21e94227e3583Fe3F5F', + '246': '0x34CfAC646f301356fAa8B21e94227e3583Fe3F5F', + '73799': '0x34CfAC646f301356fAa8B21e94227e3583Fe3F5F' + }, + abi: [ + { + inputs: [], + payable: false, + stateMutability: 'nonpayable', + type: 'constructor' + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: 'address', + name: 'owner', + type: 'address' + } + ], + name: 'AddedOwner', + type: 'event' + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'bytes32', + name: 'approvedHash', + type: 'bytes32' + }, + { + indexed: true, + internalType: 'address', + name: 'owner', + type: 'address' + } + ], + name: 'ApproveHash', + type: 'event' + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: 'address', + name: 'masterCopy', + type: 'address' + } + ], + name: 'ChangedMasterCopy', + type: 'event' + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: 'uint256', + name: 'threshold', + type: 'uint256' + } + ], + name: 'ChangedThreshold', + type: 'event' + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: 'contract Module', + name: 'module', + type: 'address' + } + ], + name: 'DisabledModule', + type: 'event' + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: 'contract Module', + name: 'module', + type: 'address' + } + ], + name: 'EnabledModule', + type: 'event' + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: 'bytes32', + name: 'txHash', + type: 'bytes32' + }, + { + indexed: false, + internalType: 'uint256', + name: 'payment', + type: 'uint256' + } + ], + name: 'ExecutionFailure', + type: 'event' + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'address', + name: 'module', + type: 'address' + } + ], + name: 'ExecutionFromModuleFailure', + type: 'event' + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'address', + name: 'module', + type: 'address' + } + ], + name: 'ExecutionFromModuleSuccess', + type: 'event' + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: 'bytes32', + name: 'txHash', + type: 'bytes32' + }, + { + indexed: false, + internalType: 'uint256', + name: 'payment', + type: 'uint256' + } + ], + name: 'ExecutionSuccess', + type: 'event' + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: 'address', + name: 'owner', + type: 'address' + } + ], + name: 'RemovedOwner', + type: 'event' + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'bytes32', + name: 'msgHash', + type: 'bytes32' + } + ], + name: 'SignMsg', + type: 'event' + }, + { + payable: true, + stateMutability: 'payable', + type: 'fallback' + }, + { + constant: true, + inputs: [], + name: 'NAME', + outputs: [ + { + internalType: 'string', + name: '', + type: 'string' + } + ], + payable: false, + stateMutability: 'view', + type: 'function' + }, + { + constant: true, + inputs: [], + name: 'VERSION', + outputs: [ + { + internalType: 'string', + name: '', + type: 'string' + } + ], + payable: false, + stateMutability: 'view', + type: 'function' + }, + { + constant: false, + inputs: [ + { + internalType: 'address', + name: 'owner', + type: 'address' + }, + { + internalType: 'uint256', + name: '_threshold', + type: 'uint256' + } + ], + name: 'addOwnerWithThreshold', + outputs: [], + payable: false, + stateMutability: 'nonpayable', + type: 'function' + }, + { + constant: true, + inputs: [ + { + internalType: 'address', + name: '', + type: 'address' + }, + { + internalType: 'bytes32', + name: '', + type: 'bytes32' + } + ], + name: 'approvedHashes', + outputs: [ + { + internalType: 'uint256', + name: '', + type: 'uint256' + } + ], + payable: false, + stateMutability: 'view', + type: 'function' + }, + { + constant: false, + inputs: [ + { + internalType: 'address', + name: '_masterCopy', + type: 'address' + } + ], + name: 'changeMasterCopy', + outputs: [], + payable: false, + stateMutability: 'nonpayable', + type: 'function' + }, + { + constant: false, + inputs: [ + { + internalType: 'uint256', + name: '_threshold', + type: 'uint256' + } + ], + name: 'changeThreshold', + outputs: [], + payable: false, + stateMutability: 'nonpayable', + type: 'function' + }, + { + constant: false, + inputs: [ + { + internalType: 'contract Module', + name: 'prevModule', + type: 'address' + }, + { + internalType: 'contract Module', + name: 'module', + type: 'address' + } + ], + name: 'disableModule', + outputs: [], + payable: false, + stateMutability: 'nonpayable', + type: 'function' + }, + { + constant: true, + inputs: [], + name: 'domainSeparator', + outputs: [ + { + internalType: 'bytes32', + name: '', + type: 'bytes32' + } + ], + payable: false, + stateMutability: 'view', + type: 'function' + }, + { + constant: false, + inputs: [ + { + internalType: 'contract Module', + name: 'module', + type: 'address' + } + ], + name: 'enableModule', + outputs: [], + payable: false, + stateMutability: 'nonpayable', + type: 'function' + }, + { + constant: false, + inputs: [ + { + internalType: 'address', + name: 'to', + type: 'address' + }, + { + internalType: 'uint256', + name: 'value', + type: 'uint256' + }, + { + internalType: 'bytes', + name: 'data', + type: 'bytes' + }, + { + internalType: 'enum Enum.Operation', + name: 'operation', + type: 'uint8' + } + ], + name: 'execTransactionFromModule', + outputs: [ + { + internalType: 'bool', + name: 'success', + type: 'bool' + } + ], + payable: false, + stateMutability: 'nonpayable', + type: 'function' + }, + { + constant: false, + inputs: [ + { + internalType: 'address', + name: 'to', + type: 'address' + }, + { + internalType: 'uint256', + name: 'value', + type: 'uint256' + }, + { + internalType: 'bytes', + name: 'data', + type: 'bytes' + }, + { + internalType: 'enum Enum.Operation', + name: 'operation', + type: 'uint8' + } + ], + name: 'execTransactionFromModuleReturnData', + outputs: [ + { + internalType: 'bool', + name: 'success', + type: 'bool' + }, + { + internalType: 'bytes', + name: 'returnData', + type: 'bytes' + } + ], + payable: false, + stateMutability: 'nonpayable', + type: 'function' + }, + { + constant: true, + inputs: [], + name: 'getModules', + outputs: [ + { + internalType: 'address[]', + name: '', + type: 'address[]' + } + ], + payable: false, + stateMutability: 'view', + type: 'function' + }, + { + constant: true, + inputs: [ + { + internalType: 'address', + name: 'start', + type: 'address' + }, + { + internalType: 'uint256', + name: 'pageSize', + type: 'uint256' + } + ], + name: 'getModulesPaginated', + outputs: [ + { + internalType: 'address[]', + name: 'array', + type: 'address[]' + }, + { + internalType: 'address', + name: 'next', + type: 'address' + } + ], + payable: false, + stateMutability: 'view', + type: 'function' + }, + { + constant: true, + inputs: [], + name: 'getOwners', + outputs: [ + { + internalType: 'address[]', + name: '', + type: 'address[]' + } + ], + payable: false, + stateMutability: 'view', + type: 'function' + }, + { + constant: true, + inputs: [], + name: 'getThreshold', + outputs: [ + { + internalType: 'uint256', + name: '', + type: 'uint256' + } + ], + payable: false, + stateMutability: 'view', + type: 'function' + }, + { + constant: true, + inputs: [ + { + internalType: 'address', + name: 'owner', + type: 'address' + } + ], + name: 'isOwner', + outputs: [ + { + internalType: 'bool', + name: '', + type: 'bool' + } + ], + payable: false, + stateMutability: 'view', + type: 'function' + }, + { + constant: true, + inputs: [], + name: 'nonce', + outputs: [ + { + internalType: 'uint256', + name: '', + type: 'uint256' + } + ], + payable: false, + stateMutability: 'view', + type: 'function' + }, + { + constant: false, + inputs: [ + { + internalType: 'address', + name: 'prevOwner', + type: 'address' + }, + { + internalType: 'address', + name: 'owner', + type: 'address' + }, + { + internalType: 'uint256', + name: '_threshold', + type: 'uint256' + } + ], + name: 'removeOwner', + outputs: [], + payable: false, + stateMutability: 'nonpayable', + type: 'function' + }, + { + constant: false, + inputs: [ + { + internalType: 'address', + name: 'handler', + type: 'address' + } + ], + name: 'setFallbackHandler', + outputs: [], + payable: false, + stateMutability: 'nonpayable', + type: 'function' + }, + { + constant: true, + inputs: [ + { + internalType: 'bytes32', + name: '', + type: 'bytes32' + } + ], + name: 'signedMessages', + outputs: [ + { + internalType: 'uint256', + name: '', + type: 'uint256' + } + ], + payable: false, + stateMutability: 'view', + type: 'function' + }, + { + constant: false, + inputs: [ + { + internalType: 'address', + name: 'prevOwner', + type: 'address' + }, + { + internalType: 'address', + name: 'oldOwner', + type: 'address' + }, + { + internalType: 'address', + name: 'newOwner', + type: 'address' + } + ], + name: 'swapOwner', + outputs: [], + payable: false, + stateMutability: 'nonpayable', + type: 'function' + }, + { + constant: false, + inputs: [ + { + internalType: 'address[]', + name: '_owners', + type: 'address[]' + }, + { + internalType: 'uint256', + name: '_threshold', + type: 'uint256' + }, + { + internalType: 'address', + name: 'to', + type: 'address' + }, + { + internalType: 'bytes', + name: 'data', + type: 'bytes' + }, + { + internalType: 'address', + name: 'fallbackHandler', + type: 'address' + }, + { + internalType: 'address', + name: 'paymentToken', + type: 'address' + }, + { + internalType: 'uint256', + name: 'payment', + type: 'uint256' + }, + { + internalType: 'address payable', + name: 'paymentReceiver', + type: 'address' + } + ], + name: 'setup', + outputs: [], + payable: false, + stateMutability: 'nonpayable', + type: 'function' + }, + { + constant: false, + inputs: [ + { + internalType: 'address', + name: 'to', + type: 'address' + }, + { + internalType: 'uint256', + name: 'value', + type: 'uint256' + }, + { + internalType: 'bytes', + name: 'data', + type: 'bytes' + }, + { + internalType: 'enum Enum.Operation', + name: 'operation', + type: 'uint8' + }, + { + internalType: 'uint256', + name: 'safeTxGas', + type: 'uint256' + }, + { + internalType: 'uint256', + name: 'baseGas', + type: 'uint256' + }, + { + internalType: 'uint256', + name: 'gasPrice', + type: 'uint256' + }, + { + internalType: 'address', + name: 'gasToken', + type: 'address' + }, + { + internalType: 'address payable', + name: 'refundReceiver', + type: 'address' + }, + { + internalType: 'bytes', + name: 'signatures', + type: 'bytes' + } + ], + name: 'execTransaction', + outputs: [ + { + internalType: 'bool', + name: 'success', + type: 'bool' + } + ], + payable: false, + stateMutability: 'nonpayable', + type: 'function' + }, + { + constant: false, + inputs: [ + { + internalType: 'address', + name: 'to', + type: 'address' + }, + { + internalType: 'uint256', + name: 'value', + type: 'uint256' + }, + { + internalType: 'bytes', + name: 'data', + type: 'bytes' + }, + { + internalType: 'enum Enum.Operation', + name: 'operation', + type: 'uint8' + } + ], + name: 'requiredTxGas', + outputs: [ + { + internalType: 'uint256', + name: '', + type: 'uint256' + } + ], + payable: false, + stateMutability: 'nonpayable', + type: 'function' + }, + { + constant: false, + inputs: [ + { + internalType: 'bytes32', + name: 'hashToApprove', + type: 'bytes32' + } + ], + name: 'approveHash', + outputs: [], + payable: false, + stateMutability: 'nonpayable', + type: 'function' + }, + { + constant: false, + inputs: [ + { + internalType: 'bytes', + name: '_data', + type: 'bytes' + } + ], + name: 'signMessage', + outputs: [], + payable: false, + stateMutability: 'nonpayable', + type: 'function' + }, + { + constant: false, + inputs: [ + { + internalType: 'bytes', + name: '_data', + type: 'bytes' + }, + { + internalType: 'bytes', + name: '_signature', + type: 'bytes' + } + ], + name: 'isValidSignature', + outputs: [ + { + internalType: 'bytes4', + name: '', + type: 'bytes4' + } + ], + payable: false, + stateMutability: 'nonpayable', + type: 'function' + }, + { + constant: true, + inputs: [ + { + internalType: 'bytes', + name: 'message', + type: 'bytes' + } + ], + name: 'getMessageHash', + outputs: [ + { + internalType: 'bytes32', + name: '', + type: 'bytes32' + } + ], + payable: false, + stateMutability: 'view', + type: 'function' + }, + { + constant: true, + inputs: [ + { + internalType: 'address', + name: 'to', + type: 'address' + }, + { + internalType: 'uint256', + name: 'value', + type: 'uint256' + }, + { + internalType: 'bytes', + name: 'data', + type: 'bytes' + }, + { + internalType: 'enum Enum.Operation', + name: 'operation', + type: 'uint8' + }, + { + internalType: 'uint256', + name: 'safeTxGas', + type: 'uint256' + }, + { + internalType: 'uint256', + name: 'baseGas', + type: 'uint256' + }, + { + internalType: 'uint256', + name: 'gasPrice', + type: 'uint256' + }, + { + internalType: 'address', + name: 'gasToken', + type: 'address' + }, + { + internalType: 'address', + name: 'refundReceiver', + type: 'address' + }, + { + internalType: 'uint256', + name: '_nonce', + type: 'uint256' + } + ], + name: 'encodeTransactionData', + outputs: [ + { + internalType: 'bytes', + name: '', + type: 'bytes' + } + ], + payable: false, + stateMutability: 'view', + type: 'function' + }, + { + constant: true, + inputs: [ + { + internalType: 'address', + name: 'to', + type: 'address' + }, + { + internalType: 'uint256', + name: 'value', + type: 'uint256' + }, + { + internalType: 'bytes', + name: 'data', + type: 'bytes' + }, + { + internalType: 'enum Enum.Operation', + name: 'operation', + type: 'uint8' + }, + { + internalType: 'uint256', + name: 'safeTxGas', + type: 'uint256' + }, + { + internalType: 'uint256', + name: 'baseGas', + type: 'uint256' + }, + { + internalType: 'uint256', + name: 'gasPrice', + type: 'uint256' + }, + { + internalType: 'address', + name: 'gasToken', + type: 'address' + }, + { + internalType: 'address', + name: 'refundReceiver', + type: 'address' + }, + { + internalType: 'uint256', + name: '_nonce', + type: 'uint256' + } + ], + name: 'getTransactionHash', + outputs: [ + { + internalType: 'bytes32', + name: '', + type: 'bytes32' + } + ], + payable: false, + stateMutability: 'view', + type: 'function' + } + ] +} as const