API Kit
The API Kit (opens in a new tab) facilitates the interaction with the Safe Transaction Service API (opens in a new tab), allowing to propose and share transactions with the other signers of a Safe, sending the signatures to the service to collect them, getting information about a Safe (like reading the transaction history, pending transactions, enabled Modules and Guards, etc.), among other features.
Quickstart
In this guide we will see how to propose transactions to the service and collect the signatures from the owners so they become executable.
For more detailed information, see the guide Integrating the Protocol Kit and API Kit (opens in a new tab) and the API Kit Reference.
Prerequisites
- Node.js and npm (opens in a new tab)
- A Safe with several signers
Install dependencies
To add the API Kit to your project, run:
_10yarn add @safe-global/api-kit
Instantiate an EthAdapter
First of all, we need to create an EthAdapter
, which contains all the required utilities for the SDKs to interact with the blockchain. It acts as a wrapper for web3.js (opens in a new tab) or ethers.js (opens in a new tab) Ethereum libraries.
Depending on the library used by the dapp, there are two options:
- Create an
EthersAdapter
instance (opens in a new tab) - Create a
Web3Adapter
instance (opens in a new tab)
Once the instance of EthersAdapter
or Web3Adapter
is created, it can be used in the initialization of the API Kit.
_10import { EthersAdapter } from '@safe-global/protocol-kit'_10_10const provider = new ethers.JsonRpcProvider(config.RPC_URL)_10const signer = new ethers.Wallet(config.SIGNER_ADDRESS_PRIVATE_KEY, provider)_10_10const ethAdapter = new EthersAdapter({_10 ethers,_10 signerOrProvider: signer_10})
Initialize the API Kit
We need to create an instance of the API Kit. In chains where Safe provides a Transaction Service, it's enough to specify the chainId
. You can set your own service using the optional txServiceUrl
parameter.
_12import SafeApiKit from '@safe-global/api-kit'_12_12const apiKit = new SafeApiKit({_12 chainId: 1n_12})_12_12_12// or using a custom service_12const apiKit = new SafeApiKit({_12 chainId: 1n, // set the correct chainId_12 txServiceUrl: 'https://url-to-your-custom-service'_12})
Propose a transaction to the service
Before a transaction can be executed, any of the Safe signers needs to initiate the process by creating a proposal of a transaction. We send this transaction to the service to make it accessible by the other owners so they can give their approval and sign the transaction as well.
_30import Safe from '@safe-global/protocol-kit'_30_30// Create Safe instance_30const protocolKit = await Safe.create({_30 ethAdapter,_30 safeAddress: config.SAFE_ADDRESS_30})_30_30// Create transaction_30const safeTransactionData: MetaTransactionData = {_30 to: '0x',_30 value: '1', // 1 wei_30 data: '0x',_30 operation: OperationType.Call_30}_30_30const safeTransaction = await protocolKit.createTransaction({ transactions: [safeTransactionData] })_30_30const senderAddress = await signer.getAddress()_30const safeTxHash = await protocolKit.getTransactionHash(safeTransaction)_30const signature = await protocolKit.signHash(safeTxHash)_30_30// Propose transaction to the service_30await apiKit.proposeTransaction({_30 safeAddress: await protocolKit.getAddress(),_30 safeTransactionData: safeTransaction.data,_30 safeTxHash,_30 senderAddress,_30 senderSignature: signature.data_30})
Retrieve the pending transactions
Different methods in the API Kit are available to retrieve pending transactions depending on the situation. To retrieve a transaction given the Safe transaction hash use the method that's not commented.
_10const transaction = await service.getTransaction("<SAFE_TX_HASH>")_10// const transactions = await service.getPendingTransactions()_10// const transactions = await service.getIncomingTransactions()_10// const transactions = await service.getMultisigTransactions()_10// const transactions = await service.getModuleTransactions()_10// const transactions = await service.getAllTransactions()
Confirm the transaction
In this step we need to sign the transaction with the Protocol Kit and submit the signature to the Safe Transaction Service using the confirmTransaction
method.
_10const safeTxHash = transaction.transactionHash_10const signature = await protocolKit.signHash(safeTxHash)_10_10// Confirm the Safe transaction_10const signatureResponse = await apiKit.confirmTransaction(safeTxHash, signature.data)
The Safe transaction is now ready to be executed. This can be done using the Safe{Wallet} web interface, the Protocol Kit or any other tool that's available.