-
Notifications
You must be signed in to change notification settings - Fork 4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from serrrfirat/rebase
Rebase
- Loading branch information
Showing
11 changed files
with
666 additions
and
5 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
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 |
---|---|---|
@@ -1,6 +1,7 @@ | ||
node_modules | ||
/out | ||
|
||
|
||
.env | ||
.env.production | ||
concatenated-output.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
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,32 @@ | ||
{ | ||
"name": "@ai16z/plugin-near", | ||
"version": "0.0.1", | ||
"main": "dist/index.js", | ||
"type": "module", | ||
"types": "dist/index.d.ts", | ||
"dependencies": { | ||
"@ai16z/eliza": "workspace:*", | ||
"@ai16z/plugin-trustdb": "workspace:*", | ||
"@ref-finance/ref-sdk": "^1.4.6", | ||
"tsup": "8.3.5", | ||
"near-api-js": "5.0.1", | ||
"bignumber.js": "9.1.2", | ||
"node-cache": "5.1.2" | ||
}, | ||
"devDependencies": { | ||
"eslint": "^9.15.0", | ||
"eslint-config-prettier": "9.1.0", | ||
"eslint-plugin-prettier": "5.2.1", | ||
"eslint-plugin-vitest": "0.5.4" | ||
}, | ||
"scripts": { | ||
"build": "tsup --format esm,cjs --dts", | ||
"test": "vitest run", | ||
"test:watch": "vitest", | ||
"lint": "eslint . --fix" | ||
}, | ||
"peerDependencies": { | ||
"whatwg-url": "7.1.0", | ||
"form-data": "4.0.1" | ||
} | ||
} |
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,241 @@ | ||
import { | ||
ActionExample, | ||
HandlerCallback, | ||
IAgentRuntime, | ||
Memory, | ||
ModelClass, | ||
State, | ||
type Action, | ||
composeContext, | ||
generateObject, | ||
} from "@ai16z/eliza"; | ||
import { connect, keyStores, utils } from "near-api-js"; | ||
import BigNumber from "bignumber.js"; | ||
import { init_env, ftGetTokenMetadata, estimateSwap, instantSwap, fetchAllPools, FT_MINIMUM_STORAGE_BALANCE_LARGE } from '@ref-finance/ref-sdk'; | ||
import { walletProvider } from "../providers/wallet"; | ||
import { KeyPairString } from "near-api-js/lib/utils"; | ||
|
||
// Initialize Ref SDK with testnet environment | ||
init_env('testnet'); | ||
|
||
async function swapToken( | ||
runtime: IAgentRuntime, | ||
inputTokenId: string, | ||
outputTokenId: string, | ||
amount: string, | ||
slippageTolerance: number = 0.1 | ||
): Promise<any> { | ||
try { | ||
// Get token metadata | ||
const tokenIn = await ftGetTokenMetadata(inputTokenId); | ||
const tokenOut = await ftGetTokenMetadata(outputTokenId); | ||
|
||
// Get all pools for estimation | ||
const { ratedPools, unRatedPools, simplePools} = await fetchAllPools(200); | ||
|
||
console.log("Pools:", simplePools); | ||
const swapTodos = await estimateSwap({ | ||
tokenIn, | ||
tokenOut, | ||
amountIn: amount, | ||
simplePools, | ||
options: { | ||
enableSmartRouting: true, | ||
} | ||
}); | ||
|
||
if (!swapTodos || swapTodos.length === 0) { | ||
throw new Error('No valid swap route found'); | ||
} | ||
|
||
// Get account ID from runtime settings | ||
const accountId = runtime.getSetting("NEAR_ADDRESS"); | ||
if (!accountId) { | ||
throw new Error("NEAR_ADDRESS not configured"); | ||
} | ||
|
||
// Execute swap | ||
const transactions = await instantSwap({ | ||
tokenIn, | ||
tokenOut, | ||
amountIn: amount, | ||
swapTodos, | ||
slippageTolerance, | ||
AccountId: accountId | ||
}); | ||
|
||
return transactions; | ||
} catch (error) { | ||
console.error("Error in swapToken:", error); | ||
throw error; | ||
} | ||
} | ||
|
||
const swapTemplate = `Respond with a JSON markdown block containing only the extracted values. Use null for any values that cannot be determined. | ||
Example response: | ||
\`\`\`json | ||
{ | ||
"inputTokenId": "wrap.testnet", | ||
"outputTokenId": "ref.fakes.testnet", | ||
"amount": "1.5" | ||
} | ||
\`\`\` | ||
{{recentMessages}} | ||
Given the recent messages and wallet information below: | ||
{{walletInfo}} | ||
Extract the following information about the requested token swap: | ||
- Input token ID (the token being sold) | ||
- Output token ID (the token being bought) | ||
- Amount to swap | ||
Respond with a JSON markdown block containing only the extracted values. Use null for any values that cannot be determined. The result should be a valid JSON object with the following schema: | ||
\`\`\`json | ||
{ | ||
"inputTokenId": string | null, | ||
"outputTokenId": string | null, | ||
"amount": string | null | ||
} | ||
\`\`\``; | ||
|
||
export const executeSwap: Action = { | ||
name: "EXECUTE_SWAP_NEAR", | ||
similes: ["SWAP_TOKENS_NEAR", "TOKEN_SWAP_NEAR", "TRADE_TOKENS_NEAR", "EXCHANGE_TOKENS_NEAR"], | ||
validate: async (runtime: IAgentRuntime, message: Memory) => { | ||
console.log("Message:", message); | ||
return true; | ||
}, | ||
description: "Perform a token swap using Ref Finance.", | ||
handler: async ( | ||
runtime: IAgentRuntime, | ||
message: Memory, | ||
state: State, | ||
_options: { [key: string]: unknown }, | ||
callback?: HandlerCallback | ||
): Promise<boolean> => { | ||
// Compose state | ||
if (!state) { | ||
state = (await runtime.composeState(message)) as State; | ||
} else { | ||
state = await runtime.updateRecentMessageState(state); | ||
} | ||
|
||
const walletInfo = await walletProvider.get(runtime, message, state); | ||
state.walletInfo = walletInfo; | ||
|
||
const swapContext = composeContext({ | ||
state, | ||
template: swapTemplate, | ||
}); | ||
|
||
const response = await generateObject({ | ||
runtime, | ||
context: swapContext, | ||
modelClass: ModelClass.LARGE, | ||
}); | ||
|
||
console.log("Response:", response); | ||
|
||
if (!response.inputTokenId || !response.outputTokenId || !response.amount) { | ||
console.log("Missing required parameters, skipping swap"); | ||
const responseMsg = { | ||
text: "I need the input token ID, output token ID, and amount to perform the swap", | ||
}; | ||
callback?.(responseMsg); | ||
return true; | ||
} | ||
|
||
try { | ||
// Get account credentials | ||
const accountId = runtime.getSetting("NEAR_ADDRESS"); | ||
const secretKey = runtime.getSetting("NEAR_WALLET_SECRET_KEY"); | ||
|
||
if (!accountId || !secretKey) { | ||
throw new Error("NEAR wallet credentials not configured"); | ||
} | ||
|
||
// Create keystore and connect to NEAR | ||
const keyStore = new keyStores.InMemoryKeyStore(); | ||
const keyPair = utils.KeyPair.fromString(secretKey as KeyPairString); | ||
await keyStore.setKey("testnet", accountId, keyPair); | ||
|
||
const nearConnection = await connect({ | ||
networkId: "testnet", | ||
keyStore, | ||
nodeUrl: "https://rpc.testnet.near.org", | ||
}); | ||
|
||
// Execute swap | ||
const swapResult = await swapToken( | ||
runtime, | ||
response.inputTokenId, | ||
response.outputTokenId, | ||
response.amount, | ||
0.1 // 1% slippage tolerance | ||
); | ||
|
||
// Sign and send transactions | ||
const account = await nearConnection.account(accountId); | ||
const results = []; | ||
|
||
for (const tx of swapResult) { | ||
for (const functionCall of tx.functionCalls) { | ||
const result = await account.functionCall({ | ||
contractId: tx.receiverId, | ||
methodName: functionCall.methodName, | ||
args: functionCall.args, | ||
gas: functionCall.gas, | ||
attachedDeposit: BigInt(1), | ||
}); | ||
results.push(result); | ||
} | ||
} | ||
|
||
console.log("Swap completed successfully!"); | ||
const txHashes = results.map(r => r.transaction.hash).join(", "); | ||
|
||
const responseMsg = { | ||
text: `Swap completed successfully! Transaction hashes: ${txHashes}`, | ||
}; | ||
|
||
callback?.(responseMsg); | ||
return true; | ||
} catch (error) { | ||
console.error("Error during token swap:", error); | ||
const responseMsg = { | ||
text: `Error during swap: ${error instanceof Error ? error.message : String(error)}`, | ||
}; | ||
callback?.(responseMsg); | ||
return false; | ||
} | ||
}, | ||
examples: [ | ||
[ | ||
{ | ||
user: "{{user1}}", | ||
content: { | ||
inputTokenId: "wrap.testnet", | ||
outputTokenId: "ref.fakes.testnet", | ||
amount: "1.0", | ||
}, | ||
}, | ||
{ | ||
user: "{{user2}}", | ||
content: { | ||
text: "Swapping 1.0 NEAR for REF...", | ||
action: "TOKEN_SWAP", | ||
}, | ||
}, | ||
{ | ||
user: "{{user2}}", | ||
content: { | ||
text: "Swap completed successfully! Transaction hash: ...", | ||
}, | ||
}, | ||
], | ||
] as ActionExample[][], | ||
} as Action; |
Oops, something went wrong.