Skip to content

Commit

Permalink
upd: added the ability to get back price information of a rune
Browse files Browse the repository at this point in the history
  • Loading branch information
JoeyKhd committed Jan 5, 2025
1 parent 65142c6 commit 716a68d
Show file tree
Hide file tree
Showing 7 changed files with 176 additions and 13 deletions.
93 changes: 93 additions & 0 deletions packages/plugin-ordinals/src/actions/runes/price-information.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import {
ActionExample,
HandlerCallback,
IAgentRuntime,
Memory,
State,
type Action,
generateObject,
composeContext,
ModelClass,
} from "@elizaos/core";
import API from "../../utils/api";
import { z } from "zod";
import { runePriceInformationTemplate } from "../../templates";
import { dollarFormatter, handleError } from "../../utils";
import BigNumber from "bignumber.js";

export const runeSchema = z.object({
rune: z.string(),
});

export default {
name: "GET_RUNE_PRICE",
similes: ["GET_PRICE_RUNE", "RETRIEVE_RUNE_PRICE"],
validate: async () => {
return true;
},
description: "Retrieves the agents Ordinals wallet's runes portfolio.",
handler: async (
runtime: IAgentRuntime,
message: Memory,
state: State,
_options: { [key: string]: unknown },
callback?: HandlerCallback
): Promise<boolean> => {
try {
const context = composeContext({
state,
template: runePriceInformationTemplate,
});

const content: { object: { rune?: string } } = await generateObject(
{
runtime,
context,
schema: runeSchema,
modelClass: ModelClass.LARGE,
}
);

const rune = content?.object?.rune;

if (!rune) {
throw new Error("Unable to find rune name in messages.");
}

const api = new API();

const priceInfo = await api.getRunePrice(rune);

const currentPrice = priceInfo.pricePerToken;
const totalSupply = priceInfo?.supply?.current;
const marketcap = new BigNumber(currentPrice)
.multipliedBy(new BigNumber(totalSupply))
.toNumber();

callback({
text: `The price of ${rune} is ${dollarFormatter.format(currentPrice)} per token with a market cap of: ${dollarFormatter.format(marketcap)}`,
});

return true;
} catch (error) {
handleError(error, callback);
}
},
examples: [
[
{
user: "{{user1}}",
content: {
text: "What is the price of GIZMO•IMAGINARY•KITTEN ?",
},
},
{
user: "{{user2}}",
content: {
text: "The price of GIZMO•IMAGINARY•KITTEN is:",
action: "GET_RUNE_PRICE",
},
},
],
] as ActionExample[][],
} as Action;
2 changes: 1 addition & 1 deletion packages/plugin-ordinals/src/actions/runes/transfer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ export default {
// Send 500 UNCOMMON•GOODS to bc1pud2j5tpy5s3c5u6y7e2lqn8tp5208q0mmxjtjqncmzp9wyj5gssswnz8nk
// { rune: 'WHICH RUNE', amount: 'WHAT AMOUNT', toAddress: ''}

const api = new API(runtime.getSetting("ORDISCAN_API_KEY"));
const api = new API();
const runeInfo = await api.getRuneInfo(nonSpacedName);
elizaLogger.info(JSON.stringify(runeInfo));

Expand Down
5 changes: 3 additions & 2 deletions packages/plugin-ordinals/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { elizaLogger, Plugin } from "@elizaos/core";
import { walletProvider } from "./providers/wallet.ts";
import { Plugin } from "@elizaos/core";
import { WalletProvider } from "./providers/wallet.ts";
import runePortfolio from "./actions/runes/portfolio.ts";
import runeTransfer from "./actions/runes/transfer.ts";
import runePrice from "./actions/runes/price-information.ts";
import walletAddress from "./actions/wallet/address.ts";
import walletBalance from "./actions/wallet/balance.ts";
import walletUtxos from "./actions/wallet/utxo.ts";
Expand All @@ -19,6 +19,7 @@ export const ordinalsPlugin: Plugin = {
walletUtxos,
txStatus,
runePortfolio,
runePrice,
],
evaluators: [],
providers: [],
Expand Down
21 changes: 21 additions & 0 deletions packages/plugin-ordinals/src/templates.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,24 @@
export const runePriceInformationTemplate = `
## Recent Messages
{{recentMessages}}
Knowledge:
- A Rune looks similar to: UNCOMMON•GOODS
Given the most recent message, extract the rune:
- **rune** (string | null): The Rune
Provide the values in the following JSON format:
\`\`\`json
{
"rune": "the rune or null",
}
\`\`\`
`;

export const runeTransferTemplate = `
## Recent Messages
Expand Down
37 changes: 37 additions & 0 deletions packages/plugin-ordinals/src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,40 @@ export interface IBalance {
priceChangePercentage24h: number;
currentPrice: number;
}

export interface IRuneInfo {
id: string;
name: string;
spaced_name: string;
number: number;
divisibility: number;
symbol: string;
turbo: boolean;
mint_terms: {
amount: string;
cap: string;
height_start: number;
height_end: number;
offset_start: number;
offset_end: number;
};
supply: {
current: string;
minted: string;
total_mints: string;
mint_percentage: string;
mintable: boolean;
burned: string;
total_burns: string;
premine: string;
};
location: {
block_hash: string;
block_height: number;
tx_id: string;
tx_index: number;
vout: number;
output: string;
timestamp: number;
};
}
30 changes: 20 additions & 10 deletions packages/plugin-ordinals/src/utils/api.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { elizaLogger } from "@elizaos/core";
import { IBalance } from "../types";
import { IBalance, IRuneInfo } from "../types";

const ORDISCAN_BASE_URL = "https://api.ordiscan.com/v1";
const HIRO_BASE_URL = "https://api.hiro.so";

const fetcher = async (url: string, apiKey?: string) => {
Expand All @@ -27,20 +26,15 @@ const fetcher = async (url: string, apiKey?: string) => {
};

class API {
ordiscanApiKey: string;

constructor(ordiscanApiKey?: string) {
this.ordiscanApiKey = ordiscanApiKey;
}

async getRunesPortfolio(address: string): Promise<IBalance[]> {
return await fetcher(
`https://api-3.xverse.app/v2/address/${address}/rune-balance?includeUnconfirmed=true`
);
}

async getRuneInfo(name: string) {
return fetcher(`${HIRO_BASE_URL}/runes/v1/etchings/${name}`);
async getRuneInfo(name: string): Promise<IRuneInfo> {
const nonSpacedName = name?.replaceAll("•", "");
return await fetcher(`${HIRO_BASE_URL}/runes/v1/etchings/${nonSpacedName}`);
}

async getRunesUtxos(address: string, runeName: string) {
Expand All @@ -54,6 +48,22 @@ class API {
// `https://api-3.xverse.app/v1/market/address/${address}/rune/${runeName}/utxos`
// );
}

async getRunePrice(
name: string
): Promise<IRuneInfo & { pricePerToken: number }> {
const info = await this.getRuneInfo(name);
const priceInfo = await fetcher(
`https://api-3.xverse.app/v1/runes/fiat-rates?currency=USD&runeIds[]=${info?.id}`
);

const pricePerToken =
priceInfo?.[
`${info?.location?.block_height}:${info?.location?.tx_index}`
].USD;

return { ...info, pricePerToken };
}
}

export default API;
1 change: 1 addition & 0 deletions packages/plugin-ordinals/src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,4 +82,5 @@ export const estimateTransactionSize = (
export const dollarFormatter = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
maximumFractionDigits: 8
});

0 comments on commit 716a68d

Please sign in to comment.