Skip to content

Commit 2ff9488

Browse files
committed
Mantra tx crafting sdk (#175)
* mantra sdk example and sign fx * remove ts ignore example mantra * remove ts ignore example mantra * remove restake rewards from example * bump v4.0.5
1 parent acdbddd commit 2ff9488

File tree

3 files changed

+114
-0
lines changed

3 files changed

+114
-0
lines changed

examples/mantra.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { omToUom, Kiln } from '../src/kiln.ts';
2+
import fs from 'node:fs';
3+
import 'dotenv/config';
4+
import type { FireblocksIntegration } from '../src/fireblocks.ts';
5+
6+
const apiSecret = fs.readFileSync(`${__dirname}/fireblocks_secret_prod.key`, 'utf8');
7+
8+
const k = new Kiln({
9+
baseUrl: process.env.KILN_API_URL as string,
10+
apiToken: process.env.KILN_API_KEY as string,
11+
});
12+
13+
const vault: FireblocksIntegration = {
14+
provider: 'fireblocks',
15+
fireblocksApiKey: process.env.FIREBLOCKS_API_KEY as string,
16+
fireblocksSecretKey: apiSecret,
17+
vaultId: 17,
18+
};
19+
20+
try {
21+
console.log('crafting...');
22+
const tx = await k.client.POST('/mantra/transaction/stake', {
23+
body: {
24+
account_id: process.env.KILN_ACCOUNT_ID as string,
25+
pubkey: '028dfa6f41c655e38a0f8f2e3f3aa3e1246907a9bb299933f11996e2a345a21e10',
26+
validator: 'mantravaloper146mj09yzu3mvz7pmy4dvs4z9wr2mst7ram37xw',
27+
amount_uom: omToUom('0.01').toString(),
28+
},
29+
});
30+
31+
console.log(tx);
32+
console.log('signing...');
33+
if (!tx.data?.data) throw new Error('No data in response');
34+
const signResponse = await k.fireblocks.signMantraTx(vault, tx.data.data);
35+
console.log('broadcasting...');
36+
if (!signResponse.signed_tx?.data?.signed_tx_serialized) throw new Error('No signed_tx in response');
37+
const broadcastedTx = await k.client.POST('/mantra/transaction/broadcast', {
38+
body: {
39+
tx_serialized: signResponse.signed_tx.data.signed_tx_serialized,
40+
},
41+
});
42+
console.log(broadcastedTx);
43+
} catch (err) {
44+
console.log(err);
45+
}

src/fireblocks.ts

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,61 @@ export class FireblocksService {
345345
};
346346
}
347347

348+
/**
349+
* Sign a MANTRA transaction on Fireblocks
350+
*/
351+
async signMantraTx(
352+
integration: FireblocksIntegration,
353+
tx: components['schemas']['MANTRAUnsignedTx'] | components['schemas']['MANTRAStakeUnsignedTx'],
354+
note?: string,
355+
): Promise<{
356+
signed_tx: { data: components['schemas']['MANTRASignedTx'] };
357+
fireblocks_tx: TransactionResponse;
358+
}> {
359+
const payload = {
360+
rawMessageData: {
361+
messages: [
362+
{
363+
content: tx.unsigned_tx_hash,
364+
derivationPath: [44, 118, integration.vaultId, 0, 0],
365+
preHash: {
366+
content: tx.unsigned_tx_serialized,
367+
hashAlgorithm: 'SHA256',
368+
},
369+
},
370+
],
371+
algorithm: SigningAlgorithm.MPC_ECDSA_SECP256K1,
372+
},
373+
};
374+
375+
const fbSigner = this.getSigner(integration);
376+
const fbNote = note ? note : 'MANTRA tx from @kilnfi/sdk';
377+
const fbTx = await fbSigner.sign(payload, undefined, fbNote);
378+
const signature = fbTx.signedMessages?.[0]?.signature.fullSig;
379+
380+
if (!signature) {
381+
throw new Error('Fireblocks signature is missing');
382+
}
383+
384+
const preparedTx = await this.client.POST('/mantra/transaction/prepare', {
385+
body: {
386+
pubkey: tx.pubkey,
387+
tx_body: tx.tx_body,
388+
tx_auth_info: tx.tx_auth_info,
389+
signature: signature,
390+
},
391+
});
392+
393+
if (preparedTx.error) {
394+
throw new Error('Failed to prepare transaction');
395+
}
396+
397+
return {
398+
signed_tx: preparedTx.data,
399+
fireblocks_tx: fbTx,
400+
};
401+
}
402+
348403
/**
349404
* Sign a INJ transaction on Fireblocks
350405
*/

src/utils.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,13 @@ export const kavaToUkava = (kava: string): bigint => {
7171
return parseUnits(kava, 6);
7272
};
7373

74+
/**
75+
* Convert OM to uOM
76+
*/
77+
export const omToUom = (om: string): bigint => {
78+
return parseUnits(om, 6);
79+
};
80+
7481
/**
7582
* Convert uZETA to ZETA
7683
*/
@@ -176,6 +183,13 @@ export const ukavaToKava = (ukava: bigint): string => {
176183
return formatUnits(ukava, 6);
177184
};
178185

186+
/**
187+
* Convert uOM to OM
188+
*/
189+
export const uomToOm = (uom: bigint): string => {
190+
return formatUnits(uom, 6);
191+
};
192+
179193
/**
180194
* Get a cosmos address from its public key and prefix
181195
* @param pubkey

0 commit comments

Comments
 (0)