dp-contract-proxy-kit
Version:
Enable batched transactions and contract account interactions using a unique deterministic Gnosis Safe.
172 lines (152 loc) • 5.38 kB
text/typescript
import cpkFactoryAbi from '../abis/CpkFactoryAbi.json'
import multiSendAbi from '../abis/MultiSendAbi.json'
import safeAbiV111 from '../abis/SafeAbiV1-1-1.json'
import safeAbiV120 from '../abis/SafeAbiV1-2-0.json'
import { NormalizedNetworkConfigEntry } from '../config/networks'
import EthLibAdapter, { Contract } from '../ethLibAdapters/EthLibAdapter'
import { Address } from '../utils/basicTypes'
import ContractV111Utils from './ContractV111Utils'
import ContractV120Utils from './ContractV120Utils'
import ContractVersionUtils from './ContractVersionUtils'
export interface ContractManagerProps {
ethLibAdapter: EthLibAdapter
network: NormalizedNetworkConfigEntry
ownerAccount: Address | undefined
saltNonce: string
isSafeApp: boolean
isConnectedToSafe: boolean
}
class ContractManager {
static async create(opts: ContractManagerProps): Promise<ContractManager> {
const contractManager = new ContractManager(opts.ethLibAdapter, opts.network)
await contractManager.init(opts)
return contractManager
}
constructor(ethLibAdapter: EthLibAdapter, network: NormalizedNetworkConfigEntry) {
this.
this.
this.
this.
}
async init(opts: ContractManagerProps): Promise<void> {
await this.calculateVersionUtils(opts)
}
private async calculateVersionUtils(opts: ContractManagerProps) {
const { ethLibAdapter, ownerAccount, saltNonce, network, isSafeApp, isConnectedToSafe } = opts
let proxyAddress
let properVersion
if (isSafeApp || isConnectedToSafe) {
const temporaryContract = ethLibAdapter.getContract(safeAbiV111, ownerAccount)
properVersion = await temporaryContract.call('VERSION', [])
proxyAddress = ownerAccount
} else {
const salt = ethLibAdapter.keccak256(
ethLibAdapter.abiEncode(['address', 'uint256'], [ownerAccount, saltNonce])
)
for (const masterCopyVersion of network.masterCopyAddressVersions) {
proxyAddress = await this.calculateProxyAddress(
masterCopyVersion.address,
salt,
ethLibAdapter
)
const codeAtAddress = await ethLibAdapter.getCode(proxyAddress)
const isDeployed = codeAtAddress !== '0x'
if (isDeployed) {
const temporaryContract = ethLibAdapter.getContract(safeAbiV111, proxyAddress)
properVersion = await temporaryContract.call('VERSION', [])
break
}
}
if (!properVersion) {
// Last version released
properVersion = network.masterCopyAddressVersions[0].version
proxyAddress = await this.calculateProxyAddress(
network.masterCopyAddressVersions[0].address,
salt,
ethLibAdapter
)
}
}
switch (properVersion) {
case '1.2.0':
this.
this.
break
case '1.1.1':
this.
this.
break
default:
throw new Error('CPK Proxy version is not valid')
}
}
private async calculateProxyAddress(
masterCopyAddress: Address,
salt: string,
ethLibAdapter: EthLibAdapter
): Promise<Address> {
const initCode = ethLibAdapter.abiEncodePacked(
{ type: 'bytes', value: await this.
{
type: 'bytes',
value: ethLibAdapter.abiEncode(['address'], [masterCopyAddress])
}
)
const proxyAddress = ethLibAdapter.calcCreate2Address(
this.
salt,
initCode
)
return proxyAddress
}
get versionUtils(): ContractVersionUtils | undefined {
return this.
}
/**
* Returns the instance of the Safe contract in use.
*
* @returns The instance of the Safe contract in use
*/
get contract(): Contract | undefined {
return this.
}
/**
* Returns the instance of the Proxy Factory contract in use.
*
* @returns The instance of the Proxy Factory contract in use
*/
get proxyFactory(): Contract {
return this.
}
/**
* Returns the Master Copy contract address in use.
*
* @returns The Master Copy contract address in use
*/
get masterCopyAddress(): Address {
return this.
}
/**
* Returns the instance of the MultiSend contract in use.
*
* @returns The instance of the MultiSend contract in use
*/
get multiSend(): Contract {
return this.
}
/**
* Returns the FallbackHandler contract address in use.
*
* @returns The FallbackHandler contract address in use
*/
get fallbackHandlerAddress(): Address {
return this.
}
}
export default ContractManager