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): Predict Safe address improvements #982

Merged
merged 31 commits into from
Sep 26, 2024
Merged
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
d249e00
Add getContractInfo method
yagopv Sep 18, 2024
3a7a472
Merge branch 'development' of https://github.com/safe-global/safe-cor…
yagopv Sep 19, 2024
203c26d
Add tests
yagopv Sep 19, 2024
d9e9761
Add test
yagopv Sep 19, 2024
4e0cea9
Add some changes to allow to choose the deploymentType
yagopv Sep 20, 2024
c10fd16
Some changes to fix the BaseContract deploymenttype search
yagopv Sep 23, 2024
7f2af83
Add deploymentType as SafeProvider parameter
yagopv Sep 23, 2024
5c8d944
extract common type
yagopv Sep 23, 2024
aa9c1e6
Make SafeProvider.init options an object
yagopv Sep 24, 2024
fc42f97
Improve BaseContract logic
yagopv Sep 24, 2024
b2f5f36
Use types
yagopv Sep 24, 2024
bd77ffe
Fix issue
yagopv Sep 24, 2024
4f541f0
Remove console.log
yagopv Sep 24, 2024
8a195cf
Execute new tests for >= 1.3.0
yagopv Sep 24, 2024
30852ee
Log the failing address
yagopv Sep 24, 2024
2a370a2
Change sepolia to optimism because there is a memoizing issue
yagopv Sep 24, 2024
a3fd9f2
update type
yagopv Sep 24, 2024
ea4bffa
Merge branch 'development' of https://github.com/safe-global/safe-cor…
yagopv Sep 25, 2024
52b8e99
Remove deploymentType from SafeProvider
yagopv Sep 25, 2024
b943451
Spread deploymentType
yagopv Sep 25, 2024
44fa727
update tests
yagopv Sep 25, 2024
9cbc29e
add deploymentType for all contract instances
yagopv Sep 25, 2024
7ec5cb5
Add comments
yagopv Sep 25, 2024
9d65688
Update rpc's
yagopv Sep 25, 2024
401bc29
Improve BaseContract contractAddress logic
yagopv Sep 25, 2024
855907c
Avoid exception
yagopv Sep 25, 2024
421e5ea
Add deploymentType to getInitCode
yagopv Sep 25, 2024
a10d8e6
Add more chains to the test
yagopv Sep 26, 2024
3d09d3e
Remove prop from type
yagopv Sep 26, 2024
eab2f3d
beforeEach => before
yagopv Sep 26, 2024
9fca597
Remove only
yagopv Sep 26, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 20 additions & 7 deletions packages/protocol-kit/src/Safe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import {
getPredictedSafeAddressInitCode,
predictSafeAddress
} from './contracts/utils'
import { DEFAULT_SAFE_VERSION } from './contracts/config'
import { ContractInfo, DEFAULT_SAFE_VERSION, getContractInfo } from './contracts/config'
import ContractManager from './managers/contractManager'
import FallbackHandlerManager from './managers/fallbackHandlerManager'
import GuardManager from './managers/guardManager'
Expand Down Expand Up @@ -124,12 +124,12 @@ class Safe {
async #initializeProtocolKit(config: SafeConfig) {
const { provider, signer, isL1SafeSingleton, contractNetworks } = config

this.#safeProvider = await SafeProvider.init(
this.#safeProvider = await SafeProvider.init({
provider,
signer,
DEFAULT_SAFE_VERSION,
safeVersion: DEFAULT_SAFE_VERSION,
contractNetworks
)
})

if (isSafeConfigWithPredictedSafe(config)) {
this.#predictedSafe = config.predictedSafe
Expand All @@ -155,7 +155,12 @@ class Safe {
}

const safeVersion = this.getContractVersion()
this.#safeProvider = await SafeProvider.init(provider, signer, safeVersion, contractNetworks)
this.#safeProvider = await SafeProvider.init({
provider,
signer,
safeVersion,
contractNetworks
})

this.#ownerManager = new OwnerManager(this.#safeProvider, this.#contractManager.safeContract)
this.#moduleManager = new ModuleManager(this.#safeProvider, this.#contractManager.safeContract)
Expand All @@ -169,14 +174,14 @@ class Safe {
if (isPasskeySigner) {
const safeAddress = await this.getAddress()
const owners = await this.getOwners()
this.#safeProvider = await SafeProvider.init(
this.#safeProvider = await SafeProvider.init({
provider,
signer,
safeVersion,
contractNetworks,
safeAddress,
owners
)
})
}
}

Expand Down Expand Up @@ -1636,6 +1641,14 @@ class Safe {
return false
}
}

getContractInfo = ({
contractAddress
}: {
contractAddress: string
}): ContractInfo | undefined => {
return getContractInfo(contractAddress)
}
}

export default Safe
7 changes: 6 additions & 1 deletion packages/protocol-kit/src/SafeFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,12 @@ class SafeFactory {
}: SafeFactoryInitConfig) {
this.#provider = provider
this.#signer = signer
this.#safeProvider = await SafeProvider.init(provider, signer, safeVersion, contractNetworks)
this.#safeProvider = await SafeProvider.init({
provider,
signer,
safeVersion,
contractNetworks
})
this.#safeVersion = safeVersion
this.#isL1SafeSingleton = isL1SafeSingleton
this.#contractNetworks = contractNetworks
Expand Down
22 changes: 10 additions & 12 deletions packages/protocol-kit/src/SafeProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,18 @@
EIP712TypedDataMessage,
EIP712TypedDataTx,
Eip3770Address,
SafeEIP712Args,
SafeVersion
SafeEIP712Args
} from '@safe-global/types-kit'
import {
SafeProviderTransaction,
SafeProviderConfig,
SafeProviderInitOptions,
ExternalClient,
ExternalSigner,
Eip1193Provider,
HttpTransport,
SocketTransport,
SafeSigner,
SafeConfig,
ContractNetworksConfig,
PasskeyArgType,
PasskeyClient
} from '@safe-global/protocol-kit/types'
Expand Down Expand Up @@ -102,14 +100,14 @@
return this.#externalProvider
}

static async init(
provider: SafeConfig['provider'],
signer?: SafeConfig['signer'],
safeVersion: SafeVersion = DEFAULT_SAFE_VERSION,
contractNetworks?: ContractNetworksConfig,
safeAddress?: string,
owners?: string[]
): Promise<SafeProvider> {
static async init({
provider,
signer,
safeVersion = DEFAULT_SAFE_VERSION,
contractNetworks,
safeAddress,
owners
}: SafeProviderInitOptions): Promise<SafeProvider> {
const isPasskeySigner = signer && typeof signer !== 'string'

if (isPasskeySigner) {
Expand Down Expand Up @@ -365,11 +363,11 @@
}

// TODO: fix anys
encodeParameters(types: string, values: any[]): string {

Check warning on line 366 in packages/protocol-kit/src/SafeProvider.ts

View workflow job for this annotation

GitHub Actions / eslint

Unexpected any. Specify a different type
return encodeAbiParameters(parseAbiParameters(types), values)
}

decodeParameters(types: string, values: string): { [key: string]: any } {

Check warning on line 370 in packages/protocol-kit/src/SafeProvider.ts

View workflow job for this annotation

GitHub Actions / eslint

Unexpected any. Specify a different type
return decodeAbiParameters(parseAbiParameters(types), asHex(values))
}

Expand Down
47 changes: 39 additions & 8 deletions packages/protocol-kit/src/contracts/BaseContract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
Chain
} from 'viem'
import { estimateContractGas, getTransactionReceipt } from 'viem/actions'
import { SingletonDeployment } from '@safe-global/safe-deployments'
import { contractName, getContractDeployment } from '@safe-global/protocol-kit/contracts/config'
import { DeploymentType } from '@safe-global/protocol-kit/types'
import SafeProvider from '@safe-global/protocol-kit/SafeProvider'
import {
EncodeFunction,
Expand Down Expand Up @@ -62,6 +64,7 @@
* @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.
* @param deploymentType - Optional deployment type for the contract. If not provided, the first deployment retrieved from the safe-deployments array will be used.
*/
constructor(
contractName: contractName,
Expand All @@ -70,24 +73,27 @@
defaultAbi: ContractAbiType,
safeVersion: SafeVersion,
customContractAddress?: string,
customContractAbi?: ContractAbiType
customContractAbi?: ContractAbiType,
deploymentType?: DeploymentType
) {
const deployment = getContractDeployment(safeVersion, chainId, contractName)

const contractAddress =
customContractAddress || deployment?.networkAddresses[chainId.toString()]
const resolvedAddress =
customContractAddress ??
this.#resolveAddress(
deployment?.networkAddresses[chainId.toString()],
deployment,
deploymentType
)

if (!contractAddress) {
if (!resolvedAddress) {
throw new Error(`Invalid ${contractName.replace('Version', '')} contract address`)
}

this.chainId = chainId
this.contractName = contractName
this.safeVersion = safeVersion
this.contractAddress =
Array.isArray(contractAddress) && contractAddress.length
? contractAddress[0]
: contractAddress.toString()
this.contractAddress = resolvedAddress
this.contractAbi =
customContractAbi ||
(deployment?.abi as unknown as ContractAbiType) || // this cast is required because abi is set as any[] in safe-deployments
Expand All @@ -97,6 +103,31 @@
this.safeProvider = safeProvider
}

#resolveAddress(
networkAddresses: string | string[] | undefined,
deployment: SingletonDeployment,
deploymentType?: DeploymentType
): string | undefined {
if (!networkAddresses) {
return undefined
}

if (typeof networkAddresses === 'string') {
return networkAddresses
}

if (deploymentType) {
const customDeploymentTypeAddress = deployment.deployments[deploymentType]?.address

return (
networkAddresses.find((address) => address === customDeploymentTypeAddress) ??
networkAddresses[0]
)
}

return networkAddresses[0]
}

async init() {
this.wallet = await this.safeProvider.getExternalSigner()
}
Expand Down Expand Up @@ -175,7 +206,7 @@
functionName
>
>(functionName: functionName, args: functionArgs, options?: TransactionOptions) {
const converted = this.convertOptions(options) as any

Check warning on line 209 in packages/protocol-kit/src/contracts/BaseContract.ts

View workflow job for this annotation

GitHub Actions / eslint

Unexpected any. Specify a different type

return await this.getWallet().writeContract({
address: this.contractAddress,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Abi } from 'abitype'

import SafeProvider from '@safe-global/protocol-kit/SafeProvider'
import BaseContract from '@safe-global/protocol-kit/contracts/BaseContract'
import { DeploymentType } from '@safe-global/protocol-kit/types'
import { SafeVersion } from '@safe-global/types-kit'
import { contractName } from '@safe-global/protocol-kit/contracts/config'

Expand Down Expand Up @@ -33,14 +34,16 @@ abstract class CompatibilityFallbackHandlerBaseContract<
* @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.
* @param deploymentType - Optional deployment type for the contract. If not provided, the first deployment retrieved from the safe-deployments array will be used.
*/
constructor(
chainId: bigint,
safeProvider: SafeProvider,
defaultAbi: CompatibilityFallbackHandlerContractAbiType,
safeVersion: SafeVersion,
customContractAddress?: string,
customContractAbi?: CompatibilityFallbackHandlerContractAbiType
customContractAbi?: CompatibilityFallbackHandlerContractAbiType,
deploymentType?: DeploymentType
) {
const contractName = 'compatibilityFallbackHandler'

Expand All @@ -51,7 +54,8 @@ abstract class CompatibilityFallbackHandlerBaseContract<
defaultAbi,
safeVersion,
customContractAddress,
customContractAbi
customContractAbi,
deploymentType
)

this.contractName = contractName
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import CompatibilityFallbackHandlerBaseContract from '@safe-global/protocol-kit/contracts/CompatibilityFallbackHandler/CompatibilityFallbackHandlerBaseContract'
import SafeProvider from '@safe-global/protocol-kit/SafeProvider'
import { DeploymentType } from '@safe-global/protocol-kit/types'
import {
CompatibilityFallbackHandlerContract_v1_3_0_Abi,
CompatibilityFallbackHandlerContract_v1_3_0_Contract,
Expand All @@ -25,17 +26,27 @@ class CompatibilityFallbackHandlerContract_v1_3_0
* @param safeProvider - An instance of SafeProvider.
* @param customContractAddress - Optional custom address for the contract. If not provided, the address is derived from the CompatibilityFallbackHandler 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.
* @param deploymentType - Optional deployment type for the contract. If not provided, the first deployment retrieved from the safe-deployments array will be used.
*/
constructor(
chainId: bigint,
safeProvider: SafeProvider,
customContractAddress?: string,
customContractAbi?: CompatibilityFallbackHandlerContract_v1_3_0_Abi
customContractAbi?: CompatibilityFallbackHandlerContract_v1_3_0_Abi,
deploymentType?: DeploymentType
) {
const safeVersion = '1.3.0'
const defaultAbi = compatibilityFallbackHandler_1_3_0_ContractArtifacts.abi

super(chainId, safeProvider, defaultAbi, safeVersion, customContractAddress, customContractAbi)
super(
chainId,
safeProvider,
defaultAbi,
safeVersion,
customContractAddress,
customContractAbi,
deploymentType
)
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import CompatibilityFallbackHandlerBaseContract from '@safe-global/protocol-kit/contracts/CompatibilityFallbackHandler/CompatibilityFallbackHandlerBaseContract'
import SafeProvider from '@safe-global/protocol-kit/SafeProvider'
import { DeploymentType } from '@safe-global/protocol-kit/types'
import {
compatibilityFallbackHandler_1_4_1_ContractArtifacts,
CompatibilityFallbackHandlerContract_v1_4_1_Abi,
Expand All @@ -25,17 +26,27 @@ class CompatibilityFallbackHandlerContract_v1_4_1
* @param safeProvider - An instance of SafeProvider.
* @param customContractAddress - Optional custom address for the contract. If not provided, the address is derived from the CompatibilityFallbackHandler 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.
* @param deploymentType - Optional deployment type for the contract. If not provided, the first deployment retrieved from the safe-deployments array will be used.
*/
constructor(
chainId: bigint,
safeProvider: SafeProvider,
customContractAddress?: string,
customContractAbi?: CompatibilityFallbackHandlerContract_v1_4_1_Abi
customContractAbi?: CompatibilityFallbackHandlerContract_v1_4_1_Abi,
deploymentType?: DeploymentType
) {
const safeVersion = '1.4.1'
const defaultAbi = compatibilityFallbackHandler_1_4_1_ContractArtifacts.abi

super(chainId, safeProvider, defaultAbi, safeVersion, customContractAddress, customContractAbi)
super(
chainId,
safeProvider,
defaultAbi,
safeVersion,
customContractAddress,
customContractAbi,
deploymentType
)
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Abi } from 'abitype'

import SafeProvider from '@safe-global/protocol-kit/SafeProvider'
import { DeploymentType } from '@safe-global/protocol-kit/types'
import BaseContract from '@safe-global/protocol-kit/contracts/BaseContract'
import { SafeVersion } from '@safe-global/types-kit'
import { contractName } from '@safe-global/protocol-kit/contracts/config'
Expand Down Expand Up @@ -33,14 +34,16 @@ abstract class CreateCallBaseContract<
* @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.
* @param deploymentType - Optional deployment type for the contract. If not provided, the first deployment retrieved from the safe-deployments array will be used.
*/
constructor(
chainId: bigint,
safeProvider: SafeProvider,
defaultAbi: CreateCallContractAbiType,
safeVersion: SafeVersion,
customContractAddress?: string,
customContractAbi?: CreateCallContractAbiType
customContractAbi?: CreateCallContractAbiType,
deploymentType?: DeploymentType
) {
const contractName = 'createCallVersion'

Expand All @@ -51,7 +54,8 @@ abstract class CreateCallBaseContract<
defaultAbi,
safeVersion,
customContractAddress,
customContractAbi
customContractAbi,
deploymentType
)

this.contractName = contractName
Expand Down
Loading
Loading