Skip to content

Commit

Permalink
Add AI landing pages (#674)
Browse files Browse the repository at this point in the history
* 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
valle-xyz and louis-md authored Jan 24, 2025
1 parent 11931af commit e0a04dc
Show file tree
Hide file tree
Showing 16 changed files with 913 additions and 0 deletions.
7 changes: 7 additions & 0 deletions .github/styles/config/vocabularies/default/accept.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
[Ee]ndhint
[Ee]rigon
[Ee]thereum
[Ee]thers
[Gg]asless
[Gg]elato
[Gg]oerli
Expand All @@ -52,6 +53,7 @@
[Pp]ostgres
[Pp]luggable
[Qq]uicknode
[Qq]uickstarts
[Rr]eact
[Rr]eauthenticate
[Rr]elayer
Expand Down Expand Up @@ -105,6 +107,7 @@ Cronos
Crossbell
Cyber
DAO
DAOs
Darwinia
Degen
Devnet
Expand Down Expand Up @@ -236,12 +239,14 @@ Transaction Service
Transciever
U2U
UI Kit
Uniswap
Ultron
USD
Velas
Venidium
Viction
Vitalik
Virtuals
Vite
Vue
WEMIX3.0
Expand Down Expand Up @@ -283,6 +288,8 @@ saltNonce
stablecoin
superset
textWrap
timelock
timelocks
trace_block
trace_filter
trace_transaction
Expand Down
Binary file added assets/ai-agent-approve-transaction-1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/ai-agent-approve-transaction-2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 7 additions & 0 deletions pages/home/_meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
11 changes: 11 additions & 0 deletions pages/home/ai-advanced-setups.mdx
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



5 changes: 5 additions & 0 deletions pages/home/ai-agent-actions/_meta.json
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 pages/home/ai-agent-actions/ai-agent-swaps-on-uniswap.mdx
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.
Loading

0 comments on commit e0a04dc

Please sign in to comment.