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

Support CreateCall contract library #277

Merged
merged 13 commits into from
Oct 20, 2022
6 changes: 5 additions & 1 deletion guides/integrating-the-safe-core-sdk.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,14 @@ const contractNetworks: ContractNetworksConfig = {
multiSendCallOnlyAddress: '<MULTI_SEND_CALL_ONLY_ADDRESS>',
safeMasterCopyAddress: '<MASTER_COPY_ADDRESS>',
safeProxyFactoryAddress: '<PROXY_FACTORY_ADDRESS>',
signMessageLibAddress: '<SIGN_MESSAGE_LIB_ADDRESS>',
createCallAddress: '<CREATE_CALL_ADDRESS>',
multiSendAbi: '<MULTI_SEND_ABI>', // Optional. Only needed with web3.js
multiSendCallOnlyAbi: '<MULTI_SEND_CALL_ONLY_ABI>', // Optional. Only needed with web3.js
safeMasterCopyAbi: '<MASTER_COPY_ABI>', // Optional. Only needed with web3.js
safeProxyFactoryAbi: '<PROXY_FACTORY_ABI>' // Optional. Only needed with web3.js
safeProxyFactoryAbi: '<PROXY_FACTORY_ABI>', // Optional. Only needed with web3.js
signMessageLibAbi: '<SIGN_MESSAGE_LIB_ABI>', // Optional. Only needed with web3.js
createCallAbi: '<CREATE_CALL_ABI>' // Optional. Only needed with web3.js
}
}

Expand Down
18 changes: 18 additions & 0 deletions packages/safe-core-sdk-types/src/contracts/CreateCallContract.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { TransactionOptions, TransactionResult } from '../types'

export interface CreateCallContract {
getAddress(): string
performCreate2(
value: string,
deploymentData: string,
salt: string,
options?: TransactionOptions
): Promise<TransactionResult>
performCreate(
value: string,
deploymentData: string,
options?: TransactionOptions
): Promise<TransactionResult>
encode(methodName: any, params: any): string
estimateGas(methodName: string, params: any[], options: TransactionOptions): Promise<number>
}
16 changes: 16 additions & 0 deletions packages/safe-core-sdk-types/src/ethereumLibs/EthAdapter.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { BigNumber } from '@ethersproject/bignumber'
import { SingletonDeployment } from '@gnosis.pm/safe-deployments'
import { AbiItem } from 'web3-utils'
import { CreateCallContract } from '../contracts/CreateCallContract'
import { GnosisSafeContract } from '../contracts/GnosisSafeContract'
import { GnosisSafeProxyFactoryContract } from '../contracts/GnosisSafeProxyFactoryContract'
import { MultiSendCallOnlyContract } from '../contracts/MultiSendCallOnlyContract'
import { MultiSendContract } from '../contracts/MultiSendContract'
import { SignMessageLibContract } from '../contracts/SignMessageLibContract'
import { Eip3770Address, SafeTransactionEIP712Args, SafeVersion } from '../types'

export interface EthAdapterTransaction {
Expand Down Expand Up @@ -61,6 +63,20 @@ export interface EthAdapter {
customContractAddress,
customContractAbi
}: GetContractProps): GnosisSafeProxyFactoryContract
getSignMessageLibContract({
safeVersion,
chainId,
singletonDeployment,
customContractAddress,
customContractAbi
}: GetContractProps): SignMessageLibContract
getCreateCallContract({
safeVersion,
chainId,
singletonDeployment,
customContractAddress,
customContractAbi
}: GetContractProps): CreateCallContract
getContractCode(address: string, defaultBlock?: string | number): Promise<string>
isContractDeployed(address: string, defaultBlock?: string | number): Promise<boolean>
getStorageAt(address: string, position: string): Promise<string>
Expand Down
1 change: 1 addition & 0 deletions packages/safe-core-sdk-types/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './contracts/CreateCallContract'
export * from './contracts/GnosisSafeContract'
export * from './contracts/GnosisSafeProxyFactoryContract'
export * from './contracts/MultiSendCallOnlyContract'
Expand Down
18 changes: 15 additions & 3 deletions packages/safe-core-sdk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,10 +174,14 @@ const safeFactory = await SafeFactory.create({ ethAdapter })
multiSendCallOnlyAddress: '<MULTI_SEND_CALL_ONLY_ADDRESS>',
safeMasterCopyAddress: '<MASTER_COPY_ADDRESS>',
safeProxyFactoryAddress: '<PROXY_FACTORY_ADDRESS>',
signMessageLibAddress: '<SIGN_MESSAGE_LIB_ADDRESS>',
createCallAddress: '<CREATE_CALL_ADDRESS>',
multiSendAbi: '<MULTI_SEND_ABI>', // Optional. Only needed with web3.js
multiSendCallOnlyAbi: '<MULTI_SEND_CALL_ONLY_ABI>', // Optional. Only needed with web3.js
safeMasterCopyAbi: '<MASTER_COPY_ABI>', // Optional. Only needed with web3.js
safeProxyFactoryAbi: '<PROXY_FACTORY_ABI>' // Optional. Only needed with web3.js
safeProxyFactoryAbi: '<PROXY_FACTORY_ABI>', // Optional. Only needed with web3.js
signMessageLibAbi: '<SIGN_MESSAGE_LIB_ABI>', // Optional. Only needed with web3.js
createCallAbi: '<CREATE_CALL_ABI>' // Optional. Only needed with web3.js
}
}

Expand Down Expand Up @@ -302,10 +306,14 @@ const safeSdk = await Safe.create({ ethAdapter, safeAddress })
multiSendCallOnlyAddress: '<MULTI_SEND_CALL_ONLY_ADDRESS>',
safeMasterCopyAddress: '<MASTER_COPY_ADDRESS>',
safeProxyFactoryAddress: '<PROXY_FACTORY_ADDRESS>',
signMessageLibAddress: '<SIGN_MESSAGE_LIB_ADDRESS>',
createCallAddress: '<CREATE_CALL_ADDRESS>',
multiSendAbi: '<MULTI_SEND_ABI>', // Optional. Only needed with web3.js
multiSendCallOnlyAbi: '<MULTI_SEND_CALL_ONLY_ABI>', // Optional. Only needed with web3.js
safeMasterCopyAbi: '<MASTER_COPY_ABI>', // Optional. Only needed with web3.js
safeProxyFactoryAbi: '<PROXY_FACTORY_ABI>' // Optional. Only needed with web3.js
safeProxyFactoryAbi: '<PROXY_FACTORY_ABI>', // Optional. Only needed with web3.js
signMessageLibAbi: '<SIGN_MESSAGE_LIB_ABI>', // Optional. Only needed with web3.js
createCallAbi: '<CREATE_CALL_ABI>' // Optional. Only needed with web3.js
}
}

Expand Down Expand Up @@ -341,10 +349,14 @@ const safeSdk2 = await safeSdk.connect({ ethAdapter, safeAddress })
multiSendCallOnlyAddress: '<MULTI_SEND_CALL_ONLY_ADDRESS>',
safeMasterCopyAddress: '<MASTER_COPY_ADDRESS>',
safeProxyFactoryAddress: '<PROXY_FACTORY_ADDRESS>',
signMessageLibAddress: '<SIGN_MESSAGE_LIB_ADDRESS>',
createCallAddress: '<CREATE_CALL_ADDRESS>',
multiSendAbi: '<MULTI_SEND_ABI>', // Optional. Only needed with web3.js
multiSendCallOnlyAbi: '<MULTI_SEND_CALL_ONLY_ABI>', // Optional. Only needed with web3.js
safeMasterCopyAbi: '<MASTER_COPY_ABI>', // Optional. Only needed with web3.js
safeProxyFactoryAbi: '<PROXY_FACTORY_ABI>' // Optional. Only needed with web3.js
safeProxyFactoryAbi: '<PROXY_FACTORY_ABI>', // Optional. Only needed with web3.js
signMessageLibAbi: '<SIGN_MESSAGE_LIB_ABI>', // Optional. Only needed with web3.js
createCallAbi: '<CREATE_CALL_ABI>' // Optional. Only needed with web3.js
}
}
const safeSdk = await Safe.connect({ ethAdapter, safeAddress, contractNetworks })
Expand Down
4 changes: 4 additions & 0 deletions packages/safe-core-sdk/contracts/Deps_V1_3_0.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,13 @@ import { GnosisSafeProxyFactory } from "@gnosis.pm/safe-contracts-v1.3.0/contrac
import { GnosisSafe } from "@gnosis.pm/safe-contracts-v1.3.0/contracts/GnosisSafe.sol";
import { MultiSend } from "@gnosis.pm/safe-contracts-v1.3.0/contracts/libraries/MultiSend.sol";
import { MultiSendCallOnly } from "@gnosis.pm/safe-contracts-v1.3.0/contracts/libraries/MultiSendCallOnly.sol";
import { SignMessageLib } from "@gnosis.pm/safe-contracts-v1.3.0/contracts/examples/libraries/SignMessage.sol";
import { CreateCall } from "@gnosis.pm/safe-contracts-v1.3.0/contracts/libraries/CreateCall.sol";
import { DebugTransactionGuard } from "@gnosis.pm/safe-contracts-v1.3.0/contracts/examples/guards/DebugTransactionGuard.sol";

contract ProxyFactory_SV1_3_0 is GnosisSafeProxyFactory {}
contract GnosisSafe_SV1_3_0 is GnosisSafe {}
contract MultiSend_SV1_3_0 is MultiSend {}
contract MultiSendCallOnly_SV1_3_0 is MultiSendCallOnly {}
contract SignMessageLib_SV1_3_0 is SignMessageLib {}
contract CreateCall_SV1_3_0 is CreateCall {}
28 changes: 28 additions & 0 deletions packages/safe-core-sdk/hardhat/deploy/deploy-contracts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,24 @@ const multiSendCallOnlyContracts = {
'1.1.1': { name: 'MultiSendCallOnly_SV1_3_0' }
}

const signMessageLibContracts = {
'1.3.0': { name: 'SignMessageLib_SV1_3_0' },
'1.2.0': { name: 'SignMessageLib_SV1_3_0' },
'1.1.1': { name: 'SignMessageLib_SV1_3_0' }
}

const createCallContracts = {
'1.3.0': { name: 'CreateCall_SV1_3_0' },
'1.2.0': { name: 'CreateCall_SV1_3_0' },
'1.1.1': { name: 'CreateCall_SV1_3_0' }
}

export const gnosisSafeDeployed = gnosisSafeContracts[safeVersionDeployed]
export const proxyFactoryDeployed = proxyFactoryContracts[safeVersionDeployed]
export const multiSendDeployed = multiSendContracts[safeVersionDeployed]
export const multiSendCallOnlyDeployed = multiSendCallOnlyContracts[safeVersionDeployed]
export const signMessageLibDeployed = signMessageLibContracts[safeVersionDeployed]
export const createCallDeployed = createCallContracts[safeVersionDeployed]

const deploy: DeployFunction = async (hre: HardhatRuntimeEnvironment): Promise<void> => {
const { deployments, getNamedAccounts } = hre
Expand Down Expand Up @@ -66,6 +80,20 @@ const deploy: DeployFunction = async (hre: HardhatRuntimeEnvironment): Promise<v
deterministicDeployment: true
})

await deploy(signMessageLibDeployed.name, {
from: deployer,
args: [],
log: true,
deterministicDeployment: true
})

await deploy(createCallDeployed.name, {
from: deployer,
args: [],
log: true,
deterministicDeployment: true
})

await deploy('DailyLimitModule', {
from: deployer,
args: [],
Expand Down
14 changes: 11 additions & 3 deletions packages/safe-core-sdk/src/contracts/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ type SafeDeploymentsVersions = {
safeProxyFactoryVersion: string
multiSendVersion: string
multiSendCallOnlyVersion: string
signMessageLibVersion: string
createCallVersion: string
}
}

Expand All @@ -19,21 +21,27 @@ export const safeDeploymentsVersions: SafeDeploymentsVersions = {
safeMasterCopyL2Version: '1.3.0',
safeProxyFactoryVersion: '1.3.0',
multiSendVersion: '1.3.0',
multiSendCallOnlyVersion: '1.3.0'
multiSendCallOnlyVersion: '1.3.0',
signMessageLibVersion: '1.3.0',
createCallVersion: '1.3.0'
},
'1.2.0': {
safeMasterCopyVersion: '1.2.0',
safeMasterCopyL2Version: undefined,
safeProxyFactoryVersion: '1.1.1',
multiSendVersion: '1.1.1',
multiSendCallOnlyVersion: '1.3.0'
multiSendCallOnlyVersion: '1.3.0',
signMessageLibVersion: '1.3.0',
createCallVersion: '1.3.0'
},
'1.1.1': {
safeMasterCopyVersion: '1.1.1',
safeMasterCopyL2Version: undefined,
safeProxyFactoryVersion: '1.1.1',
multiSendVersion: '1.1.1',
multiSendCallOnlyVersion: '1.3.0'
multiSendCallOnlyVersion: '1.3.0',
signMessageLibVersion: '1.3.0',
createCallVersion: '1.3.0'
}
}

Expand Down
70 changes: 67 additions & 3 deletions packages/safe-core-sdk/src/contracts/safeDeploymentContracts.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
import {
CreateCallContract,
EthAdapter,
GnosisSafeContract,
GnosisSafeProxyFactoryContract,
MultiSendCallOnlyContract,
MultiSendContract,
SafeVersion
SafeVersion,
SignMessageLibContract
} from '@gnosis.pm/safe-core-sdk-types'
import {
DeploymentFilter,
getCreateCallDeployment,
getMultiSendCallOnlyDeployment,
getMultiSendDeployment,
getProxyFactoryDeployment,
getSafeL2SingletonDeployment,
getSafeSingletonDeployment,
getSignMessageLibDeployment,
SingletonDeployment
} from '@gnosis.pm/safe-deployments'
import { ContractNetworkConfig } from '../types'
Expand Down Expand Up @@ -67,6 +71,22 @@ export function getSafeProxyFactoryContractDeployment(
return getProxyFactoryDeployment({ version, network: chainId.toString(), released: true })
}

export function getSignMessageLibContractDeployment(
safeVersion: SafeVersion,
chainId: number
): SingletonDeployment | undefined {
const version = safeDeploymentsVersions[safeVersion].signMessageLibVersion
return getSignMessageLibDeployment({ version, network: chainId.toString(), released: true })
}

export function getCreateCallContractDeployment(
safeVersion: SafeVersion,
chainId: number
): SingletonDeployment | undefined {
const version = safeDeploymentsVersions[safeVersion].createCallVersion
return getCreateCallDeployment({ version, network: chainId.toString(), released: true })
}

export async function getSafeContract({
ethAdapter,
safeVersion,
Expand Down Expand Up @@ -145,8 +165,8 @@ export async function getMultiSendCallOnlyContract({
safeVersion,
chainId,
singletonDeployment: multiSendCallOnlyDeployment,
customContractAddress: customContracts?.multiSendAddress,
customContractAbi: customContracts?.multiSendAbi
customContractAddress: customContracts?.multiSendCallOnlyAddress,
customContractAbi: customContracts?.multiSendCallOnlyAbi
})
const isContractDeployed = await ethAdapter.isContractDeployed(
multiSendCallOnlyContract.getAddress()
Expand All @@ -156,3 +176,47 @@ export async function getMultiSendCallOnlyContract({
}
return multiSendCallOnlyContract
}

export async function getSignMessageLibContract({
ethAdapter,
safeVersion,
chainId,
customContracts
}: GetContractInstanceProps): Promise<SignMessageLibContract> {
const signMessageLibDeployment = getSignMessageLibContractDeployment(safeVersion, chainId)
const signMessageLibContract = await ethAdapter.getSignMessageLibContract({
safeVersion,
chainId,
singletonDeployment: signMessageLibDeployment,
customContractAddress: customContracts?.signMessageLibAddress,
customContractAbi: customContracts?.signMessageLibAbi
})
const isContractDeployed = await ethAdapter.isContractDeployed(
signMessageLibContract.getAddress()
)
if (!isContractDeployed) {
throw new Error('SignMessageLib contract is not deployed on the current network')
}
return signMessageLibContract
}

export async function getCreateCallContract({
ethAdapter,
safeVersion,
chainId,
customContracts
}: GetContractInstanceProps): Promise<CreateCallContract> {
const createCallDeployment = getCreateCallContractDeployment(safeVersion, chainId)
const createCallContract = await ethAdapter.getCreateCallContract({
safeVersion,
chainId,
singletonDeployment: createCallDeployment,
customContractAddress: customContracts?.createCallAddress,
customContractAbi: customContracts?.createCallAbi
})
const isContractDeployed = await ethAdapter.isContractDeployed(createCallContract.getAddress())
if (!isContractDeployed) {
throw new Error('CreateCall contract is not deployed on the current network')
}
return createCallContract
}
8 changes: 8 additions & 0 deletions packages/safe-core-sdk/src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ export interface ContractNetworkConfig {
safeProxyFactoryAddress: string
/** safeProxyFactoryAbi - Abi of the GnosisSafeProxyFactory contract deployed on a specific network */
safeProxyFactoryAbi?: AbiItem | AbiItem[]
/** 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?: AbiItem | AbiItem[]
/** 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?: AbiItem | AbiItem[]
}

export interface ContractNetworksConfig {
Expand Down
10 changes: 8 additions & 2 deletions packages/safe-core-sdk/tests/contractManager.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ import Safe, { ContractNetworksConfig } from '../src'
import { ZERO_ADDRESS } from '../src/utils/constants'
import { getContractNetworks } from './utils/setupContractNetworks'
import {
getCreateCall,
getFactory,
getMultiSend,
getMultiSendCallOnly,
getSafeSingleton,
getSafeWithOwners
getSafeWithOwners,
getSignMessageLib
} from './utils/setupContracts'
import { getEthAdapter } from './utils/setupEthAdapter'
import { getAccounts } from './utils/setupTestNetwork'
Expand Down Expand Up @@ -75,7 +77,11 @@ describe('Safe contracts manager', () => {
safeMasterCopyAddress: ZERO_ADDRESS,
safeMasterCopyAbi: (await getSafeSingleton()).abi,
safeProxyFactoryAddress: ZERO_ADDRESS,
safeProxyFactoryAbi: (await getFactory()).abi
safeProxyFactoryAbi: (await getFactory()).abi,
signMessageLibAddress: ZERO_ADDRESS,
signMessageLibAbi: (await getSignMessageLib()).abi,
createCallAddress: ZERO_ADDRESS,
createCallAbi: (await getCreateCall()).abi
}
}
const [account1] = accounts
Expand Down
Loading