-
Notifications
You must be signed in to change notification settings - Fork 163
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Comoswallet, cosmosbank module and cosmos langchain example (#222)
* Update Chain.ts, with feature CosmosChain * add cosmos wallet * add cosmosbank module plugin * add cosmos langchian example * Update bank.service.ts * Delete typescript/examples/langchain/cosmos/CHANGELOG.md * Delete typescript/packages/plugins/cosmosbank/CHANGELOG.md * Delete typescript/packages/wallets/cosmos/CHANGELOG.md * Fix PR --------- Co-authored-by: Agus <[email protected]>
- Loading branch information
1 parent
e8c0e49
commit a6970f8
Showing
24 changed files
with
1,001 additions
and
10 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
# Langchain with cosmos Example using cohere-ai. | ||
|
||
## Setup | ||
|
||
Copy the `.env.template` and populate with your values. | ||
|
||
``` | ||
cp .env.template .env | ||
``` | ||
|
||
## Usage | ||
|
||
``` | ||
npx ts-node index.ts | ||
``` |
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,3 @@ | ||
COHERE_API_KEY= | ||
WALLET_MNEMONICS= | ||
RPC_PROVIDER_URL= |
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,60 @@ | ||
import { ChatCohere } from "@langchain/cohere"; | ||
import type { ChatPromptTemplate } from "@langchain/core/prompts"; | ||
import { AgentExecutor, createStructuredChatAgent } from "langchain/agents"; | ||
import { pull } from "langchain/hub"; | ||
|
||
import { DirectSecp256k1HdWallet } from "@cosmjs/proto-signing"; | ||
import { SigningStargateClient } from "@cosmjs/stargate"; | ||
|
||
import { getOnChainTools } from "@goat-sdk/adapter-langchain"; | ||
import { cosmosbank } from "@goat-sdk/plugin-cosmosbank"; | ||
import { CosmosWalletOptions, cosmos } from "@goat-sdk/wallet-cosmos"; | ||
|
||
require("dotenv").config(); | ||
|
||
(async (): Promise<void> => { | ||
const mnemonic = process.env.WALLET_MNEMONICS as `0x${string}`; | ||
const wallet = await DirectSecp256k1HdWallet.fromMnemonic( | ||
mnemonic, | ||
{ prefix: "pryzm" }, // e.g atom, pryzm, pokt, dora e.t.c | ||
); | ||
|
||
const [Account] = await wallet.getAccounts(); | ||
const rpcEndpoint = process.env.RPC_PROVIDER_URL as `0x${string}`; | ||
const client = await SigningStargateClient.connectWithSigner(rpcEndpoint, wallet); | ||
|
||
const walletClient: CosmosWalletOptions = { | ||
client: client, | ||
account: Account, | ||
}; | ||
|
||
const llm = new ChatCohere({ | ||
model: "command-r-plus", | ||
}); | ||
|
||
const prompt = await pull<ChatPromptTemplate>("hwchase17/structured-chat-agent"); | ||
|
||
const tools = await getOnChainTools({ | ||
wallet: cosmos(walletClient), | ||
plugins: [await cosmosbank()], | ||
}); | ||
|
||
const agent = await createStructuredChatAgent({ | ||
llm, | ||
tools, | ||
prompt, | ||
}); | ||
|
||
const agentExecutor = new AgentExecutor({ | ||
agent, | ||
tools, | ||
}); | ||
|
||
const response = await agentExecutor.invoke({ | ||
//input: "get the {{PRYZM}} token total supply", | ||
//input: "get the {{PRYZM}} token balance of this address {{_addr}}", | ||
//input: "send 1 {{PRYZM}} token to {{_addr}}", | ||
}); | ||
|
||
console.log(response); | ||
})(); |
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,23 @@ | ||
{ | ||
"name": "goat-examples-langchain-cosmos", | ||
"version": "0.0.1", | ||
"description": "", | ||
"private": true, | ||
"scripts": { | ||
"test": "vitest run --passWithNoTests" | ||
}, | ||
"author": "", | ||
"license": "MIT", | ||
"dependencies": { | ||
"@goat-sdk/adapter-langchain": "workspace:*", | ||
"@goat-sdk/plugin-cosmosbank": "workspace:*", | ||
"@goat-sdk/wallet-cosmos": "workspace:*", | ||
"@goat-sdk/core": "workspace:*", | ||
"@cosmjs/stargate": "^0.32.4", | ||
"@langchain/core": "catalog:", | ||
"@langchain/cohere": "^0.3.2", | ||
"@cosmjs/proto-signing": "^0.32.4", | ||
"dotenv": "^16.4.5", | ||
"langchain": "^0.3.2" | ||
} | ||
} |
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,8 @@ | ||
{ | ||
"extends": "../../../tsconfig.base.json", | ||
"compilerOptions": { | ||
"outDir": "dist" | ||
}, | ||
"include": ["index.ts"], | ||
"exclude": ["node_modules", "dist"] | ||
} |
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,31 @@ | ||
# Goat CosmosBank Plugin 🐐 - TypeScript | ||
|
||
CosmosBank plugin for [Goat 🐐](https://ohmygoat.dev). Allows you to create tools for interacting with the bank module on cosmos chains. | ||
|
||
## Installation | ||
``` | ||
npm install @goat-sdk/plugin-cosmosbank | ||
``` | ||
|
||
## Usage | ||
|
||
```typescript | ||
import { cosmosbank } from "@goat-sdk/plugin-cosmosbank"; | ||
|
||
|
||
const plugin = cosmosbank(); | ||
``` | ||
|
||
## Working example | ||
|
||
See the [LangChain example](https://github.com/goat-sdk/goat/tree/main/typescript/examples/langchain/cosmos) for a working example of how to use the CosmosBank plugin. | ||
|
||
## Goat | ||
|
||
<div align="center"> | ||
Go out and eat some grass. | ||
|
||
[Docs](https://ohmygoat.dev) | [Examples](https://github.com/goat-sdk/goat/tree/main/typescript/examples) | [Discord](https://discord.gg/2F8zTVnnFz)</div> | ||
|
||
## Goat 🐐 | ||
Goat 🐐 (Great Onchain Agent Toolkit) is an open-source library enabling AI agents to interact with blockchain protocols and smart contracts via their own wallets. |
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,47 @@ | ||
{ | ||
"name": "@goat-sdk/plugin-cosmosbank", | ||
"version": "0.0.1", | ||
"files": ["dist/**/*", "README.md", "package.json"], | ||
"scripts": { | ||
"build": "tsup", | ||
"clean": "rm -rf dist", | ||
"test": "vitest run --passWithNoTests" | ||
}, | ||
"sideEffects": false, | ||
"main": "./dist/index.js", | ||
"module": "./dist/index.mjs", | ||
"types": "./dist/index.d.ts", | ||
|
||
"dependencies": { | ||
"@goat-sdk/core": "workspace:*", | ||
"@goat-sdk/wallet-cosmos": "workspace:*", | ||
"@cosmjs/stargate": "^0.32.4", | ||
"cosmjs-types": "^0.9.0", | ||
"chain-registry": "^1.69.74", | ||
"zod": "catalog:" | ||
}, | ||
|
||
"peerDependencies": { | ||
"@goat-sdk/core": "workspace:*", | ||
"@cosmjs/stargate": "^0.32.4", | ||
"cosmjs-types": "^0.9.0" | ||
}, | ||
|
||
"engines": { | ||
"node": ">=20.12.2 <21", | ||
"npm": "please-use-pnpm", | ||
"pnpm": ">=9", | ||
"yarn": "please-use-pnpm" | ||
}, | ||
"homepage": "https://ohmygoat.dev", | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/goat-sdk/goat.git" | ||
}, | ||
"license": "MIT", | ||
"bugs": { | ||
"url": "https://github.com/goat-sdk/goat/issues" | ||
}, | ||
"keywords": ["ai", "agents", "web3"], | ||
"packageManager": "[email protected]" | ||
} |
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,15 @@ | ||
import { Chain, PluginBase } from "@goat-sdk/core"; | ||
import { CosmosClient } from "@goat-sdk/wallet-cosmos"; | ||
import { BankService } from "./bank.service"; | ||
|
||
export class BANKPlugin extends PluginBase<CosmosClient> { | ||
constructor() { | ||
super("cosmosbank", [new BankService()]); | ||
} | ||
|
||
supportsChain = (chain: Chain) => chain.type === "cosmos"; | ||
} | ||
|
||
export async function cosmosbank() { | ||
return new BANKPlugin(); | ||
} |
155 changes: 155 additions & 0 deletions
155
typescript/packages/plugins/cosmosbank/src/bank.service.ts
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,155 @@ | ||
import { Tool } from "@goat-sdk/core"; | ||
import { CosmosClient } from "@goat-sdk/wallet-cosmos"; | ||
import { assets, chains } from "chain-registry"; | ||
import { | ||
QueryBalanceRequest, | ||
QueryBalanceResponse, | ||
QueryDenomMetadataRequest, | ||
QueryDenomMetadataResponse, | ||
QuerySupplyOfRequest, | ||
QuerySupplyOfResponse, | ||
} from "cosmjs-types/cosmos/bank/v1beta1/query"; | ||
import { | ||
denomMetadataParametersSchema, | ||
getBalanceParametersSchema, | ||
sendTokenObjectParametersSchema, | ||
supplyOfParametersSchema, | ||
} from "./parameters"; | ||
|
||
export class BankService { | ||
@Tool({ | ||
description: "Gets the balance of a token denom in base units. Convert to decimal units before returning.", | ||
}) | ||
async tokenBalance(walletClient: CosmosClient, parameters: getBalanceParametersSchema) { | ||
try { | ||
const t = await this.getChainInfo(walletClient); | ||
const _d = t.asset?.assets.find((a) => a.symbol === parameters.symbol); | ||
|
||
if (!_d) throw new Error("the Requested Token is unavailabe on the network"); | ||
|
||
const data = QueryBalanceRequest.encode({ address: parameters.address, denom: _d?.base }).finish(); | ||
const message = { typeUrl: "/cosmos.bank.v1beta1.Query/Balance", value: data }; | ||
|
||
const rawBalance = await walletClient.read({ message }); | ||
const decode = QueryBalanceResponse.decode(rawBalance.value.value); | ||
|
||
if (!decode?.balance) throw new Error("the requested balance is unavailable"); | ||
|
||
const ex = t.asset?.assets.find((a) => a.base === decode.balance?.denom); | ||
const xp = ex?.denom_units.find((d) => d.denom === ex?.display)?.exponent ?? 0; | ||
const bal = await this.convertFromBaseUnit(Number(decode.balance.amount), xp); | ||
return bal.toString(); | ||
} catch (error) { | ||
throw Error(`Failed to fetch balance: ${error}`); | ||
} | ||
} | ||
|
||
@Tool({ | ||
description: "Get the metadata of a token with the specified symbol.", | ||
}) | ||
async demonMetada(walletClient: CosmosClient, parameters: denomMetadataParametersSchema) { | ||
try { | ||
const _d = (await this.getChainInfo(walletClient)).asset?.assets.find( | ||
(a) => a.symbol === parameters.symbol, | ||
); | ||
|
||
if (!_d) throw new Error("the Requested Token is unavailabe on the network"); | ||
|
||
const data = QueryDenomMetadataRequest.encode({ denom: _d?.base }).finish(); | ||
const message = { typeUrl: "/cosmos.bank.v1beta1.Query/DenomMetadata", value: data }; | ||
|
||
const metadata = await walletClient.read({ message }); | ||
const decode = QueryDenomMetadataResponse.decode(metadata.value.value); | ||
|
||
if (!decode.metadata) throw new Error("the requested metadata is unavailable"); | ||
|
||
return `${decode.metadata.display}-${decode.metadata.name}-${decode.metadata.description} | ||
-${decode.metadata.symbol}`; | ||
} catch (error) { | ||
throw Error(`Failed to fetch denom metadata: ${error}`); | ||
} | ||
} | ||
|
||
@Tool({ | ||
description: "Get the total supply of a token with the specified symbol.", | ||
}) | ||
async supplyOf(walletClient: CosmosClient, parameters: supplyOfParametersSchema) { | ||
try { | ||
const t = await this.getChainInfo(walletClient); | ||
const _d = t.asset?.assets.find((a) => a.symbol === parameters.symbol); | ||
|
||
if (!_d) throw new Error("the Requested Token is unavailabe on the network"); | ||
|
||
const data = QuerySupplyOfRequest.encode({ denom: _d?.base }).finish(); | ||
const message = { typeUrl: "/cosmos.bank.v1beta1.Query/SupplyOf", value: data }; | ||
|
||
const supplyof = await walletClient.read({ message }); | ||
const decode = QuerySupplyOfResponse.decode(supplyof.value.value); | ||
|
||
if (!decode.amount) throw new Error("the requested token data is unavailable"); | ||
|
||
const ex = t.asset?.assets.find((a) => a.base === decode.amount?.denom); | ||
const xp = ex?.denom_units.find((d) => d.denom === ex?.display)?.exponent ?? 0; | ||
const total = await this.convertFromBaseUnit(Number(decode.amount.amount), xp); | ||
return `$${total.toString()}_${decode.amount.denom}`; | ||
} catch (error) { | ||
throw Error(`Failed to fetch total supply: ${error}`); | ||
} | ||
} | ||
|
||
@Tool({ | ||
description: "Sends an amount of a Token of a specified symbol to a receivers address.", | ||
}) | ||
async sendToken(walletClient: CosmosClient, parameters: sendTokenObjectParametersSchema) { | ||
try { | ||
const t = await this.getChainInfo(walletClient); | ||
const _d = t.asset?.assets.find((a) => a.symbol === parameters.amount.symbol); | ||
|
||
if (!_d) throw new Error("the Requested Token is unavailabe on the network"); | ||
|
||
const ex = t.asset?.assets.find((a) => a.base === _d?.base); | ||
const xp = ex?.denom_units.find((d) => d.denom === ex?.display)?.exponent ?? 0; | ||
const amount = await this.convertToBaseUnit(Number(parameters.amount.amount), xp); | ||
|
||
const hash = await walletClient.sendTransaction({ | ||
message: { | ||
typeUrl: "/cosmos.bank.v1beta1.MsgSend", | ||
value: { | ||
fromAddress: walletClient.getAddress(), | ||
toAddress: parameters.toAddress, | ||
amount: [{ denom: _d?.base, amount: amount.toString() }], | ||
}, | ||
}, | ||
}); | ||
|
||
if (!hash.value.transactionHash) throw new Error("transaction was incomplete"); | ||
|
||
return hash.value.transactionHash; | ||
} catch (error) { | ||
throw Error(`Failed to send token: ${error}`); | ||
} | ||
} | ||
|
||
private async getChainInfo(walletClient: CosmosClient) { | ||
const id = await walletClient.getChainId(); | ||
const chain = chains.find((ch) => ch.chain_id === id); | ||
|
||
if (!chain) throw new Error("Network data is unavailable"); | ||
|
||
const asset = assets.find((ast) => ast.chain_name === chain?.chain_name); | ||
return { | ||
chain: chain, | ||
asset: asset, | ||
}; | ||
} | ||
|
||
private async convertToBaseUnit(amount: number, decimals: number) { | ||
const baseUnit = amount * 10 ** decimals; | ||
return Number(baseUnit); | ||
} | ||
|
||
private async convertFromBaseUnit(amount: number, decimals: number) { | ||
const decimalUnit = amount / 10 ** decimals; | ||
return Number(decimalUnit); | ||
} | ||
} |
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 @@ | ||
export * from "./bank.plugin"; |
Oops, something went wrong.