diff --git a/.github/styles/config/vocabularies/default/accept.txt b/.github/styles/config/vocabularies/default/accept.txt index bc4cef348..a9bc51eef 100644 --- a/.github/styles/config/vocabularies/default/accept.txt +++ b/.github/styles/config/vocabularies/default/accept.txt @@ -28,6 +28,7 @@ [Ee]ndhint [Ee]rigon [Ee]thereum +[Ee]thers [Gg]asless [Gg]elato [Gg]oerli @@ -52,6 +53,7 @@ [Pp]ostgres [Pp]luggable [Qq]uicknode +[Qq]uickstarts [Rr]eact [Rr]eauthenticate [Rr]elayer @@ -105,6 +107,7 @@ Cronos Crossbell Cyber DAO +DAOs Darwinia Degen Devnet @@ -236,12 +239,14 @@ Transaction Service Transciever U2U UI Kit +Uniswap Ultron USD Velas Venidium Viction Vitalik +Virtuals Vite Vue WEMIX3.0 @@ -283,6 +288,8 @@ saltNonce stablecoin superset textWrap +timelock +timelocks trace_block trace_filter trace_transaction diff --git a/assets/ai-agent-approve-transaction-1.png b/assets/ai-agent-approve-transaction-1.png new file mode 100644 index 000000000..27c673a1d Binary files /dev/null and b/assets/ai-agent-approve-transaction-1.png differ diff --git a/assets/ai-agent-approve-transaction-2.png b/assets/ai-agent-approve-transaction-2.png new file mode 100644 index 000000000..f78e1bffe Binary files /dev/null and b/assets/ai-agent-approve-transaction-2.png differ diff --git a/pages/home/_meta.json b/pages/home/_meta.json index 4c29d4511..34839dab5 100644 --- a/pages/home/_meta.json +++ b/pages/home/_meta.json @@ -9,6 +9,13 @@ "title": "Tutorials", "href": "/resource-hub?source=Safe+Team&tag=Tutorial" }, + "-- AI": { + "type": "separator", + "title": "AI" + }, + "ai-overview": "Overview", + "ai-agent-quickstarts": "Quickstart Guides", + "ai-agent-actions": "Action Guides", "-- Help": { "type": "separator", "title": "Help" diff --git a/pages/home/ai-advanced-setups.mdx b/pages/home/ai-advanced-setups.mdx new file mode 100644 index 000000000..7676547ce --- /dev/null +++ b/pages/home/ai-advanced-setups.mdx @@ -0,0 +1,11 @@ +# Advanced Safe Smart Account Setups for AI agents + +Here you find advanced setups for Safe Smart Accounts for AI agents. + +* Agent proposes transactions, human executes them +* Multi-agent setup +* Agent manages a certain amount of funds +* Agent is scoped to selected actions + + + diff --git a/pages/home/ai-agent-actions/_meta.json b/pages/home/ai-agent-actions/_meta.json new file mode 100644 index 000000000..49ba97438 --- /dev/null +++ b/pages/home/ai-agent-actions/_meta.json @@ -0,0 +1,5 @@ +{ + "introduction": "Introduction", + "ai-agent-swaps-with-cow-swap": "AI agent swaps on CoW Swap", + "ai-agent-swaps-on-uniswap": "AI agent swaps on Uniswap" +} diff --git a/pages/home/ai-agent-actions/ai-agent-swaps-on-uniswap.mdx b/pages/home/ai-agent-actions/ai-agent-swaps-on-uniswap.mdx new file mode 100644 index 000000000..192592f8d --- /dev/null +++ b/pages/home/ai-agent-actions/ai-agent-swaps-on-uniswap.mdx @@ -0,0 +1,191 @@ +import { Steps } from 'nextra/components' + +# AI agent swaps on Uniswap + +You can find a working code example to run locally in our [example repository](https://github.com/5afe/safe-uniswap-example). + + +## Requirements +- A deployed Safe Smart Account +- The AI agent is a signer on the Safe +- This example assumes, that the threshold of the Safe Smart Account is one, so the AI agent can sign autonomously. +If you require more signatures, you have to collect those signatures programmatically of with the [Safe Wallet](https://app.safe.global/). +- This guide assumes the Safe owns WETH. +The example repository shows how to swap ETH to WETH. + +## Swap on Uniswap + +Here is a quick guide to get you up and running: + + + +### Setup the Safe Smart Account + +Your Safe Smart Account should be deployed. +Now, initialize an instance with the Safe [Protocol Kit](./../../sdk/protocol-kit.mdx): + +```typescript +import Safe from "@safe-global/protocol-kit"; + +const preExistingSafe = await Safe.init({ + provider: RPC_URL, + signer: AGENT_PRIVATE_KEY, + safeAddress: SAFE_ADDRESS, +}); +``` + +### Fetch Uniswap pool data + +First, you have to fetch the pool data from Uniswap. +This data provides information about the liquidity at the current and at other prices. +Uniswap has a unique [Pricing Math](https://docs.uniswap.org/contracts/v3/reference/core/libraries/SqrtPriceMath). + +```typescript +import { + Address, + createPublicClient, + createWalletClient, + defineChain, + encodeFunctionData, + http, + PublicClient, +} from "viem"; + +// Fetch slot0 data (current price, tick, etc.) +const slot0 = (await publicClient.readContract({ + address: poolAddress, + abi: POOL_ABI, + functionName: "slot0", +})) as any; + +// Fetch liquidity +const liquidity = (await publicClient.readContract({ + address: poolAddress, + abi: POOL_ABI, + functionName: "liquidity", +})) as any; + +const sqrtPriceX96 = BigInt(slot0[0]); +const tick = slot0[1]; +``` + +### Execute Swap + +Now, you can setup your Safe Smart Account and send a swap transaction to Uniswap: + +```typescript +import { + FeeAmount, + Pool, + Route, + SwapRouter, + CurrencyAmount, + TradeType, + Percent +} from "@uniswap/v3-sdk"; +import { Token, SwapOptions } from "@uniswap/sdk-core"; +import JSBI from "jsbi"; +import { OperationType, MetaTransactionData } from "@safe-global/types-kit"; + +// Set up viem clients and accounts +const account = privateKeyToAccount(AGENT_PRIVATE_KEY as `0x${string}`); + +const publicClient = createPublicClient({ + transport: http(RPC_URL!) +}); +const walletClient = createWalletClient({ + transport: http(RPC_URL!) +}); + +const chainId = (await publicClient.getChainId()); + +// Example Values for WETH/USDC Uniswap Pool on Sepolia: +const WETH_ADDRESS = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"; +const USDC_ADDRESS = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"; +const USDC_ETH_POOL_ADDRESS = "0x88e6A0c2dDD26FEEb64F039a2c41296FcB3f5640"; +const SWAP_ROUTER_ADDRESS = "0xE592427A0AEce92De3Edee1F18E0157C05861564"; // Uniswap V3 Router +const INPUT_AMOUNT = "100000000000"; // Amount of ETH to swap to USDC +const OUTOUT_AMOUNT = "0"; // 0 USDC + +// Define token details +const USDC = new Token(chainId, USDC_ADDRESS, 6, "USDC", "USD Coin"); +const WETH = new Token(chainId, WETH_ADDRESS, 18, "WETH", "Wrapped Ether"); + +const callDataApprove = encodeFunctionData({ + abi: WETH_ABI, + functionName: "approve", + args: [SWAP_ROUTER_ADDRESS, INPUT_AMOUNT], +}); + +const safeApproveTx: MetaTransactionData = { + to: WETH_ADDRESS, + value: "0", + data: callDataApprove, + operation: OperationType.Call, +}; + +const options: SwapOptions = { + slippageTolerance: new Percent(50, 10_000), // 50 bips, or 0.50% + deadline: Math.floor(Date.now() / 1000) + 60 * 20, // 20 minutes from the current Unix time + recipient: SAFE_ADDRESS, +}; + +const poolInfo = await fetchPoolData(publicClient, USDC_ETH_POOL_ADDRESS); + +// Create the pool object +const pool = new Pool( + WETH, + USDC, + FeeAmount.MEDIUM, + JSBI.BigInt(poolInfo.sqrtPriceX96.toString()), + JSBI.BigInt(poolInfo.liquidity.toString()), + poolInfo.tick +); + +const swapRoute = new Route([pool], WETH, USDC); + +const uncheckedTrade = Trade.createUncheckedTrade({ + tradeType: TradeType.EXACT_INPUT, + route: swapRoute, + inputAmount: CurrencyAmount.fromRawAmount(WETH, + INPUT_AMOUNT + ), + outputAmount: CurrencyAmount.fromRawAmount(USDC, OUTOUT_AMOUNT), +}); + +const methodParameters = SwapRouter.swapCallParameters( + [uncheckedTrade], + options +); + +const safeSwapTx: MetaTransactionData = { + to: SWAP_ROUTER_ADDRESS, + value: methodParameters.value, + data: methodParameters.calldata, + operation: OperationType.Call, +}; + +const safeTx = await preExistingSafe.createTransaction({ + transactions: [safeApproveTx, safeSwapTx], + onlyCalls: true, +}); + +// You might need to collect more signatures here, depending on the threshold + +const txResponse = await preExistingSafe.executeTransaction(safeTx); + await publicClient.waitForTransactionReceipt({ + hash: txResponse.hash as `0x${string}`, +}); + +console.log(`Deposit and approve transaction: [${txResponse.hash}]`); +``` + +Now your AI agent executed a swap on Uniswap. + + + +## Next steps + +You can find more information about Swaps on Uniswap in their [docs about swaps](https://docs.uniswap.org/contracts/v4/quickstart/swap). + +If you have a technical question about Safe Smart Accounts, feel free to reach out on [Stack Exchange](https://ethereum.stackexchange.com/questions/tagged/safe-core) with the safe-core tag. \ No newline at end of file diff --git a/pages/home/ai-agent-actions/ai-agent-swaps-with-cow-swap.mdx b/pages/home/ai-agent-actions/ai-agent-swaps-with-cow-swap.mdx new file mode 100644 index 000000000..50dda527c --- /dev/null +++ b/pages/home/ai-agent-actions/ai-agent-swaps-with-cow-swap.mdx @@ -0,0 +1,134 @@ +import { Steps } from 'nextra/components' + +# AI agent swaps on CoW Swap + +CoW swap ensures best prices and fastest execution and minimizes MEV. + +You can find a working code example to run locally in our [AI agent with Safe Smart Account CoW Swap example repository](https://github.com/5afe/safe-cowswap). + +Here is a quick guide to get you up and running: + +## Requirements + +- A deployed Safe Smart Account +- The AI agent is a signer on the Safe +- This example assumes, that the threshold of the Safe Smart Account is one, so the AI agent can sign autonomously. +If you require more signatures, you have to collect those signatures programmatically of with the [Safe Wallet](https://app.safe.global/). + +## Let your AI agent send an intent + + +### Setup the Safe Smart Account + +Your Safe Smart Account should be deployed. +Now, initialize an instance with the [Protocol Kit](./../../sdk/protocol-kit.mdx): + +```typescript +import Safe from "@safe-global/protocol-kit"; + +const preExistingSafe = await Safe.init({ + provider: RPC_URL, + signer: AGENT_PRIVATE_KEY, + safeAddress: SAFE_ADDRESS, +}); +``` + +### Send swap intent + +Now, you can use the CoW Swap SDK to assemble a transaction that you can sign and execute with your Safe Smart Account. +The swap will then be executed. + +Please be aware that the CoW Swap's SDK uses Ethers, while Safe's SDK use viem. +You will see some warnings in the logs, but the code works nonetheless. + +In this example, we buy COW and pay with WETH. + +```typescript +import { + SwapAdvancedSettings, + TradeParameters, + TradingSdk, + SupportedChainId, + OrderKind, + SigningScheme, +} from "@cowprotocol/cow-sdk"; +import { VoidSigner } from "@ethersproject/abstract-signer"; +import { JsonRpcProvider } from "@ethersproject/providers"; + +const traderParams = { + chainId: SupportedChainId.SEPOLIA, + signer: new VoidSigner( + smartContractWalletAddress: SAFE_ADDRESS, + new JsonRpcProvider("https://sepolia.gateway.tenderly.co") + ), + appCode: "awesome-app", +}; + +const cowSdk = new TradingSdk(traderParams, { logs: false }); + +const parameters: TradeParameters = { + kind: OrderKind.SELL, + sellToken: WETH_ADDRESS, + sellTokenDecimals: 18, + buyToken: COW_ADDRESS, + buyTokenDecimals: 18, + amount: INPUT_AMOUNT, +}; + +const advancedParameters: SwapAdvancedSettings = { + quoteRequest: { + // Specify the signing scheme + signingScheme: SigningScheme.PRESIGN, + }, +}; + +const orderId = await cowSdk.postSwapOrder(parameters, advancedParameters); + +console.log(`Order ID: [${orderId}]`); + +const preSignTransaction = await cowSdk.getPreSignTransaction({ + orderId, + account: smartContractWalletAddress, +}); + +const customChain = defineChain({ + ...sepolia, + name: "custom chain", + transport: http(RPC_URL), +}); + +const publicClient = createPublicClient({ + chain: customChain, + transport: http(RPC_URL), +}); + +const safePreSignTx: MetaTransactionData = { + to: preSignTransaction.to, + value: preSignTransaction.value, + data: preSignTransaction.data, + operation: OperationType.Call, +}; + +const safeTx = await preExistingSafe.createTransaction({ + transactions: [safePreSignTx], + onlyCalls: true, +}); + +// You might need to collect more signatures here + +const txResponse = await preExistingSafe.executeTransaction(safeTx); +console.log(`Sent tx hash: [${txResponse.hash}]`); +console.log("Waiting for the tx to be mined"); +await publicClient.waitForTransactionReceipt({ + hash: txResponse.hash as `0x${string}`, +}); +``` + + + +## Next steps + +Now, where your AI agent can execute trades autonomously, you are free to use this power as you like. +You can find more specific information in the [CoW Swap Trading SDK docs](https://github.com/cowprotocol/cow-sdk/tree/main/src/trading#readme). + +If you have a technical question about Safe Smart Accounts, feel free to reach out on [Stack Exchange](https://ethereum.stackexchange.com/questions/tagged/safe-core) with the safe-core tag. \ No newline at end of file diff --git a/pages/home/ai-agent-actions/introduction.mdx b/pages/home/ai-agent-actions/introduction.mdx new file mode 100644 index 000000000..cfc560bb3 --- /dev/null +++ b/pages/home/ai-agent-actions/introduction.mdx @@ -0,0 +1,6 @@ +# Introduction + +Here you find example actions your AI agent can do. + +1. [AI agent swaps on CoW Swap](./ai-agent-swaps-with-cow-swap.mdx): The AI agent sends a swap intent to CoW Swap, which ensures the best swap rates and reduces MEV losses. +2. [AI agent swaps on Uniswap](./ai-agent-swaps-on-uniswap.mdx): An example of how your AI agent can trade tokens on Uniswap. diff --git a/pages/home/ai-agent-quickstarts/_meta.json b/pages/home/ai-agent-quickstarts/_meta.json new file mode 100644 index 000000000..98e2925bb --- /dev/null +++ b/pages/home/ai-agent-quickstarts/_meta.json @@ -0,0 +1,7 @@ +{ + "introduction": "Introduction", + "basic-agent-setup": "Setup your Agent with a Safe account", + "human-approval": "Human approval for agent action", + "multi-agent-setup": "Multiple Agent setup", + "agent-with-spending-limit": "Agent with spending limit" +} diff --git a/pages/home/ai-agent-quickstarts/agent-with-spending-limit.mdx b/pages/home/ai-agent-quickstarts/agent-with-spending-limit.mdx new file mode 100644 index 000000000..d4934743b --- /dev/null +++ b/pages/home/ai-agent-quickstarts/agent-with-spending-limit.mdx @@ -0,0 +1,203 @@ +import { Steps } from 'nextra/components' + +# AI agent with a spending limit for a treasury + +This setup is used by DAOs or other organizations that want to utilize AI agents to manage their funds. + +This setup uses Safe's [allowance module](https://github.com/safe-global/safe-modules/blob/main/modules/allowances/contracts/AllowanceModule.sol). +After activating it for a Safe Smart Account, you can set an allowance per token for a spender (the delegator). +It can be a one-time allowance, or an allowance that resets after a certain time interval (for example, 100 USDC every day). + +You can find an easy to run example for the allowance module in our [example repository](https://github.com/5afe/allowance-module-scripts). + +You can setup an allowance (spending limit) on a Safe Smart Account with the [Safe Wallet](https://app.safe.global) interface following [this guide](https://help.safe.global/en/articles/40842-set-up-and-use-spending-limits). +Then, your agent can spend the allowance, as described in the last step. + +Here are the important code snippets to get you up and running: + +## Pre-requisites + +- A deployed Safe Smart Account +- The Smart Account should hold an amount of the ERC20 token for which the allowance will be given + +## Set and use a spending limit for the AI agent + + + +### Enable the Allowance module on your Safe + +When you set a spending limit from Safe Wallet, the allowance module will be enabled automatically. +You will use the Safe [Protocol Kit](./../../sdk/protocol-kit.mdx). +Here is a code example to enable it programmatically: + +```typescript +import Safe from '@safe-global/protocol-kit' +import { getAllowanceModuleDeployment } from '@safe-global/safe-modules-deployments' + +const preExistingSafe = await Safe.init({ + provider: RPC_URL, + signer: OWNER_1_PRIVATE_KEY, + safeAddress: safeAddress +}) + +// Add Module +const allowanceModule = getAllowanceModuleDeployment({ network: '11155111' })! +const safeTransaction = await preExistingSafe.createEnableModuleTx( + allowanceModule.networkAddresses['11155111'] +) +const txResponse = await preExistingSafe.executeTransaction(safeTransaction) +console.log(txResponse) +``` + +### Set spending limit for AI agent + +Now you can set a spending limit to your AI agent: + +```typescript +import { getAllowanceModuleDeployment } from '@safe-global/safe-modules-deployments' +import Safe from '@safe-global/protocol-kit' +import { getAllowanceModuleDeployment } from '@safe-global/safe-modules-deployments' +import { OperationType, MetaTransactionData } from '@safe-global/types-kit' + +const ERC20_TOKEN_ADDRESS = '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238' +const preExistingSafe = await Safe.init({ + provider: RPC_URL, + signer: OWNER_1_PRIVATE_KEY, + safeAddress: safeAddress +}) + +const allowanceModule = getAllowanceModuleDeployment({ network: '11155111' })! + +const allowanceModuleAddress = allowanceModule.networkAddresses['11155111'] + +const callData1 = encodeFunctionData({ + abi: allowanceModule.abi, + functionName: 'addDelegate', + args: [AGENT_ADDRESS] +}) +// agent can spend 1 USDC per day: +const callData2 = encodeFunctionData({ + abi: allowanceModule.abi, + functionName: 'setAllowance', + args: [ + AGENT_ADDRESS, // delegate + ERC20_TOKEN_ADDRESS, // token + 1_000_000, // allowance amount (1 USDC) + 1_440, // reset time in minutes (1440 mins = 1 day) + 0 // reset base (fine to set zero) + ] +}) + +const safeTransactionData1: MetaTransactionData = { + to: allowanceModuleAddress, + value: '0', + data: callData1, + operation: OperationType.Call +} + +const safeTransactionData2: MetaTransactionData = { + to: allowanceModuleAddress, + value: '0', + data: callData2, + operation: OperationType.Call +} + +const safeTransaction = await preExistingSafe.createTransaction({ + transactions: [safeTransactionData1, safeTransactionData2], + onlyCalls: true +}) + +const txResponse = await preExistingSafe.executeTransaction(safeTransaction) +console.log(txResponse) +``` + +### Let the AI agent use the spending limit + +Now your agent has a spending limit, either set programmatically or from Safe Wallet. + +Here is how the agent can spend it: + +```typescript +import { + createPublicClient, + http, + encodeFunctionData, + zeroAddress, + createWalletClient, +} from 'viem' +import { privateKeyToAccount } from 'viem/accounts' +const ERC20_TOKEN_ADDRESS = '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238' + +const allowanceModule = getAllowanceModuleDeployment({ network: '11155111' })! + +const allowanceModuleAddress = allowanceModule.networkAddresses[ + '11155111' +] as `0x${string}` + +const publicClient = createPublicClient({ transport: http(RPC_URL!) }) + +// Read allowance module to get current nonce +const allowance = await publicClient.readContract({ + address: allowanceModuleAddress, + abi: allowanceModule.abi, + functionName: 'getTokenAllowance', + args: [safeAddress, AGENT_ADDRESS, ERC20_TOKEN_ADDRESS] +}) + +const amount = 1 // You might want to adapt the amount + +// generate hash +const hash = await publicClient.readContract({ + address: allowanceModuleAddress, + abi: allowanceModule.abi, + functionName: 'generateTransferHash', + args: [ + safeAddress, + ERC20_TOKEN_ADDRESS, + AGENT_ADDRESS, + amount, + zeroAddress, + 0, + allowance[4] // nonce + ] +}) + +const agentAccount = privateKeyToAccount( + AGENT_PRIVATE_KEY as `0x${string}` +) +const signature = await agentAccount.sign({ + hash: hash as unknown as `0x${string}` +}) + +const { request } = await publicClient.simulateContract({ + address: allowanceModuleAddress, + abi: allowanceModule.abi, + functionName: 'executeAllowanceTransfer', + args: [ + safeAddress, + ERC20_TOKEN_ADDRESS, + AGENT_ADDRESS, + amount, + zeroAddress, + 0, + AGENT_ADDRESS, + signature + ], + account: agentAccount +}) + +const walletClient = createWalletClient({ transport: http(RPC_URL!) }) + +const tx = await walletClient.writeContract(request) +console.log(tx) +``` + +In this example, your agent will get a daily spending limit of 10 USDC. + + + +## Next steps + +You can find more info in the example repository or in the documentation about the allowance module. + +If you have a technical question, feel free to reach out on [Stack Exchange](https://ethereum.stackexchange.com/questions/tagged/safe-core) with the safe-core tag. \ No newline at end of file diff --git a/pages/home/ai-agent-quickstarts/basic-agent-setup.mdx b/pages/home/ai-agent-quickstarts/basic-agent-setup.mdx new file mode 100644 index 000000000..cf179fabe --- /dev/null +++ b/pages/home/ai-agent-quickstarts/basic-agent-setup.mdx @@ -0,0 +1,38 @@ +# Basic setup to equip your AI agent with a Smart Account + +Get started with Safe AI integration in just a few steps. + +This guide will help you set up a Safe Smart Account with the AI agent as the only signer. +This 1-out-of-1 signer setup is discouraged by Safe, as it is not the most secure. +However, many projects choose this setup for simplicity. + +## Installation + +First, add the Safe [Protocol Kit](./../../sdk/protocol-kit.mdx) to your project: + +```bash +import Safe from '@safe-global/protocol-kit' +``` + +## Creating a Safe Smart Account for your AI agent + +When your AI agent is ready to interact with the blockchain, you can create a Safe Smart Account for it. + +```typescript +import Safe from '@safe-global/protocol-kit' + +const SIGNER_ADDRESS = // ... +const SIGNER_PRIVATE_KEY = // ... +const RPC_URL = 'https://rpc.ankr.com/eth_sepolia' + +const safeClient = await Safe.init({ + provider: RPC_URL, + signer: SIGNER_PRIVATE_KEY, + safeOptions: { + owners: [SIGNER_ADDRESS], + threshold: 1 + } +}) +``` + +This creates a Safe Smart Account, but the actual smart contract will be deployed when you send the first transaction. diff --git a/pages/home/ai-agent-quickstarts/human-approval.mdx b/pages/home/ai-agent-quickstarts/human-approval.mdx new file mode 100644 index 000000000..ed05f4621 --- /dev/null +++ b/pages/home/ai-agent-quickstarts/human-approval.mdx @@ -0,0 +1,114 @@ +import { Steps } from 'nextra/components' + +# Human approval for AI agent actions + +This page describes a setup, where an autonomous agent proposes transactions, and one or more human signers approve and execute the transaction. + +This setup benefits from increased security, as the Smart Account can not be compromised by convincing the agent to execute a malicious transaction. + +On the other hand, it can take minutes or hours to collect the necessary approvals, which reduces the agility of this setup. + +## Setup the Smart Account + +For this setup, we recommend a 2-out-of-3, 3-out-of-5, or 5-out-of-7 threshold. +The important considerations are: + +* The AI agent should be one signer +* The threshold should be two more, so at least one human approval is required +* The amount of signers should be higher than the threshold to make sure the Safe Smart Account is functional when one key is lost + + + +Here is an example setup: + +### Deploy Safe + +You can add the AI agent as a signer in the [Safe Wallet](https://app.safe.global/). + +You can also setup the Safe Smart Account programmatically like this using the Safe [Protocol Kit](./../../sdk/protocol-kit.mdx): + +```typescript +import Safe from '@safe-global/protocol-kit' + +const AGENT_ADDRESS = // ... +const AGENT_PRIVATE_KEY = // ... +const HUMAN_SIGNER_1_ADDRESS = // ... +const HUMAN_SIGNER_2_ADDRESS = // ... +const RPC_URL = 'https://rpc.ankr.com/eth_sepolia' + +const newSafe = await Safe.init({ + provider: RPC_URL, + signer: AGENT_PRIVATE_KEY, + safeOptions: { + owners: [AGENT_ADDRESS, HUMAN_SIGNER_1_ADDRESS, HUMAN_SIGNER_2_ADDRESS], + threshold: 2 + } +}) +``` + +Here, the AI agent creates the Safe Smart Account and adds two human signers for a 2-out-of-3 setup. +The Smart Account will be deployed when the first transaction is executed. + +### Assemble and propose a transaction + +The AI agent can now propose transactions. +We recommend sending the transactions to the [Safe Transaction Service](./../../../core-api/transaction-service-overview.mdx). +By this, you make sure that the transactions show up in the Safe Wallet interface and can easily be checked, approved and executed by the human signers. + +You can use the [API Kit](./../../sdk/api-kit.mdx) to propose transactions to the Safe Transaction Service. + +A simple example transaction to the zero address can be proposed like this: + +```typescript +import SafeApiKit from '@safe-global/api-kit' + +const apiKit = new SafeApiKit({ + chainId: 11155111n +}) + +const tx = await newSafe.createTransaction({ + transactions: [ + { + to: '0x0000000000000000000000000000000000000000', + data: '0x', + value: '0' + } + ] +}) + +// Every transaction has a Safe (Smart Account) Transaction Hash different than the final transaction hash +const safeTxHash = await newSafe.getTransactionHash(tx) +// The AI agent signs this Safe (Smart Account) Transaction Hash +const signature = await newSafe.signHash(safeTxHash) + +// Now the transaction with the signature is sent to the Transaction Service with the Api Kit: +await apiKit.proposeTransaction({ + safeAddress: safeAddress, + safeTransactionData: tx.data, + safeTxHash, + senderSignature: signature.data, + senderAddress: AGENT_ADDRESS +}) +``` + +## Approve and execute the transactions + +The transactions will now show up in the transaction interface of the [Safe Wallet](https://app.safe.global). +The human signers now have to connect their Metamask, and approve and/or execute the transactions with a click. +They can also use the [Mobile App](https://help.safe.global/en/articles/40844-sign-transactions) to sign the transactions. + +In the Safe Wallet, the human signers will see the transaction in the queued transaction view: + +![ai-agent-approve-transaction-1](../../../assets/ai-agent-approve-transaction-1.png) + +And can either add a signature or execute the transaction when enough signatures were collected: + +![ai-agent-approve-transaction-2](../../../assets/ai-agent-approve-transaction-2.png) + + + +## Next steps +Now your AI agent is equipped with a Safe Smart Account and you are in full control of the transactions. +We are exited to see what you will build. + +If you have a technical question, feel free to reach out on [Stack Exchange](https://ethereum.stackexchange.com/questions/tagged/safe-core) with the safe-core tag. \ No newline at end of file diff --git a/pages/home/ai-agent-quickstarts/introduction.mdx b/pages/home/ai-agent-quickstarts/introduction.mdx new file mode 100644 index 000000000..642810b6a --- /dev/null +++ b/pages/home/ai-agent-quickstarts/introduction.mdx @@ -0,0 +1,10 @@ +# Quickstarts to set up your AI agent with Safe Smart Account + +In these pages you will find quickstart guides to set your AI agent up and running with Safe Smart Accounts. + +We describe these different setups: + +1. [Basic Agent Setup](./basic-agent-setup.mdx): The simplest and fastest setup for your agent. +2. [Human Approval for agent actions](./human-approval.mdx): The AI agent proposes transactions, human signers approve and execute the transaction. Highest security, but not the fastest. +3. [Multi Agent Setup](./multi-agent-setup.mdx): Multiple Agents are signers of a Smart Account. They have to approve and execute each others transactions. +4. [Agent with a spending limit](./agent-with-spending-limit.mdx): An AI agent gets a spending limit on your treasury or DAO funds. This advanced setup allows fast transactions with a good amount of security. \ No newline at end of file diff --git a/pages/home/ai-agent-quickstarts/multi-agent-setup.mdx b/pages/home/ai-agent-quickstarts/multi-agent-setup.mdx new file mode 100644 index 000000000..1e0badc3b --- /dev/null +++ b/pages/home/ai-agent-quickstarts/multi-agent-setup.mdx @@ -0,0 +1,117 @@ +import { Steps } from 'nextra/components' + +# Multi-Agent Setup + +In this guide, you'll learn how to set up and manage a Safe Smart Account with multiple agents. +This setup ensures that every transaction proposed by one agent is approved by at least one other agent. +To maintain full functionality, we recommend including human signers in addition to the AI agents. + +Below, we demonstrate a 2-out-of-4 setup as an example. + +# Two Agents Propose, Check, and Execute Transactions + + + +### Setup Safe Smart Account with agent one + +You will use the Safe [Protocol Kit](./../../sdk/protocol-kit.mdx). + +```typescript +import Safe from '@safe-global/protocol-kit' + +const AGENT_1_ADDRESS = // ... +const AGENT_1_PRIVATE_KEY = // ... +const AGENT_2_ADDRESS = // ... +const HUMAN_SIGNER_1_ADDRESS = // ... +const HUMAN_SIGNER_2_ADDRESS = // ... +const RPC_URL = 'https://rpc.ankr.com/eth_sepolia' + +const newSafe = await Safe.init({ + provider: RPC_URL, + signer: AGENT_1_PRIVATE_KEY, + safeOptions: { + owners: [AGENT_1_ADDRESS, AGENT_2_ADDRESS, HUMAN_SIGNER_1_ADDRESS, HUMAN_SIGNER_2_ADDRESS], + threshold: 2 + } +}) +``` +The Smart Account is now created with a fixed address. If the account has not been deployed yet, it will automatically deploy when the first transaction is executed. + +### Propose a Transaction with Agent One + +Agent One can now propose transactions. We recommend sending these transactions to the [Safe Transaction Service](./../../../core-api/transaction-service-overview.mdx). Using this service provides several benefits: +- It allows Agent Two to easily receive, sign, and execute the transaction. +- Transactions appear in the Safe Wallet interface, where human signers can review, approve, and execute them. + +You can use the [API Kit](./../../sdk/api-kit.mdx) to propose transactions to the Safe Transaction Service. + +Here's an example of how Agent One can propose a simple transaction to the zero address: + + +```typescript +import SafeApiKit from '@safe-global/api-kit' + +const apiKit = new SafeApiKit({ + chainId: 11155111n +}) + +const tx = await newSafe.createTransaction({ + transactions: [ + { + to: '0x0000000000000000000000000000000000000000', + data: '0x', + value: '0' + } + ] +}) + +// Every transaction has a Safe (Smart Account) Transaction Hash different than the final transaction hash +const safeTxHash = await newSafe.getTransactionHash(tx) +// The AI agent signs this Safe (Smart Account) Transaction Hash +const signature = await newSafe.signHash(safeTxHash) + +// Now the transaction with the signature is sent to the Transaction Service with the Api Kit: +await apiKit.proposeTransaction({ + safeAddress: safeAddress, + safeTransactionData: tx.data, + safeTxHash, + senderSignature: signature.data, + senderAddress: AGENT_ADDRESS +}) +``` + +### Receive and sign transaction with agent two + +In the next step, the second AI agent needs to receive the transaction and, after performing any necessary checks, sign and execute it. + +The second AI agent will run on its own machine, so you would have to initialize the Safe instance with the Smart Account's address. + + +```typescript +const SAFE_ADDRESS = '0x...' // The address of the Smart Account from step one + +// Initialize the Safe object with the same address, but a different signer +const existingSafe = await Safe.init({ + provider: RPC_URL, + signer: AGENT_2_PRIVATE_KEY, + safeAddress: SAFE_ADDRESS +}) + +// Get pending transactions that need a signature +const pendingTransactions = await apiKit.getPendingTransactions(SAFE_ADDRESS) +// We assume there is only one pending transaction +const transaction = pendingTransactions.results[0] + +// Here, your AI agent could check this transaction. + +// As only one more signater is required, AI agent two can execute the transaction: +existingSafe.executeTransaction(transaction) +``` + + + +## Next steps +Your AI agents can make autonomous decisions, and the human signers can do so, too. +We are exited to see what you will build. + +If you have a technical question, feel free to reach out on [Stack Exchange](https://ethereum.stackexchange.com/questions/tagged/safe-core) with the safe-core tag. \ No newline at end of file diff --git a/pages/home/ai-overview.mdx b/pages/home/ai-overview.mdx new file mode 100644 index 000000000..8231eda61 --- /dev/null +++ b/pages/home/ai-overview.mdx @@ -0,0 +1,63 @@ +import { Callout } from 'nextra/components' +import { Grid } from '@mui/material' +import Lock from '../../assets/svg/lock.svg' +import SafeCore from '../../assets/svg/code.svg' +import CustomCard from '../../components/CustomCard' + +# AI agents Powered by Safe Smart Accounts + +The intersection of AI and blockchain technology is evolving rapidly. +This section provides a fast-track guide to getting started with AI agents that leverage Safe Smart Accounts for blockchain interactions. + +## Quickstart Guides + +Eager to start building? Get started quickly and efficiently here: + + + + } + newTab={false} + /> + + + } + newTab={false} + /> + + + +## Why Use Safe Smart Accounts for AI agents? + +Safe Smart Accounts offer a secure and modular solution for enabling AI agents to interact with the blockchain. +While other options include giving an AI agent a private key, using Multi-Party Computation (MPC), relying on custodial services with an API, or manually sending transactions from a user's wallet, Safe Smart Accounts offer distinct advantages. + +## Key Benefits of Safe Smart Accounts for AI agents: + +1. **Enhanced Security**: Safe Smart Accounts offer robust security features, making them one of the most secure methods for blockchain interactions. +Signers retain control of private keys, and signers can be replaced if necessary. Additional security measures, such as spending limits, timelocks, and whitelists, can be easily added to safeguard transactions. +*This is especially crucial since many AI agents can be influenced by specific prompts.* + +2. **True Self-Custody**: With Safe Smart Accounts, there's no reliance on third-party intermediaries. +This reduces costs and eliminates single points of failure, aligning with blockchain's core principle of decentralization. + +3. **Modular Design**: Safe Smart Accounts provide unmatched modularity. Native and third-party modules extend functionality, allowing you to customize accounts based on your project's needs. + +4. **Flexibility**: Multiple signers can propose transactions within a Safe Smart Account. +This allows your AI agent to propose transactions while maintaining your control over the account, with the option to withdraw funds or intervene at any point. + +5. **Multi-Signer Setup**: Some use cases involve multiple AI agents acting as signers on a single Smart Account. +These agents must reach consensus before a transaction is signed, adding an extra layer of security and decentralization.