Skip to content

Commit 752528a

Browse files
committed
feat(klesia): add experimental mina_estimateFees
1 parent 9649399 commit 752528a

File tree

12 files changed

+180
-11
lines changed

12 files changed

+180
-11
lines changed

apps/klesia/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
"@hono/zod-openapi": "^0.16.0",
2424
"@mina-js/shared": "workspace:*",
2525
"@urql/core": "^5.0.6",
26+
"bigint-quantile": "^0.0.2",
2627
"dayjs": "^1.11.13",
2728
"dotenv": "^16.4.5",
2829
"hono": "^4.5.10",

apps/klesia/src/index.spec.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,4 +55,16 @@ describe("Mina Devnet RPC", () => {
5555
expect(BigInt(result.nonce)).toBeGreaterThanOrEqual(0);
5656
expect(BigInt(result.balance)).toBeGreaterThanOrEqual(0);
5757
});
58+
59+
it("returns result for mina_estimateFee", async () => {
60+
const response = await request({
61+
json: {
62+
method: "mina_estimateFees",
63+
},
64+
});
65+
const { result } = (await response.json()) as {
66+
result: { medium: string };
67+
};
68+
expect(result.medium.length).toBeGreaterThan(0);
69+
});
5870
});

apps/klesia/src/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,10 @@ export const klesiaRpcRoute = api.openapi(rpcRoute, async ({ req, json }) => {
123123
});
124124
return json(buildResponse({ result }), 200);
125125
})
126+
.with({ method: RpcMethod.enum.mina_estimateFees }, async () => {
127+
const result = await mina.estimateFees();
128+
return json(buildResponse({ result }), 200);
129+
})
126130
.exhaustive();
127131
});
128132

apps/klesia/src/methods/mina.spec.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,8 @@ it("should get account info", async () => {
2828
expect(BigInt(result.nonce)).toBeGreaterThanOrEqual(0);
2929
expect(BigInt(result.balance)).toBeGreaterThanOrEqual(0);
3030
});
31+
32+
it("should estimate fee", async () => {
33+
const result = await mina.estimateFees();
34+
expect(result.medium.length).toBeGreaterThan(0);
35+
});

apps/klesia/src/methods/mina.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
11
import { SignedTransactionSchema } from "@mina-js/shared";
22
import { gql } from "@urql/core";
3+
import { calculateQuantile } from "bigint-quantile";
34
import { match } from "ts-pattern";
45
import { getNodeClient } from "../utils/node";
56

7+
export const PRIORITY = {
8+
low: 0.25,
9+
medium: 0.5,
10+
high: 0.75,
11+
} as Record<string, number>;
12+
613
const getTransactionCount = async ({ publicKey }: { publicKey: string }) => {
714
const client = getNodeClient();
815
try {
@@ -163,11 +170,43 @@ const getAccount = async ({ publicKey }: { publicKey: string }) => {
163170
}
164171
};
165172

173+
const estimateFees = async () => {
174+
const client = getNodeClient();
175+
try {
176+
const { data } = await client.query(
177+
gql`
178+
query {
179+
snarkPool {
180+
fee
181+
}
182+
}
183+
`,
184+
{},
185+
);
186+
const fees = data.snarkPool
187+
.map((entry: { fee: string }) => entry.fee)
188+
.filter((entry: string) => entry !== "0")
189+
.map((entry: string) => BigInt(entry));
190+
return {
191+
low: String(calculateQuantile(fees, PRIORITY.low)),
192+
medium: String(calculateQuantile(fees, PRIORITY.medium)),
193+
high: String(calculateQuantile(fees, PRIORITY.high)),
194+
};
195+
} catch {
196+
return {
197+
low: "10000000",
198+
medium: "100000000",
199+
high: "200000000",
200+
};
201+
}
202+
};
203+
166204
export const mina = {
167205
getTransactionCount,
168206
getBalance,
169207
blockHash,
170208
chainId,
171209
sendTransaction,
172210
getAccount,
211+
estimateFees,
173212
};

apps/klesia/src/schema.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export const RpcMethod = z.enum([
1313
"mina_chainId",
1414
"mina_sendTransaction",
1515
"mina_getAccount",
16+
"mina_estimateFees",
1617
]);
1718
export type RpcMethodType = z.infer<typeof RpcMethod>;
1819

@@ -41,6 +42,10 @@ export const RpcMethodSchema = z.discriminatedUnion("method", [
4142
method: z.literal(RpcMethod.enum.mina_getAccount),
4243
params: PublicKeyParamsSchema,
4344
}),
45+
z.object({
46+
method: z.literal(RpcMethod.enum.mina_estimateFees),
47+
params: EmptyParamsSchema,
48+
}),
4449
]);
4550

4651
export const JsonRpcResponse = z.object({
@@ -87,6 +92,14 @@ export const RpcResponseSchema = z.union([
8792
balance: z.string(),
8893
}),
8994
}),
95+
JsonRpcResponse.extend({
96+
method: z.literal(RpcMethod.enum.mina_estimateFees),
97+
result: z.object({
98+
low: z.string(),
99+
medium: z.string(),
100+
high: z.string(),
101+
}),
102+
}),
90103
]),
91104
ErrorSchema,
92105
]);

bun.lockb

400 Bytes
Binary file not shown.

packages/accounts/src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,5 @@ export { hdKeyToAccount } from "./accounts/hd-key-to-account";
99
export { mnemonicToAccount } from "./accounts/mnemonic-to-account";
1010
export { privateKeyToAccount } from "./accounts/private-key-to-account";
1111
export { toAccount } from "./accounts/to-account";
12+
13+
export * from "./types";

packages/connect/src/__snapshots__/client.spec.ts.snap

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,26 @@
22

33
exports[`matches snapshot of local source 1`] = `
44
{
5+
"createNullifier": [Function: AsyncFunction],
56
"getAccounts": [Function: AsyncFunction],
67
"getBalance": [Function: AsyncFunction],
8+
"getChainId": [Function: AsyncFunction],
9+
"getTransactionCount": [Function: AsyncFunction],
10+
"signFields": [Function: AsyncFunction],
11+
"signMessage": [Function: AsyncFunction],
12+
"signTransaction": [Function: AsyncFunction],
713
}
814
`;
915

1016
exports[`matches snapshot of json-rpc source 1`] = `
1117
{
18+
"createNullifier": [Function: AsyncFunction],
1219
"getAccounts": [Function: AsyncFunction],
1320
"getBalance": [Function: AsyncFunction],
21+
"getChainId": [Function: AsyncFunction],
22+
"getTransactionCount": [Function: AsyncFunction],
23+
"signFields": [Function: AsyncFunction],
24+
"signMessage": [Function: AsyncFunction],
25+
"signTransaction": [Function: AsyncFunction],
1426
}
1527
`;

packages/connect/src/client.spec.ts

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,47 @@ describe("json-rpc source", () => {
3232
expect(accounts[0]).toEqual(PUBLIC_KEY);
3333
});
3434

35-
// it('returns balance', async () => {
36-
// const account = toAccount(PUBLIC_KEY)
37-
// const client = createWalletClient({ account, network: 'devnet', providerSource: 'klesia' })
38-
// const balance = await client.getBalance()
39-
// console.log(balance)
40-
// expect(balance).toBeGreaterThanOrEqual(0)
41-
// })
35+
it("returns balance", async () => {
36+
const account = toAccount(PUBLIC_KEY);
37+
const client = createWalletClient({
38+
account,
39+
network: "devnet",
40+
providerSource: "klesia",
41+
});
42+
const balance = await client.getBalance();
43+
expect(balance).toBeGreaterThanOrEqual(0);
44+
});
45+
46+
it("returns transaction count", async () => {
47+
const account = toAccount(PUBLIC_KEY);
48+
const client = createWalletClient({
49+
account,
50+
network: "devnet",
51+
providerSource: "klesia",
52+
});
53+
const transactionCount = await client.getTransactionCount();
54+
expect(transactionCount).toBeGreaterThanOrEqual(0);
55+
});
56+
57+
it("returns chain id", async () => {
58+
const account = toAccount(PUBLIC_KEY);
59+
const client = createWalletClient({
60+
account,
61+
network: "devnet",
62+
providerSource: "klesia",
63+
});
64+
const chainId = await client.getChainId();
65+
expect(chainId.length).toBeGreaterThan(0);
66+
});
67+
});
68+
69+
describe("local source", () => {
70+
it("signs a message", async () => {
71+
const account = privateKeyToAccount({
72+
privateKey: Test.accounts[0].privateKey,
73+
});
74+
const client = createWalletClient({ account, network: "devnet" });
75+
const signature = await client.signMessage({ message: "hello" });
76+
expect(signature.data).toEqual("hello");
77+
});
4278
});

0 commit comments

Comments
 (0)