diff --git a/package.json b/package.json index dd2d3cd1..8293d863 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "version": "4.5.4", + "version": "4.6.0", "description": "Safe docs", "scripts": { "build": "next build", diff --git a/pages/advanced/_meta.json b/pages/advanced/_meta.json index af2e36fe..200417d0 100644 --- a/pages/advanced/_meta.json +++ b/pages/advanced/_meta.json @@ -14,13 +14,6 @@ "smart-account-supported-networks": "Supported Networks", "smart-account-audits": "Audits", "smart-account-bug-bounty": "Bug Bounty", - "-- Safe{Core} API Infrastructure": { - "type": "separator", - "title": "Safe{Core} API Infrastructure" - }, - "api-overview": "Overview", - "api-safe-transaction-service": "Safe Transaction Service", - "api-new-networks": "Add New Networks", "-- Safe CLI": { "type": "separator", "title": "Safe CLI" diff --git a/pages/core-api/_meta.json b/pages/core-api/_meta.json index db79003c..d7909683 100644 --- a/pages/core-api/_meta.json +++ b/pages/core-api/_meta.json @@ -3,9 +3,16 @@ "title": "← Go Home", "href": "/" }, - "-- Safe Transaction Service API": { + "-- Safe{Core} Infrastructure": { "type": "separator", - "title": "Safe Transaction Service API" + "title": "Safe{Core} Infrastructure" + }, + "api-overview": "Overview", + "api-safe-transaction-service": "Running the Safe Transaction Service", + "api-support-new-chains": "Support New Chains", + "-- Safe Transaction Service": { + "type": "separator", + "title": "Safe Transaction Service" }, "transaction-service-overview": "Overview", "transaction-service-supported-networks": "Supported Networks", diff --git a/pages/advanced/api-overview.md b/pages/core-api/api-overview.md similarity index 76% rename from pages/advanced/api-overview.md rename to pages/core-api/api-overview.md index e808b7d6..2b81bc6d 100644 --- a/pages/advanced/api-overview.md +++ b/pages/core-api/api-overview.md @@ -1,23 +1,29 @@ -# Service architecture +# Safe{Core} Infrastructure -The Safe{Core} infrastructure consists of the following services: +The Safe{Core} Infrastructure consists of the following services: -* [Safe Transaction Service](https://github.com/safe-global/safe-transaction-service): Keeps track of transactions related to Safe contracts (Python). -* [Safe Events Service](https://github.com/safe-global/safe-events-service): Handles Safe indexing events from the Transaction Service and delivers them as HTTP webhooks (NodeJS). +## Safe Transaction Service -Safe{Wallet} uses these services to offer functionality to end customers via the web and mobile applications. The [Safe Client Gateway](https://github.com/safe-global/safe-client-gateway-nest) acts as a facade between the end customer and the Safe{Core} services and the [Safe Config Service](https://github.com/safe-global/safe-config-service) stores all supported networks and chain-specific variables. +The Safe Transaction Service tracks transactions related to Safe contracts using tracing on Mainnet, Sepolia, and Gnosis Chain. It uses event indexing for the other chains. For each [supported network](./transaction-service-supported-networks.md) there is one instance of the Transaction Service. -Safe's production setup consists of several instances of the Transaction Service orchestrated by the Config Service, which are later consumed by the Safe Client Gateway. The Events Service notifies the Safe Client Gateway when new events are indexed, helping to improve the user experience. +- Learn about the [tech stack and how to run the service](./api-safe-transaction-service.mdx). +- Learn about the [Safe Transaction Service API](./transaction-service-overview.mdx). +- Check the [API Reference](./transaction-service-reference.mdx). +- Check the [GitHub repository](https://github.com/safe-global/safe-transaction-service) (Python). -![Overview of the backend services and their components.](../../assets/diagram-services.png) +## Safe Events Service -## Safe Transaction Service +The Events Service handles Safe indexing events and delivers them as HTTP webhooks, connection to the events queue processed by the Transaction Service. The service's database stores the configuration of webhook destinations. -The Transaction Service uses tracing in Mainnet/Sepolia and Gnosis Chain and event indexing in other chains to keep track of transactions related to Safe contracts. One instance of the Transaction Service runs per supported network (Mainnet, Sepolia, Gnosis Chain, Polygon, etc.). +- Check the [GitHub repository](https://github.com/safe-global/safe-events-service) (NodeJS). -## Safe Events Service +## Architecture + +Safe{Wallet} uses these services to offer functionality to end customers via the web and mobile applications. The [Safe Client Gateway](https://github.com/safe-global/safe-client-gateway-nest) acts as a facade between the end customer and the Safe{Core} services and the [Safe Config Service](https://github.com/safe-global/safe-config-service) stores all supported networks and chain-specific variables. -The Events Service connects to the events queue processed by the Transaction Service. It handles Safe indexing events and delivers them as HTTP webhooks. The service's database stores the configuration of webhook destinations. +Safe's production setup consists of several instances of the Transaction Service orchestrated by the Config Service, which are later consumed by the Safe Client Gateway. The Events Service notifies the Safe Client Gateway when new events are indexed, helping to improve the user experience. + +![Overview of the backend services and their components.](../../assets/diagram-services.png) ## Integration Flow for Safe{Wallet} and Safe{Core} diff --git a/pages/advanced/api-safe-transaction-service.mdx b/pages/core-api/api-safe-transaction-service.mdx similarity index 99% rename from pages/advanced/api-safe-transaction-service.mdx rename to pages/core-api/api-safe-transaction-service.mdx index f0eac901..d0152a3d 100644 --- a/pages/advanced/api-safe-transaction-service.mdx +++ b/pages/core-api/api-safe-transaction-service.mdx @@ -1,4 +1,4 @@ -# Safe Transaction Service +# Running the Safe Transaction Service The Safe Transaction Service tracks transactions sent via Safe contracts. It indexes these transactions using events (L2 chains) and tracing (L1 chains) mechanisms. diff --git a/pages/advanced/api-safe-transaction-service/_meta.json b/pages/core-api/api-safe-transaction-service/_meta.json similarity index 100% rename from pages/advanced/api-safe-transaction-service/_meta.json rename to pages/core-api/api-safe-transaction-service/_meta.json diff --git a/pages/advanced/api-safe-transaction-service/faq.md b/pages/core-api/api-safe-transaction-service/faq.md similarity index 100% rename from pages/advanced/api-safe-transaction-service/faq.md rename to pages/core-api/api-safe-transaction-service/faq.md diff --git a/pages/advanced/api-safe-transaction-service/rpc-requirements.md b/pages/core-api/api-safe-transaction-service/rpc-requirements.md similarity index 100% rename from pages/advanced/api-safe-transaction-service/rpc-requirements.md rename to pages/core-api/api-safe-transaction-service/rpc-requirements.md diff --git a/pages/advanced/api-new-networks.mdx b/pages/core-api/api-support-new-chains.mdx similarity index 99% rename from pages/advanced/api-new-networks.mdx rename to pages/core-api/api-support-new-chains.mdx index 5bc0266b..4975fac5 100644 --- a/pages/advanced/api-new-networks.mdx +++ b/pages/core-api/api-support-new-chains.mdx @@ -1,6 +1,6 @@ import { Steps } from 'nextra/components' -# Add New Networks +# Support New Chains Safe's vision is to make every web3 account a smart account. Therefore, we prioritize teams and chains building with smart accounts, especially if they push account abstraction (for example, ERC-4337/EIP-1271 adoption) with Safe (learn more [here](https://docs.safe.global/home/4337-safe)). diff --git a/pages/core-api/transaction-service-guides/delegates.mdx b/pages/core-api/transaction-service-guides/delegates.mdx index 12425ee9..25d10331 100644 --- a/pages/core-api/transaction-service-guides/delegates.mdx +++ b/pages/core-api/transaction-service-guides/delegates.mdx @@ -43,7 +43,6 @@ The different steps are implemented using [Curl](https://github.com/curl/curl) r ```typescript import { ethers } from 'ethers' import SafeApiKit, { AddSafeDelegateProps } from '@safe-global/api-kit' - import { EthersAdapter } from '@safe-global/protocol-kit' ``` @@ -65,22 +64,11 @@ The different steps are implemented using [Curl](https://github.com/curl/curl) r ```typescript - const ethProvider = new ethers.JsonRpcProvider(config.RPC_URL) - - // Instantiate an EthAdapter with Owner A - const ownerA = new ethers.Wallet(config.OWNER_A_PRIVATE_KEY, ethProvider) - const ethAdapterOwnerA = new EthersAdapter({ - ethers, - signerOrProvider: ownerA - }) - // Initialize the API Kit const apiKit = new SafeApiKit({ chainId: 11155111n }) - const ownerAAddress = await ethAdapterOwnerA.getSignerAddress() - // Get the Safe delegates const delegates = await apiKit.getSafeDelegates({ delegatorAddress: config.SAFE_ADDRESS @@ -118,15 +106,13 @@ The different steps are implemented using [Curl](https://github.com/curl/curl) r ```typescript - const ownerB = new ethers.Wallet(config.OWNER_B_PRIVATE_KEY, ethProvider) + const provider = new ethers.JsonRpcProvider(config.RPC_URL) - // Instantiate an EthAdapter with Owner B - const ethAdapterOwnerB = new EthersAdapter({ - ethers, - signerOrProvider: ownerB - }) + const ownerA = new ethers.Wallet(config.OWNER_A_PRIVATE_KEY, provider) + const ownerAAddress = await ownerA.getAddress() - const ownerBAddress = await ethAdapterOwnerB.getSignerAddress() + const ownerB = new ethers.Wallet(config.OWNER_B_PRIVATE_KEY, provider) + const ownerBAddress = await ownerB.getAddress() const delegateConfig: AddSafeDelegateProps = { delegateAddress: ownerBAddress || '0x', diff --git a/pages/core-api/transaction-service-guides/messages.mdx b/pages/core-api/transaction-service-guides/messages.mdx index 11c45a89..1424ee92 100644 --- a/pages/core-api/transaction-service-guides/messages.mdx +++ b/pages/core-api/transaction-service-guides/messages.mdx @@ -22,7 +22,7 @@ The different steps are implemented using [Curl](https://github.com/curl/curl) r ```bash - yarn add ethers @safe-global/api-kit @safe-global/protocol-kit @safe-global/safe-core-sdk-types + yarn add @safe-global/api-kit @safe-global/protocol-kit @safe-global/safe-core-sdk-types ``` @@ -41,9 +41,8 @@ The different steps are implemented using [Curl](https://github.com/curl/curl) r ```typescript - import { ethers } from 'ethers' import SafeApiKit, { AddMessageProps } from '@safe-global/api-kit' - import Safe, { EthersAdapter, hashSafeMessage } from '@safe-global/protocol-kit' + import Safe, { hashSafeMessage } from '@safe-global/protocol-kit' ``` @@ -67,18 +66,10 @@ The different steps are implemented using [Curl](https://github.com/curl/curl) r ```typescript - const ethProvider = new ethers.JsonRpcProvider(config.RPC_URL) - - // Instantiate an EthAdapter with Owner A - const ownerA = new ethers.Wallet(config.OWNER_A_PRIVATE_KEY, ethProvider) - const ethAdapterOwnerA = new EthersAdapter({ - ethers, - signerOrProvider: ownerA - }) - // Initialize the Protocol Kit with Owner A - const protocolKitOwnerA = await Safe.create({ - ethAdapter: ethAdapterOwnerA, + const protocolKitOwnerA = await Safe.init({ + provider: config.RPC_URL, + signer: config.OWNER_A_PRIVATE_KEY, safeAddress: config.SAFE_ADDRESS }) @@ -194,16 +185,10 @@ The different steps are implemented using [Curl](https://github.com/curl/curl) r ```typescript - // Instantiate an EthAdapter with Owner B - const ownerB = new ethers.Wallet(config.OWNER_B_PRIVATE_KEY, ethProvider) - const ethAdapterOwnerB = new EthersAdapter({ - ethers, - signerOrProvider: ownerB - }) - // Initialize the Protocol Kit with Owner B - const protocolKitOwnerB = await Safe.create({ - ethAdapter: ethAdapterOwnerB, + const protocolKitOwnerB = await Safe.init({ + provider: config.RPC_URL, + signer: config.OWNER_B_PRIVATE_KEY, safeAddress: config.SAFE_ADDRESS }) @@ -243,7 +228,8 @@ The different steps are implemented using [Curl](https://github.com/curl/curl) r // Sign the message with Owner B const signedMessageOwnerB = await protocolKitOwnerB.signMessage(safeServiceMessage) - const ownerBAddress = (await ethAdapterOwnerB.getSignerAddress()) || '0x' + // Get Owner B address + const ownerBAddress = '0x...' // Send the message to the Transaction Service with the signature from Owner B await apiKit.addMessageSignature( diff --git a/pages/core-api/transaction-service-guides/transactions.mdx b/pages/core-api/transaction-service-guides/transactions.mdx index 82747e72..ac429b65 100644 --- a/pages/core-api/transaction-service-guides/transactions.mdx +++ b/pages/core-api/transaction-service-guides/transactions.mdx @@ -22,7 +22,7 @@ The different steps are implemented using [Curl](https://github.com/curl/curl) r ```bash - yarn add ethers @safe-global/api-kit @safe-global/protocol-kit @safe-global/safe-core-sdk-types + yarn add @safe-global/api-kit @safe-global/protocol-kit @safe-global/safe-core-sdk-types ``` @@ -41,9 +41,8 @@ The different steps are implemented using [Curl](https://github.com/curl/curl) r ```typescript - import { ethers } from 'ethers' import SafeApiKit from '@safe-global/api-kit' - import Safe, { EthersAdapter } from '@safe-global/protocol-kit' + import Safe from '@safe-global/protocol-kit' import { MetaTransactionData, OperationType @@ -69,18 +68,10 @@ The different steps are implemented using [Curl](https://github.com/curl/curl) r ```typescript - const ethProvider = new ethers.JsonRpcProvider(config.RPC_URL) - - // Instantiate an EthAdapter with Owner A - const ownerA = new ethers.Wallet(config.OWNER_A_PRIVATE_KEY, ethProvider) - const ethAdapterOwnerA = new EthersAdapter({ - ethers, - signerOrProvider: ownerA - }) - // Initialize the Protocol Kit with Owner A - const protocolKitOwnerA = await Safe.create({ - ethAdapter: ethAdapterOwnerA, + const protocolKitOwnerA = await Safe.init({ + provider: config.RPC_URL, + signer: config.OWNER_A_PRIVATE_KEY, safeAddress: config.SAFE_ADDRESS }) @@ -176,14 +167,12 @@ The different steps are implemented using [Curl](https://github.com/curl/curl) r chainId: 11155111n }) - const senderAddress = await ownerA.getAddress() - // Send the transaction to the Transaction Service with the signature from Owner A await apiKit.proposeTransaction({ safeAddress: config.SAFE_ADDRESS, safeTransactionData: safeTransaction.data, safeTxHash, - senderAddress, + senderAddress: config.OWNER_A_ADDRESS, senderSignature: signatureOwnerA.data }) ``` @@ -242,16 +231,10 @@ The different steps are implemented using [Curl](https://github.com/curl/curl) r ```typescript - // Instantiate an EthAdapter with Owner B - const ownerB = new ethers.Wallet(config.OWNER_B_PRIVATE_KEY, ethProvider) - const ethAdapterOwnerB = new EthersAdapter({ - ethers, - signerOrProvider: ownerB - }) - // Initialize the Protocol Kit with Owner B - const protocolKitOwnerB = await Safe.create({ - ethAdapter: ethAdapterOwnerB, + const protocolKitOwnerB = await Safe.init({ + provider: config.RPC_URL, + signer: config.OWNER_B_PRIVATE_KEY, safeAddress: config.SAFE_ADDRESS }) diff --git a/pages/core-api/transaction-service-overview.mdx b/pages/core-api/transaction-service-overview.mdx index b61f942a..b2631901 100644 --- a/pages/core-api/transaction-service-overview.mdx +++ b/pages/core-api/transaction-service-overview.mdx @@ -4,9 +4,9 @@ import Reference from '../../assets/svg/reference.svg' # Safe Transaction Service API -The Safe Transaction Service API offers REST endpoints to keep track of transactions sent via Safe contracts. It also offers endpoints to send transactions to allow off-chain collecting of signatures or informing the owners about a pending transaction to be sent to the blockchain. +The Safe Transaction Service offers a REST API to track transactions sent via the Safe Smart Account. It also provides endpoints to send transactions, allow off-chain collecting of signatures, or informing the owners about a pending transaction to be sent to the blockchain. -We also offer the [API Kit](../sdk/api-kit), a TypeScript client for the Safe Transaction Service API in the Safe\{Core\} SDK. +Additionally, the Safe\{Core\} SDK provides the [API Kit](../sdk/api-kit), a TypeScript client for the Safe Transaction Service API. } title="Guides" href="./transaction-service-guides/transactions" /> @@ -15,4 +15,4 @@ We also offer the [API Kit](../sdk/api-kit), a TypeScript client for the Safe Tr ## Getting started -Are you new to our API and not sure where to get started? We recommend heading over to the guides on the [Safe Transaction Service API](../core-api/transaction-service-guides/transactions.mdx). +Are you new to our API and not sure where to get started? We recommend heading over to the [guides](../core-api/transaction-service-guides/transactions.mdx) on the Safe Transaction Service API. diff --git a/pages/sdk/api-kit.mdx b/pages/sdk/api-kit.mdx index b4e49df1..567bf548 100644 --- a/pages/sdk/api-kit.mdx +++ b/pages/sdk/api-kit.mdx @@ -1,4 +1,5 @@ import { Grid } from '@mui/material' +import { Steps } from 'nextra/components' import CustomCard from '../../components/CustomCard' # API Kit @@ -19,122 +20,149 @@ In this guide we will see how to propose transactions to the service and collect For more detailed information, see the guide [Integrating the Protocol Kit and API Kit](https://github.com/safe-global/safe-core-sdk/blob/main/guides/integrating-the-safe-core-sdk.md) and the [API Kit Reference](./api-kit/reference.md). -### Prerequisites +## Prerequisites 1. [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) 2. A Safe with several signers +## Steps -## Install dependencies + -To add the API Kit to your project, run: + ### Install dependencies -```bash -yarn add @safe-global/api-kit -``` + First, we need to install some dependencies. -## Instantiate an EthAdapter + ```bash + yarn add @safe-global/api-kit \ + @safe-global/protocol-kit \ + @safe-global/safe-core-sdk-types + ``` -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](https://web3js.readthedocs.io/) or [ethers.js](https://docs.ethers.org/v6/) Ethereum libraries. + ### Imports -Depending on the library used by the dapp, there are two options: + Here are all the necessary imports for this guide. -- [Create an `EthersAdapter` instance](https://github.com/safe-global/safe-core-sdk/tree/main/packages/protocol-kit/src/adapters/ethers) -- [Create a `Web3Adapter` instance](https://github.com/safe-global/safe-core-sdk/tree/main/packages/protocol-kit/src/adapters/web3) + ```typescript + import SafeApiKit from '@safe-global/api-kit' + import Safe from '@safe-global/protocol-kit' + import { + MetaTransactionData, + OperationType + } from '@safe-global/safe-core-sdk-types' + ``` -Once the instance of `EthersAdapter` or `Web3Adapter` is created, it can be used in the initialization of the API Kit. + ### Setup -```typescript -import { EthersAdapter } from '@safe-global/protocol-kit' + We will use a Safe account setup with two or more signers, and threshold two, so at least multiple signatures will need to be collected when executing a transaction. -const provider = new ethers.JsonRpcProvider(config.RPC_URL) -const signer = new ethers.Wallet(config.SIGNER_ADDRESS_PRIVATE_KEY, provider) + ```typescript + // https://chainlist.org/?search=sepolia&testnets=true + const RPC_URL = 'https://eth-sepolia.public.blastapi.io' -const ethAdapter = new EthersAdapter({ - ethers, - signerOrProvider: signer -}) -``` + const SAFE_ADDRESS = // ... -## Initialize the API Kit + const OWNER_1_ADDRESS = // ... + const OWNER_1_PRIVATE_KEY = // ... -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. + const OWNER_2_PRIVATE_KEY = // ... + ``` -```typescript -import SafeApiKit from '@safe-global/api-kit' + ### Initialize the API Kit -const apiKit = new SafeApiKit({ - chainId: 1n -}) + Firstly, we need to create an instance of the API Kit. In chains where the [Safe Transaction Service](../core-api/transaction-service-overview.mdx) is supported, it's enough to specify the `chainId` property. + ```typescript + const apiKit = new SafeApiKit({ + chainId: 1n + }) + ``` -// or using a custom service -const apiKit = new SafeApiKit({ - chainId: 1n, // set the correct chainId - txServiceUrl: 'https://url-to-your-custom-service' -}) -``` + Alternatively, we can use a custom service using the optional `txServiceUrl` property. -## Propose a transaction to the service + ```typescript + const apiKit = new SafeApiKit({ + chainId: 1n, // set the correct chainId + txServiceUrl: 'https://url-to-your-custom-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. + ### Initialize the Protocol Kit -```typescript -import Safe from '@safe-global/protocol-kit' + To handle transactions and signatures, we need to create an instance of the Protocol Kit with the `provider`, `signer` and `safeAddress`. -// Create Safe instance -const protocolKit = await Safe.create({ - ethAdapter, - safeAddress: config.SAFE_ADDRESS -}) + ```typescript + const protocolKitOwner1 = await Safe.init({ + provider: RPC_URL, + signer: OWNER_1_PRIVATE_KEY, + safeAddress: SAFE_ADDRESS + }) + ``` -// Create transaction -const safeTransactionData: MetaTransactionData = { - to: '0x', - value: '1', // 1 wei - data: '0x', - operation: OperationType.Call -} + ### Propose a transaction to the service -const safeTransaction = await protocolKit.createTransaction({ transactions: [safeTransactionData] }) + 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. -const senderAddress = await signer.getAddress() -const safeTxHash = await protocolKit.getTransactionHash(safeTransaction) -const signature = await protocolKit.signHash(safeTxHash) + ```typescript + // Create transaction + const safeTransactionData: MetaTransactionData = { + to: '0x', + value: '1', // 1 wei + data: '0x', + operation: OperationType.Call + } -// Propose transaction to the service -await apiKit.proposeTransaction({ - safeAddress: await protocolKit.getAddress(), - safeTransactionData: safeTransaction.data, - safeTxHash, - senderAddress, - senderSignature: signature.data -}) -``` + const safeTransaction = await protocolKitOwner1.createTransaction({ + transactions: [safeTransactionData] + }) -## Retrieve the pending transactions + const safeTxHash = await protocolKitOwner1.getTransactionHash(safeTransaction) + const signature = await protocolKitOwner1.signHash(safeTxHash) -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. + // Propose transaction to the service + await apiKit.proposeTransaction({ + safeAddress: SAFE_ADDRESS, + safeTransactionData: safeTransaction.data, + safeTxHash, + senderAddress: OWNER_1_ADDRESS, + senderSignature: signature.data + }) + ``` -```typescript -const transaction = await service.getTransaction("") -// const transactions = await service.getPendingTransactions() -// const transactions = await service.getIncomingTransactions() -// const transactions = await service.getMultisigTransactions() -// const transactions = await service.getModuleTransactions() -// const transactions = await service.getAllTransactions() -``` + ### Retrieve the pending transactions -## Confirm the transaction + 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. -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. + ```typescript + const transaction = await service.getTransaction(safeTxHash) + // const transactions = await service.getPendingTransactions() + // const transactions = await service.getIncomingTransactions() + // const transactions = await service.getMultisigTransactions() + // const transactions = await service.getModuleTransactions() + // const transactions = await service.getAllTransactions() + ``` -```typescript -const safeTxHash = transaction.transactionHash -const signature = await protocolKit.signHash(safeTxHash) + ### Confirm the transaction -// Confirm the Safe transaction -const signatureResponse = await apiKit.confirmTransaction(safeTxHash, signature.data) -``` + 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. -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. + ```typescript + const protocolKitOwner2 = await Safe.init({ + provider: RPC_URL, + signer: OWNER_2_PRIVATE_KEY, + safeAddress: SAFE_ADDRESS + }) + + const safeTxHash = transaction.transactionHash + const signature = await protocolKitOwner2.signHash(safeTxHash) + + // Confirm the Safe transaction + const 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, the Safe CLI or any other tool that's available. + + diff --git a/pages/sdk/api-kit/reference/migrating-to-v1.md b/pages/sdk/api-kit/reference/migrate-to-v1.md similarity index 99% rename from pages/sdk/api-kit/reference/migrating-to-v1.md rename to pages/sdk/api-kit/reference/migrate-to-v1.md index e554cf89..2c2466b3 100644 --- a/pages/sdk/api-kit/reference/migrating-to-v1.md +++ b/pages/sdk/api-kit/reference/migrate-to-v1.md @@ -1,4 +1,4 @@ -# Migrating to v1 +# Migrate to v1 This guide references the major changes between `safe-service-client` and `api-kit` v1 to help those migrating an existing application. diff --git a/pages/sdk/api-kit/reference/migrating-to-v2.md b/pages/sdk/api-kit/reference/migrate-to-v2.md similarity index 98% rename from pages/sdk/api-kit/reference/migrating-to-v2.md rename to pages/sdk/api-kit/reference/migrate-to-v2.md index 0d8ec4d4..6d4f2d5a 100644 --- a/pages/sdk/api-kit/reference/migrating-to-v2.md +++ b/pages/sdk/api-kit/reference/migrate-to-v2.md @@ -1,4 +1,4 @@ -# Migrating to v2 +# Migrate to v2 This guide references the major changes between v1 and v2 to help those migrating an existing app. diff --git a/pages/sdk/auth-kit/guides/safe-auth.mdx b/pages/sdk/auth-kit/guides/safe-auth.mdx index 54842c12..5c44774c 100644 --- a/pages/sdk/auth-kit/guides/safe-auth.mdx +++ b/pages/sdk/auth-kit/guides/safe-auth.mdx @@ -31,7 +31,6 @@ The `SafeAuthPack` is an authentication system that utilizes the [Web3Auth](http SafeAuthConfig, SafeAuthInitOptions, } from '@safe-global/auth-kit' - import { EthersAdapter } from '@safe-global/protocol-kit' ``` ### Create a SafeAuthPack instance @@ -54,7 +53,7 @@ The `SafeAuthPack` is an authentication system that utilizes the [Web3Auth](http showWidgetButton: false, chainConfig: { chainId: '0x1', - rpcTarget: `${rpcUrl}` + rpcTarget: RPC_URL } } @@ -93,7 +92,7 @@ The `SafeAuthPack` is an authentication system that utilizes the [Web3Auth](http await safeAuthPack.signOut() ``` - After the user is authenticated, call `getProvider()` to get the Ethereum provider instance. This is a [EIP-1193](https://eips.ethereum.org/EIPS/eip-1193) compatible provider you can wrap using your favorite library (web3, ethers). + After the user is authenticated, call `getProvider()` to get an Ethereum [EIP-1193](https://eips.ethereum.org/EIPS/eip-1193) compatible provider. ```typescript safeAuthPack.getProvider() @@ -118,24 +117,14 @@ The `SafeAuthPack` is an authentication system that utilizes the [Web3Auth](http ### Sign and execute transactions - The `SafeAuthPack` can be used with the [Protocol Kit](../../protocol-kit.mdx) to establish a connection to a Safe. This connection is made using the `provider` and `signer` associated with the authenticated account. + The `SafeAuthPack` can be used with the [Protocol Kit](../../protocol-kit.mdx) to establish a connection to a Safe using the `provider`. We don't need to pass the `signer` property in the `create()` method as it will be automatically taken from the passed `provider`. After connecting, you can use any of the methods provided in the [Protocol Kit](https://github.com/safe-global/safe-core-sdk/tree/main/packages/protocol-kit#sdk-api). ```typescript - // Wrap EIP-1193 provider with ethers - const provider = new ethers.BrowserProvider(safeAuthPack.getProvider()) - const signer = provider.getSigner() - - // Create the Safe EthersAdapter - const ethAdapter = new EthersAdapter({ - ethers, - signerOrProvider: signer || provider, - }) - // Instantiate the Protocol Kit - const protocolKit = await Safe.create({ - ethAdapter, + const protocolKit = await Safe.init({ + provider: safeAuthPack.getProvider(), safeAddress, }) diff --git a/pages/sdk/protocol-kit.mdx b/pages/sdk/protocol-kit.mdx index 0666335e..3ccde7d0 100644 --- a/pages/sdk/protocol-kit.mdx +++ b/pages/sdk/protocol-kit.mdx @@ -26,75 +26,37 @@ For a more detailed guide, including how to integrate with `web3.js` and more Sa ### Install dependencies -First, we need to install some dependencies from `safe-core-sdk` and the `ethers` library. - -To interact with Ethereum and other EVM blockchains in Node, we can either use: web3.js or ethers.js. In this tutorial, we will use the ethers.js library. To use `web3js`, see [Instantiate an EthAdapter section in Guide: Integrating the Safe Core SDK](https://github.com/safe-global/safe-core-sdk/blob/main/guides/integrating-the-safe-core-sdk.md#instantiate-an-ethadapter). - -The Protocol Kit is compatible only with **ethers.js v6**. Make sure you specify this version when installing the SDK. - -You can store your environment variables such as private keys in a `.env` file. To read easily from `.env` files, use the `dotenv` library. +First, we need to install some dependencies. ```bash -yarn add ethers @safe-global/protocol-kit \ +yarn add @safe-global/protocol-kit \ @safe-global/api-kit \ - @safe-global/safe-core-sdk-types \ - dotenv -``` - -Create the `.env` file: - -```bash -touch .env -``` - -Put your signing account private keys into the `.env` file you just created. - -```bash -export OWNER_1_PRIVATE_KEY='' -export OWNER_2_PRIVATE_KEY='' -export OWNER_3_PRIVATE_KEY='' -``` - -Create an `index.ts` file that you will use to run the following code snippets. - -```bash -touch index.ts + @safe-global/safe-core-sdk-types ``` -Tip: Use [ts-node](https://github.com/TypeStrong/ts-node) to run a Typescript file in Node.js. - -```bash -npx ts-node examples/protocol-kit/index.ts -``` - -### Initialize Signers, Providers, and EthAdapter +### Initialize Signers and Providers The signers trigger transactions to the Ethereum blockchain or off-chain transactions. The provider connects to the Ethereum blockchain. You can get a public RPC URL from [Chainlist](https://chainlist.org), however, public RPC URLs can be unreliable so you can also try a dedicated provider like Infura or Alchemy. -For this tutorial, we will be creating a Safe on the Sepolia Testnet. +For this guide, we will be creating a Safe on the Sepolia Testnet. ```tsx -import { ethers } from 'ethers' -import { EthersAdapter } from '@safe-global/protocol-kit' -import dotenv from 'dotenv' - -dotenv.config() - // https://chainlist.org/?search=sepolia&testnets=true -const RPC_URL='https://eth-sepolia.public.blastapi.io' -const provider = new ethers.JsonRpcProvider(RPC_URL) +const RPC_URL = 'https://eth-sepolia.public.blastapi.io' // Initialize signers -const owner1Signer = new ethers.Wallet(process.env.OWNER_1_PRIVATE_KEY!, provider) -const owner2Signer = new ethers.Wallet(process.env.OWNER_2_PRIVATE_KEY!, provider) -const owner3Signer = new ethers.Wallet(process.env.OWNER_3_PRIVATE_KEY!, provider) +const OWNER_1_ADDRESS = // ... +const OWNER_1_PRIVATE_KEY = // ... -const ethAdapterOwner1 = new EthersAdapter({ - ethers, - signerOrProvider: owner1Signer -}) +const OWNER_2_ADDRESS = // ... +const OWNER_2_PRIVATE_KEY = // ... + +const OWNER_3_ADDRESS = // ... + +const provider = new ethers.JsonRpcProvider(RPC_URL) +const owner1Signer = new ethers.Wallet(OWNER_1_PRIVATE_KEY, provider) ``` ### Initialize the API Kit @@ -111,7 +73,7 @@ const apiKit = new SafeApiKit({ }) -// or using a custom service +// Or using a custom service const apiKit = new SafeApiKit({ chainId: 1n, // set the correct chainId txServiceUrl: 'https://url-to-your-custom-service' @@ -120,14 +82,15 @@ const apiKit = new SafeApiKit({ ### Initialize the Protocol Kit -Sepolia is a supported network so you don't need to specify the contract addresses, however, to see how to create a safe on a local or unsupported network, see [Instantiate an EthAdapter](https://github.com/safe-global/safe-core-sdk/blob/main/guides/integrating-the-safe-core-sdk.md#instantiate-an-ethadapter). - -Safe Factory is used to create Safes. While Safe class represents an instance of a specific Safe account. +The `SafeFactory` class allows the deployment of new Safe accounts while the `Safe` class represents an instance of a specific Safe account. ```tsx import { SafeFactory } from '@safe-global/protocol-kit' -const safeFactory = await SafeFactory.create({ ethAdapter: ethAdapterOwner1 }) +const safeFactory = await SafeFactory.init({ + provider: RPC_URL, + signer: OWNER_1_PRIVATE_KEY +}) ``` ### Deploy a Safe @@ -139,16 +102,15 @@ import { SafeAccountConfig } from '@safe-global/protocol-kit' const safeAccountConfig: SafeAccountConfig = { owners: [ - await owner1Signer.getAddress(), - await owner2Signer.getAddress(), - await owner3Signer.getAddress() + await OWNER_1_ADDRESS, + await OWNER_2_ADDRESS, + await OWNER_3_ADDRESS ], threshold: 2, - // ... (Optional params) + // Optional params } -/* This Safe is tied to owner 1 because the factory was initialized with -an adapter that had owner 1 as the signer. */ +/* This Safe is tied to owner 1 because the factory was initialized with the owner 1 as the signer. */ const protocolKitOwner1 = await safeFactory.deploySafe({ safeAccountConfig }) const safeAddress = await protocolKitOwner1.getAddress() @@ -238,7 +200,7 @@ await apiKit.proposeTransaction({ safeAddress, safeTransactionData: safeTransaction.data, safeTxHash, - senderAddress: await owner1Signer.getAddress(), + senderAddress: OWNER_1_ADDRESS, senderSignature: senderSignature.data, }) ``` @@ -260,13 +222,9 @@ When owner 2 is connected to the application, the Protocol Kit should be initial const transaction = pendingTransactions[0] const safeTxHash = transaction.safeTxHash -const ethAdapterOwner2 = new EthersAdapter({ - ethers, - signerOrProvider: owner2Signer -}) - -const protocolKitOwner2 = await Safe.create({ - ethAdapter: ethAdapterOwner2, +const protocolKitOwner2 = await Safe.init({ + provider: RPC_URL, + signer: OWNER_2_PRIVATE_KEY, safeAddress }) diff --git a/pages/sdk/protocol-kit/guides/signatures.md b/pages/sdk/protocol-kit/guides/signatures.md index 34a5403f..e37cbc6d 100644 --- a/pages/sdk/protocol-kit/guides/signatures.md +++ b/pages/sdk/protocol-kit/guides/signatures.md @@ -12,24 +12,28 @@ In the following guides, there are different accounts involved that will be used | Who | Description | Address for this example | | :--- | :--- | :--- | -| `safe3_4` | 3/4 Safe (3 signatures required out of 4 owners) | 0xb3b3862D8e38a1E965eb350B09f2167B2371D652 | -| `owner1` | EOA and owner of `safe3_4` | 0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1 | -| `owner2` | EOA and owner of `safe3_4` | 0xFFcf8FDEE72ac11b5c542428B35EEF5769C409f0 | -| `safe1_1` | 1/1 Safe and owner of `safe3_4` | 0x215033cdE0619D60B7352348F4598316Cc39bC6E | -| `owner3` | EOA and owner of `safe1_1` | 0x22d491Bde2303f2f43325b2108D26f1eAbA1e32b | -| `safe2_3` | 2/3 Safe and owner of `safe3_4` | 0xf75D61D6C27a7CC5788E633c1FC130f0F4a62D33 | -| `owner4` | EOA and owner of `safe2_3` | 0xE11BA2b4D45Eaed5996Cd0823791E0C93114882d | -| `owner5` | EOA and owner of `safe2_3` | 0xd03ea8624C8C5987235048901fB614fDcA89b117 | - -Each EOA owner described above is bound to an `EthAdapter` instance that should also be initialized. - -| Adapter | Signer | -| :--- | :--- | -| `ethAdapter1` | `owner1` | -| `ethAdapter2` | `owner2` | -| `ethAdapter3` | `owner3` | -| `ethAdapter4` | `owner4` | -| `ethAdapter5` | `owner5` | +| `SAFE_3_4_ADDRESS` | 3/4 Safe (3 signatures required out of 4 owners) | 0xb3b3862D8e38a1E965eb350B09f2167B2371D652 | +| `OWNER_1_ADDRESS` | EOA and owner of `SAFE_3_4_ADDRESS` | 0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1 | +| `OWNER_2_ADDRESS` | EOA and owner of `SAFE_3_4_ADDRESS` | 0xFFcf8FDEE72ac11b5c542428B35EEF5769C409f0 | +| `SAFE_1_1_ADDRESS` | 1/1 Safe and owner of `SAFE_3_4_ADDRESS` | 0x215033cdE0619D60B7352348F4598316Cc39bC6E | +| `OWNER_3_ADDRESS` | EOA and owner of `SAFE_1_1_ADDRESS` | 0x22d491Bde2303f2f43325b2108D26f1eAbA1e32b | +| `SAFE_2_3_ADDRESS` | 2/3 Safe and owner of `SAFE_3_4_ADDRESS` | 0xf75D61D6C27a7CC5788E633c1FC130f0F4a62D33 | +| `OWNER_4_ADDRESS` | EOA and owner of `SAFE_2_3_ADDRESS` | 0xE11BA2b4D45Eaed5996Cd0823791E0C93114882d | +| `OWNER_5_ADDRESS` | EOA and owner of `SAFE_2_3_ADDRESS` | 0xd03ea8624C8C5987235048901fB614fDcA89b117 | + +We need to instantiate all the signers based on the Safe owner accounts. + +```typescript +// https://chainlist.org/?search=sepolia&testnets=true +const RPC_URL = 'https://eth-sepolia.public.blastapi.io' + +// Initialize signers +const OWNER_1_PRIVATE_KEY = // ... +const OWNER_2_PRIVATE_KEY = // ... +const OWNER_3_PRIVATE_KEY = // ... +const OWNER_4_PRIVATE_KEY = // ... +const OWNER_5_PRIVATE_KEY = // ... +``` ## Guides diff --git a/pages/sdk/protocol-kit/guides/signatures/messages.mdx b/pages/sdk/protocol-kit/guides/signatures/messages.mdx index 179ae796..6660e91f 100644 --- a/pages/sdk/protocol-kit/guides/signatures/messages.mdx +++ b/pages/sdk/protocol-kit/guides/signatures/messages.mdx @@ -104,32 +104,38 @@ Using the Protocol Kit, this guide explains how to generate and sign messages fr Once the `safeMessage` object is created, we need to collect the signatures from the signers who will sign it. - Following our [setup](../signatures.md), we will sign a message with `safe3_4`, the main Safe account in this guide. To do that, we first need to sign the same message with its owners: `owner1`, `owner2`, `safe1_1`, and `safe2_3`. + Following our [setup](../signatures.md), we will sign a message with `SAFE_3_4_ADDRESS`, the main Safe account in this guide. To do that, we first need to sign the same message with its owners: `OWNER_1_ADDRESS`, `OWNER_2_ADDRESS`, `SAFE_1_1_ADDRESS`, and `SAFE_2_3_ADDRESS`. #### ECDSA signatures - This applies to `owner1` and `owner2` accounts, as both are EOAs. + This applies to `OWNER_1_ADDRESS` and `OWNER_2_ADDRESS` accounts, as both are EOAs. The `signMessage` method takes the `safeMessage` together with a `SigningMethod` and adds the new signature to the `signMessage.signatures` map. Depending on the type of message, the `SigningMethod` can take these values: - `SigningMethod.ETH_SIGN` - `SigningMethod.ETH_SIGN_TYPED_DATA_V4` ```typescript - // Connect the EthAdapter from owner1 - protocolKit = await protocolKit.connect({ ethAdapter: ethAdapter1 }) + // Connect OWNER_1_ADDRESS + protocolKit = await protocolKit.connect({ + provider: RPC_URL + signer: OWNER_1_PRIVATE_KEY + }) - // Sign the safeMessage with owner1 - // After this, the safeMessage contains the signature from owner1 + // Sign the safeMessage with OWNER_1_ADDRESS + // After this, the safeMessage contains the signature from OWNER_1_ADDRESS safeMessage = await protocolKit.signMessage( safeMessage, SigningMethod.ETH_SIGN_TYPED_DATA_V4 ) - // Connect the EthAdapter from owner2 - protocolKit = await protocolKit.connect({ ethAdapter: ethAdapter2 }) + // Connect OWNER_2_ADDRESS + protocolKit = await protocolKit.connect({ + provider: RPC_URL + signer: OWNER_2_PRIVATE_KEY + }) - // Sign the safeMessage with owner2 - // After this, the safeMessage contains the signature from owner1 and owner2 + // Sign the safeMessage with OWNER_2_ADDRESS + // After this, the safeMessage contains the signature from OWNER_1_ADDRESS and OWNER_2_ADDRESS safeMessage = await protocolKit.signMessage( safeMessage, SigningMethod.ETH_SIGN_TYPED_DATA_V4 @@ -142,36 +148,37 @@ Using the Protocol Kit, this guide explains how to generate and sign messages fr ##### 1/1 Safe account - This applies to the `safe1_1` account, another owner of `safe3_4`. + This applies to the `SAFE_1_1_ADDRESS` account, another owner of `SAFE_3_4_ADDRESS`. - We need to connect the Protocol Kit to `safe1_1` and the `owner3` account (the only owner of `safe1_1`) and sign the message. + We need to connect the Protocol Kit to `SAFE_1_1_ADDRESS` and the `OWNER_3_ADDRESS` account (the only owner of `SAFE_1_1_ADDRESS`) and sign the message. ```typescript // Create a new message object let messageSafe1_1 = await createMessage(TYPED_MESSAGE) - // Connect the EthAdapter from owner3 and the address of safe1_1 + // Connect OWNER_3_ADDRESS and SAFE_1_1_ADDRESS protocolKit = await protocolKit.connect({ - ethAdapter: ethAdapter3, - safeAddress: safe1_1 + provider: RPC_URL + signer: OWNER_3_PRIVATE_KEY, + safeAddress: SAFE_1_1_ADDRESS }) - // Sign the messageSafe1_1 with owner3 - // After this, the messageSafe1_1 contains the signature from owner3 + // Sign the messageSafe1_1 with OWNER_3_ADDRESS + // After this, the messageSafe1_1 contains the signature from OWNER_3_ADDRESS messageSafe1_1 = await signMessage( messageSafe1_1, SigningMethod.SAFE_SIGNATURE, - safe3_4 // Parent Safe address + SAFE_3_4_ADDRESS // Parent Safe address ) - // Build the contract signature of safe1_1 + // Build the contract signature of SAFE_1_1_ADDRESS const signatureSafe1_1 = await buildContractSignature( Array.from(messageSafe1_1.signatures.values()), - safe1_1 + SAFE_1_1_ADDRESS ) // Add the signatureSafe1_1 to safeMessage - // After this, the safeMessage contains the signature from owner1, owner2 and safe1_1 + // After this, the safeMessage contains the signature from OWNER_1_ADDRESS, OWNER_2_ADDRESS and SAFE_1_1_ADDRESS safeMessage.addSignature(signatureSafe1_1) ``` @@ -179,47 +186,51 @@ Using the Protocol Kit, this guide explains how to generate and sign messages fr ##### 2/3 Safe account - This applies to the `safe2_3` account, another owner of `safe3_4`. + This applies to the `SAFE_2_3_ADDRESS` account, another owner of `SAFE_3_4_ADDRESS`. - We need to connect the Protocol Kit to `safe2_3` and the `owner4` and `owner5` accounts (owners of `safe2_3`) and sign the message. + We need to connect the Protocol Kit to `SAFE_2_3_ADDRESS` and the `OWNER_4_ADDRESS` and `OWNER_5_ADDRESS` accounts (owners of `SAFE_2_3_ADDRESS`) and sign the message. ```typescript // Create a new message object let messageSafe2_3 = await createMessage(TYPED_MESSAGE) - // Connect the EthAdapter from owner4 and the address of safe2_3 + // Connect OWNER_4_ADDRESS and SAFE_2_3_ADDRESS protocolKit = await protocolKit.connect({ - ethAdapter: ethAdapter4, - safeAddress: safe2_3 + provider: RPC_URL, + signer: OWNER_4_PRIVATE_KEY, + safeAddress: SAFE_2_3_ADDRESS }) - // Sign the messageSafe2_3 with owner4 - // After this, the messageSafe2_3 contains the signature from owner4 + // Sign the messageSafe2_3 with OWNER_4_ADDRESS + // After this, the messageSafe2_3 contains the signature from OWNER_4_ADDRESS messageSafe2_3 = await protocolKit.signMessage( messageSafe2_3, SigningMethod.SAFE_SIGNATURE, - safe3_4 // Parent Safe address + SAFE_3_4_ADDRESS // Parent Safe address ) - // Connect the EthAdapter from owner5 - protocolKit = await protocolKit.connect({ ethAdapter: ethAdapter5 }) + // Connect OWNER_5_ADDRESS + protocolKit = await protocolKit.connect({ + provider: RPC_URL, + signer: OWNER_5_PRIVATE_KEY + }) - // Sign the messageSafe2_3 with owner5 - // After this, the messageSafe2_3 contains the signature from owner5 + // Sign the messageSafe2_3 with OWNER_5_ADDRESS + // After this, the messageSafe2_3 contains the signature from OWNER_5_ADDRESS messageSafe2_3 = await protocolKit.signMessage( messageSafe2_3, SigningMethod.SAFE_SIGNATURE, - safe3_4 // Parent Safe address + SAFE_3_4_ADDRESS // Parent Safe address ) - // Build the contract signature of safe2_3 + // Build the contract signature of SAFE_2_3_ADDRESS const signatureSafe2_3 = await buildContractSignature( Array.from(messageSafe2_3.signatures.values()), - safe2_3 + SAFE_2_3_ADDRESS ) // Add the signatureSafe2_3 to safeMessage - // After this, the safeMessage contains the signature from owner1, owner2, safe1_1 and safe2_3 + // After this, the safeMessage contains the signature from OWNER_1_ADDRESS, OWNER_2_ADDRESS, SAFE_1_1_ADDRESS and SAFE_2_3_ADDRESS safeMessage.addSignature(signatureSafe2_3) ``` @@ -249,17 +260,15 @@ Using the Protocol Kit, this guide explains how to generate and sign messages fr To store a new message, we need to call the `addMessage` from the API Kit, passing the Safe address, an object with the message, and a signature from one owner. ```typescript - const signerAddress = (await ethAdapter1.getSignerAddress()) || '0x' - - // Get the signature from owner1 - const signatureOwner1 = safeMessage.getSignature(signerAddress) as EthSafeSignature + // Get the signature from OWNER_1_ADDRESS + const signatureOwner1 = safeMessage.getSignature(OWNER_1_PRIVATE_KEY) as EthSafeSignature // Instantiate the API Kit // Use the chainId where you have the Safe account deployed const apiKit = new SafeApiKit({ chainId }) // Propose the message - apiKit.addMessage(safe3_4, { + apiKit.addMessage(SAFE_3_4_ADDRESS, { message: TYPED_MESSAGE, // or STRING_MESSAGE signature: buildSignatureBytes([signatureOwner1]) }) @@ -277,23 +286,22 @@ Using the Protocol Kit, this guide explains how to generate and sign messages fr hashSafeMessage(TYPED_MESSAGE) // or STRING_MESSAGE ) - // Get the signature from owner2 - const signerAddress = (await ethAdapter2.getSignerAddress()) || '0x' - const signatureOwner2 = safeMessage.getSignature(signerAddress) as EthSafeSignature + // Get the signature from OWNER_2_ADDRESS + const signatureOwner2 = safeMessage.getSignature(OWNER_2_ADDRESS) as EthSafeSignature - // Add signature from owner2 + // Add signature from OWNER_2_ADDRESS await apiKit.addMessageSignature( safeMessageHash, buildSignatureBytes([signatureOwner2]) ) - // Add signature from the owner safe1_1 + // Add signature from the owner SAFE_1_1_ADDRESS await apiKit.addMessageSignature( safeMessageHash, buildSignatureBytes([signatureSafe1_1]) ) - // Add signature from the owner safe2_3 + // Add signature from the owner SAFE_2_3_ADDRESS await apiKit.addMessageSignature( safeMessageHash, buildSignatureBytes([signatureSafe2_3]) @@ -320,7 +328,7 @@ Using the Protocol Kit, this guide explains how to generate and sign messages fr ```typescript // Get the contract with the correct version - const signMessageLibContract = await ethAdapter1.getSignMessageLibContract({ + const signMessageLibContract = await getSignMessageLibContract({ safeVersion: '1.4.1' }) ``` diff --git a/pages/sdk/protocol-kit/guides/signatures/transactions.mdx b/pages/sdk/protocol-kit/guides/signatures/transactions.mdx index c1ae45a3..0d863f55 100644 --- a/pages/sdk/protocol-kit/guides/signatures/transactions.mdx +++ b/pages/sdk/protocol-kit/guides/signatures/transactions.mdx @@ -56,32 +56,38 @@ This guide explains how transactions are signed by the Safe owners using the Pro Once the `safeTransaction` object is created, we need to collect the signatures from the signers who will sign it. - Following our [setup](../signatures.md), we will sign a Safe transaction from `safe3_4`, the main Safe account in this guide. To do that, we first need to sign the same transaction with its owners: `owner1`, `owner2`, `safe1_1`, and `safe2_3`. + Following our [setup](../signatures.md), we will sign a Safe transaction from `SAFE_3_4_ADDRESS`, the main Safe account in this guide. To do that, we first need to sign the same transaction with its owners: `OWNER_1_ADDRESS`, `OWNER_2_ADDRESS`, `SAFE_1_1_ADDRESS`, and `SAFE_2_3_ADDRESS`. #### ECDSA signature - This applies to `owner1` and `owner2` accounts, as both are EOAs. + This applies to `OWNER_1_ADDRESS` and `OWNER_2_ADDRESS` accounts, as both are EOAs. The `signTransaction` method takes the `safeTransaction` together with a `SigningMethod` and adds the new signature to the `safeTransaction.signatures` map. Depending on the type of message, the `SigningMethod` can take these values: - `SigningMethod.ETH_SIGN` - `SigningMethod.ETH_SIGN_TYPED_DATA_V4` ```typescript - // Connect the EthAdapter from owner1 - protocolKit = await protocolKit.connect({ ethAdapter: ethAdapter1 }) + // Connect OWNER_1_ADDRESS + protocolKit = await protocolKit.connect({ + provider: RPC_URL, + signer: OWNER_1_PRIVATE_KEY + }) - // Sign the safeTransaction with owner1 - // After this, the safeTransaction contains the signature from owner1 + // Sign the safeTransaction with OWNER_1_ADDRESS + // After this, the safeTransaction contains the signature from OWNER_1_ADDRESS safeTransaction = await protocolKit.signTransaction( safeTransaction, SigningMethod.ETH_SIGN ) - // Connect the EthAdapter from owner2 - protocolKit = await protocolKit.connect({ ethAdapter: ethAdapter2 }) + // Connect OWNER_2_ADDRESS + protocolKit = await protocolKit.connect({ + provider: RPC_URL, + signer: OWNER_2_PRIVATE_KEY + }) - // Sign the safeTransaction with owner2 - // After this, the safeTransaction contains the signature from owner1 and owner2 + // Sign the safeTransaction with OWNER_2_ADDRESS + // After this, the safeTransaction contains the signature from OWNER_1_ADDRESS and OWNER_2_ADDRESS safeTransaction = await protocolKit.signTransaction( safeTransaction, SigningMethod.ETH_SIGN_TYPED_DATA_V4 @@ -143,9 +149,9 @@ This guide explains how transactions are signed by the Safe owners using the Pro ##### 1/1 Safe account - This applies to the `safe1_1` account, another owner of `safe3_4`. + This applies to the `SAFE_1_1_ADDRESS` account, another owner of `SAFE_3_4_ADDRESS`. - We need to connect the Protocol Kit to `safe1_1` and the `owner3` account (the only owner of `safe1_1`) and sign the transaction. + We need to connect the Protocol Kit to `SAFE_1_1_ADDRESS` and the `OWNER_3_ADDRESS` account (the only owner of `SAFE_1_1_ADDRESS`) and sign the transaction. ```typescript // Create a new transaction object @@ -153,18 +159,19 @@ This guide explains how transactions are signed by the Safe owners using the Pro transactions: [safeTransactionData] }) - // Connect the adapter from owner3 and the address of safe1_1 + // Connect OWNER_3_ADDRESS and SAFE_1_1_ADDRESS protocolKit = await protocolKit.connect({ - ethAdapter: ethAdapter3, - safeAddress: safe1_1 + provider: RPC_URL, + signer: OWNER_3_PRIVATE_KEY, + safeAddress: SAFE_1_1_ADDRESS }) - // Sign the transactionSafe1_1 with owner3 - // After this, transactionSafe1_1 contains the signature from owner3 + // Sign the transactionSafe1_1 with OWNER_3_ADDRESS + // After this, transactionSafe1_1 contains the signature from OWNER_3_ADDRESS transactionSafe1_1 = await protocolKit.signTransaction( transactionSafe1_1, SigningMethod.SAFE_SIGNATURE, - safe3_4 // Parent Safe address + SAFE_3_4_ADDRESS // Parent Safe address ) ``` @@ -187,17 +194,17 @@ This guide explains how transactions are signed by the Safe owners using the Pro The `signatures.data` represents a specific signature. The `isContractSignature` flag set to `false` indicates that the signature isn't a smart contract signature but an ECDSA signature instead. - To generate a Safe compatible signature, we use the `buildContractSignature` method, which takes an array of signatures and returns another signature that can be used with Safe accounts. After that, we add the signature from `safe1_1` to our initial transaction. + To generate a Safe compatible signature, we use the `buildContractSignature` method, which takes an array of signatures and returns another signature that can be used with Safe accounts. After that, we add the signature from `SAFE_1_1_ADDRESS` to our initial transaction. ```typescript - // Build the contract signature of safe1_1 + // Build the contract signature of SAFE_1_1_ADDRESS const signatureSafe1_1 = await buildContractSignature( Array.from(transactionSafe1_1.signatures.values()), - safe1_1 + SAFE_1_1_ADDRESS ) // Add the signatureSafe1_1 to safeTransaction - // After this, the safeTransaction contains the signature from owner1, owner2 and safe1_1 + // After this, the safeTransaction contains the signature from OWNER_1_ADDRESS, OWNER_2_ADDRESS and SAFE_1_1_ADDRESS safeTransaction.addSignature(signatureSafe1_1) ``` @@ -211,7 +218,7 @@ This guide explains how transactions are signed by the Safe owners using the Pro } ``` - The `isContractSignature` flag is now `true` because `signatureSafe1_1` is an EIP-1271 smart contract signature from the `safe1_1` account. + The `isContractSignature` flag is now `true` because `signatureSafe1_1` is an EIP-1271 smart contract signature from the `SAFE_1_1_ADDRESS` account. The `signatureSafe1_1.data` signature should look like this: @@ -230,9 +237,9 @@ This guide explains how transactions are signed by the Safe owners using the Pro ##### 2/3 Safe account - This applies to the `safe2_3` account, another owner of `safe3_4`. + This applies to the `SAFE_2_3_ADDRESS` account, another owner of `SAFE_3_4_ADDRESS`. - We need to connect the Protocol Kit to `safe2_3` and the `owner4` and `owner5` accounts (owners of `safe2_3`) and sign the transaction. + We need to connect the Protocol Kit to `SAFE_2_3_ADDRESS` and the `OWNER_4_ADDRESS` and `OWNER_5_ADDRESS` accounts (owners of `SAFE_2_3_ADDRESS`) and sign the transaction. ```typescript // Create a new transaction object @@ -240,29 +247,33 @@ This guide explains how transactions are signed by the Safe owners using the Pro transactions: [safeTransactionData] }) - // Connect the EthAdapter from owner4 and the address of safe2_3 + // Connect OWNER_4_ADDRESS and the address of SAFE_2_3_ADDRESS protocolKit = await protocolKit.connect({ - ethAdapter: ethAdapter4, - safeAddress: safe2_3 + provider: RPC_URL, + signer: OWNER_4_ADDRESS, + safeAddress: SAFE_2_3_ADDRESS }) - // Sign the transactionSafe2_3 with owner4 - // After this, the transactionSafe2_3 contains the signature from owner4 + // Sign the transactionSafe2_3 with OWNER_4_ADDRESS + // After this, the transactionSafe2_3 contains the signature from OWNER_4_ADDRESS transactionSafe2_3 = await protocolKit.signTransaction( transactionSafe2_3, SigningMethod.SAFE_SIGNATURE, - safe3_4 // Parent Safe address + SAFE_3_4_ADDRESS // Parent Safe address ) - // Connect the adapter for owner5 - protocolKit = await protocolKit.connect({ ethAdapter: ethAdapter5 }) + // Connect OWNER_5_ADDRESS + protocolKit = await protocolKit.connect({ + provider: RPC_URL, + signer: OWNER_5_ADDRESS + }) - // Sign the transactionSafe2_3 with owner5 - // After this, the transactionSafe2_3 contains the signature from owner5 + // Sign the transactionSafe2_3 with OWNER_5_ADDRESS + // After this, the transactionSafe2_3 contains the signature from OWNER_5_ADDRESS transactionSafe2_3 = await protocolKit.signTransaction( transactionSafe2_3, SigningMethod.SAFE_SIGNATURE, - safe3_4 // Parent Safe address + SAFE_3_4_ADDRESS // Parent Safe address ) ``` @@ -286,21 +297,21 @@ This guide explains how transactions are signed by the Safe owners using the Pro } ``` - We now have two signatures from the owners, `owner4` and `owner5`. Following the same process, we can create the contract signature and examine the result. + We now have two signatures from the owners, `OWNER_4_ADDRESS` and `OWNER_5_ADDRESS`. Following the same process, we can create the contract signature and examine the result. The `signatures.data` represents a specific signature. The `isContractSignature` flag set to `false` indicates that the signature isn't a smart contract signature but an ECDSA signature instead. To generate a Safe compatible signature, we use the `buildContractSignature` method, which takes an array of signatures and returns another signature that can be used with Safe accounts. After that, we add the signature from `safe1_1` to our initial transaction. ```typescript - // Build the contract signature of safe2_3 + // Build the contract signature of SAFE_2_3_ADDRESS const signatureSafe2_3 = await buildContractSignature( Array.from(transactionSafe2_3.signatures.values()), - safe2_3 + SAFE_2_3_ADDRESS ) // Add the signatureSafe2_3 to safeTransaction - // After this, the safeTransaction contains the signature from owner1, owner2, safe1_1 and safe2_3 + // After this, the safeTransaction contains the signature from OWNER_1_ADDRESS, OWNER_2_ADDRESS, SAFE_1_1_ADDRESS and SAFE_2_3_ADDRESS safeTransaction.addSignature(signatureSafe2_3) ``` @@ -375,10 +386,8 @@ This guide explains how transactions are signed by the Safe owners using the Pro To store a new transaction, we need to call the `proposeTransaction` from the API Kit, passing the Safe address, an object with the transaction, and a signature from one owner. ```typescript - const signerAddress = (await ethAdapter1.getSignerAddress()) || '0x' - - // Get the signature from owner1 - const signatureOwner1 = safeTransaction.getSignature(signerAddress) as EthSafeSignature + // Get the signature from OWNER_1_ADDRESS + const signatureOwner1 = safeTransaction.getSignature(OWNER_1_ADDRESS) as EthSafeSignature // Get the transaction hash of the safeTransaction const safeTransactionHash = await protocolKit.getTransactionHash(safeTransaction) @@ -389,7 +398,7 @@ This guide explains how transactions are signed by the Safe owners using the Pro // Propose the transaction await apiKit.proposeTransaction({ - safeAddress: safe3_4, + safeAddress: SAFE_3_4_ADDRESS, safeTransactionData: safeTransaction.data, safeTxHash: safeTransactionHash, senderAddress: signerAddress, @@ -406,23 +415,21 @@ This guide explains how transactions are signed by the Safe owners using the Pro Once a transaction is proposed, it becomes available on [Safe\{Wallet\}](https://app.safe.global). However, to execute the transaction, all the confirmations from the owners are needed. ```typescript - const signerAddress = (await ethAdapter2.getSignerAddress()) || '0x' - - const signatureOwner2 = safeTransaction.getSignature(signerAddress) as EthSafeSignature + const signatureOwner2 = safeTransaction.getSignature(OWNER_2_ADDRESS) as EthSafeSignature - // Confirm the transaction from owner2 + // Confirm the transaction from OWNER_2_ADDRESS await apiKit.confirmTransaction( safeTransactionHash, buildSignatureBytes([signatureOwner2]) ) - // Confirm the transaction with the owner safe1_1 + // Confirm the transaction with the owner SAFE_1_1_ADDRESS await apiKit.confirmTransaction( safeTransactionHash, buildSignatureBytes([signatureSafe1_1]) ) - // Add signature from the owner safe2_3 + // Add signature from the owner SAFE_2_3_ADDRESS await apiKit.confirmTransaction( safeTransactionHash, buildSignatureBytes([signerSafeSig2_3]) @@ -449,12 +456,13 @@ This guide explains how transactions are signed by the Safe owners using the Pro ### Execute the transaction - Connect the Safe and the adapter of an owner to the Protocol Kit. Ensure enough funds are available in the owner's account to execute the transaction and cover the gas costs. Once the Protocol Kit is initialized, the `executeTransaction` method receives and executes the transaction with the required signatures. + Connect the Safe and an a signer to the Protocol Kit. Ensure enough funds are available in the owner's account to execute the transaction and cover the gas costs. Once the Protocol Kit is initialized, the `executeTransaction` method receives and executes the transaction with the required signatures. ```typescript protocolKit = await protocolKit.connect({ - ethAdapter: ethAdapter1, - safeAddress: safe3_4 + provider: RPC_URL, + signer: OWNER_1_PRIVATE_KEY, + safeAddress: SAFE_3_4_ADDRESS }) // Execute the Safe transaction @@ -479,14 +487,14 @@ This guide explains how transactions are signed by the Safe owners using the Pro | 1/1 Safe signer | Safe Address | 32 | 32 |
000000000000000000000000215033cdE0619D60B7352348F4598316Cc39bC6E
| | Data position for 1/1 Safe | 104 hex = Signature data for 1/1 Safe start at byte 260 | 32 | 64 |
0000000000000000000000000000000000000000000000000000000000000104
| | Signature Type | Smart contract signature | 1 | 65 |
00
| - | Owner signature | `owner1` signature | 65 | 130 |
969308e2abeda61a0c9c41b3c615012f50dd7456ca76ea39a18e3b975abeb67f275b07810dd59fc928f3f9103e52557c1578c7c5c171ffc983afa5306466b1261f
| + | Owner signature | `OWNER_1_ADDRESS` signature | 65 | 130 |
969308e2abeda61a0c9c41b3c615012f50dd7456ca76ea39a18e3b975abeb67f275b07810dd59fc928f3f9103e52557c1578c7c5c171ffc983afa5306466b1261f
| | 2/3 Safe signer | Safe Address | 32 | 162 |
000000000000000000000000f75D61D6C27a7CC5788E633c1FC130f0F4a62D33
| | Data position for 2/3 Verifier | 165 hex = Signature data for 2/3 Safe start at byte 357 | 32 | 194 |
0000000000000000000000000000000000000000000000000000000000000165
| | Signature | Type Smart contract signature | 1 | 195 |
00
| - | Owner signature | `owner2` signature | 65 | 260 |
4d63c79cf9d743782bc31ad58c1a316020b39839ab164caee7ecac9829f685cc44ec0d066a5dfe646b2ffeeb37575df131daf9c96ced41b8c7c4aea8dc5461801c
| + | Owner signature | `OWNER_2_ADDRESS` signature | 65 | 260 |
4d63c79cf9d743782bc31ad58c1a316020b39839ab164caee7ecac9829f685cc44ec0d066a5dfe646b2ffeeb37575df131daf9c96ced41b8c7c4aea8dc5461801c
| | 1/1 Safe Signature Length | Start of the 1/1 Safe Signature. 41 hex = 65 bytes | 32 | 292 |
0000000000000000000000000000000000000000000000000000000000000041
| - | Signature | `owner3` signature | 65 | 357 |
5edb6ffe67dd935d93d07c634970944ba0b096f767b92018ad635e8b28effeea5a1e512f1ad6f886690e0e30a3fae2c8c61d3f83d24d43276acdb3254b92ea5b1f
| + | Signature | `OWNER_3_ADDRESS` signature | 65 | 357 |
5edb6ffe67dd935d93d07c634970944ba0b096f767b92018ad635e8b28effeea5a1e512f1ad6f886690e0e30a3fae2c8c61d3f83d24d43276acdb3254b92ea5b1f
| | 2/3 Safe Signature length | Start of the 2/3 Safe Signature. 82 hex = 130 bytes | 32 | 389 |
0000000000000000000000000000000000000000000000000000000000000082
| - | Signature | `owner4` and `owner5` concatenated signatures | 130 | 519 |
023d1746ed548e90f387a6b8ddba26e6b80a78d5bfbc36e5bfcbfd63e136f8071db6e91c037fa36bde72159138bbb74fc359b35eb515e276a7c0547d5eaa042520d3e6565e5590641db447277243cf24711dce533cfcaaf3a64415dcb9fa309fbf2de1ae4709c6450752acc0d45e01b67b55379bdf4e3dc32b2d89ad0a60c231d61f
| + | Signature | `OWNER_4_ADDRESS` and `OWNER_5_ADDRESS` concatenated signatures | 130 | 519 |
023d1746ed548e90f387a6b8ddba26e6b80a78d5bfbc36e5bfcbfd63e136f8071db6e91c037fa36bde72159138bbb74fc359b35eb515e276a7c0547d5eaa042520d3e6565e5590641db447277243cf24711dce533cfcaaf3a64415dcb9fa309fbf2de1ae4709c6450752acc0d45e01b67b55379bdf4e3dc32b2d89ad0a60c231d61f
| diff --git a/pages/sdk/protocol-kit/reference/_meta.json b/pages/sdk/protocol-kit/reference/_meta.json index 17040c88..bfe57133 100644 --- a/pages/sdk/protocol-kit/reference/_meta.json +++ b/pages/sdk/protocol-kit/reference/_meta.json @@ -1,6 +1,7 @@ { - "safe-factory": "Safe Factory", - "safe": "Safe", - "migrating-to-v1": "Migrating to V1", - "migrating-to-v2": "Migrating to V2" + "safe-factory": "Safe Factory", + "safe": "Safe", + "migrate-to-v1": "Migrate to v1", + "migrate-to-v2": "Migrate to v2", + "migrate-to-v3": "Migrate to v3" } diff --git a/pages/sdk/protocol-kit/reference/migrating-to-v1.md b/pages/sdk/protocol-kit/reference/migrate-to-v1.md similarity index 99% rename from pages/sdk/protocol-kit/reference/migrating-to-v1.md rename to pages/sdk/protocol-kit/reference/migrate-to-v1.md index 76d61650..23b8168a 100644 --- a/pages/sdk/protocol-kit/reference/migrating-to-v1.md +++ b/pages/sdk/protocol-kit/reference/migrate-to-v1.md @@ -1,4 +1,4 @@ -# Migrating to v1 +# Migrate to v1 This guide references the major changes between `safe-core-sdk` and `protocol-kit` v1 to help those migrating an existing application. diff --git a/pages/sdk/protocol-kit/reference/migrating-to-v2.md b/pages/sdk/protocol-kit/reference/migrate-to-v2.md similarity index 98% rename from pages/sdk/protocol-kit/reference/migrating-to-v2.md rename to pages/sdk/protocol-kit/reference/migrate-to-v2.md index c1807e0f..fb5090a5 100644 --- a/pages/sdk/protocol-kit/reference/migrating-to-v2.md +++ b/pages/sdk/protocol-kit/reference/migrate-to-v2.md @@ -1,4 +1,4 @@ -# Migrating to v2 +# Migrate to v2 This guide references the major changes between v1 and v2 to help those migrating an existing app. diff --git a/pages/sdk/protocol-kit/reference/migrate-to-v3.md b/pages/sdk/protocol-kit/reference/migrate-to-v3.md new file mode 100644 index 00000000..6b46501d --- /dev/null +++ b/pages/sdk/protocol-kit/reference/migrate-to-v3.md @@ -0,0 +1,21 @@ +# Migrate to v3 + +This guide references the major changes between v2 and v3 to help those migrating an existing app. + +**Note:** When upgrading to `protocol-kit` v3, it's necessary to upgrade to `safe-core-sdk-types` v4. + +## The signTransactionHash() was renamed signHash() + +The `signTransactionHash()` method was renamed to `signHash()` to align with the method's purpose. The method is not strictly for transactions, as the parameter is a hash, so the new name is more accurate. + +```js +// old: +protocolKit.signTransactionHash(safeTxHash); + +// new: +protocolKit.signHash(safeTxHash); +``` + +## Type changes + +The `SafeTransactionEIP712Args` was renamed `SafeEIP712Args` as the EIP-712 is not exclusive for transactions. diff --git a/pages/sdk/protocol-kit/reference/migrate-to-v4.md b/pages/sdk/protocol-kit/reference/migrate-to-v4.md new file mode 100644 index 00000000..9d0d7164 --- /dev/null +++ b/pages/sdk/protocol-kit/reference/migrate-to-v4.md @@ -0,0 +1,79 @@ +# Migrate to v4 + +This guide references the major changes between v3 and v4 to help those migrating an existing app. + +**Note:** When upgrading to `protocol-kit` v4, it's necessary to upgrade to `safe-core-sdk-types` v5. + +## The create() method was renamed init() in the SafeFactory and Safe classes + +We renamed the `create()` method to `init()` to better reflect the method's purpose. The term `create()` was misleading, suggesting a new Safe account would be created and deployed. However, this method only initializes the `Safe` class, so `init()` is a more accurate and descriptive name. + +```js +// old +const protocolKit = await Safe.create({ ... }) +const safeFactory = await SafeFactory.create({ ... }) + +// new +const protocolKit = await Safe.init({ ... }) +const safeFactory = await SafeFactory.init({ ... }) +``` + +## Remove the adapters + +We have removed the concept of adapters from the `protocol-kit` to simplify the library. Instead of using specific library adapters, we use now an internal `SafeProvider` object to interact with the Safe. This `SafeProvider` will be created using: + +- An Ethereum provider, an [EIP-1193](https://eips.ethereum.org/EIPS/eip-1193) compatible provider, or an RPC URL. +- An optional address of the signer that is connected to the provider or a private key. If not provided, the first account of the provider (`eth_accounts`) will be selected as the signer. + +The `EthAdapter` interface, the `EthersAdapter` class, and the `Web3Adapter` class are no longer available. Similarly, `EthersAdapterConfig` and `Web3AdapterConfig` were removed as well. + + +```js +// old +const ethAdapter = new EthersAdapter({ ethers, signerOrProvider }) +// const ethAdapter = new Web3Adapter({ web3, signerAddress }) +await Safe.create({ + ethAdapter, + safeAddress: '0xSafeAddress' + ... +}) + +// new +await Safe.init({ + provider: window.ethereum, // Or any compatible EIP-1193 provider + signer: "0xSignerAddressOrPrivateKey", // Signer address or private key + safeAddress: '0xSafeAddress' + ... +}) + +// ...or... +await Safe.init({ + provider: 'http://rpc.url', // Or websocket + signer: '0xPrivateKey' // Signer private key + safeAddress: '0xSafeAddress' + ... +}) +``` + +## `EthersTransactionOptions` and `Web3TransactionOptions` types are now `TransactionOptions` + +Together with the adapters, we also removed the specific transaction options objects for each library, leaving just a single `TransactionOptions` type. + +We removed the `gas` property from the `TransactionOptions` object as it was a specific property for the web3.js library. Now, you should use the `gasLimit` property instead. + +## `EthersTransactionResult` and `Web3TransactionResult` types are now `TransactionResult` + +Together with the adapters, we also removed the specific transaction result objects for each library, leaving just a single `TransactionResult` type. + +## Contract classes suffixed with Ethers and Web3 + +All the contract classes that were suffixed with `Ethers` or `Web3` were renamed to remove the suffix. + +```js +SafeBaseContractEthers, SafeBaseContractWeb3 -> SafeBaseContract +MultiSendBaseContractEthers, MultiSendBaseContractWeb3 -> MultiSendBaseContract +MultiSendCallOnlyBaseContractEthers, MultiSendCallOnlyBaseContractWeb3 -> MultiSendCallOnlyBaseContract +SafeProxyFactoryBaseContractEthers, SafeProxyFactoryBaseContractWeb3 -> SafeProxyFactoryBaseContract +SignMessageLibBaseContractEthers, SignMessageLibBaseContractWeb3 -> SignMessageLibBaseContract +CreateCallBaseContractEthers, CreateCallBaseContractWeb3 -> CreateCallBaseContract +``` diff --git a/pages/sdk/protocol-kit/reference/safe-factory.md b/pages/sdk/protocol-kit/reference/safe-factory.md index 6e437f0c..a344e889 100644 --- a/pages/sdk/protocol-kit/reference/safe-factory.md +++ b/pages/sdk/protocol-kit/reference/safe-factory.md @@ -1,13 +1,18 @@ # Safe Factory reference -### `create` +### `init` -Returns an instance of the Safe Factory. +It receives a provider and a signer as required parameters and returns an instance of the Safe Factory. + +The `provider` property can be an [EIP-1193](https://eips.ethereum.org/EIPS/eip-1193) compatible provider or an RPC URL. The `signer` property can be the signer address or its private key. ```typescript import { SafeFactory } from '@safe-global/protocol-kit' -const safeFactory = await SafeFactory.create({ ethAdapter }) +const safeFactory = await SafeFactory.init({ + provider, + signer +}) ``` - The `isL1SafeSingleton` flag @@ -17,7 +22,11 @@ const safeFactory = await SafeFactory.create({ ethAdapter }) By default, `Safe.sol` will only be used on Ethereum Mainnet. For the rest of the networks where the Safe contracts are already deployed, the `SafeL2.sol` contract will be used unless you add the `isL1SafeSingleton` flag to force using the `Safe.sol` contract. ```typescript - const safeFactory = await SafeFactory.create({ ethAdapter, isL1SafeSingleton: true }) + const safeFactory = await SafeFactory.init({ + provider, + signer, + isL1SafeSingleton: true + }) ``` - The `contractNetworks` property @@ -25,9 +34,14 @@ const safeFactory = await SafeFactory.create({ ethAdapter }) If the Safe contracts aren't deployed to your current network, the `contractNetworks` property will be required to point to the addresses of the Safe contracts previously deployed by you. ```typescript - import { ContractNetworksConfig } from '@safe-global/protocol-kit' + import { + ContractNetworksConfig, + SafeProvider + } from '@safe-global/protocol-kit' + + const safeProvider = new SafeProvider({ provider, signer }) + const chainId = await safeProvider.getChainId() - const chainId = await ethAdapter.getChainId() const contractNetworks: ContractNetworksConfig = { [chainId]: { safeSingletonAddress: '', @@ -49,7 +63,11 @@ const safeFactory = await SafeFactory.create({ ethAdapter }) } } - const safeFactory = await SafeFactory.create({ ethAdapter, contractNetworks }) + const safeFactory = await SafeFactory.init({ + provider, + signer, + contractNetworks + }) ``` - The `safeVersion` property @@ -58,7 +76,11 @@ const safeFactory = await SafeFactory.create({ ethAdapter }) ```typescript const safeVersion = 'X.Y.Z' - const safeFactory = await SafeFactory.create({ ethAdapter, safeVersion }) + const safeFactory = await SafeFactory.init({ + provider, + signer, + safeVersion + }) ``` ### `deploySafe` @@ -102,18 +124,7 @@ const protocolKit = await safeFactory.deploySafe({ safeAccountConfig, saltNonce Optionally, some properties can be passed as execution options: ```typescript -const options: Web3TransactionOptions = { - from, // Optional - gas, // Optional - gasPrice, // Optional - maxFeePerGas, // Optional - maxPriorityFeePerGas // Optional - nonce // Optional -} -``` - -```typescript -const options: EthersTransactionOptions = { +const options: TransactionOptions = { from, // Optional gasLimit, // Optional gasPrice, // Optional diff --git a/pages/sdk/protocol-kit/reference/safe.md b/pages/sdk/protocol-kit/reference/safe.md index d54201e1..69e55b5c 100644 --- a/pages/sdk/protocol-kit/reference/safe.md +++ b/pages/sdk/protocol-kit/reference/safe.md @@ -2,30 +2,39 @@ ## Initialization -### `connect` +### `init` -Returns a new instance of the Protocol Kit connected to a new Safe or a new Signer. The new connected signer can be passed via the `ethAdapter` property while the new connected Safe can be passed using a `safeAddress` or a `predictedSafe`. +Returns an instance of the Protocol Kit connected to a Safe. -Connection of a deployed Safe using the `safeAddress` property: +The `provider` property can be an [EIP-1193](https://eips.ethereum.org/EIPS/eip-1193) compatible provider or an RPC URL. The `signer` property can be the signer address or its private key. The provided Safe must be a `safeAddress` or a `predictedSafe`. + +Initialization of a deployed Safe using the `safeAddress` property: ```typescript -let protocolKit = await Safe.create({ ethAdapter, safeAddress }) -protocolKit = await protocolKit.connect({ ethAdapter: anotherEthAdapter, safeAddress: anotherSafeAddress }) +import Safe from '@safe-global/protocol-kit' + +const protocolKit = await Safe.init({ + provider, + signer, + safeAddress +}) ``` -Connection of an undeployed Safe using the `predictedSafe` property. Because Safes are deployed in a deterministic way, passing a `predictedSafe` will allow to connect a Safe to the SDK with the Safe configuration: +Initialization of an undeployed Safe using the `predictedSafe` property. Because Safes are deployed in a deterministic way, passing a `predictedSafe` will allow to initialize the SDK with the Safe configuration and use it to some extent before it's deployed: ```typescript -import { PredictedSafeProps } from '@safe-global/protocol-kit' +import Safe, { PredictedSafeProps } from '@safe-global/protocol-kit' const predictedSafe: PredictedSafeProps = { safeAccountConfig, safeDeploymentConfig } -let protocolKit = await Safe.create({ ethAdapter, safeAddress }) -... -protocolKit = await protocolKit.connect({ predictedSafe }) +const protocolKit = await Safe.init({ + provider, + signer, + predictedSafe +}) ``` - The `isL1SafeSingleton` flag @@ -35,7 +44,12 @@ protocolKit = await protocolKit.connect({ predictedSafe }) By default `Safe.sol` will only be used on Ethereum Mainnet. For the rest of the networks where the Safe contracts are already deployed, the `SafeL2.sol` contract will be used unless you add the `isL1SafeSingleton` flag to force using the `Safe.sol` contract. ```typescript - protocolKit = await protocolKit.connect({ ethAdapter, safeAddress, isL1SafeSingleton: true }) + const protocolKit = await Safe.init({ + provider, + signer, + safeAddress, + isL1SafeSingleton: true + }) ``` - The `contractNetworks` property @@ -43,9 +57,14 @@ protocolKit = await protocolKit.connect({ predictedSafe }) If the Safe contracts aren't deployed to your current network, the `contractNetworks` property will be required to point to the addresses of the Safe contracts previously deployed by you. ```typescript - import { ContractNetworksConfig } from '@safe-global/protocol-kit' + import { + ContractNetworksConfig, + SafeProvider + } from '@safe-global/protocol-kit' + + const safeProvider = new SafeProvider({ provider, signer }) + const chainId = await safeProvider.getChainId() - const chainId = await ethAdapter.getChainId() const contractNetworks: ContractNetworksConfig = { [chainId]: { safeSingletonAddress: '', @@ -66,34 +85,55 @@ protocolKit = await protocolKit.connect({ predictedSafe }) simulateTxAccessorAbi: '' // Optional. Only needed with web3.js } } - let protocolKit = await Safe.create({ ethAdapter, safeAddress }) - ... - protocolKit = await protocolKit.connect({ contractNetworks }) + + const protocolKit = await Safe.init({ + provider, + signer, + safeAddress, + contractNetworks + }) ``` -### `create` +### `connect` + +Returns a new instance of the Protocol Kit connected to a new Safe or a new signer. The new connected signer can be passed via the `signer` property while the new connected Safe can be passed using a `safeAddress` or a `predictedSafe`. -Returns an instance of the Protocol Kit connected to a Safe. The provided Safe must be a `safeAddress` or a `predictedSafe`. +The `provider` property can be an [EIP-1193](https://eips.ethereum.org/EIPS/eip-1193) compatible provider or an RPC URL. The `signer` property can be the signer address or its private key. -Initialization of a deployed Safe using the `safeAddress` property: +Connection of a deployed Safe using the `safeAddress` property: ```typescript -import Safe from '@safe-global/protocol-kit' +let protocolKit = await Safe.init({ + provider, + signer, + safeAddress +}) -const protocolKit = await Safe.create({ ethAdapter, safeAddress }) +protocolKit = await protocolKit.connect({ + signer: anotherSigner, + safeAddress: anotherSafeAddress +}) ``` -Initialization of an undeployed Safe using the `predictedSafe` property. Because Safes are deployed in a deterministic way, passing a `predictedSafe` will allow to initialize the SDK with the Safe configuration and use it to some extent before it's deployed: +Connection of an undeployed Safe using the `predictedSafe` property. Because Safes are deployed in a deterministic way, passing a `predictedSafe` will allow to connect a Safe to the SDK with the Safe configuration: ```typescript -import Safe, { PredictedSafeProps } from '@safe-global/protocol-kit' +import { PredictedSafeProps } from '@safe-global/protocol-kit' const predictedSafe: PredictedSafeProps = { safeAccountConfig, safeDeploymentConfig } -const protocolKit = await Safe.create({ ethAdapter, predictedSafe }) +let protocolKit = await Safe.init({ + provider, + signer, + safeAddress +}) + +// ... + +protocolKit = await protocolKit.connect({ predictedSafe }) ``` - The `isL1SafeSingleton` flag @@ -103,7 +143,12 @@ const protocolKit = await Safe.create({ ethAdapter, predictedSafe }) By default `Safe.sol` will only be used on Ethereum Mainnet. For the rest of the networks where the Safe contracts are already deployed, the `SafeL2.sol` contract will be used unless you add the `isL1SafeSingleton` flag to force using the `Safe.sol` contract. ```typescript - const protocolKit = await Safe.create({ ethAdapter, safeAddress, isL1SafeSingleton: true }) + protocolKit = await protocolKit.connect({ + provider, + signer, + safeAddress, + isL1SafeSingleton: true + }) ``` - The `contractNetworks` property @@ -111,9 +156,14 @@ const protocolKit = await Safe.create({ ethAdapter, predictedSafe }) If the Safe contracts aren't deployed to your current network, the `contractNetworks` property will be required to point to the addresses of the Safe contracts previously deployed by you. ```typescript - import { ContractNetworksConfig } from '@safe-global/protocol-kit' + import { + ContractNetworksConfig, + SafeProvider + } from '@safe-global/protocol-kit' + + const safeProvider = new SafeProvider({ provider, signer }) + const chainId = await safeProvider.getChainId() - const chainId = await ethAdapter.getChainId() const contractNetworks: ContractNetworksConfig = { [chainId]: { safeSingletonAddress: '', @@ -135,7 +185,15 @@ const protocolKit = await Safe.create({ ethAdapter, predictedSafe }) } } - const protocolKit = await Safe.create({ ethAdapter, safeAddress, contractNetworks }) + let protocolKit = await Safe.init({ + provider, + signer, + safeAddress + }) + + // ... + + protocolKit = await protocolKit.connect({ contractNetworks }) ``` ## Safe Info @@ -296,18 +354,7 @@ await txResponse.transactionResponse?.wait() Optionally, some properties can be passed as execution options: ```typescript -const options: Web3TransactionOptions = { - from, // Optional - gas, // Optional - gasPrice, // Optional - maxFeePerGas, // Optional - maxPriorityFeePerGas // Optional - nonce // Optional -} -``` - -```typescript -const options: EthersTransactionOptions = { +const options: TransactionOptions = { from, // Optional gasLimit, // Optional gasPrice, // Optional @@ -348,18 +395,7 @@ const isValidTx = await protocolKit.isValidTransaction(safeTransaction) Optionally, some properties can be passed as execution options: ```typescript -const options: Web3TransactionOptions = { - from, // Optional - gas, // Optional - gasPrice, // Optional - maxFeePerGas, // Optional - maxPriorityFeePerGas // Optional - nonce // Optional -} -``` - -```typescript -const options: EthersTransactionOptions = { +const options: TransactionOptions = { from, // Optional gasLimit, // Optional gasPrice, // Optional @@ -392,18 +428,7 @@ await txResponse.transactionResponse?.wait() Optionally, some properties can be passed as execution options: ```typescript -const options: Web3TransactionOptions = { - from, // Optional - gas, // Optional - gasPrice, // Optional - maxFeePerGas, // Optional - maxPriorityFeePerGas // Optional - nonce // Optional -} -``` - -```typescript -const options: EthersTransactionOptions = { +const options: TransactionOptions = { from, // Optional gasLimit, // Optional gasPrice, // Optional diff --git a/pages/sdk/relay-kit/guides/4337-safe-sdk.mdx b/pages/sdk/relay-kit/guides/4337-safe-sdk.mdx index c48d2343..ab65ddd9 100644 --- a/pages/sdk/relay-kit/guides/4337-safe-sdk.mdx +++ b/pages/sdk/relay-kit/guides/4337-safe-sdk.mdx @@ -16,7 +16,7 @@ Read the [Safe4337Module documentation](../../../home/4337-safe.mdx) to understa ## Install dependencies ```bash -yarn add ethers @safe-global/protocol-kit @safe-global/relay-kit +yarn add @safe-global/relay-kit ``` ## Steps @@ -30,8 +30,6 @@ yarn add ethers @safe-global/protocol-kit @safe-global/relay-kit {/* */} ```typescript - import { ethers } from 'ethers' - import { EthersAdapter } from '@safe-global/protocol-kit' import { Safe4337Pack } from '@safe-global/relay-kit' ``` @@ -39,21 +37,16 @@ yarn add ethers @safe-global/protocol-kit @safe-global/relay-kit ### Create a signer - Firstly, we need to get and instantiate a signer using the `EthersAdapter` from the Protocol Kit, which will be the owner of a Safe account after it's deployed. + Firstly, we need to get a signer, which will be the owner of a Safe account after it's deployed. - In this example, we use a private key, but any method to get a [signer](https://docs.ethers.org/v6/api/providers/#Signer) can be used. + In this example, we use a private key, but any way to get an EIP-1193 compatible signer can be used. {/* */} ```typescript - const PRIVATE_KEY = '0x...' - - const provider = new ethers.JsonRpcProvider('https://rpc.ankr.com/eth_sepolia') - const signer = new ethers.Wallet(PRIVATE_KEY, provider) - const ethersAdapter = new EthersAdapter({ - ethers, - signerOrProvider: signer - }) + const SIGNER_ADDRESS = // ... + const SIGNER_PRIVATE_KEY = // ... + const RPC_URL = 'https://rpc.ankr.com/eth_sepolia' ``` {/* */} @@ -72,11 +65,12 @@ yarn add ethers @safe-global/protocol-kit @safe-global/relay-kit ```typescript const safe4337Pack = await Safe4337Pack.init({ - ethersAdapter, - rpcUrl: 'https://rpc.ankr.com/eth_sepolia', + provider: RPC_URL, + signer: SIGNER_PRIVATE_KEY, + rpcUrl: RPC_URL, bundlerUrl: `https://api.pimlico.io/v1/sepolia/rpc?apikey=${PIMLICO_API_KEY}`, options: { - owners: [await signer.getAddress()], + owners: [SIGNER_ADDRESS], threshold: 1 }, // ... @@ -88,8 +82,9 @@ yarn add ethers @safe-global/protocol-kit @safe-global/relay-kit ```typescript const safe4337Pack = await Safe4337Pack.init({ - ethersAdapter, - rpcUrl: 'https://rpc.ankr.com/eth_sepolia', + provider: RPC_URL, + signer: SIGNER_PRIVATE_KEY, + rpcUrl: RPC_URL, bundlerUrl: `https://api.pimlico.io/v1/sepolia/rpc?apikey=${PIMLICO_API_KEY}`, options: { safeAddress: '0x...' diff --git a/pages/sdk/relay-kit/guides/gelato-relay.mdx b/pages/sdk/relay-kit/guides/gelato-relay.mdx index 604acc3d..087d507c 100644 --- a/pages/sdk/relay-kit/guides/gelato-relay.mdx +++ b/pages/sdk/relay-kit/guides/gelato-relay.mdx @@ -47,7 +47,7 @@ For the 1Balance quickstart tutorial, you will use the Gelato relayer to pay for ```typescript import { ethers } from 'ethers' import { GelatoRelayPack } from '@safe-global/relay-kit' - import Safe, { EthersAdapter } from '@safe-global/protocol-kit' + import Safe from '@safe-global/protocol-kit' import { MetaTransactionData, MetaTransactionOptions @@ -60,9 +60,8 @@ For the 1Balance quickstart tutorial, you will use the Gelato relayer to pay for ```typescript // https://chainlist.org - const RPC_URL='https://endpoints.omniatech.io/v1/bsc/mainnet/public' - const provider = new ethers.JsonRpcProvider(RPC_URL) - const signer = new ethers.Wallet(process.env.OWNER_1_PRIVATE_KEY!, provider) + const RPC_URL = 'https://endpoints.omniatech.io/v1/bsc/mainnet/public' + const OWNER_PRIVATE_KEY = process.env.OWNER_PRIVATE_KEY const safeAddress = '0x...' // Safe from which the transaction will be sent // Any address can be used for destination. In this example, we use vitalik.eth @@ -88,13 +87,9 @@ For the 1Balance quickstart tutorial, you will use the Gelato relayer to pay for ### Instantiate the Protocol Kit and Relay Kit ```typescript - const ethAdapter = new EthersAdapter({ - ethers, - signerOrProvider: signer - }) - - const protocolKit = await Safe.create({ - ethAdapter, + const protocolKit = await Safe.init({ + provider: RPC_URL, + signer: OWNER_PRIVATE_KEY, safeAddress }) @@ -141,7 +136,7 @@ For the SyncFee quickstart tutorial, you will use the Gelato relayer to pay for ```typescript import { ethers } from 'ethers' import { GelatoRelayPack } from '@safe-global/relay-kit' - import Safe, { EthersAdapter } from '@safe-global/protocol-kit' + import Safe from '@safe-global/protocol-kit' import { MetaTransactionData } from '@safe-global/safe-core-sdk-types' ``` @@ -151,9 +146,8 @@ For the SyncFee quickstart tutorial, you will use the Gelato relayer to pay for ```typescript // https://chainlist.org - const RPC_URL='https://endpoints.omniatech.io/v1/bsc/mainnet/public' - const provider = new ethers.JsonRpcProvider(RPC_URL) - const signer = new ethers.Wallet(process.env.OWNER_1_PRIVATE_KEY!, provider) + const RPC_URL = 'https://endpoints.omniatech.io/v1/bsc/mainnet/public' + const OWNER_PRIVATE_KEY = process.env.OWNER_PRIVATE_KEY const safeAddress = '0x...' // Safe from which the transaction will be sent // Any address can be used for destination. In this example, we use vitalik.eth @@ -175,13 +169,9 @@ For the SyncFee quickstart tutorial, you will use the Gelato relayer to pay for ### Instantiate the Protocol Kit and Relay Kit ```typescript - const ethAdapter = new EthersAdapter({ - ethers, - signerOrProvider: signer - }) - - const protocolKit = await Safe.create({ - ethAdapter, + const protocolKit = await Safe.init({ + provider: RPC_URL, + signer: OWNER_PRIVATE_KEY, safeAddress }) diff --git a/pages/sdk/relay-kit/reference/_meta.json b/pages/sdk/relay-kit/reference/_meta.json index 1d6bcdd5..0f6e0655 100644 --- a/pages/sdk/relay-kit/reference/_meta.json +++ b/pages/sdk/relay-kit/reference/_meta.json @@ -1,4 +1,5 @@ { "safe-4337-pack": "Safe4337Pack", - "migrating-to-v2": "Migrating to V2" + "migrate-to-v2": "Migrate to v2", + "migrate-to-v3": "Migrate to v3" } diff --git a/pages/sdk/relay-kit/reference/migrating-to-v2.md b/pages/sdk/relay-kit/reference/migrate-to-v2.md similarity index 97% rename from pages/sdk/relay-kit/reference/migrating-to-v2.md rename to pages/sdk/relay-kit/reference/migrate-to-v2.md index 1ec283b6..5b4a4077 100644 --- a/pages/sdk/relay-kit/reference/migrating-to-v2.md +++ b/pages/sdk/relay-kit/reference/migrate-to-v2.md @@ -1,4 +1,4 @@ -# Migrating to v2 +# Migrate to v2 This guide references the major changes between v1 and v2 to help those migrating an existing app. diff --git a/pages/sdk/relay-kit/reference/migrate-to-v3.md b/pages/sdk/relay-kit/reference/migrate-to-v3.md new file mode 100644 index 00000000..8aa7d027 --- /dev/null +++ b/pages/sdk/relay-kit/reference/migrate-to-v3.md @@ -0,0 +1,35 @@ +# Migrate to v3 + +This guide references the major changes between v2 and v3 to help those migrating an existing app. + +## Remove the adapters + +We have removed the concept of adapters from the `protocol-kit` to simplify the library. Instead of using specific library adapters, we use now an internal `SafeProvider` object to interact with the Safe. This `SafeProvider` will be created using: + +- An Ethereum provider, an [EIP-1193](https://eips.ethereum.org/EIPS/eip-1193) compatible provider, or an RPC URL. +- An optional address of the signer that is connected to the provider or a private key. If not provided, the first account of the provider (`eth_accounts`) will be selected as the signer. + +These changes affect the creation of the `Safe4337Pack` instance, as it was previously using an `ethAdapter` compatible object. + +```typescript +// old +const safe4337Pack = await Safe4337Pack.init({ + ethAdapter: new EthersAdapter({ ethers, signerOrProvider }), + // ... +}); +``` + +```typescript +// new +const safe4337Pack = await Safe4337Pack.init({ + provider: window.ethereum, // Or any compatible EIP-1193 provider, + signer: "signerAddressOrPrivateKey", // Signer address or signer private key + // ... +}); + +const safe4337Pack = await Safe4337Pack.init({ + provider: "http://rpc.url", // Or websocket + signer: "privateKey", // Signer private key + // ... +}); +``` diff --git a/pages/sdk/relay-kit/reference/safe-4337-pack.mdx b/pages/sdk/relay-kit/reference/safe-4337-pack.mdx index 1b987b15..9d963667 100644 --- a/pages/sdk/relay-kit/reference/safe-4337-pack.mdx +++ b/pages/sdk/relay-kit/reference/safe-4337-pack.mdx @@ -18,7 +18,8 @@ The `Safe4337Pack` class make easy to use the [Safe 4337 Module](https://github. ```typescript const safe4337Pack = await Safe4337Pack.init({ - ethersAdapter, + provider, + signer, rpcUrl, bundlerUrl, safeModulesVersion, @@ -38,7 +39,8 @@ The `Safe4337InitOptions` used in the `init()` method are: ```typescript Safe4337InitOptions = { - ethersAdapter: EthersAdapter + provider: Eip1193Provider | HttpTransport | SocketTransport + signer?: HexAddress | PrivateKey bundlerUrl: string rpcUrl: string safeModulesVersion?: string @@ -51,6 +53,20 @@ Safe4337InitOptions = { paymasterOptions?: PaymasterOptions } +HexAddress = string +PrivateKey = string +HttpTransport = string +SocketTransport = string + +Eip1193Provider = { + request: (args: RequestArguments) => Promise +} + +RequestArguments = { + method: string + params?: readonly unknown[] | object +} + ExistingSafeOptions = { safeAddress: string } @@ -72,8 +88,9 @@ PaymasterOptions = { } ``` -- **`ethersAdapter`** : An instance of the `EthersAdapter` class. -- **`rpcUrl`** : The RPC for the selected chain. +- **`provider`** : The EIP-1193 compatible provider or RPC URL of the selected chain. +- **`signer`** : The signer private address if the `provider` doesn't resolve to a signer account. If the `provider` resolves to multiple signer addresses, the `signer` property can be used to specify which account to connect, otherwise the first address returned will be used. +- **`rpcUrl`** : The RPC URL of the selected chain. - **`bundlerUrl`** : The bundler's URL. - **`safeModulesVersion`** : The version of the [Safe Modules contract](https://github.com/safe-global/safe-modules-deployments/tree/main/src/assets/safe-4337-module). - **`customContracts`** : An object with custom contract addresses. This is optional, if no custom contracts are provided, default ones will be used. @@ -100,7 +117,6 @@ A promise that resolves to an instance of the `Safe4337Pack`. **Caveats** - Use this method to create the initial instance instead of the standard constructor. -- You can refer to [this link](https://github.com/safe-global/safe-core-sdk/tree/main/packages/protocol-kit/src/adapters/ethers) to create instances of `EthersAdapter`. - You should search for some API services URLs and contract addresses in the management dashboards of your selected provider. These include `bundlerUrl`, `paymasterUrl`, `paymasterAddress`, `paymasterTokenAddress`, `sponsorshipPolicyId`, and `rpcUrl` (In this case any valid RPC should be fine). - The SDK uses default versions when `safeModulesVersion` or `safeVersion` are not specified. You can find more details about the current versions [here](https://github.com/safe-global/safe-core-sdk/blob/924ae56ff707509e561c99296fb5e1fbc2050d28/packages/relay-kit/src/packs/safe-4337/Safe4337Pack.ts#L34-L35). - The `saltNonce` derives different Safe addresses by using the `protocol-kit` method `predictSafeAddress`. You can find more details about this process [here](https://github.com/safe-global/safe-core-sdk/blob/924ae56ff707509e561c99296fb5e1fbc2050d28/packages/protocol-kit/src/contracts/utils.ts#L245-L315). @@ -195,7 +211,7 @@ A promise that resolves to the signed `SafeOperation`. **Caveats** - Use this method after the `SafeOperation` is generated with the `createTransaction` method. -- This method adds the signer's signature from the `EthersAdapter` to the signatures map of the `SafeOperation` object. Additional signatures can be included from multiple owners. +- This method adds the signer's signature to the signatures map of the `SafeOperation` object. Additional signatures can be included from multiple owners. - It works similar to `signTransaction` and `signMessage` methods in the `protocol-kit` but using `SafeOperation` instead of `SafeTransaction` or `SafeMessage`. For more information, refer to the Safe [docs](https://docs.safe.global/sdk/protocol-kit/guides/signatures). ### `executeTransaction(safe4337ExecutableProps)` @@ -225,7 +241,7 @@ A promise, resolves to the user operation hash. **Caveats** -- The process converts the `SafeOperation` to a standard user operation, then forwards it to the bundler. The `SafeOperation` must be created and signed by the Safe owner using `EthersAdapter`. +- The process converts the `SafeOperation` to a standard user operation, then forwards it to the bundler. The `SafeOperation` must be created and signed by the Safe owner. - You can use the user operation hash to browse the status (e.g `https://jiffyscan.xyz/userOpHash/{userOpHash}`) ### `getUserOperationByHash(userOpHash)` diff --git a/redirects.json b/redirects.json index e06a268e..a2f685ac 100644 --- a/redirects.json +++ b/redirects.json @@ -231,22 +231,32 @@ }, { "source": "/safe-core-aa-sdk/protocol-kit/reference/v1", - "destination": "/sdk/protocol-kit/reference/migrating-to-v1", + "destination": "/sdk/protocol-kit/reference/migrate-to-v1", "permanent": true }, { "source": "/sdk-protocol-kit/reference/migrating-to-v1", - "destination": "/sdk/protocol-kit/reference/migrating-to-v1", + "destination": "/sdk/protocol-kit/reference/migrate-to-v1", + "permanent": true + }, + { + "source": "/sdk/protocol-kit/reference/migrating-to-v1", + "destination": "/sdk/protocol-kit/reference/migrate-to-v1", "permanent": true }, { "source": "/safe-core-aa-sdk/protocol-kit/reference/v2", - "destination": "/sdk/protocol-kit/reference/migrating-to-v2", + "destination": "/sdk/protocol-kit/reference/migrate-to-v2", "permanent": true }, { "source": "/sdk-protocol-kit/reference/migrating-to-v2", - "destination": "/sdk/protocol-kit/reference/migrating-to-v2", + "destination": "/sdk/protocol-kit/reference/migrate-to-v2", + "permanent": true + }, + { + "source": "/sdk/protocol-kit/reference/migrating-to-v2", + "destination": "/sdk/protocol-kit/reference/migrate-to-v2", "permanent": true }, { @@ -341,12 +351,17 @@ }, { "source": "/safe-core-aa-sdk/relay-kit/reference/v2", - "destination": "/sdk/relay-kit/reference/migrating-to-v2", + "destination": "/sdk/relay-kit/reference/migrate-to-v2", "permanent": true }, { "source": "/sdk-relay-kit/reference/migrating-to-v2", - "destination": "/sdk/relay-kit/reference/migrating-to-v2", + "destination": "/sdk/relay-kit/reference/migrate-to-v2", + "permanent": true + }, + { + "source": "/sdk/relay-kit/reference/migrating-to-v2", + "destination": "/sdk/relay-kit/reference/migrate-to-v2", "permanent": true }, { @@ -371,67 +386,92 @@ }, { "source": "/safe-core-aa-sdk/api-kit/reference/v1", - "destination": "/sdk/api-kit/reference/migrating-to-v1", + "destination": "/sdk/api-kit/reference/migrate-to-v1", "permanent": true }, { "source": "/sdk-api-kit/reference/migrating-to-v1", - "destination": "/sdk/api-kit/reference/migrating-to-v1", + "destination": "/sdk/api-kit/reference/migrate-to-v1", + "permanent": true + }, + { + "source": "/sdk/api-kit/reference/migrating-to-v1", + "destination": "/sdk/api-kit/reference/migrate-to-v1", "permanent": true }, { "source": "/safe-core-aa-sdk/api-kit/reference/v2", - "destination": "/sdk/api-kit/reference/migrating-to-v2", + "destination": "/sdk/api-kit/reference/migrate-to-v2", + "permanent": true + }, + { + "source": "/sdk/api-kit/reference/migrating-to-v2", + "destination": "/sdk/api-kit/reference/migrate-to-v2", "permanent": true }, { - "source": "/sdk-api-kit/reference/migrating-to-v2", - "destination": "/sdk/api-kit/reference/migrating-to-v2", + "source": "/sdk/api-kit/reference/migrating-to-v2", + "destination": "/sdk/api-kit/reference/migrate-to-v2", "permanent": true }, { "source": "/safe-core-api", - "destination": "/advanced/api-service-architecture", + "destination": "/core-api/api-overview", "permanent": true }, { "source": "/api-service-architecture", - "destination": "/advanced/api-service-architecture", + "destination": "/core-api/api-overview", "permanent": true }, { "source": "/safe-core-api/service-architecture", - "destination": "/advanced/api-service-architecture", + "destination": "/core-api/api-overview", "permanent": true }, { "source": "/api-service-architecture", - "destination": "/advanced/api-service-architecture", + "destination": "/core-api/api-overview", + "permanent": true + }, + { + "source": "/advanced/api-service-architecture", + "destination": "/core-api/api-overview", "permanent": true }, { "source": "/safe-core-api/service-architecture/safe-transaction-service", - "destination": "/advanced/api-service-architecture/safe-transaction-service", + "destination": "/core-api/api-safe-transaction-service", "permanent": true }, { "source": "/api-service-architecture/safe-transaction-service", - "destination": "/advanced/api-service-architecture/safe-transaction-service", + "destination": "/core-api/api-safe-transaction-service", + "permanent": true + }, + { + "source": "/advanced/api-service-architecture/safe-transaction-service", + "destination": "/core-api/api-safe-transaction-service", "permanent": true }, { "source": "/safe-core-api/rpc-requirements", - "destination": "/advanced/api-safe-transaction-service/rpc-requirements", + "destination": "/core-api/api-safe-transaction-service/rpc-requirements", "permanent": true }, { "source": "/api-rpc-requirements", - "destination": "/advanced/api-safe-transaction-service/rpc-requirements", + "destination": "/core-api/api-safe-transaction-service/rpc-requirements", "permanent": true }, { "source": "/advanced/api-rpc-requirements", - "destination": "/advanced/api-safe-transaction-service/rpc-requirements", + "destination": "/core-api/api-safe-transaction-service/rpc-requirements", + "permanent": true + }, + { + "source": "/advanced/api-safe-transaction-service/rpc-requirements", + "destination": "/core-api/api-safe-transaction-service/rpc-requirements", "permanent": true }, { @@ -449,6 +489,16 @@ "destination": "/core-api/transaction-service-supported-networks", "permanent": true }, + { + "source": "/advanced/api-new-networks", + "destination": "/core-api/api-support-new-chains", + "permanent": true + }, + { + "source": "/core-api/api-new-networks", + "destination": "/core-api/api-support-new-chains", + "permanent": true + }, { "source": "/safe-core-aa-sdk/safe-apps", "destination": "https://github.com/safe-global/safe-apps-sdk",