Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(protocol-kit): Migrate SimulateTxAccessor contract to Abitype #744

Merged
6 changes: 2 additions & 4 deletions packages/protocol-kit/scripts/generateTypechainFiles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,11 @@ const safeContractsPath = '../../node_modules/@safe-global/safe-deployments/dist

const safeContracts_V1_4_1 = [
`${safeContractsPath}/v1.4.1/compatibility_fallback_handler.json`,
`${safeContractsPath}/v1.4.1/create_call.json`,
`${safeContractsPath}/v1.4.1/simulate_tx_accessor.json`
`${safeContractsPath}/v1.4.1/create_call.json`
].join(' ')
const safeContracts_V1_3_0 = [
`${safeContractsPath}/v1.3.0/compatibility_fallback_handler.json`,
`${safeContractsPath}/v1.3.0/create_call.json`,
`${safeContractsPath}/v1.3.0/simulate_tx_accessor.json`
`${safeContractsPath}/v1.3.0/create_call.json`
].join(' ')

// Won't be included in dist/ folder
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { contractName, getContractDeployment } from '@safe-global/protocol-kit/contracts/config'
import { SafeVersion } from '@safe-global/safe-core-sdk-types'

/**
* Abstract class SimulateTxAccessorBaseContract serves as a base for creating a SimulateTxAccessorBaseContract contract for a specific adapter (Ethers.js, Web3.js, or viem.js)
* This class is designed to be extended by adapter-specific abstract classes, such as SimulateTxAccessorBaseContractEthers, SimulateTxAccessorBaseContractWeb3, and SimulateTxAccessorBaseContractViem.
* It includes the core logic for selecting the appropriate ABI and the address from SimulateTxAccessor deployments.
*
* @template SimulateTxAccessorContractAbiType - The ABI associated with the SimulateTxAccessor contract.
*
* Example subclasses extending this base class:
* - SimulateTxAccessorBaseContractEthers<SimulateTxAccessorContract_v1_3_0_Abi> extends SimulateTxAccessorBaseContract<SimulateTxAccessorContract_v1_3_0_Abi>
* - SimulateTxAccessorBaseContractWeb3<SimulateTxAccessorContract_v1_3_0_Abi> extends SimulateTxAccessorBaseContract<SimulateTxAccessorContract_v1_3_0_Abi>
* - SimulateTxAccessorBaseContractViem<SimulateTxAccessorContract_v1_3_0_Abi> extends SimulateTxAccessorBaseContract<SimulateTxAccessorContract_v1_3_0_Abi>
*/
abstract class SimulateTxAccessorBaseContract<SimulateTxAccessorContractAbiType> {
contractAbi: SimulateTxAccessorContractAbiType
contractAddress: string

contractName: contractName
abstract safeVersion: SafeVersion

abstract contract: unknown // This needs to be implemented for each adapter.
abstract adapter: unknown // This needs to be implemented for each adapter.

/**
* Constructs a new SimulateTxAccessorBaseContract instance.
*
* @param chainId - The chain ID of the contract.
* @param defaultAbi - The hardcoded ABI of the SimulateTxAccessor contract.
* @param safeVersion - The version of the SimulateTxAccessor contract.
* @param customContractAddress - Optional custom address for the contract.
* @param customContractAbi - Optional custom ABI for the contract.
* @throws Will throw an error if the contract address is invalid.
*/
constructor(
chainId: bigint,
defaultAbi: SimulateTxAccessorContractAbiType,
safeVersion: SafeVersion,
customContractAddress?: string,
customContractAbi?: SimulateTxAccessorContractAbiType
) {
this.contractName = 'simulateTxAccessorVersion'

const deployment = getContractDeployment(safeVersion, chainId, this.contractName)

const contractAddress = customContractAddress || deployment?.defaultAddress

if (!contractAddress) {
throw new Error('Invalid contract address')
}

this.contractAddress = contractAddress
this.contractAbi =
customContractAbi ||
(deployment?.abi as SimulateTxAccessorContractAbiType) || // this cast is required because abi is set as any[] in safe-deployments
defaultAbi // if no customAbi and no abi is present in the safe-deployments we use our hardcoded abi
}
}

export default SimulateTxAccessorBaseContract
17 changes: 11 additions & 6 deletions packages/protocol-kit/src/adapters/ethers/EthersAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ import {
EthAdapterTransaction,
GetContractProps,
SafeEIP712Args,
SignMessageLibContract
SignMessageLibContract,
SimulateTxAccessorContract
} from '@safe-global/safe-core-sdk-types'
import { ethers, TransactionResponse, AbstractSigner, Provider } from 'ethers'
import CompatibilityFallbackHandlerContractEthers from './contracts/CompatibilityFallbackHandler/CompatibilityFallbackHandlerEthersContract'
import CreateCallEthersContract from './contracts/CreateCall/CreateCallEthersContract'
import SafeContractEthers from './contracts/Safe/SafeContractEthers'
import SimulateTxAccessorEthersContract from './contracts/SimulateTxAccessor/SimulateTxAccessorEthersContract'
import {
getCompatibilityFallbackHandlerContractInstance,
getCreateCallContractInstance,
Expand Down Expand Up @@ -235,16 +235,21 @@ class EthersAdapter implements EthAdapter {
async getSimulateTxAccessorContract({
safeVersion,
singletonDeployment,
customContractAddress
}: GetContractProps): Promise<SimulateTxAccessorEthersContract> {
customContractAddress,
customContractAbi
}: GetContractProps): Promise<SimulateTxAccessorContract> {
const chainId = await this.getChainId()
const contractAddress =
customContractAddress ?? singletonDeployment?.networkAddresses[chainId.toString()]
if (!contractAddress) {
throw new Error('Invalid SimulateTxAccessor contract address')
}
const signerOrProvider = this.#signer || this.#provider
return getSimulateTxAccessorContractInstance(safeVersion, contractAddress, signerOrProvider)
return getSimulateTxAccessorContractInstance(
safeVersion,
contractAddress,
this,
customContractAbi
)
}

async getContractCode(address: string, blockTag?: string | number): Promise<string> {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { Contract, ContractRunner, InterfaceAbi } from 'ethers'

import EthersAdapter from '@safe-global/protocol-kit/adapters/ethers/EthersAdapter'
import SimulateTxAccessorBaseContract from '@safe-global/protocol-kit/adapters/SimulateTxAccessorBaseContract'
import { SafeVersion } from '@safe-global/safe-core-sdk-types'

/**
* Abstract class SimulateTxAccessorBaseContractEthers extends SimulateTxAccessorBaseContract to specifically integrate with the Ethers.js v6 library.
* It is designed to be instantiated for different versions of the Safe contract.
*
* This abstract class sets up the Ethers v6 Contract object that interacts with a SimulateTxAccessor contract version.
*
* Subclasses of SimulateTxAccessorBaseContractEthers are expected to represent specific versions of the contract.
*
* @template SimulateTxAccessorContractAbiType - The ABI type specific to the version of the SimulateTxAccessor contract, extending InterfaceAbi from Ethers.
* @extends SimulateTxAccessorBaseContract<SimulateTxAccessorContractAbiType> - Extends the generic SimulateTxAccessorBaseContract with Ethers-specific implementation.
*
* Example subclasses:
* - SimulateTxAccessorContract_v1_4_1_Ethers extends SimulateTxAccessorBaseContractEthers<SimulateTxAccessorContract_v1_4_1_Abi>
* - SimulateTxAccessorContract_v1_3_0_Ethers extends SimulateTxAccessorBaseContractEthers<SimulateTxAccessorContract_v1_3_0_Abi>
*/
abstract class SimulateTxAccessorBaseContractEthers<
SimulateTxAccessorContractAbiType extends InterfaceAbi
> extends SimulateTxAccessorBaseContract<SimulateTxAccessorContractAbiType> {
contract: Contract
adapter: EthersAdapter

/**
* @constructor
* Constructs an instance of SimulateTxAccessorBaseContractEthers.
*
* @param chainId - The chain ID of the contract.
* @param ethersAdapter - An instance of EthersAdapter.
* @param defaultAbi - The default ABI for the SimulateTxAccessor contract. It should be compatible with the specific version of the contract.
* @param safeVersion - The version of the Safe contract.
* @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 ABI is derived from the Safe deployments or the defaultAbi is used.
*/
constructor(
chainId: bigint,
ethersAdapter: EthersAdapter,
defaultAbi: SimulateTxAccessorContractAbiType,
safeVersion: SafeVersion,
customContractAddress?: string,
customContractAbi?: SimulateTxAccessorContractAbiType,
runner?: ContractRunner | null
) {
super(chainId, defaultAbi, safeVersion, customContractAddress, customContractAbi)

this.adapter = ethersAdapter
this.contract = new Contract(
this.contractAddress,
this.contractAbi,
runner || this.adapter.getSigner()
)
}
}

export default SimulateTxAccessorBaseContractEthers

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import SimulateTxAccessorBaseContractEthers from '@safe-global/protocol-kit/adapters/ethers/contracts/SimulateTxAccessor/SimulateTxAccessorBaseContractEthers'
import EthersAdapter from '@safe-global/protocol-kit/adapters/ethers/EthersAdapter'
import SimulateTxAccessorContract_v1_3_0_Contract, {
SimulateTxAccessorContract_v1_3_0_Abi
} from '@safe-global/protocol-kit/contracts/AbiType/SimulateTxAccessor/v1.3.0/SimulateTxAccessorContract_v1_3_0'
import SimulateTxAccessor_1_3_0_ContractArtifacts from '@safe-global/protocol-kit/contracts/AbiType/assets/SimulateTxAccessor/v1.3.0/simulate_tx_accessor'
import { SafeVersion } from '@safe-global/safe-core-sdk-types'
import {
EncodeSimulateTxAccessorFunction,
GetAddressSimulateTxAccessorFunction
} from '@safe-global/protocol-kit/contracts/AbiType/SimulateTxAccessor/SimulateTxAccessorBaseContract'

/**
* SimulateTxAccessorContract_v1_3_0_Ethers is the implementation specific to the SimulateTxAccessor contract version 1.3.0.
*
* This class specializes in handling interactions with the SimulateTxAccessor contract version 1.3.0 using Ethers.js v6.
*
* @extends SimulateTxAccessorBaseContractEthers<SimulateTxAccessorContract_v1_3_0_Abi> - Inherits from SimulateTxAccessorBaseContractEthers with ABI specific to SimulateTxAccessor contract version 1.3.0.
* @implements SimulateTxAccessorContract_v1_3_0_Contract - Implements the interface specific to SimulateTxAccessor contract version 1.3.0.
*/
class SimulateTxAccessorContract_v1_3_0_Ethers
extends SimulateTxAccessorBaseContractEthers<SimulateTxAccessorContract_v1_3_0_Abi>
implements SimulateTxAccessorContract_v1_3_0_Contract
{
safeVersion: SafeVersion

/**
* Constructs an instance of SimulateTxAccessorContract_v1_3_0_Ethers
*
* @param chainId - The chain ID where the contract resides.
* @param ethersAdapter - An instance of EthersAdapter.
* @param customContractAddress - Optional custom address for the contract. If not provided, the address is derived from the SimulateTxAccessor deployments based on the chainId and safeVersion.
* @param customContractAbi - Optional custom ABI for the contract. If not provided, the default ABI for version 1.3.0 is used.
*/
constructor(
chainId: bigint,
ethersAdapter: EthersAdapter,
customContractAddress?: string,
customContractAbi?: SimulateTxAccessorContract_v1_3_0_Abi
) {
const safeVersion = '1.3.0'
const defaultAbi = SimulateTxAccessor_1_3_0_ContractArtifacts.abi

super(chainId, ethersAdapter, defaultAbi, safeVersion, customContractAddress, customContractAbi)

this.safeVersion = safeVersion
}

getAddress: GetAddressSimulateTxAccessorFunction = () => {
return this.contract.getAddress()
}

encode: EncodeSimulateTxAccessorFunction<SimulateTxAccessorContract_v1_3_0_Abi> = (
functionToEncode,
args
) => {
return this.contract.interface.encodeFunctionData(functionToEncode, args)
}

simulate: SimulateTxAccessorContract_v1_3_0_Contract['simulate'] = (
args: readonly [to: string, value: bigint, data: string, operation: number]
) => {
return this.contract.simulate(...args)
}
}

export default SimulateTxAccessorContract_v1_3_0_Ethers

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import SimulateTxAccessorBaseContractEthers from '@safe-global/protocol-kit/adapters/ethers/contracts/SimulateTxAccessor/SimulateTxAccessorBaseContractEthers'
import EthersAdapter from '@safe-global/protocol-kit/adapters/ethers/EthersAdapter'
import SimulateTxAccessorContract_v1_4_1_Contract, {
SimulateTxAccessorContract_v1_4_1_Abi
} from '@safe-global/protocol-kit/contracts/AbiType/SimulateTxAccessor/v1.4.1/SimulateTxAccessorContract_v1_4_1'
import SimulateTxAccessor_1_4_1_ContractArtifacts from '@safe-global/protocol-kit/contracts/AbiType/assets/SimulateTxAccessor/v1.4.1/simulate_tx_accessor'
import { SafeVersion } from '@safe-global/safe-core-sdk-types'
import {
EncodeSimulateTxAccessorFunction,
GetAddressSimulateTxAccessorFunction
} from '@safe-global/protocol-kit/contracts/AbiType/SimulateTxAccessor/SimulateTxAccessorBaseContract'

/**
* SimulateTxAccessorContract_v1_4_1_Ethers is the implementation specific to the SimulateTxAccessor contract version 1.4.1.
*
* This class specializes in handling interactions with the SimulateTxAccessor contract version 1.4.1 using Ethers.js v6.
*
* @extends SimulateTxAccessorBaseContractEthers<SimulateTxAccessorContract_v1_4_1_Abi> - Inherits from SimulateTxAccessorBaseContractEthers with ABI specific to SimulateTxAccessor contract version 1.4.1.
* @implements SimulateTxAccessorContract_v1_4_1_Contract - Implements the interface specific to SimulateTxAccessor contract version 1.4.1.
*/
class SimulateTxAccessorContract_v1_4_1_Ethers
extends SimulateTxAccessorBaseContractEthers<SimulateTxAccessorContract_v1_4_1_Abi>
implements SimulateTxAccessorContract_v1_4_1_Contract
{
safeVersion: SafeVersion

/**
* Constructs an instance of SimulateTxAccessorContract_v1_4_1_Ethers
*
* @param chainId - The chain ID where the contract resides.
* @param ethersAdapter - An instance of EthersAdapter.
* @param customContractAddress - Optional custom address for the contract. If not provided, the address is derived from the SimulateTxAccessor deployments based on the chainId and safeVersion.
* @param customContractAbi - Optional custom ABI for the contract. If not provided, the default ABI for version 1.4.1 is used.
*/
constructor(
chainId: bigint,
ethersAdapter: EthersAdapter,
customContractAddress?: string,
customContractAbi?: SimulateTxAccessorContract_v1_4_1_Abi
) {
const safeVersion = '1.4.1'
const defaultAbi = SimulateTxAccessor_1_4_1_ContractArtifacts.abi

super(chainId, ethersAdapter, defaultAbi, safeVersion, customContractAddress, customContractAbi)

this.safeVersion = safeVersion
}

getAddress: GetAddressSimulateTxAccessorFunction = () => {
return this.contract.getAddress()
}

encode: EncodeSimulateTxAccessorFunction<SimulateTxAccessorContract_v1_4_1_Abi> = (
functionToEncode,
args
) => {
return this.contract.interface.encodeFunctionData(functionToEncode, args)
}

simulate: SimulateTxAccessorContract_v1_4_1_Contract['simulate'] = (
args: readonly [to: string, value: bigint, data: string, operation: number]
) => {
return this.contract.simulate(...args)
}
}

export default SimulateTxAccessorContract_v1_4_1_Ethers
Loading
Loading