-
Notifications
You must be signed in to change notification settings - Fork 75
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* WIP add draft pages * solve vale errors * move AI section to home * add new structure * correct typo * add cards to overview * move cards * add agent as swapper preview * add spending limit guide * add ai wording * update sections * correct vale errors * add uniswap example * typo * add cow swap example * change spelling of AI agent * refine uniswap example * correct indentation * add comment * finalize human approval * refine multi agent setup * add multi agent setup * remove starter kit * add correct links * correct vale typos * resolve comments * correct * Update pages/home/ai-agent-quickstarts/basic-agent-setup.mdx Co-authored-by: louis-md <[email protected]> * Update pages/home/ai-agent-quickstarts/agent-with-spending-limit.mdx Co-authored-by: louis-md <[email protected]> * Update pages/home/ai-agent-quickstarts/agent-with-spending-limit.mdx Co-authored-by: louis-md <[email protected]> * vale --------- Co-authored-by: louis-md <[email protected]>
- Loading branch information
Showing
16 changed files
with
913 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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" | ||
} |
191 changes: 191 additions & 0 deletions
191
pages/home/ai-agent-actions/ai-agent-swaps-on-uniswap.mdx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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: | ||
|
||
<Steps> | ||
|
||
### 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. | ||
|
||
</Steps> | ||
|
||
## 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. |
Oops, something went wrong.