Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 93 additions & 0 deletions examples/sui.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import type { FireblocksIntegration } from '../src/fireblocks.ts';
import { KILN_VALIDATORS, Kiln, suiToMist } from '../src/kiln.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: 'SUI', vaultAccountId: vault.vaultId, limit: 1 })
).data.addresses?.[0].address;
if (!fireblocksWallet) {
console.log('Failed to get pubkey');
process.exit(0);
}

console.log(fireblocksWallet);

//
// Craft the transaction
//
console.log('Crafting transaction...');
console.log('params:', {
account_id: kilnAccountId,
sender: fireblocksWallet,
validator_address: KILN_VALIDATORS.SUI.mainnet.KILN,
amount_mist: suiToMist('1.1').toString(),
});
const txRequest = await k.client.POST('/sui/transaction/stake', {
body: {
account_id: kilnAccountId,
sender: fireblocksWallet,
validator_address: KILN_VALIDATORS.SUI.mainnet.KILN,
amount_mist: suiToMist('1.1').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');

//
// Sign the transaction
//
console.log('Signing transaction...');
const signRequest = await (async () => {
try {
return await k.fireblocks.signSuiTx(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('/sui/transaction/broadcast', {
body: {
tx_serialized: signRequest.signed_tx.data.tx_serialized,
serialized_signature: signRequest.signed_tx.data.serialized_signature,
},
});
if (broadcastedRequest.error) {
console.log('Failed to broadcast transaction:', broadcastedRequest);
process.exit(1);
} else {
console.log('Broadcasted transaction:', broadcastedRequest.data);
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@kilnfi/sdk",
"version": "4.2.16",
"version": "4.2.17",
"autor": "Kiln <support@kiln.fi> (https://kiln.fi)",
"license": "BUSL-1.1",
"description": "JavaScript sdk for Kiln API",
Expand Down
51 changes: 51 additions & 0 deletions src/fireblocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export type FireblocksIntegration = (
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.',
MISSING_PUBLIC_KEY: 'An error occurred while attempting to retrieve the public key from Fireblocks.',
};

export class FireblocksService {
Expand Down Expand Up @@ -1271,4 +1272,54 @@ export class FireblocksService {
fireblocks_tx: fbTx,
};
}

async signSuiTx(
integration: FireblocksIntegration,
tx: components['schemas']['SUITx'],
note?: string,
): Promise<{
signed_tx: { data: components['schemas']['SUIBroadcastTxPayload'] };
fireblocks_tx: TransactionResponse;
}> {
const payload = {
rawMessageData: {
messages: [
{
content: tx.unsigned_tx_hash.substring(2),
},
],
},
};

const fbSigner = this.getSigner(integration);
const fbNote = note ? note : 'SUI tx from @kilnfi/sdk';
const fbTx = await fbSigner.sign(payload, 'SUI', fbNote);
const signature = fbTx.signedMessages?.[0]?.signature?.fullSig;
const fbPubkey = fbTx.signedMessages?.[0]?.publicKey;

if (!signature) {
throw new Error(ERRORS.MISSING_SIGNATURE);
}

if (!fbPubkey) {
throw new Error(ERRORS.MISSING_PUBLIC_KEY);
}

const preparedTx = await this.client.POST('/sui/transaction/prepare', {
body: {
pubkey: fbPubkey,
signature: signature,
tx_serialized: tx.unsigned_tx_serialized,
},
});

if (preparedTx.error) {
throw new Error(ERRORS.FAILED_TO_PREPARE);
}

return {
signed_tx: preparedTx.data,
fireblocks_tx: fbTx,
};
}
}
3 changes: 2 additions & 1 deletion src/fireblocks_signer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ export type FireblocksAssetId =
| 'KAVA_KAVA'
| 'TRX'
| 'BTC'
| 'SEI';
| 'SEI'
| 'SUI';

export class FireblocksSigner {
constructor(
Expand Down
133 changes: 121 additions & 12 deletions src/openapi/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8414,6 +8414,26 @@ export interface paths {
patch?: never;
trace?: never;
};
"/sui/transaction/prepare": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
get?: never;
put?: never;
/**
* Prepare Transaction
* @description Prepare a transaction.
*/
post: operations["postSuiPrepareTx"];
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/sui/transaction/status": {
parameters: {
query?: never;
Expand Down Expand Up @@ -40004,16 +40024,6 @@ export interface components {
* @example 9020446847418
*/
net_rewards: string;
/**
* @description Total withdrawn rewards by this stake since its first ever delegation
* @example 9020446847418
*/
withdrawn_rewards: string;
/**
* @description Total withdrawable rewards by this stake
* @example 0
*/
withdrawable_rewards: string;
/**
* @description The amount of SUI currently staked
* @example 92908788559
Expand Down Expand Up @@ -40051,6 +40061,11 @@ export interface components {
* @example 2.02
*/
net_apy: number;
/**
* @description Stake Object ID involved in the operation
* @example 0x23f9f0342c9ee0c7e74df0dc6655d2ae672ae08fe12dc4ac2d604074687555a3
*/
stake_id: string;
};
SUIRewardByEpoch: {
/**
Expand Down Expand Up @@ -40305,6 +40320,20 @@ export interface components {
*/
digest: string;
};
SUIPrepareTx: {
/**
* Format: base64
* @description Serialized transaction as base64 encoded bcs
* @example AAACAAgAypo7AAAAAAAg2+ZDD9PphmfRs1A4Aba3bIThZOG+V+8OS/Pjq3kbI9YCAgABAQAAAQEDAAAAAAEBABsdj13zFOK3uKhs/ir/eMwbwKDsykcidGrlIiYx0U9vAjWzex7zdLfWq8gj/oP81sYt3UJzyo4bDhvRJ7E1R/tVd1fpIAAAAAAgfCKhipjlwhR0OghzVijOV+b+CFucrTVw1y6LK+g4dXUM4X57NnqLr5kjWC0veDHxiAJG0cKrkJDEubjYQ6JXundX6SAAAAAAICh1unSYqH9yQqaJuKEftzLEGT5rqV7wHUD16BMQcmLAGx2PXfMU4re4qGz+Kv94zBvAoOzKRyJ0auUiJjHRT2/oAwAAAAAAAECrPAAAAAAAAA==
*/
tx_serialized: string;
/**
* Format: base64
* @description Base64-encoded Sui serialized signature.
* @example AMQ2b2LwCWca7IK5hY1lnzkhRwb4nkYCTA3on08RpMEA6myGSgTWmBH2KDLZmaXzSXI<insert>VCNKrP3dCzBZvM3gRzTJq3RpEQpcj32BYljGTj4jFrXXGGPohME56ZK2MBDw==
*/
serialized_signature: string;
};
SUITxStatus: {
/**
* @description Transaction status
Expand Down Expand Up @@ -40396,15 +40425,34 @@ export interface components {
SUIBroadcastTxPayload: {
/**
* Format: base64
* @description Signed serialized transaction as base64 encoded bcs
* @description Serialized transaction as base64 encoded bcs
* @example AAACAAgAypo7AAAAAAAg2+ZDD9PphmfRs1A4Aba3bIThZOG+V+8OS/Pjq3kbI9YCAgABAQAAAQEDAAAAAAEBABsdj13zFOK3uKhs/ir/eMwbwKDsykcidGrlIiYx0U9vAjWzex7zdLfWq8gj/oP81sYt3UJzyo4bDhvRJ7E1R/tVd1fpIAAAAAAgfCKhipjlwhR0OghzVijOV+b+CFucrTVw1y6LK+g4dXUM4X57NnqLr5kjWC0veDHxiAJG0cKrkJDEubjYQ6JXundX6SAAAAAAICh1unSYqH9yQqaJuKEftzLEGT5rqV7wHUD16BMQcmLAGx2PXfMU4re4qGz+Kv94zBvAoOzKRyJ0auUiJjHRT2/oAwAAAAAAAECrPAAAAAAAAA==
*/
tx_serialized: string;
/**
* Format: base64
* @description Base64 encoded signature of the transaction
* @description Base64-encoded Sui serialized signature.
* @example AMQ2b2LwCWca7IK5hY1lnzkhRwb4nkYCTA3on08RpMEA6myGSgTWmBH2KDLZmaXzSXI+++VCNKrP3dCzBZvM3gRzTJq3RpEQpcj32BYljGTj4jFrXXGGPohME56ZK2MBDw==
*/
serialized_signature: string;
};
SUIPrepareTxPayload: {
/**
* @description Wallet public key, this is different than the wallet address
* @example 039ce47b2a813d13876131a9c3be77e8c4afa49e948744abbee11f939e2a420f46
*/
pubkey: string;
/**
* Format: base64
* @description Serialized transaction as base64 encoded bcs
* @example AAACAAgAypo7AAAAAAAg2+ZDD9PphmfRs1A4Aba3bIThZOG+V+8OS/Pjq3kbI9YCAgABAQAAAQEDAAAAAAEBABsdj13zFOK3uKhs/ir/eMwbwKDsykcidGrlIiYx0U9vAjWzex7zdLfWq8gj/oP81sYt3UJzyo4bDhvRJ7E1R/tVd1fpIAAAAAAgfCKhipjlwhR0OghzVijOV+b+CFucrTVw1y6LK+g4dXUM4X57NnqLr5kjWC0veDHxiAJG0cKrkJDEubjYQ6JXundX6SAAAAAAICh1unSYqH9yQqaJuKEftzLEGT5rqV7wHUD16BMQcmLAGx2PXfMU4re4qGz+Kv94zBvAoOzKRyJ0auUiJjHRT2/oAwAAAAAAAECrPAAAAAAAAA==
*/
tx_serialized: string;
/**
* Format: base64
* @description Hex-encoded raw signature bytes.
* @example a11afeea9af497fdae1caa2c02cf5f1b964251093ee7acd47a7193d991c64eefb3d9879a3fa3015f2003b0d61b95bdf9de1f5f155fac6be4bbe058cdcda4c60b
*/
signature: string;
};
SUIDecodeTxPayload: {
Expand Down Expand Up @@ -40506,6 +40554,11 @@ export interface components {
* @description Base64-encoded payload data of the operation
*/
data: string;
/**
* @description Stake Object ID involved in the operation
* @example 0x23f9f0342c9ee0c7e74df0dc6655d2ae672ae08fe12dc4ac2d604074687555a3
*/
stake_id: string;
};
SEIStake: {
/**
Expand Down Expand Up @@ -42668,6 +42721,8 @@ export interface components {
SUIDelegatorsParam: string[];
/** @description Comma-separated list of validator addresses */
SUIValidatorsParam: string[];
/** @description Comma-separated list of stake object ids */
SUIStakeIdsParam: string[];
/** @description Transaction hash */
SUITxHashParam: string;
/** @description Comma-separated list of validators addresses, these addresses
Expand Down Expand Up @@ -63775,6 +63830,8 @@ export interface operations {
delegators?: components["parameters"]["SUIDelegatorsParam"];
/** @description Comma-separated list of validator addresses */
validators?: components["parameters"]["SUIValidatorsParam"];
/** @description Comma-separated list of stake object ids */
stake_ids?: components["parameters"]["SUIStakeIdsParam"];
/** @description Comma-separated list of Kiln accounts identifiers */
accounts?: components["parameters"]["AccountsParam"];
};
Expand Down Expand Up @@ -63825,6 +63882,8 @@ export interface operations {
delegators?: components["parameters"]["SUIDelegatorsParam"];
/** @description Comma-separated list of validator addresses */
validators?: components["parameters"]["SUIValidatorsParam"];
/** @description Comma-separated list of stake object ids */
stake_ids?: components["parameters"]["SUIStakeIdsParam"];
/** @description The format of the response. Defaults to `daily` */
format?: components["parameters"]["SUIRewardsFormatParam"];
/** @description Comma-separated list of Kiln accounts identifiers */
Expand Down Expand Up @@ -63883,6 +63942,8 @@ export interface operations {
delegators?: components["parameters"]["SUIDelegatorsParam"];
/** @description Comma-separated list of validator addresses */
validators?: components["parameters"]["SUIValidatorsParam"];
/** @description Comma-separated list of stake object ids */
stake_ids?: components["parameters"]["SUIStakeIdsParam"];
/** @description Transaction hash */
tx_hash?: components["parameters"]["SUITxHashParam"];
/** @description Comma-separated list of Kiln accounts identifiers */
Expand Down Expand Up @@ -64256,6 +64317,54 @@ export interface operations {
};
};
};
postSuiPrepareTx: {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
/** @description Prepare a transaction on SUI. */
requestBody: {
content: {
"application/json; charset=utf-8": components["schemas"]["SUIPrepareTxPayload"];
};
};
responses: {
/** @description Successful operation */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json; charset=utf-8": {
data: components["schemas"]["SUIPrepareTx"];
};
};
};
/** @description Invalid parameters */
400: {
headers: {
[name: string]: unknown;
};
content?: never;
};
/** @description Unauthorized */
401: {
headers: {
[name: string]: unknown;
};
content?: never;
};
/** @description Internal server error */
500: {
headers: {
[name: string]: unknown;
};
content?: never;
};
};
};
getSuiTxStatus: {
parameters: {
query: {
Expand Down
Loading