Skip to content

Commit

Permalink
cleanup fireblocks signer (#100)
Browse files Browse the repository at this point in the history
* refacto fet FB signing

* refacto fet FB signing

* wip

* fix injective tx crafting

* nits
  • Loading branch information
nooxx authored Apr 26, 2024
1 parent fac5856 commit 82d635b
Show file tree
Hide file tree
Showing 16 changed files with 1,566 additions and 2,181 deletions.
3,619 changes: 1,501 additions & 2,118 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

69 changes: 38 additions & 31 deletions src/integrations/fb_signer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import {
CreateTransactionResponse,
FireblocksSDK,
PeerType,
SigningAlgorithm,
TransactionArguments,
TransactionOperation,
TransactionResponse,
Expand Down Expand Up @@ -47,7 +46,7 @@ export class FbSigner {

/**
* Wait for given transaction to be completed
* @param fbTx: fireblocks transaction
* @param fbTx fireblocks transaction
* @private
*/
protected async waitForTxCompletion(fbTx: CreateTransactionResponse): Promise<TransactionResponse> {
Expand Down Expand Up @@ -76,19 +75,25 @@ export class FbSigner {

/**
* Sign a transaction with fireblocks using Fireblocks raw message signing feature
* @param payloadToSign: transaction data in hexadecimal
* @param assetId: fireblocks asset id
* @param note: optional fireblocks custom note
* @param payloadToSign transaction data in hexadecimal
* @param assetId fireblocks asset id
* @param note optional fireblocks custom note
*/
public async signWithFB(payloadToSign: any, assetId: AssetId, note?: string): Promise<TransactionResponse> {
public async sign(payloadToSign: any, assetId?: AssetId, note?: string): Promise<TransactionResponse> {
try {
const assetArgs = assetId
? {
assetId,
source: {
type: PeerType.VAULT_ACCOUNT,
id: this.vaultId.toString(),
},
}
: {};

const tx: TransactionArguments = {
assetId: assetId,
...assetArgs,
operation: TransactionOperation.RAW,
source: {
type: PeerType.VAULT_ACCOUNT,
id: this.vaultId.toString(),
},
note,
extraParameters: payloadToSign,
};
Expand All @@ -101,52 +106,54 @@ export class FbSigner {
}

/**
* Sign a generic transaction with fireblocks using Fireblocks raw message signing feature.
* @param payloadToSign: transaction data in hexadecimal
* @param derivationPath: derivation path of the token to sign
* @param algorithm: algorithm of the token to sign
* @param note: optional fireblocks custom note
* Sign an EIP-712 Ethereum typed message with fireblocks
* @param eip712message eip712message to sign
* @param assetId fireblocks asset id
* @param note optional fireblocks custom note
*/
public async signGenericWithFB(
payloadContent: string,
derivationPath: number[],
algorithm: SigningAlgorithm,
public async signTypedMessage(
eip712message: any,
assetId: "ETH" | "ETH_TEST3" | "ETH_TEST6",
note?: string,
): Promise<TransactionResponse> {
try {
const payloadToSign = {
operation: TransactionOperation.RAW,
const tx: TransactionArguments = {
assetId: assetId,
operation: TransactionOperation.TYPED_MESSAGE,
source: {
type: PeerType.VAULT_ACCOUNT,
id: this.vaultId.toString(),
},
note,
extraParameters: {
rawMessageData: {
messages: [
{
content: payloadContent,
derivationPath,
content: eip712message,
type: "EIP712",
},
],
algorithm,
},
},
};
const fbTx = await this.fireblocks.createTransaction(payloadToSign);
const fbTx = await this.fireblocks.createTransaction(tx);
return await this.waitForTxCompletion(fbTx);
} catch (err: any) {
console.log(err);
throw new Error("Fireblocks signer (signGenericWithFB): " + err);
throw new Error("Fireblocks signer (signWithFB): " + err);
}
}

/**
* Sign and broadcast a transaction with fireblocks using Fireblocks contract call feature
* @param payloadToSign: transaction data in hexadecimal
* @param assetId: fireblocks asset id
* @param note: optional fireblocks custom note
* @param payloadToSign transaction data in hexadecimal
* @param assetId fireblocks asset id
* @param note optional fireblocks custom note
* @param tx Ethereum transaction
* @param destinationId Fireblocks destination id, this corresponds to the Fireblocks whitelisted contract address id
* @param sendAmount send the amount in tx to smart contract
*/
public async signAndBroadcastWithFB(
public async signAndBroadcastWith(
payloadToSign: any,
assetId: AssetId,
tx: EthTx | MaticTx,
Expand Down
2 changes: 1 addition & 1 deletion src/services/ada.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ export class AdaService extends Service {
};

const fbNote = note ? note : "ADA tx from @kilnfi/sdk";
const fbTx = await fbSigner.signWithFB(payload, this.testnet ? "ADA_TEST" : "ADA", fbNote);
const fbTx = await fbSigner.sign(payload, this.testnet ? "ADA_TEST" : "ADA", fbNote);

if (!fbTx.signedMessages) {
throw new Error(`Could not sign the transaction.`);
Expand Down
3 changes: 1 addition & 2 deletions src/services/atom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ export class AtomService extends Service {
/**
* Craft atom restake rewards transaction
* @param pubkey wallet pubkey, this is different from the wallet address
* @param validatorAccount validator account address (wallet controlling the validator)
* @param validatorAddress validator address to which the delegation has been made
*/
async craftRestakeRewardsTx(pubkey: string, validatorAddress: string): Promise<CosmosTx> {
Expand Down Expand Up @@ -131,7 +130,7 @@ export class AtomService extends Service {
};
const fbNote = note ? note : "ATOM tx from @kilnfi/sdk";
const signer = this.getFbSigner(integration);
const fbTx = await signer.signWithFB(payload, this.testnet ? "ATOM_COS_TEST" : "ATOM_COS", fbNote);
const fbTx = await signer.sign(payload, this.testnet ? "ATOM_COS_TEST" : "ATOM_COS", fbNote);
const signature: string = fbTx.signedMessages![0].signature.fullSig;
const { data } = await api.post<CosmosSignedTx>(`/v1/atom/transaction/prepare`, {
pubkey: tx.data.pubkey,
Expand Down
2 changes: 1 addition & 1 deletion src/services/dot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ export class DotService extends Service {

const fbSigner = this.getFbSigner(integration);
const fbNote = note ? note : "DOT tx from @kilnfi/sdk";
const fbTx = await fbSigner.signWithFB(payload, this.testnet ? "WND" : "DOT", fbNote);
const fbTx = await fbSigner.sign(payload, this.testnet ? "WND" : "DOT", fbNote);
const signature = `0x00${fbTx.signedMessages![0].signature.fullSig}`;

const { data } = await api.post<DotSignedTx>(`/v1/dot/transaction/prepare`, {
Expand Down
2 changes: 1 addition & 1 deletion src/services/dydx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ export class DydxService extends Service {
};
const fbNote = note ? note : "DYDX tx from @kilnfi/sdk";
const signer = this.getFbSigner(integration);
const fbTx = await signer.signWithFB(payload, "DYDX_DYDX", fbNote);
const fbTx = await signer.sign(payload, "DYDX_DYDX", fbNote);
const signature: string = fbTx.signedMessages![0].signature.fullSig;
const { data } = await api.post<CosmosSignedTx>(`/v1/dydx/transaction/prepare`, {
pubkey: tx.data.pubkey,
Expand Down
11 changes: 2 additions & 9 deletions src/services/eth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export class EthService extends Service {
const fbSigner = this.getFbSigner(integration);
const assetId = this.testnet ? "ETH_TEST6" : "ETH";
const fbNote = note ? note : "ETH tx from @kilnfi/sdk";
const fbTx = await fbSigner.signWithFB(payload, assetId, fbNote);
const fbTx = await fbSigner.sign(payload, assetId, fbNote);
const { data } = await api.post<EthSignedTx>(`/v1/eth/transaction/prepare`, {
unsigned_tx_serialized: tx.data.unsigned_tx_serialized,
r: `0x${fbTx?.signedMessages?.[0].signature.r}`,
Expand Down Expand Up @@ -98,14 +98,7 @@ export class EthService extends Service {
const fbSigner = this.getFbSigner(integration);
const assetId = this.testnet ? "ETH_TEST6" : "ETH";
const fbNote = note ? note : "ETH tx from @kilnfi/sdk";
return await fbSigner.signAndBroadcastWithFB(
payload,
assetId,
tx,
integration.fireblocksDestinationId,
true,
fbNote,
);
return await fbSigner.signAndBroadcastWith(payload, assetId, tx, integration.fireblocksDestinationId, true, fbNote);
}

/**
Expand Down
18 changes: 12 additions & 6 deletions src/services/fet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ export class FetService extends Service {
/**
* Craft fetch.ai restake rewards transaction
* @param pubkey wallet pubkey, this is different from the wallet address
* @param validatorAccount validator account address (wallet controlling the validator)
* @param validatorAddress validator address to which the delegation has been made
*/
async craftRestakeRewardsTx(pubkey: string, validatorAddress: string): Promise<CosmosTx> {
Expand Down Expand Up @@ -120,13 +119,20 @@ export class FetService extends Service {
* @param note note to identify the transaction in your custody solution
*/
async sign(integration: Integration, tx: CosmosTx, note?: string): Promise<CosmosSignedTx> {
const payloadContent = tx.data.unsigned_tx_hash;
const derivationPath = [44, 118, integration.vaultId, 0, 0];
const signingAlgorithm = SigningAlgorithm.MPC_ECDSA_SECP256K1;
const fbNote = note ? note : "FET tx from @kilnfi/sdk";

const signer = this.getFbSigner(integration);
const fbTx = await signer.signGenericWithFB(payloadContent, derivationPath, signingAlgorithm, fbNote);
const payload = {
rawMessageData: {
messages: [
{
content: tx.data.unsigned_tx_hash,
derivationPath: [44, 118, integration.vaultId, 0, 0],
},
],
algorithm: SigningAlgorithm.MPC_ECDSA_SECP256K1,
},
};
const fbTx = await signer.sign(payload, undefined, fbNote);
const signature: string = fbTx.signedMessages![0].signature.fullSig;
const { data } = await api.post<CosmosSignedTx>(`/v1/fet/transaction/prepare`, {
pubkey: tx.data.pubkey,
Expand Down
3 changes: 1 addition & 2 deletions src/services/inj.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ export class InjService extends Service {
/**
* Craft inj restake rewards transaction
* @param pubkey wallet pubkey, this is different from the wallet address
* @param validatorAccount validator account address (wallet controlling the validator)
* @param validatorAddress validator address to which the delegation has been made
*/
async craftRestakeRewardsTx(pubkey: string, validatorAddress: string): Promise<CosmosTx> {
Expand Down Expand Up @@ -130,7 +129,7 @@ export class InjService extends Service {
};
const fbNote = note ? note : "INJ tx from @kilnfi/sdk";
const signer = this.getFbSigner(integration);
const fbTx = await signer.signWithFB(payload, "INJ_INJ", fbNote);
const fbTx = await signer.sign(payload, "INJ_INJ", fbNote);
const signature: string = fbTx.signedMessages![0].signature.fullSig;
const { data } = await api.post<CosmosSignedTx>(`/v1/inj/transaction/prepare`, {
pubkey: tx.data.pubkey,
Expand Down
4 changes: 2 additions & 2 deletions src/services/matic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ export class MaticService extends Service {

const fbSigner = this.getFbSigner(integration);
const fbNote = note ? note : "MATIC tx from @kilnfi/sdk";
const fbTx = await fbSigner.signWithFB(payload, this.testnet ? "ETH_TEST3" : "ETH", fbNote);
const fbTx = await fbSigner.sign(payload, this.testnet ? "ETH_TEST3" : "ETH", fbNote);
const { data } = await api.post<MaticSignedTx>(`/v1/matic/transaction/prepare`, {
unsigned_tx_serialized: tx.data.unsigned_tx_serialized,
r: `0x${fbTx?.signedMessages?.[0].signature.r}`,
Expand Down Expand Up @@ -164,7 +164,7 @@ export class MaticService extends Service {
const fbSigner = this.getFbSigner(integration);
const fbNote = note ? note : "MATIC tx from @kilnfi/sdk";
const assetId = this.testnet ? "ETH_TEST3" : "ETH";
return await fbSigner.signAndBroadcastWithFB(
return await fbSigner.signAndBroadcastWith(
payload,
assetId,
tx,
Expand Down
2 changes: 1 addition & 1 deletion src/services/near.ts
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ export class NearService extends Service {

const fbSigner = this.getFbSigner(integration);
const fbNote = note ? note : "NEAR tx from @kilnfi/sdk";
const fbTx = await fbSigner.signWithFB(payload, this.testnet ? "NEAR_TEST" : "NEAR", fbNote);
const fbTx = await fbSigner.sign(payload, this.testnet ? "NEAR_TEST" : "NEAR", fbNote);
const signature = fbTx.signedMessages![0];

const signedTx = new transactions.SignedTransaction({
Expand Down
2 changes: 1 addition & 1 deletion src/services/noble.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ export class NobleService extends Service {
const fbNote = note ? note : "NOBLE tx from @kilnfi/sdk";
const signer = this.getFbSigner(integration);
// NOBLE chain is not supported by Fireblocks, so we use DYDX_DYDX
const fbTx = await signer.signWithFB(payload, "DYDX_DYDX", fbNote);
const fbTx = await signer.sign(payload, "DYDX_DYDX", fbNote);
const signature: string = fbTx.signedMessages![0].signature.fullSig;
const { data } = await api.post<CosmosSignedTx>(`/v1/noble/transaction/prepare`, {
pubkey: tx.data.pubkey,
Expand Down
3 changes: 1 addition & 2 deletions src/services/osmo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ export class OsmoService extends Service {
/**
* Craft osmo restake rewards transaction
* @param pubkey wallet pubkey, this is different from the wallet address
* @param validatorAccount validator account address (wallet controlling the validator)
* @param validatorAddress validator address to which the delegation has been made
*/
async craftRestakeRewardsTx(pubkey: string, validatorAddress: string): Promise<CosmosTx> {
Expand Down Expand Up @@ -131,7 +130,7 @@ export class OsmoService extends Service {
};
const fbNote = note ? note : "OSMO tx from @kilnfi/sdk";
const signer = this.getFbSigner(integration);
const fbTx = await signer.signWithFB(payload, "OSMO", fbNote);
const fbTx = await signer.sign(payload, "OSMO", fbNote);
const signature: string = fbTx.signedMessages![0].signature.fullSig;
const { data } = await api.post<CosmosSignedTx>(`/v1/osmo/transaction/prepare`, {
pubkey: tx.data.pubkey,
Expand Down
2 changes: 1 addition & 1 deletion src/services/sol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ export class SolService extends Service {

const fbSigner = this.getFbSigner(integration);
const fbNote = note ? note : "SOL tx from @kilnfi/sdk";
const fbTx = await fbSigner.signWithFB(payload, this.testnet ? "SOL_TEST" : "SOL", fbNote);
const fbTx = await fbSigner.sign(payload, this.testnet ? "SOL_TEST" : "SOL", fbNote);
const signatures: string[] = [];
fbTx.signedMessages?.forEach((signedMessage: any) => {
if (signedMessage.derivationPath[3] == 0) {
Expand Down
3 changes: 1 addition & 2 deletions src/services/tia.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ export class TiaService extends Service {
/**
* Craft tia restake rewards transaction
* @param pubkey wallet pubkey, this is different from the wallet address
* @param validatorAccount validator account address (wallet controlling the validator)
* @param validatorAddress validator address to which the delegation has been made
*/
async craftRestakeRewardsTx(pubkey: string, validatorAddress: string): Promise<CosmosTx> {
Expand Down Expand Up @@ -130,7 +129,7 @@ export class TiaService extends Service {
};
const fbNote = note ? note : "TIA tx from @kilnfi/sdk";
const signer = this.getFbSigner(integration);
const fbTx = await signer.signWithFB(payload, "CELESTIA", fbNote);
const fbTx = await signer.sign(payload, "CELESTIA", fbNote);
const signature: string = fbTx.signedMessages![0].signature.fullSig;
const { data } = await api.post<CosmosSignedTx>(`/v1/tia/transaction/prepare`, {
pubkey: tx.data.pubkey,
Expand Down
2 changes: 1 addition & 1 deletion src/services/xtz.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export class XtzService extends Service {

const fbSigner = this.getFbSigner(integration);
const fbNote = note ? note : "XTZ tx from @kilnfi/sdk";
const fbTx = await fbSigner.signWithFB(payload, this.testnet ? "XTZ_TEST" : "XTZ", fbNote);
const fbTx = await fbSigner.sign(payload, this.testnet ? "XTZ_TEST" : "XTZ", fbNote);
const signature: string = fbTx.signedMessages![0].signature.fullSig;
const { data } = await api.post<XtzSignedTx>(`/v1/xtz/transaction/prepare`, {
unsigned_tx_serialized: tx.data.unsigned_tx_serialized,
Expand Down

0 comments on commit 82d635b

Please sign in to comment.