Skip to content

Commit

Permalink
simplify error messages (#186)
Browse files Browse the repository at this point in the history
* cleanup example

* atom example

* tia example

* dydx example

* fet example

* inj example

* om example

* osmo example

* zeta example

* ada example

* improve error messages

* fix lint
LeTamanoir authored Jan 8, 2025
1 parent f3b6334 commit da62394
Showing 22 changed files with 1,009 additions and 557 deletions.
5 changes: 3 additions & 2 deletions examples/.env.example
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
KILN_API_URL=""
KILN_ACCOUNT_ID=""
KILN_API_KEY=""
FIREBLOCKS_API_KEY=""
KILN_ACCOUNT_ID=""
FIREBLOCKS_API_KEY=""
FIREBLOCKS_VAULT_ID=""
83 changes: 83 additions & 0 deletions examples/ada.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { Kiln, KILN_VALIDATORS } from '../src/kiln.ts';
import type { FireblocksIntegration } from '../src/fireblocks.ts';
import { loadEnv } from './env.ts';

const { kilnApiKey, kilnAccountId, kilnApiUrl, fireblocksApiKey, fireblocksApiSecret, fireblocksVaultId } =
await loadEnv();

const k = new Kiln({
baseUrl: kilnApiUrl,
apiToken: kilnApiKey,
});

const vault: FireblocksIntegration = {
config: {
apiKey: fireblocksApiKey,
secretKey: fireblocksApiSecret,
basePath: 'https://api.fireblocks.io/v1',
},
vaultId: fireblocksVaultId,
};

//
// Get the pubkey from Fireblocks
//
const fireblocksWallet = (
await k.fireblocks
.getSdk(vault)
.vaults.getVaultAccountAssetAddressesPaginated({ assetId: 'ADA', vaultAccountId: vault.vaultId, limit: 1 })
).data.addresses?.[0].address;
if (!fireblocksWallet) {
console.log('Failed to get pubkey');
process.exit(0);
}

//
// Craft the transaction
//
console.log('Crafting transaction...');
const txRequest = await k.client.POST('/ada/transaction/stake', {
body: {
account_id: kilnAccountId,
pool_id: KILN_VALIDATORS.ADA.mainnet.KILN0,
wallet: fireblocksWallet,
},
});
if (txRequest.error) {
console.log('Failed to craft transaction:', txRequest);
process.exit(1);
} else {
console.log('Crafted transaction:', txRequest.data);
}
console.log('\n\n\n');

//
// Sign the transaction
//
console.log('Signing transaction...');
const signRequest = await (async () => {
try {
return await k.fireblocks.signAdaTx(vault, txRequest.data.data);
} catch (err) {
console.log('Failed to sign transaction:', err);
process.exit(1);
}
})();
console.log('Signed transaction:', signRequest);
console.log('\n\n\n');

//
// Broadcast the transaction
//
console.log('Broadcasting transaction...');
const broadcastedRequest = await k.client.POST('/ada/transaction/broadcast', {
body: {
tx_serialized: signRequest.signed_tx.data.signed_tx_serialized,
},
});
if (broadcastedRequest.error) {
console.log('Failed to broadcast transaction:', broadcastedRequest);
process.exit(1);
} else {
console.log('Broadcasted transaction:', broadcastedRequest.data);
}
81 changes: 81 additions & 0 deletions examples/atom.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { atomToUatom, Kiln, KILN_VALIDATORS } from '../src/kiln.ts';
import type { FireblocksIntegration } from '../src/fireblocks.ts';
import { loadEnv } from './env.ts';

const { kilnApiKey, kilnAccountId, kilnApiUrl, fireblocksApiKey, fireblocksApiSecret, fireblocksVaultId } =
await loadEnv();

const k = new Kiln({
baseUrl: kilnApiUrl,
apiToken: kilnApiKey,
});

const vault: FireblocksIntegration = {
config: {
apiKey: fireblocksApiKey,
secretKey: fireblocksApiSecret,
basePath: 'https://api.fireblocks.io/v1',
},
vaultId: fireblocksVaultId,
};

//
// Get the pubkey from Fireblocks
//
const fireblocksPubkey = (await k.fireblocks.getPubkey(vault, 'ATOM_COS')).publicKey;
if (!fireblocksPubkey) {
console.log('Failed to get pubkey');
process.exit(0);
}

//
// Craft the transaction
//
console.log('Crafting transaction...');
const txRequest = await k.client.POST('/atom/transaction/stake', {
body: {
account_id: kilnAccountId,
pubkey: fireblocksPubkey,
validator: KILN_VALIDATORS.ATOM.mainnet.KILN,
amount_uatom: atomToUatom('0.01').toString(),
restake_rewards: false,
},
});
if (txRequest.error) {
console.log('Failed to craft transaction:', txRequest);
process.exit(1);
} else {
console.log('Crafted transaction:', txRequest.data);
}
console.log('\n\n\n');

//
// Sign the transaction
//
console.log('Signing transaction...');
const signRequest = await (async () => {
try {
return await k.fireblocks.signAtomTx(vault, txRequest.data.data);
} catch (err) {
console.log('Failed to sign transaction:', err);
process.exit(1);
}
})();
console.log('Signed transaction:', signRequest);
console.log('\n\n\n');

//
// Broadcast the transaction
//
console.log('Broadcasting transaction...');
const broadcastedRequest = await k.client.POST('/atom/transaction/broadcast', {
body: {
tx_serialized: signRequest.signed_tx.data.signed_tx_serialized,
},
});
if (broadcastedRequest.error) {
console.log('Failed to broadcast transaction:', broadcastedRequest);
process.exit(1);
} else {
console.log('Broadcasted transaction:', broadcastedRequest.data);
}
81 changes: 81 additions & 0 deletions examples/dydx.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { dydxToAdydx, Kiln, KILN_VALIDATORS } from '../src/kiln.ts';
import type { FireblocksIntegration } from '../src/fireblocks.ts';
import { loadEnv } from './env.ts';

const { kilnApiKey, kilnAccountId, kilnApiUrl, fireblocksApiKey, fireblocksApiSecret, fireblocksVaultId } =
await loadEnv();

const k = new Kiln({
baseUrl: kilnApiUrl,
apiToken: kilnApiKey,
});

const vault: FireblocksIntegration = {
config: {
apiKey: fireblocksApiKey,
secretKey: fireblocksApiSecret,
basePath: 'https://api.fireblocks.io/v1',
},
vaultId: fireblocksVaultId,
};

//
// Get the pubkey from Fireblocks
//
const fireblocksPubkey = (await k.fireblocks.getPubkey(vault, 'DYDX_DYDX')).publicKey;
if (!fireblocksPubkey) {
console.log('Failed to get pubkey');
process.exit(0);
}

//
// Craft the transaction
//
console.log('Crafting transaction...');
const txRequest = await k.client.POST('/dydx/transaction/stake', {
body: {
account_id: kilnAccountId,
pubkey: fireblocksPubkey,
validator: KILN_VALIDATORS.DYDX.mainnet.KILN,
amount_adydx: dydxToAdydx('0.01').toString(),
restake_rewards: false,
},
});
if (txRequest.error) {
console.log('Failed to craft transaction:', txRequest);
process.exit(1);
} else {
console.log('Crafted transaction:', txRequest.data);
}
console.log('\n\n\n');

//
// Sign the transaction
//
console.log('Signing transaction...');
const signRequest = await (async () => {
try {
return await k.fireblocks.signDydxTx(vault, txRequest.data.data);
} catch (err) {
console.log('Failed to sign transaction:', err);
process.exit(1);
}
})();
console.log('Signed transaction:', signRequest);
console.log('\n\n\n');

//
// Broadcast the transaction
//
console.log('Broadcasting transaction...');
const broadcastedRequest = await k.client.POST('/dydx/transaction/broadcast', {
body: {
tx_serialized: signRequest.signed_tx.data.signed_tx_serialized,
},
});
if (broadcastedRequest.error) {
console.log('Failed to broadcast transaction:', broadcastedRequest);
process.exit(1);
} else {
console.log('Broadcasted transaction:', broadcastedRequest.data);
}
37 changes: 37 additions & 0 deletions examples/env.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
export const loadEnv = async () => {
if (!Bun.env.KILN_API_URL) {
console.log('KILN_API_URL is required');
process.exit(1);
}

if (!Bun.env.KILN_ACCOUNT_ID) {
console.log('KILN_ACCOUNT_ID is required');
process.exit(1);
}

if (!Bun.env.KILN_API_KEY) {
console.log('KILN_API_KEY is required');
process.exit(1);
}

if (!Bun.env.FIREBLOCKS_API_KEY) {
console.log('FIREBLOCKS_API_KEY is required');
process.exit(1);
}

if (!Bun.env.FIREBLOCKS_VAULT_ID) {
console.log('FIREBLOCKS_VAULT_ID is required');
process.exit(1);
}

const fireblocksApiSecret = await Bun.file('fireblocks_secret_prod.key').text();

return {
kilnApiUrl: Bun.env.KILN_API_URL,
kilnApiKey: Bun.env.KILN_API_KEY,
kilnAccountId: Bun.env.KILN_ACCOUNT_ID,
fireblocksApiKey: Bun.env.FIREBLOCKS_API_KEY,
fireblocksVaultId: Bun.env.FIREBLOCKS_VAULT_ID as `${number}`,
fireblocksApiSecret,
};
};
52 changes: 0 additions & 52 deletions examples/eth.ts

This file was deleted.

87 changes: 87 additions & 0 deletions examples/fet.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { fetToAfet, Kiln, KILN_VALIDATORS } from '../src/kiln.ts';
import type { FireblocksIntegration } from '../src/fireblocks.ts';
import { loadEnv } from './env.ts';

const { kilnApiKey, kilnAccountId, kilnApiUrl, fireblocksApiKey, fireblocksApiSecret, fireblocksVaultId } =
await loadEnv();

const k = new Kiln({
baseUrl: kilnApiUrl,
apiToken: kilnApiKey,
});

const vault: FireblocksIntegration = {
config: {
apiKey: fireblocksApiKey,
secretKey: fireblocksApiSecret,
basePath: 'https://api.fireblocks.io/v1',
},
vaultId: fireblocksVaultId,
};

//
// Get the pubkey from Fireblocks
//
const fireblocksPubkey = (
await k.fireblocks.getSdk(vault).vaults.getPublicKeyInfo({
algorithm: 'MPC_ECDSA_SECP256K1',
derivationPath: JSON.stringify([44, 118, Number(vault.vaultId), 0, 0]),
compressed: true,
})
).data.publicKey;
if (!fireblocksPubkey) {
console.log('Failed to get pubkey');
process.exit(0);
}

//
// Craft the transaction
//
console.log('Crafting transaction...');
const txRequest = await k.client.POST('/fet/transaction/stake', {
body: {
account_id: kilnAccountId,
pubkey: fireblocksPubkey,
validator: KILN_VALIDATORS.FET.mainnet.KILN,
amount_afet: fetToAfet('0.01').toString(),
restake_rewards: false,
},
});
if (txRequest.error) {
console.log('Failed to craft transaction:', txRequest);
process.exit(1);
} else {
console.log('Crafted transaction:', txRequest.data);
}
console.log('\n\n\n');

//
// Sign the transaction
//
console.log('Signing transaction...');
const signRequest = await (async () => {
try {
return await k.fireblocks.signFetTx(vault, txRequest.data.data);
} catch (err) {
console.log('Failed to sign transaction:', err);
process.exit(1);
}
})();
console.log('Signed transaction:', signRequest);
console.log('\n\n\n');

//
// Broadcast the transaction
//
console.log('Broadcasting transaction...');
const broadcastedRequest = await k.client.POST('/fet/transaction/broadcast', {
body: {
tx_serialized: signRequest.signed_tx.data.signed_tx_serialized,
},
});
if (broadcastedRequest.error) {
console.log('Failed to broadcast transaction:', broadcastedRequest);
process.exit(1);
} else {
console.log('Broadcasted transaction:', broadcastedRequest.data);
}
81 changes: 81 additions & 0 deletions examples/inj.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { injToInj, Kiln, KILN_VALIDATORS } from '../src/kiln.ts';
import type { FireblocksIntegration } from '../src/fireblocks.ts';
import { loadEnv } from './env.ts';

const { kilnApiKey, kilnAccountId, kilnApiUrl, fireblocksApiKey, fireblocksApiSecret, fireblocksVaultId } =
await loadEnv();

const k = new Kiln({
baseUrl: kilnApiUrl,
apiToken: kilnApiKey,
});

const vault: FireblocksIntegration = {
config: {
apiKey: fireblocksApiKey,
secretKey: fireblocksApiSecret,
basePath: 'https://api.fireblocks.io/v1',
},
vaultId: fireblocksVaultId,
};

//
// Get the pubkey from Fireblocks
//
const fireblocksPubkey = (await k.fireblocks.getPubkey(vault, 'INJ_INJ')).publicKey;
if (!fireblocksPubkey) {
console.log('Failed to get pubkey');
process.exit(0);
}

//
// Craft the transaction
//
console.log('Crafting transaction...');
const txRequest = await k.client.POST('/inj/transaction/stake', {
body: {
account_id: kilnAccountId,
pubkey: fireblocksPubkey,
validator: KILN_VALIDATORS.INJ.mainnet.KILN,
amount_inj: injToInj('0.01').toString(),
restake_rewards: false,
},
});
if (txRequest.error) {
console.log('Failed to craft transaction:', txRequest);
process.exit(1);
} else {
console.log('Crafted transaction:', txRequest.data);
}
console.log('\n\n\n');

//
// Sign the transaction
//
console.log('Signing transaction...');
const signRequest = await (async () => {
try {
return await k.fireblocks.signInjTx(vault, txRequest.data.data);
} catch (err) {
console.log('Failed to sign transaction:', err);
process.exit(1);
}
})();
console.log('Signed transaction:', signRequest);
console.log('\n\n\n');

//
// Broadcast the transaction
//
console.log('Broadcasting transaction...');
const broadcastedRequest = await k.client.POST('/inj/transaction/broadcast', {
body: {
tx_serialized: signRequest.signed_tx.data.signed_tx_serialized,
},
});
if (broadcastedRequest.error) {
console.log('Failed to broadcast transaction:', broadcastedRequest);
process.exit(1);
} else {
console.log('Broadcasted transaction:', broadcastedRequest.data);
}
116 changes: 77 additions & 39 deletions examples/kava.ts
Original file line number Diff line number Diff line change
@@ -1,48 +1,86 @@
import { kavaToUkava, Kiln } from "../src/kiln";
import fs from "node:fs";
import 'dotenv/config'
import type { FireblocksIntegration } from "../src/fireblocks.ts";
import { kavaToUkava, Kiln, KILN_VALIDATORS } from '../src/kiln.ts';
import type { FireblocksIntegration } from '../src/fireblocks.ts';
import { loadEnv } from './env.ts';


const apiSecret = fs.readFileSync(`${__dirname}/fireblocks_secret_prod.key`, 'utf8');
const { kilnApiKey, kilnAccountId, kilnApiUrl, fireblocksApiKey, fireblocksApiSecret, fireblocksVaultId } =
await loadEnv();

const k = new Kiln({
baseUrl: process.env.KILN_API_URL as string,
apiToken: process.env.KILN_API_KEY as string,
baseUrl: kilnApiUrl,
apiToken: kilnApiKey,
});

const vault: FireblocksIntegration = {
provider: 'fireblocks',
fireblocksApiKey: process.env.FIREBLOCKS_API_KEY as string,
fireblocksSecretKey: apiSecret,
vaultId: 37
config: {
apiKey: fireblocksApiKey,
secretKey: fireblocksApiSecret,
basePath: 'https://api.fireblocks.io/v1',
},
vaultId: fireblocksVaultId,
};

try {
console.log('crafting...');
const tx = await k.client.POST(
'/kava/transaction/stake',
{
body: {
account_id: process.env.KILN_ACCOUNT_ID as string,
pubkey: '0233335b6c68a85e01b85055d0e8c2fcef42fed977898422ef3a5f6baf9a9a413e',
validator: 'kavavaloper1djqecw6nn5tydxq0shan7srv8j65clsf79myt8',
amount_ukava: kavaToUkava('0.01').toString(),
}
}
);
console.log('signing...');
if(!tx.data?.data) throw new Error('No data in response');
const signResponse = await k.fireblocks.signKavaTx(vault, tx.data.data);
console.log('broadcasting...');
if(!signResponse.signed_tx?.data?.signed_tx_serialized) throw new Error('No signed_tx in response');
const broadcastedTx = await k.client.POST("/kava/transaction/broadcast", {
body: {
tx_serialized: signResponse.signed_tx.data.signed_tx_serialized,
}
});
console.log(broadcastedTx);
//
// Get the pubkey from Fireblocks
//
const fireblocksPubkey = (
await k.fireblocks.getSdk(vault).vaults.getPublicKeyInfo({
algorithm: 'MPC_ECDSA_SECP256K1',
derivationPath: JSON.stringify([44, 459, Number(vault.vaultId), 0, 0]),
compressed: true,
})
).data.publicKey;
if (!fireblocksPubkey) {
console.log('Failed to get pubkey');
process.exit(0);
}

//
// Craft the transaction
//
console.log('Crafting transaction...');
const txRequest = await k.client.POST('/kava/transaction/stake', {
body: {
account_id: kilnAccountId,
pubkey: fireblocksPubkey,
validator: KILN_VALIDATORS.KAVA.mainnet.KILN,
amount_ukava: kavaToUkava('0.01').toString(),
},
});
if (txRequest.error) {
console.log('Failed to craft transaction:', txRequest);
process.exit(1);
} else {
console.log('Crafted transaction:', txRequest.data);
}
console.log('\n\n\n');

} catch (err) {
console.log(err);
}
//
// Sign the transaction
//
console.log('Signing transaction...');
const signRequest = await (async () => {
try {
return await k.fireblocks.signKavaTx(vault, txRequest.data.data);
} catch (err) {
console.log('Failed to sign transaction:', err);
process.exit(1);
}
})();
console.log('Signed transaction:', signRequest);
console.log('\n\n\n');

//
// Broadcast the transaction
//
console.log('Broadcasting transaction...');
const broadcastedRequest = await k.client.POST('/kava/transaction/broadcast', {
body: {
tx_serialized: signRequest.signed_tx.data.signed_tx_serialized,
},
});
if (broadcastedRequest.error) {
console.log('Failed to broadcast transaction:', broadcastedRequest);
process.exit(1);
} else {
console.log('Broadcasted transaction:', broadcastedRequest.data);
}
46 changes: 0 additions & 46 deletions examples/near.ts

This file was deleted.

56 changes: 0 additions & 56 deletions examples/noble.ts

This file was deleted.

111 changes: 76 additions & 35 deletions examples/om.ts
Original file line number Diff line number Diff line change
@@ -1,46 +1,87 @@
import { omToUom, Kiln } from '../src/kiln.ts';
import fs from 'node:fs';
import 'dotenv/config';
import { Kiln, KILN_VALIDATORS, omToUom } from '../src/kiln.ts';
import type { FireblocksIntegration } from '../src/fireblocks.ts';
import { loadEnv } from './env.ts';

const apiSecret = fs.readFileSync(`${__dirname}/fireblocks_secret_prod.key`, 'utf8');
const { kilnApiKey, kilnAccountId, kilnApiUrl, fireblocksApiKey, fireblocksApiSecret, fireblocksVaultId } =
await loadEnv();

const k = new Kiln({
baseUrl: process.env.KILN_API_URL as string,
apiToken: process.env.KILN_API_KEY as string,
baseUrl: kilnApiUrl,
apiToken: kilnApiKey,
});

const vault: FireblocksIntegration = {
provider: 'fireblocks',
fireblocksApiKey: process.env.FIREBLOCKS_API_KEY as string,
fireblocksSecretKey: apiSecret,
vaultId: 17,
config: {
apiKey: fireblocksApiKey,
secretKey: fireblocksApiSecret,
basePath: 'https://api.fireblocks.io/v1',
},
vaultId: fireblocksVaultId,
};

try {
console.log('crafting...');
const tx = await k.client.POST('/om/transaction/stake', {
body: {
account_id: process.env.KILN_ACCOUNT_ID as string,
pubkey: '028dfa6f41c655e38a0f8f2e3f3aa3e1246907a9bb299933f11996e2a345a21e10',
validator: 'mantravaloper146mj09yzu3mvz7pmy4dvs4z9wr2mst7ram37xw',
amount_uom: omToUom('0.01').toString(),
restake_rewards: false,
},
});
//
// Get the pubkey from Fireblocks
//
const fireblocksPubkey = (
await k.fireblocks.getSdk(vault).vaults.getPublicKeyInfo({
algorithm: 'MPC_ECDSA_SECP256K1',
derivationPath: JSON.stringify([44, 118, Number(vault.vaultId), 0, 0]),
compressed: true,
})
).data.publicKey;
if (!fireblocksPubkey) {
console.log('Failed to get pubkey');
process.exit(0);
}

//
// Craft the transaction
//
console.log('Crafting transaction...');
const txRequest = await k.client.POST('/om/transaction/stake', {
body: {
account_id: kilnAccountId,
pubkey: fireblocksPubkey,
validator: KILN_VALIDATORS.OM.mainnet.KILN,
amount_uom: omToUom('0.01').toString(),
restake_rewards: false,
},
});
if (txRequest.error) {
console.log('Failed to craft transaction:', txRequest);
process.exit(1);
} else {
console.log('Crafted transaction:', txRequest.data);
}
console.log('\n\n\n');

//
// Sign the transaction
//
console.log('Signing transaction...');
const signRequest = await (async () => {
try {
return await k.fireblocks.signOmTx(vault, txRequest.data.data);
} catch (err) {
console.log('Failed to sign transaction:', err);
process.exit(1);
}
})();
console.log('Signed transaction:', signRequest);
console.log('\n\n\n');

console.log(tx);
console.log('signing...');
if (!tx.data?.data) throw new Error('No data in response');
const signResponse = await k.fireblocks.signOmTx(vault, tx.data.data);
console.log('broadcasting...');
if (!signResponse.signed_tx?.data?.signed_tx_serialized) throw new Error('No signed_tx in response');
const broadcastedTx = await k.client.POST('/om/transaction/broadcast', {
body: {
tx_serialized: signResponse.signed_tx.data.signed_tx_serialized,
},
});
console.log(broadcastedTx);
} catch (err) {
console.log(err);
//
// Broadcast the transaction
//
console.log('Broadcasting transaction...');
const broadcastedRequest = await k.client.POST('/om/transaction/broadcast', {
body: {
tx_serialized: signRequest.signed_tx.data.signed_tx_serialized,
},
});
if (broadcastedRequest.error) {
console.log('Failed to broadcast transaction:', broadcastedRequest);
process.exit(1);
} else {
console.log('Broadcasted transaction:', broadcastedRequest.data);
}
81 changes: 81 additions & 0 deletions examples/osmo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { Kiln, KILN_VALIDATORS, osmoToUosmo } from '../src/kiln.ts';
import type { FireblocksIntegration } from '../src/fireblocks.ts';
import { loadEnv } from './env.ts';

const { kilnApiKey, kilnAccountId, kilnApiUrl, fireblocksApiKey, fireblocksApiSecret, fireblocksVaultId } =
await loadEnv();

const k = new Kiln({
baseUrl: kilnApiUrl,
apiToken: kilnApiKey,
});

const vault: FireblocksIntegration = {
config: {
apiKey: fireblocksApiKey,
secretKey: fireblocksApiSecret,
basePath: 'https://api.fireblocks.io/v1',
},
vaultId: fireblocksVaultId,
};

//
// Get the pubkey from Fireblocks
//
const fireblocksPubkey = (await k.fireblocks.getPubkey(vault, 'OSMO')).publicKey;
if (!fireblocksPubkey) {
console.log('Failed to get pubkey');
process.exit(0);
}

//
// Craft the transaction
//
console.log('Crafting transaction...');
const txRequest = await k.client.POST('/osmo/transaction/stake', {
body: {
account_id: kilnAccountId,
pubkey: fireblocksPubkey,
validator: KILN_VALIDATORS.OSMO.mainnet.INTEROP,
amount_uosmo: osmoToUosmo('0.01').toString(),
restake_rewards: false,
},
});
if (txRequest.error) {
console.log('Failed to craft transaction:', txRequest);
process.exit(1);
} else {
console.log('Crafted transaction:', txRequest.data);
}
console.log('\n\n\n');

//
// Sign the transaction
//
console.log('Signing transaction...');
const signRequest = await (async () => {
try {
return await k.fireblocks.signOsmoTx(vault, txRequest.data.data);
} catch (err) {
console.log('Failed to sign transaction:', err);
process.exit(1);
}
})();
console.log('Signed transaction:', signRequest);
console.log('\n\n\n');

//
// Broadcast the transaction
//
console.log('Broadcasting transaction...');
const broadcastedRequest = await k.client.POST('/osmo/transaction/broadcast', {
body: {
tx_serialized: signRequest.signed_tx.data.signed_tx_serialized,
},
});
if (broadcastedRequest.error) {
console.log('Failed to broadcast transaction:', broadcastedRequest);
process.exit(1);
} else {
console.log('Broadcasted transaction:', broadcastedRequest.data);
}
48 changes: 0 additions & 48 deletions examples/sol.ts

This file was deleted.

81 changes: 81 additions & 0 deletions examples/tia.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { Kiln, KILN_VALIDATORS, tiaToUtia } from '../src/kiln.ts';
import type { FireblocksIntegration } from '../src/fireblocks.ts';
import { loadEnv } from './env.ts';

const { kilnApiKey, kilnAccountId, kilnApiUrl, fireblocksApiKey, fireblocksApiSecret, fireblocksVaultId } =
await loadEnv();

const k = new Kiln({
baseUrl: kilnApiUrl,
apiToken: kilnApiKey,
});

const vault: FireblocksIntegration = {
config: {
apiKey: fireblocksApiKey,
secretKey: fireblocksApiSecret,
basePath: 'https://api.fireblocks.io/v1',
},
vaultId: fireblocksVaultId,
};

//
// Get the pubkey from Fireblocks
//
const fireblocksPubkey = (await k.fireblocks.getPubkey(vault, 'CELESTIA')).publicKey;
if (!fireblocksPubkey) {
console.log('Failed to get pubkey');
process.exit(0);
}

//
// Craft the transaction
//
console.log('Crafting transaction...');
const txRequest = await k.client.POST('/tia/transaction/stake', {
body: {
account_id: kilnAccountId,
pubkey: fireblocksPubkey,
validator: KILN_VALIDATORS.TIA.mainnet.KILN,
amount_utia: tiaToUtia('0.01').toString(),
restake_rewards: false,
},
});
if (txRequest.error) {
console.log('Failed to craft transaction:', txRequest);
process.exit(1);
} else {
console.log('Crafted transaction:', txRequest.data);
}
console.log('\n\n\n');

//
// Sign the transaction
//
console.log('Signing transaction...');
const signRequest = await (async () => {
try {
return await k.fireblocks.signTiaTx(vault, txRequest.data.data);
} catch (err) {
console.log('Failed to sign transaction:', err);
process.exit(1);
}
})();
console.log('Signed transaction:', signRequest);
console.log('\n\n\n');

//
// Broadcast the transaction
//
console.log('Broadcasting transaction...');
const broadcastedRequest = await k.client.POST('/tia/transaction/broadcast', {
body: {
tx_serialized: signRequest.signed_tx.data.signed_tx_serialized,
},
});
if (broadcastedRequest.error) {
console.log('Failed to broadcast transaction:', broadcastedRequest);
process.exit(1);
} else {
console.log('Broadcasted transaction:', broadcastedRequest.data);
}
60 changes: 0 additions & 60 deletions examples/ton.ts

This file was deleted.

45 changes: 0 additions & 45 deletions examples/trx.ts

This file was deleted.

47 changes: 0 additions & 47 deletions examples/xtz.ts

This file was deleted.

87 changes: 87 additions & 0 deletions examples/zeta.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { Kiln, KILN_VALIDATORS, zetaToAzeta } from '../src/kiln.ts';
import type { FireblocksIntegration } from '../src/fireblocks.ts';
import { loadEnv } from './env.ts';

const { kilnApiKey, kilnAccountId, kilnApiUrl, fireblocksApiKey, fireblocksApiSecret, fireblocksVaultId } =
await loadEnv();

const k = new Kiln({
baseUrl: kilnApiUrl,
apiToken: kilnApiKey,
});

const vault: FireblocksIntegration = {
config: {
apiKey: fireblocksApiKey,
secretKey: fireblocksApiSecret,
basePath: 'https://api.fireblocks.io/v1',
},
vaultId: fireblocksVaultId,
};

//
// Get the pubkey from Fireblocks
//
const fireblocksPubkey = (
await k.fireblocks.getSdk(vault).vaults.getPublicKeyInfo({
algorithm: 'MPC_ECDSA_SECP256K1',
derivationPath: JSON.stringify([44, 118, Number(vault.vaultId), 0, 0]),
compressed: true,
})
).data.publicKey;
if (!fireblocksPubkey) {
console.log('Failed to get pubkey');
process.exit(0);
}

//
// Craft the transaction
//
console.log('Crafting transaction...');
const txRequest = await k.client.POST('/zeta/transaction/stake', {
body: {
account_id: kilnAccountId,
pubkey: fireblocksPubkey,
validator: KILN_VALIDATORS.ZETA.mainnet.KILN,
amount_azeta: zetaToAzeta('0.01').toString(),
restake_rewards: false,
},
});
if (txRequest.error) {
console.log('Failed to craft transaction:', txRequest);
process.exit(1);
} else {
console.log('Crafted transaction:', txRequest.data);
}
console.log('\n\n\n');

//
// Sign the transaction
//
console.log('Signing transaction...');
const signRequest = await (async () => {
try {
return await k.fireblocks.signZetaTx(vault, txRequest.data.data);
} catch (err) {
console.log('Failed to sign transaction:', err);
process.exit(1);
}
})();
console.log('Signed transaction:', signRequest);
console.log('\n\n\n');

//
// Broadcast the transaction
//
console.log('Broadcasting transaction...');
const broadcastedRequest = await k.client.POST('/zeta/transaction/broadcast', {
body: {
tx_serialized: signRequest.signed_tx.data.signed_tx_serialized,
},
});
if (broadcastedRequest.error) {
console.log('Failed to broadcast transaction:', broadcastedRequest);
process.exit(1);
} else {
console.log('Broadcasted transaction:', broadcastedRequest.data);
}
92 changes: 50 additions & 42 deletions src/fireblocks.ts
Original file line number Diff line number Diff line change
@@ -8,7 +8,7 @@ import {
} from '@fireblocks/ts-sdk';

import type { Client } from 'openapi-fetch';
import { FireblocksSigner } from './fireblocks_signer.js';
import { type FireblocksAssetId, FireblocksSigner } from './fireblocks_signer.js';
import type { components, paths } from './openapi/schema.js';

export type FireblocksIntegration = (
@@ -18,6 +18,11 @@ export type FireblocksIntegration = (
vaultId: `${number}`;
};

const ERRORS = {
MISSING_SIGNATURE: 'An error occurred while attempting to retrieve the signature from Fireblocks.',
FAILED_TO_PREPARE: 'An error occurred while attempting to add the signature to the transaction.',
};

export class FireblocksService {
client: Client<paths>;

@@ -46,7 +51,10 @@ export class FireblocksService {
/**
* Get fireblocks wallet pubkey compressed
*/
async getPubkey(integration: FireblocksIntegration, assetId: string): Promise<PublicKeyInformation> {
async getPubkey(
integration: FireblocksIntegration,
assetId: (string & {}) | FireblocksAssetId,
): Promise<PublicKeyInformation> {
const fbSdk = this.getSdk(integration);
const data = await fbSdk.vaults.getPublicKeyInfoForAddress({
assetId: assetId,
@@ -97,7 +105,7 @@ export class FireblocksService {
.map((signedMessage) => signedMessage.signature?.fullSig)
.filter((s) => s !== undefined);
if (!signatures) {
throw new Error('Fireblocks signature is missing');
throw new Error(ERRORS.MISSING_SIGNATURE);
}

const preparedTx = await this.client.POST('/sol/transaction/prepare', {
@@ -108,7 +116,7 @@ export class FireblocksService {
});

if (preparedTx.error) {
throw new Error('Failed to prepare transaction');
throw new Error(ERRORS.FAILED_TO_PREPARE);
}

return {
@@ -154,7 +162,7 @@ export class FireblocksService {
signature: message.signature?.fullSig as string,
}));
if (!signedMessages) {
throw new Error('Fireblocks signature is missing');
throw new Error(ERRORS.MISSING_SIGNATURE);
}

const preparedTx = await this.client.POST('/ada/transaction/prepare', {
@@ -165,7 +173,7 @@ export class FireblocksService {
});

if (preparedTx.error) {
throw new Error('Failed to prepare transaction');
throw new Error(ERRORS.FAILED_TO_PREPARE);
}

return {
@@ -205,7 +213,7 @@ export class FireblocksService {
const signature = fbTx.signedMessages?.[0]?.signature?.fullSig;

if (!signature) {
throw new Error('Fireblocks signature is missing');
throw new Error(ERRORS.MISSING_SIGNATURE);
}

const preparedTx = await this.client.POST('/atom/transaction/prepare', {
@@ -218,7 +226,7 @@ export class FireblocksService {
});

if (preparedTx.error) {
throw new Error('Failed to prepare transaction');
throw new Error(ERRORS.FAILED_TO_PREPARE);
}

return {
@@ -258,7 +266,7 @@ export class FireblocksService {
const signature = fbTx.signedMessages?.[0]?.signature?.fullSig;

if (!signature) {
throw new Error('Fireblocks signature is missing');
throw new Error(ERRORS.MISSING_SIGNATURE);
}

const preparedTx = await this.client.POST('/dydx/transaction/prepare', {
@@ -271,7 +279,7 @@ export class FireblocksService {
});

if (preparedTx.error) {
throw new Error('Failed to prepare transaction');
throw new Error(ERRORS.FAILED_TO_PREPARE);
}

return {
@@ -313,7 +321,7 @@ export class FireblocksService {
const signature = fbTx.signedMessages?.[0]?.signature?.fullSig;

if (!signature) {
throw new Error('Fireblocks signature is missing');
throw new Error(ERRORS.MISSING_SIGNATURE);
}

const preparedTx = await this.client.POST('/fet/transaction/prepare', {
@@ -326,7 +334,7 @@ export class FireblocksService {
});

if (preparedTx.error) {
throw new Error('Failed to prepare transaction');
throw new Error(ERRORS.FAILED_TO_PREPARE);
}

return {
@@ -368,7 +376,7 @@ export class FireblocksService {
const signature = fbTx.signedMessages?.[0]?.signature?.fullSig;

if (!signature) {
throw new Error('Fireblocks signature is missing');
throw new Error(ERRORS.MISSING_SIGNATURE);
}

const preparedTx = await this.client.POST('/om/transaction/prepare', {
@@ -381,7 +389,7 @@ export class FireblocksService {
});

if (preparedTx.error) {
throw new Error('Failed to prepare transaction');
throw new Error(ERRORS.FAILED_TO_PREPARE);
}

return {
@@ -421,7 +429,7 @@ export class FireblocksService {
const signature = fbTx.signedMessages?.[0]?.signature?.fullSig;

if (!signature) {
throw new Error('Fireblocks signature is missing');
throw new Error(ERRORS.MISSING_SIGNATURE);
}

const preparedTx = await this.client.POST('/inj/transaction/prepare', {
@@ -434,7 +442,7 @@ export class FireblocksService {
});

if (preparedTx.error) {
throw new Error('Failed to prepare transaction');
throw new Error(ERRORS.FAILED_TO_PREPARE);
}

return {
@@ -476,7 +484,7 @@ export class FireblocksService {
const signature = fbTx.signedMessages?.[0]?.signature?.fullSig;

if (!signature) {
throw new Error('Fireblocks signature is missing');
throw new Error(ERRORS.MISSING_SIGNATURE);
}

const preparedTx = await this.client.POST('/kava/transaction/prepare', {
@@ -489,7 +497,7 @@ export class FireblocksService {
});

if (preparedTx.error) {
throw new Error('Failed to prepare transaction');
throw new Error(ERRORS.FAILED_TO_PREPARE);
}

return {
@@ -531,7 +539,7 @@ export class FireblocksService {
const signature = fbTx.signedMessages?.[0]?.signature?.fullSig;

if (!signature) {
throw new Error('Fireblocks signature is missing');
throw new Error(ERRORS.MISSING_SIGNATURE);
}

const preparedTx = await this.client.POST('/noble/transaction/prepare', {
@@ -544,7 +552,7 @@ export class FireblocksService {
});

if (preparedTx.error) {
throw new Error('Failed to prepare transaction');
throw new Error(ERRORS.FAILED_TO_PREPARE);
}

return {
@@ -584,7 +592,7 @@ export class FireblocksService {
const signature = fbTx.signedMessages?.[0]?.signature?.fullSig;

if (!signature) {
throw new Error('Fireblocks signature is missing');
throw new Error(ERRORS.MISSING_SIGNATURE);
}

const preparedTx = await this.client.POST('/osmo/transaction/prepare', {
@@ -597,7 +605,7 @@ export class FireblocksService {
});

if (preparedTx.error) {
throw new Error('Failed to prepare transaction');
throw new Error(ERRORS.FAILED_TO_PREPARE);
}

return {
@@ -637,7 +645,7 @@ export class FireblocksService {
const signature = fbTx.signedMessages?.[0]?.signature?.fullSig;

if (!signature) {
throw new Error('Fireblocks signature is missing');
throw new Error(ERRORS.MISSING_SIGNATURE);
}

const preparedTx = await this.client.POST('/tia/transaction/prepare', {
@@ -650,7 +658,7 @@ export class FireblocksService {
});

if (preparedTx.error) {
throw new Error('Failed to prepare transaction');
throw new Error(ERRORS.FAILED_TO_PREPARE);
}

return {
@@ -692,7 +700,7 @@ export class FireblocksService {
const signature = fbTx.signedMessages?.[0]?.signature?.fullSig;

if (!signature) {
throw new Error('Fireblocks signature is missing');
throw new Error(ERRORS.MISSING_SIGNATURE);
}

const preparedTx = await this.client.POST('/zeta/transaction/prepare', {
@@ -705,7 +713,7 @@ export class FireblocksService {
});

if (preparedTx.error) {
throw new Error('Failed to prepare transaction');
throw new Error(ERRORS.FAILED_TO_PREPARE);
}

return {
@@ -740,7 +748,7 @@ export class FireblocksService {
const fbTx = await fbSigner.sign(payload, 'DOT', fbNote);

if (!fbTx.signedMessages?.[0]?.signature?.fullSig) {
throw new Error('Fireblocks signature is missing');
throw new Error(ERRORS.MISSING_SIGNATURE);
}

const signature = `0x00${fbTx.signedMessages?.[0]?.signature.fullSig}`;
@@ -753,7 +761,7 @@ export class FireblocksService {
});

if (preparedTx.error) {
throw new Error('Failed to prepare transaction');
throw new Error(ERRORS.FAILED_TO_PREPARE);
}

return {
@@ -788,7 +796,7 @@ export class FireblocksService {
const fbTx = await fbSigner.sign(payload, 'KSM', fbNote);

if (!fbTx.signedMessages?.[0]?.signature?.fullSig) {
throw new Error('Fireblocks signature is missing');
throw new Error(ERRORS.MISSING_SIGNATURE);
}

const signature = `0x00${fbTx.signedMessages?.[0]?.signature.fullSig}`;
@@ -801,7 +809,7 @@ export class FireblocksService {
});

if (preparedTx.error) {
throw new Error('Failed to prepare transaction');
throw new Error(ERRORS.FAILED_TO_PREPARE);
}

return {
@@ -843,7 +851,7 @@ export class FireblocksService {
const signature = fbTx?.signedMessages?.[0]?.signature;

if (!signature) {
throw new Error('Fireblocks signature is missing');
throw new Error(ERRORS.MISSING_SIGNATURE);
}

const preparedTx = await this.client.POST('/eth/transaction/prepare', {
@@ -856,7 +864,7 @@ export class FireblocksService {
});

if (preparedTx.error) {
throw new Error('Failed to prepare transaction');
throw new Error(ERRORS.FAILED_TO_PREPARE);
}

return {
@@ -917,7 +925,7 @@ export class FireblocksService {
const signature = fbTx?.signedMessages?.[0]?.signature;

if (!signature) {
throw new Error('Fireblocks signature is missing');
throw new Error(ERRORS.MISSING_SIGNATURE);
}

const preparedTx = await this.client.POST('/pol/transaction/prepare', {
@@ -930,7 +938,7 @@ export class FireblocksService {
});

if (preparedTx.error) {
throw new Error('Failed to prepare transaction');
throw new Error(ERRORS.FAILED_TO_PREPARE);
}

return {
@@ -986,7 +994,7 @@ export class FireblocksService {
const signature = fbTx.signedMessages?.[0]?.signature?.fullSig;

if (!signature) {
throw new Error('Fireblocks signature is missing');
throw new Error(ERRORS.MISSING_SIGNATURE);
}

const preparedTx = await this.client.POST('/ton/transaction/prepare', {
@@ -998,7 +1006,7 @@ export class FireblocksService {
});

if (preparedTx.error) {
throw new Error('Failed to prepare transaction');
throw new Error(ERRORS.FAILED_TO_PREPARE);
}

return {
@@ -1035,7 +1043,7 @@ export class FireblocksService {
const signature = fbTx.signedMessages?.[0]?.signature?.fullSig;

if (!signature) {
throw new Error('Fireblocks signature is missing');
throw new Error(ERRORS.MISSING_SIGNATURE);
}

const preparedTx = await this.client.POST('/xtz/transaction/prepare', {
@@ -1046,7 +1054,7 @@ export class FireblocksService {
});

if (preparedTx.error) {
throw new Error('Failed to prepare transaction');
throw new Error(ERRORS.FAILED_TO_PREPARE);
}

return {
@@ -1083,7 +1091,7 @@ export class FireblocksService {
const signature = fbTx.signedMessages?.[0]?.signature?.fullSig;

if (!signature) {
throw new Error('Fireblocks signature is missing');
throw new Error(ERRORS.MISSING_SIGNATURE);
}

const preparedTx = await this.client.POST('/near/transaction/prepare', {
@@ -1094,7 +1102,7 @@ export class FireblocksService {
});

if (preparedTx.error) {
throw new Error('Failed to prepare transaction');
throw new Error(ERRORS.FAILED_TO_PREPARE);
}

return {
@@ -1133,7 +1141,7 @@ export class FireblocksService {
const fbTx = await fbSigner.sign(payload, 'TRX', fbNote);

if (!fbTx.signedMessages?.[0]?.signature) {
throw new Error('Fireblocks signature is missing');
throw new Error(ERRORS.MISSING_SIGNATURE);
}

const signature = `${fbTx.signedMessages[0].signature.fullSig}0${fbTx.signedMessages[0].signature.v}`;
@@ -1146,7 +1154,7 @@ export class FireblocksService {
});

if (preparedTx.error) {
throw new Error('Failed to prepare transaction');
throw new Error(ERRORS.FAILED_TO_PREPARE);
}

return {
159 changes: 74 additions & 85 deletions src/fireblocks_signer.ts
Original file line number Diff line number Diff line change
@@ -49,24 +49,25 @@ export class FireblocksSigner {
* @param fbTx fireblocks transaction
*/
protected async waitForTxCompletion(fbTx: CreateTransactionResponse): Promise<TransactionResponse> {
try {
let tx = fbTx;
while (tx.status !== 'COMPLETED') {
if (tx.status === 'BLOCKED' || tx.status === 'FAILED' || tx.status === 'CANCELLED') {
throw Error(`Fireblocks signer: the transaction has been ${tx.status}`);
}
if (tx.status === 'REJECTED') {
throw Error(
'Fireblocks signer: the transaction has been rejected, make sure that the TAP security policy is not blocking the transaction',
);
}
tx = (await this.fireblocks.transactions.getTransaction({ txId: fbTx.id as string })).data;
let tx = fbTx;
while (tx.status !== 'COMPLETED') {
// see https://developers.fireblocks.com/reference/transaction-substatuses#failed-substatuses
const ERRORS: Record<string, string> = {
BLOCKED: 'The transaction has been blocked by the TAP security policy.',
FAILED: 'The transaction has failed.',
CANCELLED: 'The transaction has been cancelled.',
REJECTED:
'The transaction has been rejected, make sure that the TAP security policy is not blocking the transaction.',
};
if (tx.status && tx.status in ERRORS) {
throw Error(ERRORS[tx.status]);
}

return tx;
} catch (err) {
throw new Error(`Fireblocks signer (waitForTxCompletion): ${err}`);
// wait a bit before polling again
await new Promise((r) => setTimeout(r, 500));
tx = (await this.fireblocks.transactions.getTransaction({ txId: fbTx.id as string })).data;
}

return tx;
}

/**
@@ -76,28 +77,24 @@ export class FireblocksSigner {
* @param note optional fireblocks custom note
*/
public async sign(payloadToSign: object, assetId?: FireblocksAssetId, note = ''): Promise<TransactionResponse> {
try {
const assetArgs = assetId
? ({
assetId,
source: {
type: 'VAULT_ACCOUNT',
id: this.vaultId,
},
} satisfies Partial<TransactionRequest>)
: undefined;
const assetArgs = assetId
? ({
assetId,
source: {
type: 'VAULT_ACCOUNT',
id: this.vaultId,
},
} satisfies Partial<TransactionRequest>)
: undefined;

const tx: TransactionRequest = {
...assetArgs,
operation: 'RAW',
note,
extraParameters: payloadToSign,
};
const fbTx = (await this.fireblocks.transactions.createTransaction({ transactionRequest: tx })).data;
return await this.waitForTxCompletion(fbTx);
} catch (err) {
throw new Error(`Fireblocks signer (signWithFB): ${err}`);
}
const tx: TransactionRequest = {
...assetArgs,
operation: 'RAW',
note,
extraParameters: payloadToSign,
};
const fbTx = (await this.fireblocks.transactions.createTransaction({ transactionRequest: tx })).data;
return await this.waitForTxCompletion(fbTx);
}

/**
@@ -111,31 +108,27 @@ export class FireblocksSigner {
assetId: 'ETH' | 'ETH_TEST5' | 'ETH_TEST6',
note = '',
): Promise<TransactionResponse> {
try {
const tx: TransactionRequest = {
assetId: assetId,
operation: 'TYPED_MESSAGE',
source: {
type: 'VAULT_ACCOUNT',
id: this.vaultId,
},
note,
extraParameters: {
rawMessageData: {
messages: [
{
content: eip712message,
type: 'EIP712',
},
],
},
const tx: TransactionRequest = {
assetId: assetId,
operation: 'TYPED_MESSAGE',
source: {
type: 'VAULT_ACCOUNT',
id: this.vaultId,
},
note,
extraParameters: {
rawMessageData: {
messages: [
{
content: eip712message,
type: 'EIP712',
},
],
},
};
const fbTx = (await this.fireblocks.transactions.createTransaction({ transactionRequest: tx })).data;
return await this.waitForTxCompletion(fbTx);
} catch (err) {
throw new Error(`Fireblocks signer (signWithFB): ${err}`);
}
},
};
const fbTx = (await this.fireblocks.transactions.createTransaction({ transactionRequest: tx })).data;
return await this.waitForTxCompletion(fbTx);
}

/**
@@ -155,29 +148,25 @@ export class FireblocksSigner {
sendAmount = true,
note = '',
): Promise<TransactionResponse> {
try {
const txArgs: TransactionRequest = {
assetId: assetId,
operation: 'CONTRACT_CALL',
source: {
type: 'VAULT_ACCOUNT',
id: this.vaultId,
},
destination: {
type: 'EXTERNAL_WALLET',
id: destinationId,
},
amount: tx.amount_wei && sendAmount ? formatEther(BigInt(tx.amount_wei), 'wei') : '0',
note,
extraParameters: payloadToSign,
gasLimit: tx.gas_limit,
priorityFee: formatUnits(BigInt(tx.max_priority_fee_per_gas_wei), 9),
maxFee: formatUnits(BigInt(tx.max_fee_per_gas_wei), 9),
};
const fbTx = (await this.fireblocks.transactions.createTransaction({ transactionRequest: txArgs })).data;
return await this.waitForTxCompletion(fbTx);
} catch (err) {
throw new Error(`Fireblocks signer (signAndBroadcastWithFB): ${err}`);
}
const txArgs: TransactionRequest = {
assetId: assetId,
operation: 'CONTRACT_CALL',
source: {
type: 'VAULT_ACCOUNT',
id: this.vaultId,
},
destination: {
type: 'EXTERNAL_WALLET',
id: destinationId,
},
amount: tx.amount_wei && sendAmount ? formatEther(BigInt(tx.amount_wei), 'wei') : '0',
note,
extraParameters: payloadToSign,
gasLimit: tx.gas_limit,
priorityFee: formatUnits(BigInt(tx.max_priority_fee_per_gas_wei), 9),
maxFee: formatUnits(BigInt(tx.max_fee_per_gas_wei), 9),
};
const fbTx = (await this.fireblocks.transactions.createTransaction({ transactionRequest: txArgs })).data;
return await this.waitForTxCompletion(fbTx);
}
}
30 changes: 30 additions & 0 deletions src/validators.ts
Original file line number Diff line number Diff line change
@@ -65,4 +65,34 @@ export const KILN_VALIDATORS = {
KILN: 'zetavaloper1u9xeaqdjz3kky2ymdhdsn0ra5uy9tc3ep3yfhe',
},
},
KAVA: {
mainnet: {
KILN: 'kavavaloper1djqecw6nn5tydxq0shan7srv8j65clsf79myt8',
},
},
TIA: {
mainnet: {
KILN: 'celestiavaloper1djqecw6nn5tydxq0shan7srv8j65clsfmnxcfu',
},
},
DYDX: {
mainnet: {
KILN: 'dydxvaloper1u9xeaqdjz3kky2ymdhdsn0ra5uy9tc3elj2jte',
},
},
INJ: {
mainnet: {
KILN: 'injvaloper1rf0fczrw2gnhuju86kmjtku4dvf9dcc2mpe7pe',
},
},
OM: {
mainnet: {
KILN: 'mantravaloper146mj09yzu3mvz7pmy4dvs4z9wr2mst7ram37xw',
},
},
OSMO: {
mainnet: {
INTEROP: 'osmovaloper146mj09yzu3mvz7pmy4dvs4z9wr2mst7rq8p8gy',
},
},
};

0 comments on commit da62394

Please sign in to comment.