Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions typescript/agentkit/src/action-providers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,4 @@ export * from "./onramp";
export * from "./vaultsfyi";
export * from "./x402";
export * from "./zerodev";
export * from "./uniswap";
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { uniswapActionProvider } from "../uniswapActionProvider";

describe("UniswapActionProvider", () => {
const actionProvider = uniswapActionProvider();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add tests for the logic of each action. As a guide you can have a look at eg https://github.com/coinbase/agentkit/blob/main/typescript/agentkit/src/action-providers/flaunch/flaunchActionProvider.test.ts that also tests some swap actions


describe("supportsNetwork", () => {
it("should return true for base-mainnet", () => {
expect(actionProvider.supportsNetwork({ networkId: "base-mainnet", protocolFamily: "evm" })).toBe(true);

Check failure on line 8 in typescript/agentkit/src/action-providers/uniswap/__tests__/uniswapActionProvider.test.ts

View workflow job for this annotation

GitHub Actions / lint-typescript

Replace `actionProvider.supportsNetwork({·networkId:·"base-mainnet",·protocolFamily:·"evm"·})` with `⏎········actionProvider.supportsNetwork({·networkId:·"base-mainnet",·protocolFamily:·"evm"·}),⏎······`
});

it("should return true for base-sepolia", () => {
expect(actionProvider.supportsNetwork({ networkId: "base-sepolia", protocolFamily: "evm" })).toBe(true);

Check failure on line 12 in typescript/agentkit/src/action-providers/uniswap/__tests__/uniswapActionProvider.test.ts

View workflow job for this annotation

GitHub Actions / lint-typescript

Replace `actionProvider.supportsNetwork({·networkId:·"base-sepolia",·protocolFamily:·"evm"·})` with `⏎········actionProvider.supportsNetwork({·networkId:·"base-sepolia",·protocolFamily:·"evm"·}),⏎······`
});

it("should return false for ethereum-mainnet", () => {
expect(actionProvider.supportsNetwork({ networkId: "ethereum-mainnet", protocolFamily: "evm" })).toBe(false);

Check failure on line 16 in typescript/agentkit/src/action-providers/uniswap/__tests__/uniswapActionProvider.test.ts

View workflow job for this annotation

GitHub Actions / lint-typescript

Replace `actionProvider.supportsNetwork({·networkId:·"ethereum-mainnet",·protocolFamily:·"evm"·})` with `⏎········actionProvider.supportsNetwork({·networkId:·"ethereum-mainnet",·protocolFamily:·"evm"·}),⏎······`
});

it("should return false for solana", () => {
expect(actionProvider.supportsNetwork({ protocolFamily: "solana", networkId: "solana-mainnet" })).toBe(false);

Check failure on line 20 in typescript/agentkit/src/action-providers/uniswap/__tests__/uniswapActionProvider.test.ts

View workflow job for this annotation

GitHub Actions / lint-typescript

Replace `actionProvider.supportsNetwork({·protocolFamily:·"solana",·networkId:·"solana-mainnet"·})` with `⏎········actionProvider.supportsNetwork({·protocolFamily:·"solana",·networkId:·"solana-mainnet"·}),⏎······`
});
});
});

Check failure on line 23 in typescript/agentkit/src/action-providers/uniswap/__tests__/uniswapActionProvider.test.ts

View workflow job for this annotation

GitHub Actions / lint-typescript

Replace `·` with `⏎`
116 changes: 116 additions & 0 deletions typescript/agentkit/src/action-providers/uniswap/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import type { Abi } from "abitype";

/**
* Uniswap V3 contract addresses for Base networks
*/
export const UNISWAP_ADDRESSES: Record<string, Record<string, string>> = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optional: could be extended to a few more chains like ethereum, optimism, arbitrum, polygon (https://github.com/coinbase/agentkit/blob/main/typescript/agentkit/src/network/network.ts)

You can find the contract addresses here:
https://docs.uniswap.org/contracts/v3/reference/deployments/

"base-sepolia": {
SwapRouter02: "0x94cC0AaC535CCDB3C01d6787D6413C739ae12bc4",
Quoter: "0xC5290058841028F1614F3A6F0F5816cAd0df5E27",
WETH: "0x4200000000000000000000000000000000000006",
},
"base-mainnet": {
SwapRouter02: "0x2626664c2603336E57B271c5C0b26F421741e481",
Quoter: "0x3d4e44Eb1374240CE5F1B871ab261CD16335B76a",

Check failure on line 14 in typescript/agentkit/src/action-providers/uniswap/constants.ts

View workflow job for this annotation

GitHub Actions / lint-typescript

Delete `Β·`
WETH: "0x4200000000000000000000000000000000000006",
},
};

/**
* Uniswap V3 Quoter contract ABI (subset for quoting)
*/
export const UNISWAP_QUOTER_ABI: Abi = [
{
inputs: [
{
components: [
{ internalType: "address", name: "tokenIn", type: "address" },
{ internalType: "address", name: "tokenOut", type: "address" },
{ internalType: "uint256", name: "amountIn", type: "uint256" },
{ internalType: "uint24", name: "fee", type: "uint24" },
{ internalType: "uint160", name: "sqrtPriceLimitX96", type: "uint160" },
],
internalType: "struct IQuoterV2.QuoteExactInputSingleParams",
name: "params",
type: "tuple",
},
],
name: "quoteExactInputSingle",
outputs: [
{ internalType: "uint256", name: "amountOut", type: "uint256" },
{ internalType: "uint160", name: "sqrtPriceX96After", type: "uint160" },
{ internalType: "uint32", name: "initializedTicksCrossed", type: "uint32" },
{ internalType: "uint256", name: "gasEstimate", type: "uint256" },
],
stateMutability: "nonpayable",
type: "function",
},
] as const;

/**
* Uniswap V3 SwapRouter02 contract ABI (subset for swapping)
*/
export const UNISWAP_ROUTER_ABI: Abi = [
{
inputs: [
{
components: [
{ internalType: "address", name: "tokenIn", type: "address" },
{ internalType: "address", name: "tokenOut", type: "address" },
{ internalType: "uint24", name: "fee", type: "uint24" },
{ internalType: "address", name: "recipient", type: "address" },
{ internalType: "uint256", name: "amountIn", type: "uint256" },
{ internalType: "uint256", name: "amountOutMinimum", type: "uint256" },
{ internalType: "uint160", name: "sqrtPriceLimitX96", type: "uint160" },
],
internalType: "struct IV3SwapRouter.ExactInputSingleParams",
name: "params",
type: "tuple",
},
],
name: "exactInputSingle",
outputs: [{ internalType: "uint256", name: "amountOut", type: "uint256" }],
stateMutability: "payable",
type: "function",
},
] as const;

/**
* Standard ERC20 token ABI (subset needed for approvals and metadata)
*/
export const ERC20_ABI: Abi = [
{
inputs: [
{ internalType: "address", name: "spender", type: "address" },
{ internalType: "uint256", name: "amount", type: "uint256" },
],
name: "approve",
outputs: [{ internalType: "bool", name: "", type: "bool" }],
stateMutability: "nonpayable",
type: "function",
},
{
inputs: [
{ internalType: "address", name: "owner", type: "address" },
{ internalType: "address", name: "spender", type: "address" },
],
name: "allowance",
outputs: [{ internalType: "uint256", name: "", type: "uint256" }],
stateMutability: "view",
type: "function",
},
{
inputs: [],
name: "decimals",
outputs: [{ internalType: "uint8", name: "", type: "uint8" }],
stateMutability: "view",
type: "function",
},
{
inputs: [],
name: "symbol",
outputs: [{ internalType: "string", name: "", type: "string" }],
stateMutability: "view",
type: "function",
},
] as const;

Check failure on line 116 in typescript/agentkit/src/action-providers/uniswap/constants.ts

View workflow job for this annotation

GitHub Actions / lint-typescript

Replace `·` with `⏎`
3 changes: 3 additions & 0 deletions typescript/agentkit/src/action-providers/uniswap/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from "./schemas";
export * from "./constants";
export * from "./uniswapActionProvider";

Check failure on line 3 in typescript/agentkit/src/action-providers/uniswap/index.ts

View workflow job for this annotation

GitHub Actions / lint-typescript

Replace `·` with `⏎`
39 changes: 39 additions & 0 deletions typescript/agentkit/src/action-providers/uniswap/schemas.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { z } from "zod";

/**
* Input schema for Uniswap token swap action.
*/
export const SwapSchema = z
.object({
tokenIn: z.string().describe("The contract address of the token to swap from"),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggest to use .regex(/^0x[a-fA-F0-9]{40}$/, "Invalid Ethereum address format"), for all contract addresses

tokenOut: z.string().describe("The contract address of the token to swap to"),
amount: z.string().describe("The amount of tokenIn to swap (in token units, e.g. '1.5')"),
slippageTolerance: z
.number()
.min(0)
.max(100)
.default(0.5)
.describe("Maximum acceptable slippage percentage (0-100, default: 0.5%)"),
fee: z
.number()
.default(3000)
.describe("Pool fee tier in hundredths of a bip (default: 3000 = 0.3%)"),
})
.strip()
.describe("Instructions for swapping tokens on Uniswap V3");

/**
* Input schema for getting a quote for a Uniswap swap.
*/
export const QuoteSchema = z
.object({
tokenIn: z.string().describe("The contract address of the token to swap from"),
tokenOut: z.string().describe("The contract address of the token to swap to"),
amount: z.string().describe("The amount of tokenIn to quote (in token units, e.g. '1.5')"),
fee: z
.number()
.default(3000)
.describe("Pool fee tier in hundredths of a bip (default: 3000 = 0.3%)"),
})
.strip()
.describe("Instructions for getting a quote for a Uniswap V3 swap");

Check failure on line 39 in typescript/agentkit/src/action-providers/uniswap/schemas.ts

View workflow job for this annotation

GitHub Actions / lint-typescript

Replace `·` with `⏎`
Loading
Loading