import { Steps } from 'nextra/components'
This guide will teach you how to replicate a Safe address across different chains using the Protocol Kit. This process includes initializing the Protocol Kit, configuring the Safes to deploy, predicting its address on different chains, and executing the deployment transactions.
First, you need to install the Protocol Kit.
{/* */}
pnpm add @safe-global/protocol-kit viem
{/* */}
Here are all the necessary imports for this guide.
{/* */}
import Safe, {
PredictedSafeProps,
SafeAccountConfig,
SafeDeploymentConfig
} from '@safe-global/protocol-kit'
import { waitForTransactionReceipt } from 'viem/actions'
import { gnosisChiado, sepolia } from 'viem/chains'
{/* */}
You need a signer to instantiate the Protocol Kit. This example uses a private key to obtain a signer, but other EIP-1193 compatible signers are also supported. For detailed information about signers, please refer to the Protocol Kit reference.
{/* */}
const SIGNER_PRIVATE_KEY = // ...
{/* */}
Define the predictedSafe
object with the configuration for all the Safe accounts you will deploy. Check the reference to learn about all the different configuration options.
{/* */}
const safeAccountConfig: SafeAccountConfig = {
owners: ['0x...', '0x...', '0x...'],
threshold: 2
// More optional properties
}
const predictedSafe: PredictedSafeProps = {
safeAccountConfig
// More optional properties
}
{/* */}
Initialize an instance of the Protocol Kit for each network where you want to deploy a new Safe smart account by calling the init
method. Pass the provider
with its corresponding value depending on the network, the signer
executing the deployment, and the predictedSafe
with the Safe account configuration.
{/* */}
const protocolKitSepolia = await Safe.init({
provider: sepolia.rpcUrls.default.http[0],
signer: SIGNER_PRIVATE_KEY,
predictedSafe
})
const protocolKitChiado = await Safe.init({
provider: gnosisChiado.rpcUrls.default.http[0],
signer: PRIVATE_KEY,
predictedSafe
})
{/* */}
You can predict the Safe addresses by calling the getAddress
method from each Protocol Kit instance and ensure that the result addresses are the same.
{/* */}
const sepoliaPredictedSafeAddress = await protocolKitSepolia.getAddress()
const chiadoPredictedSafeAddress = await protocolKitChiado.getAddress()
{/* */}
Create the deployment transaction to deploy a new Safe account in Sepolia by calling the createSafeDeploymentTransaction
method.
{/* */}
const sepoliaDeploymentTransaction =
await protocolKitSepolia.createSafeDeploymentTransaction()
{/* */}
Call the sendTransaction
method from your Sepolia client instance and wait for the transaction to be executed.
{/* */}
const sepoliaClient =
await protocolKitSepolia.getSafeProvider().getExternalSigner()
const transactionHashSepolia = await sepoliaClient!.sendTransaction({
to: sepoliaDeploymentTransaction.to,
value: BigInt(sepoliaDeploymentTransaction.value),
data: sepoliaDeploymentTransaction.data as `0x${string}`,
chain: sepolia
})
await waitForTransactionReceipt(
sepoliaClient!,
{ hash: transactionHashSepolia }
)
{/* */}
Once the deployment transaction is executed, connect the new Safe address to the Protocol Kit instance by calling the connect
method.
{/* */}
const newProtocolKitSepolia = await protocolKitSepolia.connect({
safeAddress: sepoliaPredictedSafeAddress
})
const isSepoliaSafeDeployed = await newProtocolKitSepolia.isSafeDeployed() // True
const sepoliaDeployedSafeAddress = await newProtocolKitSepolia.getAddress()
{/* */}
If everything went well, isSepoliaSafeDeployed
should be true
, and the sepoliaDeployedSafeAddress
should equal the sepoliaPredictedSafeAddress
.
Repeat the same steps to deploy a Safe with the same configuration on Chiado testnet.
{/* */}
const chiadoDeploymentTransaction =
await protocolKitChiado.createSafeDeploymentTransaction()
const chiadoClient =
await protocolKitChiado.getSafeProvider().getExternalSigner()
const transactionHashChiado = await chiadoClient!.sendTransaction({
to: chiadoDeploymentTransaction.to,
value: BigInt(chiadoDeploymentTransaction.value),
data: chiadoDeploymentTransaction.data as `0x${string}`,
chain: gnosisChiado
})
await waitForTransactionReceipt(
chiadoClient!,
{ hash: transactionHashChiado }
)
const newProtocolKitChiado = await protocolKitChiado.connect({
safeAddress: chiadoPredictedSafeAddress
})
const isChiadoSafeDeployed = await newProtocolKitChiado.isSafeDeployed() // True
const chiadoDeployedSafeAddress = await newProtocolKitChiado.getAddress()
{/* */}
If everything went well, isChiadoSafeDeployed
should be true
, and the chiadoDeployedSafeAddress
should equal the chiadoPredictedSafeAddress
.
In addition, chiadoDeployedSafeAddress
and sepoliaDeployedSafeAddress
should have the same value.
After following this guide, you are able to deploy multiple Safe accounts with the same address on different chains using the Protocol Kit.