UNPKG

@coinbase/agentkit

Version:

Coinbase AgentKit core primitives

408 lines (407 loc) 18.2 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); const flaunchActionProvider_1 = require("./flaunchActionProvider"); const schemas_1 = require("./schemas"); const viem_1 = require("viem"); const swapUtils = __importStar(require("./swap_utils")); // Mock the actual contract calls with Jest jest.mock("viem", () => { const originalModule = jest.requireActual("viem"); return { ...originalModule, createPublicClient: jest.fn().mockReturnValue({ simulateContract: jest.fn().mockResolvedValue({ result: [BigInt(1000000000000000000)], }), }), decodeEventLog: jest.fn().mockImplementation(() => { return { eventName: "PoolCreated", args: { _memecoin: "0x1234567890123456789012345678901234567890", }, }; }), parseEther: jest.fn().mockReturnValue(BigInt(100000000000000000)), parseUnits: jest.fn().mockReturnValue(BigInt(100000000000000000)), encodeAbiParameters: jest.fn().mockReturnValue("0xencoded"), encodeFunctionData: jest.fn().mockReturnValue("0xfunctiondata"), zeroAddress: "0x0000000000000000000000000000000000000000", zeroHash: "0x0000000000000000000000000000000000000000000000000000000000000000", }; }); // Mock the metadata_utils module jest.mock("./metadata_utils", () => ({ generateTokenUri: jest.fn().mockResolvedValue("ipfs://test-uri"), })); // Mock the client_utils module jest.mock("./client_utils", () => ({ ethRequiredToFlaunch: jest.fn().mockResolvedValue(BigInt(100000000000000000)), getMemecoinAddressFromReceipt: jest .fn() .mockReturnValue("0x1234567890123456789012345678901234567890"), })); // Mock the swap_utils module jest.mock("./swap_utils", () => ({ getAmountWithSlippage: jest.fn().mockImplementation(amount => amount), memecoinToEthWithPermit2: jest.fn().mockReturnValue({ commands: "0x02", inputs: ["0x5678"], }), getSwapAmountsFromReceipt: jest.fn().mockImplementation(() => ({ coinsBought: BigInt(1000000000000000000), ethSold: BigInt(100000000000000000), coinsSold: BigInt(1000000000000000000), ethBought: BigInt(100000000000000000), })), buyFlaunchCoin: jest .fn() .mockImplementation(async (walletProvider, coinAddress, _swapType, _amount, _slippagePercent) => { // Simulate the actual behavior by calling wallet provider methods walletProvider.getNetwork(); const coinSymbol = await walletProvider.readContract({ address: coinAddress, abi: [], functionName: "symbol", }); const hash = await walletProvider.sendTransaction({ to: coinAddress, data: "0x", }); await walletProvider.waitForTransactionReceipt(hash); return `Bought ${(0, viem_1.formatEther)(BigInt(1000000000000000000))} $${coinSymbol} for ${(0, viem_1.formatEther)(BigInt(100000000000000000))} ETH`; }), })); // Mock the constants used in the test jest.mock("./constants", () => { const actualConstants = jest.requireActual("./constants"); const baseSepolia = 84532; // Base Sepolia chain ID const baseMainnet = 8453; // Base Mainnet chain ID return { ...actualConstants, // Only override the address mappings FlaunchPositionManagerAddress: { "0x14a34": "0x9A7059cA00dA92843906Cb4bCa1D005cE848AFdC", [baseSepolia]: "0x9A7059cA00dA92843906Cb4bCa1D005cE848AFdC", [baseMainnet]: "0x51Bba15255406Cfe7099a42183302640ba7dAFDC", }, FastFlaunchZapAddress: { "0x14a34": "0x251e97446a7019E5DA4860d4CF47291321C693D0", [baseSepolia]: "0x251e97446a7019E5DA4860d4CF47291321C693D0", [baseMainnet]: "0x0000000000000000000000000000000000000000", }, FLETHHooksAddress: { ...actualConstants.FLETHHooksAddress, "0x14a34": "0x4bd2ca15286c96e4e731337de8b375da6841e888", }, FLETHAddress: { ...actualConstants.FLETHAddress, "0x14a34": "0x79FC52701cD4BE6f9Ba9aDC94c207DE37e3314eb", }, QuoterAddress: { ...actualConstants.QuoterAddress, "0x14a34": "0x4a6513c898fe1b2d0e78d3b0e0a4a151589b1cba", }, UniversalRouterAddress: { ...actualConstants.UniversalRouterAddress, "0x14a34": "0x492E6456D9528771018DeB9E87ef7750EF184104", }, Permit2Address: { ...actualConstants.Permit2Address, "0x14a34": "0x000000000022D473030F116dDEE9F6B43aC78BA3", }, }; }); describe("FlaunchActionProvider", () => { const provider = new flaunchActionProvider_1.FlaunchActionProvider(); let mockWalletProvider; beforeEach(() => { mockWalletProvider = { getAddress: jest.fn().mockReturnValue("0x1234567890123456789012345678901234567890"), getBalance: jest.fn(), getName: jest.fn(), getNetwork: jest.fn().mockReturnValue({ protocolFamily: "evm", networkId: "base-sepolia", chainId: "0x14a34", }), nativeTransfer: jest.fn(), sendTransaction: jest.fn().mockResolvedValue("0xtxhash"), waitForTransactionReceipt: jest.fn().mockResolvedValue({ logs: [ { address: "0x9A7059cA00dA92843906Cb4bCa1D005cE848AFdC", // FlaunchPositionManagerAddress for base-sepolia data: "0x0000000000000000000000001234567890123456789012345678901234567890", topics: ["0x"], }, ], }), readContract: jest.fn().mockImplementation(({ functionName }) => { if (functionName === "symbol") return "TEST"; if (functionName === "allowance") return [BigInt(0), BigInt(0)]; return undefined; }), signTypedData: jest.fn().mockResolvedValue("0xsignature"), getPublicClient: jest.fn().mockReturnValue({ simulateContract: jest.fn().mockResolvedValue({ result: [BigInt(1000000000000000000)], }), }), }; }); describe("network support", () => { it("should support the supported networks", () => { expect(provider.supportsNetwork({ protocolFamily: "evm", networkId: "base-mainnet", })).toBe(true); expect(provider.supportsNetwork({ protocolFamily: "evm", networkId: "base-sepolia", })).toBe(true); }); it("should not support other protocol families", () => { expect(provider.supportsNetwork({ protocolFamily: "other-protocol-family", networkId: "base-mainnet", })).toBe(false); }); it("should not support unsupported networks", () => { expect(provider.supportsNetwork({ protocolFamily: "evm", networkId: "ethereum", })).toBe(false); }); it("should handle invalid network objects", () => { expect(provider.supportsNetwork({})).toBe(false); }); }); describe("action validation", () => { it("should validate flaunch schema", () => { const validInput = { name: "Test Token", symbol: "TEST", image: "https://example.com/image.png", description: "A test token", websiteUrl: "https://example.com", premineAmount: 5, }; const parseResult = schemas_1.FlaunchSchema.safeParse(validInput); expect(parseResult.success).toBe(true); }); it("should reject invalid flaunch input", () => { const invalidInput = { name: "", symbol: "", image: "not-a-url", description: "", premineAmount: 150, // Invalid: exceeds 100% }; const parseResult = schemas_1.FlaunchSchema.safeParse(invalidInput); expect(parseResult.success).toBe(false); }); it("should validate buyCoinWithETHInput schema", () => { const validInput = { coinAddress: "0x1234567890123456789012345678901234567890", amountIn: "0.1", slippagePercent: 3, }; const parseResult = schemas_1.BuyCoinWithETHInputSchema.safeParse(validInput); expect(parseResult.success).toBe(true); }); it("should validate buyCoinWithCoinInput schema", () => { const validInput = { coinAddress: "0x1234567890123456789012345678901234567890", amountOut: "1000", slippagePercent: 3, }; const parseResult = schemas_1.BuyCoinWithCoinInputSchema.safeParse(validInput); expect(parseResult.success).toBe(true); }); it("should validate sellCoin schema", () => { const validInput = { coinAddress: "0x1234567890123456789012345678901234567890", amountIn: "1000", slippagePercent: 3, }; const parseResult = schemas_1.SellCoinSchema.safeParse(validInput); expect(parseResult.success).toBe(true); }); }); describe("flaunch action", () => { it("should execute flaunch action with wallet provider", async () => { const args = { name: "Test Token", symbol: "TEST", image: "https://example.com/image.png", description: "A test token", websiteUrl: "https://example.com", fairLaunchPercent: 60, fairLaunchDuration: 30, initialMarketCapUSD: 10000, creatorFeeAllocationPercent: 80, creatorSplitPercent: 50, splitReceivers: [ { address: "0x1234567890123456789012345678901234567890", percent: 100, }, ], preminePercent: 5, }; const result = await provider.flaunch(mockWalletProvider, args); console.log("Test result:", result); expect(result).toContain("Flaunched"); expect(result).toContain("TEST"); expect(mockWalletProvider.getNetwork).toHaveBeenCalled(); expect(mockWalletProvider.sendTransaction).toHaveBeenCalled(); expect(mockWalletProvider.waitForTransactionReceipt).toHaveBeenCalled(); }); it("should reject premineAmount exceeding fairLaunchPercent", async () => { const args = { name: "Test Token", symbol: "TEST", image: "https://example.com/image.png", description: "A test token", websiteUrl: "https://example.com", fairLaunchPercent: 60, fairLaunchDuration: 30, initialMarketCapUSD: 10000, creatorFeeAllocationPercent: 80, creatorSplitPercent: 50, splitReceivers: [], preminePercent: 70, // Invalid: exceeds fairLaunchPercent of 60% }; const result = await provider.flaunch(mockWalletProvider, args); expect(result).toContain("premineAmount (70%) cannot exceed fairLaunchPercent (60%)"); }); }); describe("buyCoinWithETHInput action", () => { it("should execute buyCoinWithETHInput action with wallet provider", async () => { const args = { coinAddress: "0x1234567890123456789012345678901234567890", amountIn: "0.1", slippagePercent: 3, }; const result = await provider.buyCoinWithETHInput(mockWalletProvider, args); expect(result).toContain("Bought"); expect(result).toContain("TEST"); expect(result).toContain((0, viem_1.formatEther)(BigInt(1000000000000000000))); expect(mockWalletProvider.getNetwork).toHaveBeenCalled(); expect(mockWalletProvider.sendTransaction).toHaveBeenCalled(); expect(mockWalletProvider.readContract).toHaveBeenCalled(); expect(mockWalletProvider.waitForTransactionReceipt).toHaveBeenCalled(); }); it("should handle errors in buyCoinWithETHInput", async () => { // Mock buyFlaunchCoin to return an error string swapUtils.buyFlaunchCoin.mockResolvedValueOnce("Error buying coin: Transaction failed"); const args = { coinAddress: "0x1234567890123456789012345678901234567890", amountIn: "0.1", slippagePercent: 3, }; const result = await provider.buyCoinWithETHInput(mockWalletProvider, args); expect(result).toContain("Error buying coin"); }); }); describe("buyCoinWithCoinInput action", () => { it("should execute buyCoinWithCoinInput action with wallet provider", async () => { const args = { coinAddress: "0x1234567890123456789012345678901234567890", amountOut: "1000", slippagePercent: 3, }; const result = await provider.buyCoinWithCoinInput(mockWalletProvider, args); expect(result).toContain("Bought"); expect(result).toContain("TEST"); expect(result).toContain((0, viem_1.formatEther)(BigInt(1000000000000000000))); expect(mockWalletProvider.getNetwork).toHaveBeenCalled(); expect(mockWalletProvider.sendTransaction).toHaveBeenCalled(); expect(mockWalletProvider.readContract).toHaveBeenCalled(); expect(mockWalletProvider.waitForTransactionReceipt).toHaveBeenCalled(); }); it("should handle errors in buyCoinWithCoinInput", async () => { // Mock buyFlaunchCoin to return an error string swapUtils.buyFlaunchCoin.mockResolvedValueOnce("Error buying coin: Transaction failed"); const args = { coinAddress: "0x1234567890123456789012345678901234567890", amountOut: "1000", slippagePercent: 3, }; const result = await provider.buyCoinWithCoinInput(mockWalletProvider, args); expect(result).toContain("Error buying coin"); }); }); describe("sellCoin action", () => { it("should execute sellCoin action with wallet provider", async () => { const args = { coinAddress: "0x1234567890123456789012345678901234567890", amountIn: "1000", slippagePercent: 3, }; const result = await provider.sellCoin(mockWalletProvider, args); expect(result).toContain("Sold"); expect(result).toContain("TEST"); expect(result).toContain((0, viem_1.formatEther)(BigInt(1000000000000000000))); expect(mockWalletProvider.getNetwork).toHaveBeenCalled(); expect(mockWalletProvider.sendTransaction).toHaveBeenCalled(); expect(mockWalletProvider.readContract).toHaveBeenCalled(); expect(mockWalletProvider.waitForTransactionReceipt).toHaveBeenCalled(); }); it("should handle permit2 approval when allowance is insufficient", async () => { const args = { coinAddress: "0x1234567890123456789012345678901234567890", amountIn: "1000", slippagePercent: 3, }; const result = await provider.sellCoin(mockWalletProvider, args); expect(result).toContain("Sold"); expect(mockWalletProvider.signTypedData).toHaveBeenCalled(); }); it("should handle errors in sellCoin", async () => { mockWalletProvider.sendTransaction.mockRejectedValueOnce(new Error("Transaction failed")); const args = { coinAddress: "0x1234567890123456789012345678901234567890", amountIn: "1000", slippagePercent: 3, }; const result = await provider.sellCoin(mockWalletProvider, args); expect(result).toContain("Error selling coin"); }); }); });