Skip to content

Commit e602a03

Browse files
kiln-botmenefrego15
andcommitted
Update OpenAPI schema (#244)
* Update OpenAPI schema * Add SUI support for Fireblocks integration - Introduced a new example script for SUI transactions. - Added SUI to Fireblocks asset types. - Implemented SUI transaction signing and broadcasting in FireblocksService. - Added utility functions for converting SUI to mist and vice versa. - Updated KILN_VALIDATORS to include SUI mainnet validator address. * bump version --------- Co-authored-by: Kiln Bot <[email protected]> Co-authored-by: menefrego15 <[email protected]>
1 parent c9f9da0 commit e602a03

File tree

6 files changed

+286
-13
lines changed

6 files changed

+286
-13
lines changed

examples/sui.ts

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import type { FireblocksIntegration } from '../src/fireblocks.ts';
2+
import { KILN_VALIDATORS, Kiln, suiToMist } from '../src/kiln.ts';
3+
import { loadEnv } from './env.ts';
4+
5+
const { kilnApiKey, kilnAccountId, kilnApiUrl, fireblocksApiKey, fireblocksApiSecret, fireblocksVaultId } =
6+
await loadEnv();
7+
8+
const k = new Kiln({
9+
baseUrl: kilnApiUrl,
10+
apiToken: kilnApiKey,
11+
});
12+
13+
const vault: FireblocksIntegration = {
14+
config: {
15+
apiKey: fireblocksApiKey,
16+
secretKey: fireblocksApiSecret,
17+
basePath: 'https://api.fireblocks.io/v1',
18+
},
19+
vaultId: fireblocksVaultId,
20+
};
21+
22+
//
23+
// Get the pubkey from Fireblocks
24+
//
25+
const fireblocksWallet = (
26+
await k.fireblocks
27+
.getSdk(vault)
28+
.vaults.getVaultAccountAssetAddressesPaginated({ assetId: 'SUI', vaultAccountId: vault.vaultId, limit: 1 })
29+
).data.addresses?.[0].address;
30+
if (!fireblocksWallet) {
31+
console.log('Failed to get pubkey');
32+
process.exit(0);
33+
}
34+
35+
console.log(fireblocksWallet);
36+
37+
//
38+
// Craft the transaction
39+
//
40+
console.log('Crafting transaction...');
41+
console.log('params:', {
42+
account_id: kilnAccountId,
43+
sender: fireblocksWallet,
44+
validator_address: KILN_VALIDATORS.SUI.mainnet.KILN,
45+
amount_mist: suiToMist('1.1').toString(),
46+
});
47+
const txRequest = await k.client.POST('/sui/transaction/stake', {
48+
body: {
49+
account_id: kilnAccountId,
50+
sender: fireblocksWallet,
51+
validator_address: KILN_VALIDATORS.SUI.mainnet.KILN,
52+
amount_mist: suiToMist('1.1').toString(),
53+
},
54+
});
55+
if (txRequest.error) {
56+
console.log('Failed to craft transaction:', txRequest);
57+
process.exit(1);
58+
} else {
59+
console.log('Crafted transaction:', txRequest.data);
60+
}
61+
console.log('\n\n\n');
62+
63+
//
64+
// Sign the transaction
65+
//
66+
console.log('Signing transaction...');
67+
const signRequest = await (async () => {
68+
try {
69+
return await k.fireblocks.signSuiTx(vault, txRequest.data.data);
70+
} catch (err) {
71+
console.log('Failed to sign transaction:', err);
72+
process.exit(1);
73+
}
74+
})();
75+
console.log('Signed transaction:', signRequest);
76+
console.log('\n\n\n');
77+
78+
//
79+
// Broadcast the transaction
80+
//
81+
console.log('Broadcasting transaction...');
82+
const broadcastedRequest = await k.client.POST('/sui/transaction/broadcast', {
83+
body: {
84+
tx_serialized: signRequest.signed_tx.data.tx_serialized,
85+
serialized_signature: signRequest.signed_tx.data.serialized_signature,
86+
},
87+
});
88+
if (broadcastedRequest.error) {
89+
console.log('Failed to broadcast transaction:', broadcastedRequest);
90+
process.exit(1);
91+
} else {
92+
console.log('Broadcasted transaction:', broadcastedRequest.data);
93+
}

src/fireblocks.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export type FireblocksIntegration = (
2121
const ERRORS = {
2222
MISSING_SIGNATURE: 'An error occurred while attempting to retrieve the signature from Fireblocks.',
2323
FAILED_TO_PREPARE: 'An error occurred while attempting to add the signature to the transaction.',
24+
MISSING_PUBLIC_KEY: 'An error occurred while attempting to retrieve the public key from Fireblocks.',
2425
};
2526

2627
export class FireblocksService {
@@ -1271,4 +1272,54 @@ export class FireblocksService {
12711272
fireblocks_tx: fbTx,
12721273
};
12731274
}
1275+
1276+
async signSuiTx(
1277+
integration: FireblocksIntegration,
1278+
tx: components['schemas']['SUITx'],
1279+
note?: string,
1280+
): Promise<{
1281+
signed_tx: { data: components['schemas']['SUIBroadcastTxPayload'] };
1282+
fireblocks_tx: TransactionResponse;
1283+
}> {
1284+
const payload = {
1285+
rawMessageData: {
1286+
messages: [
1287+
{
1288+
content: tx.unsigned_tx_hash.substring(2),
1289+
},
1290+
],
1291+
},
1292+
};
1293+
1294+
const fbSigner = this.getSigner(integration);
1295+
const fbNote = note ? note : 'SUI tx from @kilnfi/sdk';
1296+
const fbTx = await fbSigner.sign(payload, 'SUI', fbNote);
1297+
const signature = fbTx.signedMessages?.[0]?.signature?.fullSig;
1298+
const fbPubkey = fbTx.signedMessages?.[0]?.publicKey;
1299+
1300+
if (!signature) {
1301+
throw new Error(ERRORS.MISSING_SIGNATURE);
1302+
}
1303+
1304+
if (!fbPubkey) {
1305+
throw new Error(ERRORS.MISSING_PUBLIC_KEY);
1306+
}
1307+
1308+
const preparedTx = await this.client.POST('/sui/transaction/prepare', {
1309+
body: {
1310+
pubkey: fbPubkey,
1311+
signature: signature,
1312+
tx_serialized: tx.unsigned_tx_serialized,
1313+
},
1314+
});
1315+
1316+
if (preparedTx.error) {
1317+
throw new Error(ERRORS.FAILED_TO_PREPARE);
1318+
}
1319+
1320+
return {
1321+
signed_tx: preparedTx.data,
1322+
fireblocks_tx: fbTx,
1323+
};
1324+
}
12741325
}

src/fireblocks_signer.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ export type FireblocksAssetId =
3636
| 'KAVA_KAVA'
3737
| 'TRX'
3838
| 'BTC'
39-
| 'SEI';
39+
| 'SEI'
40+
| 'SUI';
4041

4142
export class FireblocksSigner {
4243
constructor(

src/openapi/schema.ts

Lines changed: 121 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8434,6 +8434,26 @@ export interface paths {
84348434
patch?: never;
84358435
trace?: never;
84368436
};
8437+
"/sui/transaction/prepare": {
8438+
parameters: {
8439+
query?: never;
8440+
header?: never;
8441+
path?: never;
8442+
cookie?: never;
8443+
};
8444+
get?: never;
8445+
put?: never;
8446+
/**
8447+
* Prepare Transaction
8448+
* @description Prepare a transaction.
8449+
*/
8450+
post: operations["postSuiPrepareTx"];
8451+
delete?: never;
8452+
options?: never;
8453+
head?: never;
8454+
patch?: never;
8455+
trace?: never;
8456+
};
84378457
"/sui/transaction/status": {
84388458
parameters: {
84398459
query?: never;
@@ -40024,16 +40044,6 @@ export interface components {
4002440044
* @example 9020446847418
4002540045
*/
4002640046
net_rewards: string;
40027-
/**
40028-
* @description Total withdrawn rewards by this stake since its first ever delegation
40029-
* @example 9020446847418
40030-
*/
40031-
withdrawn_rewards: string;
40032-
/**
40033-
* @description Total withdrawable rewards by this stake
40034-
* @example 0
40035-
*/
40036-
withdrawable_rewards: string;
4003740047
/**
4003840048
* @description The amount of SUI currently staked
4003940049
* @example 92908788559
@@ -40071,6 +40081,11 @@ export interface components {
4007140081
* @example 2.02
4007240082
*/
4007340083
net_apy: number;
40084+
/**
40085+
* @description Stake Object ID involved in the operation
40086+
* @example 0x23f9f0342c9ee0c7e74df0dc6655d2ae672ae08fe12dc4ac2d604074687555a3
40087+
*/
40088+
stake_id: string;
4007440089
};
4007540090
SUIRewardByEpoch: {
4007640091
/**
@@ -40329,6 +40344,20 @@ export interface components {
4032940344
*/
4033040345
digest: string;
4033140346
};
40347+
SUIPrepareTx: {
40348+
/**
40349+
* Format: base64
40350+
* @description Serialized transaction as base64 encoded bcs
40351+
* @example AAACAAgAypo7AAAAAAAg2+ZDD9PphmfRs1A4Aba3bIThZOG+V+8OS/Pjq3kbI9YCAgABAQAAAQEDAAAAAAEBABsdj13zFOK3uKhs/ir/eMwbwKDsykcidGrlIiYx0U9vAjWzex7zdLfWq8gj/oP81sYt3UJzyo4bDhvRJ7E1R/tVd1fpIAAAAAAgfCKhipjlwhR0OghzVijOV+b+CFucrTVw1y6LK+g4dXUM4X57NnqLr5kjWC0veDHxiAJG0cKrkJDEubjYQ6JXundX6SAAAAAAICh1unSYqH9yQqaJuKEftzLEGT5rqV7wHUD16BMQcmLAGx2PXfMU4re4qGz+Kv94zBvAoOzKRyJ0auUiJjHRT2/oAwAAAAAAAECrPAAAAAAAAA==
40352+
*/
40353+
tx_serialized: string;
40354+
/**
40355+
* Format: base64
40356+
* @description Base64-encoded Sui serialized signature.
40357+
* @example AMQ2b2LwCWca7IK5hY1lnzkhRwb4nkYCTA3on08RpMEA6myGSgTWmBH2KDLZmaXzSXI<insert>VCNKrP3dCzBZvM3gRzTJq3RpEQpcj32BYljGTj4jFrXXGGPohME56ZK2MBDw==
40358+
*/
40359+
serialized_signature: string;
40360+
};
4033240361
SUITxStatus: {
4033340362
/**
4033440363
* @description Transaction status
@@ -40420,15 +40449,34 @@ export interface components {
4042040449
SUIBroadcastTxPayload: {
4042140450
/**
4042240451
* Format: base64
40423-
* @description Signed serialized transaction as base64 encoded bcs
40452+
* @description Serialized transaction as base64 encoded bcs
4042440453
* @example AAACAAgAypo7AAAAAAAg2+ZDD9PphmfRs1A4Aba3bIThZOG+V+8OS/Pjq3kbI9YCAgABAQAAAQEDAAAAAAEBABsdj13zFOK3uKhs/ir/eMwbwKDsykcidGrlIiYx0U9vAjWzex7zdLfWq8gj/oP81sYt3UJzyo4bDhvRJ7E1R/tVd1fpIAAAAAAgfCKhipjlwhR0OghzVijOV+b+CFucrTVw1y6LK+g4dXUM4X57NnqLr5kjWC0veDHxiAJG0cKrkJDEubjYQ6JXundX6SAAAAAAICh1unSYqH9yQqaJuKEftzLEGT5rqV7wHUD16BMQcmLAGx2PXfMU4re4qGz+Kv94zBvAoOzKRyJ0auUiJjHRT2/oAwAAAAAAAECrPAAAAAAAAA==
4042540454
*/
4042640455
tx_serialized: string;
4042740456
/**
4042840457
* Format: base64
40429-
* @description Base64 encoded signature of the transaction
40458+
* @description Base64-encoded Sui serialized signature.
4043040459
* @example AMQ2b2LwCWca7IK5hY1lnzkhRwb4nkYCTA3on08RpMEA6myGSgTWmBH2KDLZmaXzSXI+++VCNKrP3dCzBZvM3gRzTJq3RpEQpcj32BYljGTj4jFrXXGGPohME56ZK2MBDw==
4043140460
*/
40461+
serialized_signature: string;
40462+
};
40463+
SUIPrepareTxPayload: {
40464+
/**
40465+
* @description Wallet public key, this is different than the wallet address
40466+
* @example 039ce47b2a813d13876131a9c3be77e8c4afa49e948744abbee11f939e2a420f46
40467+
*/
40468+
pubkey: string;
40469+
/**
40470+
* Format: base64
40471+
* @description Serialized transaction as base64 encoded bcs
40472+
* @example AAACAAgAypo7AAAAAAAg2+ZDD9PphmfRs1A4Aba3bIThZOG+V+8OS/Pjq3kbI9YCAgABAQAAAQEDAAAAAAEBABsdj13zFOK3uKhs/ir/eMwbwKDsykcidGrlIiYx0U9vAjWzex7zdLfWq8gj/oP81sYt3UJzyo4bDhvRJ7E1R/tVd1fpIAAAAAAgfCKhipjlwhR0OghzVijOV+b+CFucrTVw1y6LK+g4dXUM4X57NnqLr5kjWC0veDHxiAJG0cKrkJDEubjYQ6JXundX6SAAAAAAICh1unSYqH9yQqaJuKEftzLEGT5rqV7wHUD16BMQcmLAGx2PXfMU4re4qGz+Kv94zBvAoOzKRyJ0auUiJjHRT2/oAwAAAAAAAECrPAAAAAAAAA==
40473+
*/
40474+
tx_serialized: string;
40475+
/**
40476+
* Format: base64
40477+
* @description Hex-encoded raw signature bytes.
40478+
* @example a11afeea9af497fdae1caa2c02cf5f1b964251093ee7acd47a7193d991c64eefb3d9879a3fa3015f2003b0d61b95bdf9de1f5f155fac6be4bbe058cdcda4c60b
40479+
*/
4043240480
signature: string;
4043340481
};
4043440482
SUIDecodeTxPayload: {
@@ -40530,6 +40578,11 @@ export interface components {
4053040578
* @description Base64-encoded payload data of the operation
4053140579
*/
4053240580
data: string;
40581+
/**
40582+
* @description Stake Object ID involved in the operation
40583+
* @example 0x23f9f0342c9ee0c7e74df0dc6655d2ae672ae08fe12dc4ac2d604074687555a3
40584+
*/
40585+
stake_id: string;
4053340586
};
4053440587
SEIStake: {
4053540588
/**
@@ -42692,6 +42745,8 @@ export interface components {
4269242745
SUIDelegatorsParam: string[];
4269342746
/** @description Comma-separated list of validator addresses */
4269442747
SUIValidatorsParam: string[];
42748+
/** @description Comma-separated list of stake object ids */
42749+
SUIStakeIdsParam: string[];
4269542750
/** @description Transaction hash */
4269642751
SUITxHashParam: string;
4269742752
/** @description Comma-separated list of validators addresses, these addresses
@@ -63799,6 +63854,8 @@ export interface operations {
6379963854
delegators?: components["parameters"]["SUIDelegatorsParam"];
6380063855
/** @description Comma-separated list of validator addresses */
6380163856
validators?: components["parameters"]["SUIValidatorsParam"];
63857+
/** @description Comma-separated list of stake object ids */
63858+
stake_ids?: components["parameters"]["SUIStakeIdsParam"];
6380263859
/** @description Comma-separated list of Kiln accounts identifiers */
6380363860
accounts?: components["parameters"]["AccountsParam"];
6380463861
};
@@ -63849,6 +63906,8 @@ export interface operations {
6384963906
delegators?: components["parameters"]["SUIDelegatorsParam"];
6385063907
/** @description Comma-separated list of validator addresses */
6385163908
validators?: components["parameters"]["SUIValidatorsParam"];
63909+
/** @description Comma-separated list of stake object ids */
63910+
stake_ids?: components["parameters"]["SUIStakeIdsParam"];
6385263911
/** @description The format of the response. Defaults to `daily` */
6385363912
format?: components["parameters"]["SUIRewardsFormatParam"];
6385463913
/** @description Comma-separated list of Kiln accounts identifiers */
@@ -63957,6 +64016,8 @@ export interface operations {
6395764016
delegators?: components["parameters"]["SUIDelegatorsParam"];
6395864017
/** @description Comma-separated list of validator addresses */
6395964018
validators?: components["parameters"]["SUIValidatorsParam"];
64019+
/** @description Comma-separated list of stake object ids */
64020+
stake_ids?: components["parameters"]["SUIStakeIdsParam"];
6396064021
/** @description Transaction hash */
6396164022
tx_hash?: components["parameters"]["SUITxHashParam"];
6396264023
/** @description Comma-separated list of Kiln accounts identifiers */
@@ -64330,6 +64391,54 @@ export interface operations {
6433064391
};
6433164392
};
6433264393
};
64394+
postSuiPrepareTx: {
64395+
parameters: {
64396+
query?: never;
64397+
header?: never;
64398+
path?: never;
64399+
cookie?: never;
64400+
};
64401+
/** @description Prepare a transaction on SUI. */
64402+
requestBody: {
64403+
content: {
64404+
"application/json; charset=utf-8": components["schemas"]["SUIPrepareTxPayload"];
64405+
};
64406+
};
64407+
responses: {
64408+
/** @description Successful operation */
64409+
200: {
64410+
headers: {
64411+
[name: string]: unknown;
64412+
};
64413+
content: {
64414+
"application/json; charset=utf-8": {
64415+
data: components["schemas"]["SUIPrepareTx"];
64416+
};
64417+
};
64418+
};
64419+
/** @description Invalid parameters */
64420+
400: {
64421+
headers: {
64422+
[name: string]: unknown;
64423+
};
64424+
content?: never;
64425+
};
64426+
/** @description Unauthorized */
64427+
401: {
64428+
headers: {
64429+
[name: string]: unknown;
64430+
};
64431+
content?: never;
64432+
};
64433+
/** @description Internal server error */
64434+
500: {
64435+
headers: {
64436+
[name: string]: unknown;
64437+
};
64438+
content?: never;
64439+
};
64440+
};
64441+
};
6433364442
getSuiTxStatus: {
6433464443
parameters: {
6433564444
query: {

0 commit comments

Comments
 (0)