diff --git a/README.md b/README.md index d110129..51ff12d 100644 --- a/README.md +++ b/README.md @@ -10,13 +10,14 @@ Check out the [full documentation](https://docs.kiln.fi/v1/connect/overview). - ADA - ATOM - DOT +- DYDX - ETH - MATIC - NEAR +- OSMO - SOL +- TIA - XTZ -- OSMO -- DYDX - More protocol to come, don't hesitate to contact us (support@kiln.fi) ## Installation diff --git a/package.json b/package.json index dc71a16..f3c1e66 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@kilnfi/sdk", - "version": "2.9.0", + "version": "2.10.0", "autor": "Kiln (https://kiln.fi)", "license": "BUSL-1.1", "description": "JavaScript sdk for Kiln API", diff --git a/src/integrations/fb_signer.ts b/src/integrations/fb_signer.ts index 09334e4..1d01380 100644 --- a/src/integrations/fb_signer.ts +++ b/src/integrations/fb_signer.ts @@ -32,6 +32,7 @@ type AssetId = | 'DOT' | 'DV4TNT_TEST' | 'DYDX_DYDX' + | 'CELESTIA' ; export class FbSigner { diff --git a/src/kiln.ts b/src/kiln.ts index 5d93936..328f4c9 100644 --- a/src/kiln.ts +++ b/src/kiln.ts @@ -12,6 +12,7 @@ import { MaticService } from './services/matic'; import { OsmoService } from './services/osmo'; import { FireblocksService } from "./services/fireblocks"; import { DydxService } from "./services/dydx"; +import { TiaService } from "./services/tia"; type Config = { apiToken: string; @@ -34,6 +35,7 @@ export class Kiln { matic: MaticService; osmo: OsmoService; dydx: DydxService; + tia: TiaService; constructor({ testnet, apiToken, baseUrl }: Config) { api.defaults.headers.common.Authorization = `Bearer ${apiToken}`; @@ -55,5 +57,6 @@ export class Kiln { this.matic = new MaticService({ testnet }); this.osmo = new OsmoService({ testnet }); this.dydx = new DydxService({ testnet }); + this.tia = new TiaService({ testnet }); } } \ No newline at end of file diff --git a/src/services/atom.ts b/src/services/atom.ts index 595cd9f..ce3a0da 100644 --- a/src/services/atom.ts +++ b/src/services/atom.ts @@ -1,10 +1,11 @@ import { Service } from "./service"; -import { AtomRewards, AtomSignedTx, AtomStakes, AtomTx, AtomTxHash, AtomTxStatus } from "../types/atom"; +import { AtomRewards, AtomStakes } from "../types/atom"; import { ServiceProps } from "../types/service"; import { Integration } from "../types/integrations"; import api from "../api"; import { DecodedTxRaw } from "@cosmjs/proto-signing"; +import { CosmosSignedTx, CosmosTx, CosmosTxHash, CosmosTxStatus } from "../types/cosmos"; export class AtomService extends Service { @@ -32,9 +33,9 @@ export class AtomService extends Service { pubkey: string, validatorAddress: string, amountAtom: number, - ): Promise { + ): Promise { try { - const { data } = await api.post( + const { data } = await api.post( `/v1/atom/transaction/stake`, { account_id: accountId, @@ -56,9 +57,9 @@ export class AtomService extends Service { async craftWithdrawRewardsTx( pubkey: string, validatorAddress: string, - ): Promise { + ): Promise { try { - const { data } = await api.post( + const { data } = await api.post( `/v1/atom/transaction/withdraw-rewards`, { pubkey: pubkey, @@ -80,9 +81,9 @@ export class AtomService extends Service { pubkey: string, validatorAddress: string, amountAtom?: number, - ): Promise { + ): Promise { try { - const { data } = await api.post( + const { data } = await api.post( `/v1/atom/transaction/unstake`, { pubkey: pubkey, @@ -109,9 +110,9 @@ export class AtomService extends Service { validatorSourceAddress: string, validatorDestinationAddress: string, amountAtom?: number, - ): Promise { + ): Promise { try { - const { data } = await api.post( + const { data } = await api.post( `/v1/atom/transaction/redelegate`, { account_id: accountId, @@ -132,7 +133,7 @@ export class AtomService extends Service { * @param tx raw transaction * @param note note to identify the transaction in your custody solution */ - async sign(integration: Integration, tx: AtomTx, note?: string): Promise { + async sign(integration: Integration, tx: CosmosTx, note?: string): Promise { const payload = { rawMessageData: { messages: [ @@ -146,7 +147,7 @@ export class AtomService extends Service { const signer = this.getFbSigner(integration); const fbTx = await signer.signWithFB(payload, this.testnet ? 'ATOM_COS_TEST' : 'ATOM_COS', fbNote); const signature: string = fbTx.signedMessages![0].signature.fullSig; - const { data } = await api.post( + const { data } = await api.post( `/v1/atom/transaction/prepare`, { pubkey: tx.data.pubkey, @@ -163,9 +164,9 @@ export class AtomService extends Service { * Broadcast transaction to the network * @param signedTx */ - async broadcast(signedTx: AtomSignedTx): Promise { + async broadcast(signedTx: CosmosSignedTx): Promise { try { - const { data } = await api.post( + const { data } = await api.post( `/v1/atom/transaction/broadcast`, { tx_serialized: signedTx.data.signed_tx_serialized, @@ -180,9 +181,9 @@ export class AtomService extends Service { * Get transaction status * @param txHash */ - async getTxStatus(txHash: string): Promise { + async getTxStatus(txHash: string): Promise { try { - const { data } = await api.get( + const { data } = await api.get( `/v1/atom/transaction/status?tx_hash=${txHash}`); return data; } catch (e: any) { diff --git a/src/services/dydx.ts b/src/services/dydx.ts index 8209c99..ca2ba8d 100644 --- a/src/services/dydx.ts +++ b/src/services/dydx.ts @@ -4,7 +4,7 @@ import { ServiceProps } from '../types/service'; import { Integration } from '../types/integrations'; import api from '../api'; import { DecodedTxRaw } from "@cosmjs/proto-signing"; -import { DydxSignedTx, DydxTxHash, DydxTxStatus, DydxTx } from "../types/dydx"; +import { CosmosSignedTx, CosmosTx, CosmosTxHash, CosmosTxStatus } from "../types/cosmos"; export class DydxService extends Service { @@ -32,9 +32,9 @@ export class DydxService extends Service { pubkey: string, validatorAddress: string, amountDydx: number, - ): Promise { + ): Promise { try { - const { data } = await api.post( + const { data } = await api.post( `/v1/dydx/transaction/stake`, { account_id: accountId, @@ -56,9 +56,9 @@ export class DydxService extends Service { async craftWithdrawRewardsTx( pubkey: string, validatorAddress: string, - ): Promise { + ): Promise { try { - const { data } = await api.post( + const { data } = await api.post( `/v1/dydx/transaction/withdraw-rewards`, { pubkey: pubkey, @@ -80,9 +80,9 @@ export class DydxService extends Service { pubkey: string, validatorAddress: string, amountDydx?: number, - ): Promise { + ): Promise { try { - const { data } = await api.post( + const { data } = await api.post( `/v1/dydx/transaction/unstake`, { pubkey: pubkey, @@ -109,9 +109,9 @@ export class DydxService extends Service { validatorSourceAddress: string, validatorDestinationAddress: string, amountDydx?: number, - ): Promise { + ): Promise { try { - const { data } = await api.post( + const { data } = await api.post( `/v1/dydx/transaction/redelegate`, { account_id: accountId, @@ -132,7 +132,7 @@ export class DydxService extends Service { * @param tx raw transaction * @param note note to identify the transaction in your custody solution */ - async sign(integration: Integration, tx: DydxTx, note?: string): Promise { + async sign(integration: Integration, tx: CosmosTx, note?: string): Promise { const payload = { rawMessageData: { messages: [ @@ -146,7 +146,7 @@ export class DydxService extends Service { const signer = this.getFbSigner(integration); const fbTx = await signer.signWithFB(payload, this.testnet ? 'DV4TNT_TEST' : 'DYDX_DYDX', fbNote); const signature: string = fbTx.signedMessages![0].signature.fullSig; - const { data } = await api.post( + const { data } = await api.post( `/v1/dydx/transaction/prepare`, { pubkey: tx.data.pubkey, @@ -163,9 +163,9 @@ export class DydxService extends Service { * Broadcast transaction to the network * @param signedTx */ - async broadcast(signedTx: DydxSignedTx): Promise { + async broadcast(signedTx: CosmosSignedTx): Promise { try { - const { data } = await api.post( + const { data } = await api.post( `/v1/dydx/transaction/broadcast`, { tx_serialized: signedTx.data.signed_tx_serialized, @@ -180,9 +180,9 @@ export class DydxService extends Service { * Get transaction status * @param txHash */ - async getTxStatus(txHash: string): Promise { + async getTxStatus(txHash: string): Promise { try { - const { data } = await api.get( + const { data } = await api.get( `/v1/dydx/transaction/status?tx_hash=${txHash}`); return data; } catch (e: any) { diff --git a/src/services/fireblocks.ts b/src/services/fireblocks.ts index c3a9a3b..1019441 100644 --- a/src/services/fireblocks.ts +++ b/src/services/fireblocks.ts @@ -1,6 +1,6 @@ import { Integration } from "../types/integrations"; import { Service } from "./service"; -import { PublicKeyResponse } from "fireblocks-sdk"; +import { AssetTypeResponse, PublicKeyResponse } from "fireblocks-sdk"; export class FireblocksService extends Service { @@ -20,4 +20,9 @@ export class FireblocksService extends Service { }); return data; } + + async getAssets(integration: Integration): Promise { + const fbSdk = this.getFbSdk(integration); + return await fbSdk.getSupportedAssets(); + } } \ No newline at end of file diff --git a/src/services/osmo.ts b/src/services/osmo.ts index 6f5d038..0a6bd96 100644 --- a/src/services/osmo.ts +++ b/src/services/osmo.ts @@ -2,16 +2,13 @@ import { Service } from './service'; import { OsmoRewards, - OsmoSignedTx, OsmoStakes, - OsmoTx, - OsmoTxHash, - OsmoTxStatus, } from '../types/osmo'; import { ServiceProps } from '../types/service'; import { Integration } from '../types/integrations'; import api from '../api'; import { DecodedTxRaw } from "@cosmjs/proto-signing"; +import { CosmosSignedTx, CosmosTx, CosmosTxHash, CosmosTxStatus } from "../types/cosmos"; export class OsmoService extends Service { @@ -39,9 +36,9 @@ export class OsmoService extends Service { pubkey: string, validatorAddress: string, amountOsmo: number, - ): Promise { + ): Promise { try { - const { data } = await api.post( + const { data } = await api.post( `/v1/osmo/transaction/stake`, { account_id: accountId, @@ -63,9 +60,9 @@ export class OsmoService extends Service { async craftWithdrawRewardsTx( pubkey: string, validatorAddress: string, - ): Promise { + ): Promise { try { - const { data } = await api.post( + const { data } = await api.post( `/v1/osmo/transaction/withdraw-rewards`, { pubkey: pubkey, @@ -87,9 +84,9 @@ export class OsmoService extends Service { pubkey: string, validatorAddress: string, amountOsmo?: number, - ): Promise { + ): Promise { try { - const { data } = await api.post( + const { data } = await api.post( `/v1/osmo/transaction/unstake`, { pubkey: pubkey, @@ -116,9 +113,9 @@ export class OsmoService extends Service { validatorSourceAddress: string, validatorDestinationAddress: string, amountOsmo?: number, - ): Promise { + ): Promise { try { - const { data } = await api.post( + const { data } = await api.post( `/v1/osmo/transaction/redelegate`, { account_id: accountId, @@ -139,7 +136,7 @@ export class OsmoService extends Service { * @param tx raw transaction * @param note note to identify the transaction in your custody solution */ - async sign(integration: Integration, tx: OsmoTx, note?: string): Promise { + async sign(integration: Integration, tx: CosmosTx, note?: string): Promise { const payload = { rawMessageData: { messages: [ @@ -153,7 +150,7 @@ export class OsmoService extends Service { const signer = this.getFbSigner(integration); const fbTx = await signer.signWithFB(payload, this.testnet ? 'OSMO_TEST' : 'OSMO', fbNote); const signature: string = fbTx.signedMessages![0].signature.fullSig; - const { data } = await api.post( + const { data } = await api.post( `/v1/osmo/transaction/prepare`, { pubkey: tx.data.pubkey, @@ -170,9 +167,9 @@ export class OsmoService extends Service { * Broadcast transaction to the network * @param signedTx */ - async broadcast(signedTx: OsmoSignedTx): Promise { + async broadcast(signedTx: CosmosSignedTx): Promise { try { - const { data } = await api.post( + const { data } = await api.post( `/v1/osmo/transaction/broadcast`, { tx_serialized: signedTx.data.signed_tx_serialized, @@ -187,9 +184,9 @@ export class OsmoService extends Service { * Get transaction status * @param txHash */ - async getTxStatus(txHash: string): Promise { + async getTxStatus(txHash: string): Promise { try { - const { data } = await api.get( + const { data } = await api.get( `/v1/osmo/transaction/status?tx_hash=${txHash}`); return data; } catch (e: any) { diff --git a/src/services/tia.ts b/src/services/tia.ts new file mode 100644 index 0000000..4a4c0d5 --- /dev/null +++ b/src/services/tia.ts @@ -0,0 +1,206 @@ +import { Service } from './service'; + +import { ServiceProps } from '../types/service'; +import { Integration } from '../types/integrations'; +import api from '../api'; +import { DecodedTxRaw } from "@cosmjs/proto-signing"; +import { CosmosSignedTx, CosmosTx, CosmosTxHash, CosmosTxStatus } from "../types/cosmos"; + +export class TiaService extends Service { + + constructor({ testnet }: ServiceProps) { + super({ testnet }); + } + + /** + * Convert TIA to uTIA + * @param amountTia + */ + tiaToUtia(amountTia: string): string { + return (parseFloat(amountTia) * 10 ** 6).toFixed(); + } + + /** + * Craft tia staking transaction + * @param accountId id of the kiln account to use for the stake transaction + * @param pubkey wallet pubkey, this is different from the wallet address + * @param validatorAddress validator address to delegate to + * @param amountTia how many tokens to stake in TIA + */ + async craftStakeTx( + accountId: string, + pubkey: string, + validatorAddress: string, + amountTia: number, + ): Promise { + try { + const { data } = await api.post( + `/v1/tia/transaction/stake`, + { + account_id: accountId, + pubkey: pubkey, + validator: validatorAddress, + amount_utia: this.tiaToUtia(amountTia.toString()), + }); + return data; + } catch (err: any) { + throw new Error(err); + } + } + + /** + * Craft tia withdraw rewards transaction + * @param pubkey wallet pubkey, this is different from the wallet address + * @param validatorAddress validator address to which the delegation has been made + */ + async craftWithdrawRewardsTx( + pubkey: string, + validatorAddress: string, + ): Promise { + try { + const { data } = await api.post( + `/v1/tia/transaction/withdraw-rewards`, + { + pubkey: pubkey, + validator: validatorAddress, + }); + return data; + } catch (err: any) { + throw new Error(err); + } + } + + /** + * Craft tia unstaking transaction + * @param pubkey wallet pubkey, this is different from the wallet address + * @param validatorAddress validator address to which the delegation has been made + * @param amountTia how many tokens to undelegate in TIA + */ + async craftUnstakeTx( + pubkey: string, + validatorAddress: string, + amountTia?: number, + ): Promise { + try { + const { data } = await api.post( + `/v1/tia/transaction/unstake`, + { + pubkey: pubkey, + validator: validatorAddress, + amount_utia: amountTia ? this.tiaToUtia(amountTia.toString()) : undefined, + }); + return data; + } catch (err: any) { + throw new Error(err); + } + } + + /** + * Craft tia redelegate transaction + * @param accountId id of the kiln account to use for the new stake + * @param pubkey wallet pubkey, this is different from the wallet address + * @param validatorSourceAddress validator address of the current delegation + * @param validatorDestinationAddress validator address to which the delegation will be moved + * @param amountTia how many tokens to redelegate in TIA + */ + async craftRedelegateTx( + accountId: string, + pubkey: string, + validatorSourceAddress: string, + validatorDestinationAddress: string, + amountTia?: number, + ): Promise { + try { + const { data } = await api.post( + `/v1/tia/transaction/redelegate`, + { + account_id: accountId, + pubkey: pubkey, + validator_source: validatorSourceAddress, + validator_destination: validatorDestinationAddress, + amount_utia: amountTia ? this.tiaToUtia(amountTia.toString()) : undefined, + }); + return data; + } catch (err: any) { + throw new Error(err); + } + } + + /** + * Sign transaction with given integration + * @param integration custody solution to sign with + * @param tx raw transaction + * @param note note to identify the transaction in your custody solution + */ + async sign(integration: Integration, tx: CosmosTx, note?: string): Promise { + const payload = { + rawMessageData: { + messages: [ + { + 'content': tx.data.unsigned_tx_hash, + }, + ], + }, + }; + const fbNote = note ? note : 'TIA tx from @kilnfi/sdk'; + const signer = this.getFbSigner(integration); + const fbTx = await signer.signWithFB(payload, 'CELESTIA', fbNote); + const signature: string = fbTx.signedMessages![0].signature.fullSig; + const { data } = await api.post( + `/v1/tia/transaction/prepare`, + { + pubkey: tx.data.pubkey, + tx_body: tx.data.tx_body, + tx_auth_info: tx.data.tx_auth_info, + signature: signature, + }); + data.data.fireblocks_tx = fbTx; + return data; + } + + + /** + * Broadcast transaction to the network + * @param signedTx + */ + async broadcast(signedTx: CosmosSignedTx): Promise { + try { + const { data } = await api.post( + `/v1/tia/transaction/broadcast`, + { + tx_serialized: signedTx.data.signed_tx_serialized, + }); + return data; + } catch (e: any) { + throw new Error(e); + } + } + + /** + * Get transaction status + * @param txHash + */ + async getTxStatus(txHash: string): Promise { + try { + const { data } = await api.get( + `/v1/tia/transaction/status?tx_hash=${txHash}`); + return data; + } catch (e: any) { + throw new Error(e); + } + } + + /** + * Decode transaction + * @param txSerialized transaction serialized + */ + async decodeTx(txSerialized: string): Promise { + try { + const { data } = await api.get( + `/v1/tia/transaction/decode?tx_serialized=${txSerialized}`); + return data; + } catch (error: any) { + throw new Error(error); + } + } +} diff --git a/src/types/atom.ts b/src/types/atom.ts index 73c7497..7838927 100644 --- a/src/types/atom.ts +++ b/src/types/atom.ts @@ -1,39 +1,3 @@ -import { IndexedTx, StdFee } from "@cosmjs/stargate"; -import { EncodeObject } from "@cosmjs/proto-signing"; -import { TransactionResponse } from "fireblocks-sdk"; - -export type AtomTx = { - data: { - unsigned_tx_hash: string; - unsigned_tx_serialized: string; - tx_body: string; - tx_auth_info: string; - pubkey: string; - message: EncodeObject; - fee: StdFee; - } -} - -export type AtomSignedTx = { - data: { - fireblocks_tx: TransactionResponse; - signed_tx_serialized: string; - }; -}; - -export type AtomTxHash = { - data: { - tx_hash: string; - }; -}; - -export type AtomTxStatus = { - data: { - status: 'success' | 'error', - receipt: IndexedTx | null, - } -} - export type AtomStake = { validator_address: string; delegator_address: string; diff --git a/src/types/dydx.ts b/src/types/cosmos.ts similarity index 83% rename from src/types/dydx.ts rename to src/types/cosmos.ts index 356958f..6611810 100644 --- a/src/types/dydx.ts +++ b/src/types/cosmos.ts @@ -2,7 +2,7 @@ import { IndexedTx, StdFee } from "@cosmjs/stargate"; import { EncodeObject } from "@cosmjs/proto-signing"; import { TransactionResponse } from "fireblocks-sdk"; -export type DydxTx = { +export type CosmosTx = { data: { unsigned_tx_hash: string; unsigned_tx_serialized: string; @@ -14,20 +14,20 @@ export type DydxTx = { } } -export type DydxSignedTx = { +export type CosmosSignedTx = { data: { fireblocks_tx: TransactionResponse; signed_tx_serialized: string; }; }; -export type DydxTxHash = { +export type CosmosTxHash = { data: { tx_hash: string; }; }; -export type DydxTxStatus = { +export type CosmosTxStatus = { data: { status: 'success' | 'error', receipt: IndexedTx | null, diff --git a/src/types/osmo.ts b/src/types/osmo.ts index 3d96e8d..3b78bde 100644 --- a/src/types/osmo.ts +++ b/src/types/osmo.ts @@ -1,39 +1,3 @@ -import { IndexedTx, StdFee } from "@cosmjs/stargate"; -import { EncodeObject } from "@cosmjs/proto-signing"; -import { TransactionResponse } from "fireblocks-sdk"; - -export type OsmoTx = { - data: { - unsigned_tx_hash: string; - unsigned_tx_serialized: string; - tx_body: string; - tx_auth_info: string; - pubkey: string; - message: EncodeObject; - fee: StdFee; - } -} - -export type OsmoSignedTx = { - data: { - fireblocks_tx: TransactionResponse; - signed_tx_serialized: string; - }; -}; - -export type OsmoTxHash = { - data: { - tx_hash: string; - }; -}; - -export type OsmoTxStatus = { - data: { - status: 'success' | 'error', - receipt: IndexedTx | null, - } -} - export type OsmoStake = { validator_address: string; delegator_address: string;