@lombard.finance/sdk-sui 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,90 @@
1
+ # @lombard.finance/sdk-sui
2
+
3
+ The Lombard's SDK SUI package provides a set of functions that allow interacting with the Lombard protocol and its features on SUI.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @lombard.finance/sdk @lombard.finance/sdk-sui
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ### Generating a BTC deposit address
14
+
15
+ Similar to the EVM SDK (`@lombard.finance/sdk`) the generation of the deposit address requires a signature.
16
+ To successfully generate a deposit address run `signLbtcDestinationAddrSui` and then use the generated signature as a parameter of the EVM SDK's `generateDepositBtcAddress`.
17
+
18
+ ```javascript
19
+
20
+ const { signature } = await signLbtcDestinationAddrSui({
21
+ // The Sui chain id
22
+ chainId: SUI_MAINNET_CHAIN,
23
+ // The Sui wallet provider, see `@wallet-standard/base`
24
+ wallet,
25
+ // The wallet account, see `@wallet-standard/core`
26
+ account,
27
+ });
28
+
29
+ const depositAddress = await generateDepositBtcAddress({
30
+ // The connected address
31
+ address,
32
+ // The chosen Solana chain (network) - prefixed with `solana:`
33
+ chainId: SUI_MAINNET_CHAIN,
34
+ // The generated signature:
35
+ signature,
36
+ // Optional env
37
+ env: Env.prod,
38
+ // Optional partnerId
39
+ partnerId,
40
+ }),
41
+
42
+ ```
43
+
44
+ ### Claiming LBTC
45
+
46
+ This operation mints the deposited amount of BTC into LBTC and transfers that
47
+ to the provided recipient address.
48
+
49
+ ```javascript
50
+ const { digest } = await claimLBTC({
51
+ // The Sui chain id
52
+ chainId: SUI_MAINNET_CHAIN,
53
+ // The Sui wallet provider, see `@wallet-standard/base`
54
+ wallet,
55
+ // The raw paylod from a deposit, obtained from `getDepositsByAddress`
56
+ payload,
57
+ // The proof of a deposit, obtained from `getDepositsByAddress
58
+ proof,
59
+ // The wallet account, see `@wallet-standard/core`
60
+ walletAccount,
61
+ // The Sui client, see @mysten/sui/client
62
+ client,
63
+ // Optional env
64
+ env = Env.prod,
65
+ });
66
+ ```
67
+
68
+ ### Unstaking LBTC
69
+
70
+ This operation burns given amount of LBTC and initiates transfer of BTC to the
71
+ given BTC address.
72
+
73
+ ```javascript
74
+ const { digest } = await unstakeLBTC({
75
+ // The Sui chain id
76
+ chainId,
77
+ // The Sui wallet provider, see `@wallet-standard/base`
78
+ wallet,
79
+ // The wallet account, see `@wallet-standard/core`
80
+ walletAccount,
81
+ // The Sui client, see @mysten/sui/client
82
+ client,
83
+ // The BTC destination address
84
+ btcAddress,
85
+ // The amount of LBTC to unstake, e.g. BigNumber(1.2)
86
+ amount,
87
+ // Optional env
88
+ env = Env.prod,
89
+ });
90
+ ```
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "@lombard.finance/sdk-sui",
3
+ "version": "1.0.1",
4
+ "exports": {
5
+ ".": {
6
+ "import": "./dist/index.js",
7
+ "require": "./dist/index.cjs",
8
+ "types": "./src/index.ts"
9
+ }
10
+ },
11
+ "license": "MIT",
12
+ "type": "module",
13
+ "types": "./src/index.ts",
14
+ "files": [
15
+ "dist",
16
+ "src"
17
+ ],
18
+ "engines": {
19
+ "node": ">= 22.14.0"
20
+ },
21
+ "scripts": {
22
+ "build-docs": "rimraf ./sdk-docs && typedoc --out sdk-docs",
23
+ "build-storybook": "storybook build -o sdk-storybook",
24
+ "build": "yarn types && vite build",
25
+ "lint": "biome lint",
26
+ "storybook": "storybook dev -p 6006",
27
+ "types": "tsc --noEmit"
28
+ },
29
+ "peerDependencies": {
30
+ "@bitcoin-js/tiny-secp256k1-asmjs": "2.2.3",
31
+ "axios": "^1",
32
+ "bignumber.js": "^9",
33
+ "bitcoinjs-lib": "6.1.5",
34
+ "web3": "^4"
35
+ },
36
+ "dependencies": {
37
+ "@lombard.finance/sdk-common": "^3.0.0",
38
+ "@lombard.finance/sdk": "^3.1.0",
39
+ "@mysten/sui": "^1.21.1"
40
+ },
41
+ "devDependencies": {
42
+ "@chromatic-com/storybook": "1.6.1",
43
+ "@storybook/addon-essentials": "^8.2.9",
44
+ "@storybook/addon-interactions": "^8.2.9",
45
+ "@storybook/addon-links": "^8.2.9",
46
+ "@storybook/addon-onboarding": "^8.2.9",
47
+ "@storybook/blocks": "^8.2.9",
48
+ "@storybook/react": "^8.2.9",
49
+ "@storybook/react-vite": "^8.2.9",
50
+ "@storybook/test": "^8.2.9",
51
+ "axios": "^1.7.4",
52
+ "bignumber.js": "^9.1.2",
53
+ "rimraf": "^5",
54
+ "storybook": "^8.2.9",
55
+ "typedoc": "^0.26.6",
56
+ "typescript": "^5.4.5"
57
+ }
58
+ }
@@ -0,0 +1,16 @@
1
+ import { Env } from '@lombard.finance/sdk-common';
2
+ import {
3
+ Wallet,
4
+ WalletAccount,
5
+ WalletWithFeatures,
6
+ } from '@wallet-standard/base';
7
+
8
+ type EnvParameter = {
9
+ env?: Env;
10
+ };
11
+
12
+ export interface CommonWriteParameters<WF extends Wallet['features']>
13
+ extends EnvParameter {
14
+ walletClient: WalletWithFeatures<WF>;
15
+ account: WalletAccount;
16
+ }
@@ -0,0 +1,3 @@
1
+ export const PHANTOM_WALLET_NAME = 'Phantom';
2
+
3
+ export const SUI_COINTYPE = '0x2::sui::SUI';
@@ -0,0 +1,4 @@
1
+ export const ERROR_COIN_METADATA_NOT_FUND = new Error(
2
+ 'Coin Metadata could not be found.',
3
+ );
4
+ export const ERROR_NOT_ENOUGH_BALANCE = new Error('Not enough balance.');
@@ -0,0 +1,101 @@
1
+ import { DEFAULT_ENV, Env } from '@lombard.finance/sdk-common';
2
+
3
+ interface IConfig {
4
+ mint: {
5
+ target: `0x${string}::treasury::${'mint' | 'mint_v2'}`;
6
+ denyList: `0x${string}`;
7
+ };
8
+ redeem: {
9
+ target: `0x${string}::treasury::redeem`;
10
+ };
11
+ LBTC: `0x${string}::lbtc::LBTC`;
12
+ treasuryAddress: `0x${string}`;
13
+ consortiumAddress: `0x${string}`;
14
+ bascule: `0x${string}`;
15
+ }
16
+
17
+ // https://github.com/lombard-finance/sui-contracts/blob/main/staging.json
18
+ const stageConfig: IConfig = {
19
+ mint: {
20
+ target:
21
+ // lbtc_v2_current
22
+ '0x2721ad6e939baca77b36f415ab91edb1c91b256cbc8614f8f6c84bf06faf74af::treasury::mint',
23
+ denyList: '0x403',
24
+ },
25
+ redeem: {
26
+ // lbtc_v2_current
27
+ target:
28
+ '0x2721ad6e939baca77b36f415ab91edb1c91b256cbc8614f8f6c84bf06faf74af::treasury::redeem',
29
+ },
30
+ // lbtc_v1_deprecated - This is intentional
31
+ LBTC: '0x2d66430a27565b912f21be970e5ae1e8c0359f0b518c3235b751c75976791ce0::lbtc::LBTC',
32
+ // objects.treasury
33
+ treasuryAddress:
34
+ '0xf9621182bf6af94142e81f5c268d1a959991df2766a5b0755c528b70e5b33531',
35
+ // objects.consortium
36
+ consortiumAddress:
37
+ '0xd8a7bff969c0f7069ccda1601516fc93013d8c06835646f718d7d345409340cc',
38
+ // objects.bascule
39
+ bascule: '0x61cf6760a04f4af6938543e1e9c0b84f7b271cf9069f0cb6c8017093fd814c68',
40
+ } as const;
41
+
42
+ // https://github.com/lombard-finance/sui-contracts/blob/main/gastald.json
43
+ const testnetConfig: IConfig = {
44
+ mint: {
45
+ // lbtc_v2_current
46
+ target:
47
+ '0xbe409fa89cd3eedbe426fdae9c53a231f2fff9dc66c3ca797163b5b5b2aba977::treasury::mint_v2',
48
+ denyList: '0x403',
49
+ },
50
+ redeem: {
51
+ // lbtc_v2_current
52
+ target:
53
+ '0xbe409fa89cd3eedbe426fdae9c53a231f2fff9dc66c3ca797163b5b5b2aba977::treasury::redeem',
54
+ },
55
+ // lbtc_v1_deprecated - This is intentional
56
+ LBTC: '0x50454d0b0fbad1288a6ab74f2e8ce0905a3317870673ab7787ebcf6f322b45fa::lbtc::LBTC',
57
+ // objects.treasury
58
+ treasuryAddress:
59
+ '0xc8f3d6d596ed86012a289166400d3650d9f888f612bf9c35b0cde7bc1b053408',
60
+ // objects.consortium
61
+ consortiumAddress:
62
+ '0x5d0922bfc25cd4babc76e7e320b0e9b4d4950408bae9632a5fedf2a1f8dc29dc',
63
+ // objects.bascule
64
+ bascule: '0xd8b1c1f9b893330180fa1fc52a316461a5fabd258fa15633e9a5ba5da71af49e',
65
+ } as const;
66
+
67
+ // https://github.com/lombard-finance/sui-contracts/blob/main/mainnet.json
68
+ const prodConfig: IConfig = {
69
+ mint: {
70
+ // lbtc_v2_current
71
+ target:
72
+ '0x818430a456ff977f7320f78650d19801f90758d200a01dd3c2c679472c521357::treasury::mint_v2',
73
+ denyList: '0x403',
74
+ },
75
+ redeem: {
76
+ // lbtc_v2_current
77
+ target:
78
+ '0x818430a456ff977f7320f78650d19801f90758d200a01dd3c2c679472c521357::treasury::redeem',
79
+ },
80
+ // lbtc_v1_deprecated - This is intentional
81
+ LBTC: '0x3e8e9423d80e1774a7ca128fccd8bf5f1f7753be658c5e645929037f7c819040::lbtc::LBTC',
82
+ // objects.treasury
83
+ treasuryAddress:
84
+ '0x1adadbca040f368abd554ac55e7c216ea6df2ff891fc647f037d66669661584a',
85
+ // objects.consortium
86
+ consortiumAddress:
87
+ '0x9f68fe752d0879d615415e39207f0363a6fc8e0b3b335e976f5f18b31f55faf3',
88
+ // objects.bascule
89
+ bascule: '0x138938cb496cf0900be970dde1407d86497b8c69182cb5aa22dc4767c92bedcc',
90
+ } as const;
91
+
92
+ export function getConfig(env: Env = DEFAULT_ENV): typeof prodConfig {
93
+ switch (env) {
94
+ case Env.prod:
95
+ return prodConfig;
96
+ case Env.testnet:
97
+ return testnetConfig;
98
+ default:
99
+ return stageConfig;
100
+ }
101
+ }
@@ -0,0 +1,3 @@
1
+ export * from './const';
2
+ export * from './errors';
3
+ export * from './getConfig';
@@ -0,0 +1,30 @@
1
+ import {
2
+ SuiChain,
3
+ SUI_TESTNET_CHAIN,
4
+ SUI_MAINNET_CHAIN,
5
+ } from '@mysten/wallet-standard';
6
+
7
+ const ERROR_NOT_FOUND_UNIFIED_ID = new Error("Unified ID hasn't been found");
8
+
9
+ /**
10
+ * It's an internal type defined by the backend.
11
+ * The main purpose is the unification of chain IDs for different networks.
12
+ */
13
+ const UnifiedChainId = {
14
+ [SUI_TESTNET_CHAIN]:
15
+ '452312848583266388373324160190187140051835877600158453279131187532193639852',
16
+ [SUI_MAINNET_CHAIN]:
17
+ '452312848583266388373324160190187140051835877600158453279131187531808459402',
18
+ } as Record<SuiChain, string>;
19
+
20
+ type UnifiedChainId = (typeof UnifiedChainId)[keyof typeof UnifiedChainId];
21
+
22
+ export function getUnifiedChainId(chainId: SuiChain) {
23
+ const unifiedChainId = UnifiedChainId[chainId];
24
+
25
+ if (!unifiedChainId) {
26
+ throw ERROR_NOT_FOUND_UNIFIED_ID;
27
+ }
28
+
29
+ return unifiedChainId;
30
+ }
package/src/index.ts ADDED
@@ -0,0 +1,9 @@
1
+ export * from './web3Sdk/signLbtcDestionationAddrSui';
2
+ export * from './web3Sdk/claimLBTC';
3
+ export * from './web3Sdk/getBalance';
4
+ export * from './web3Sdk/unstakeLBTC';
5
+ export * from './web3Sdk/signTermsOfService';
6
+ export * from './const';
7
+
8
+ // Rewards:
9
+ export * from './rewards';
@@ -0,0 +1 @@
1
+ export { claimReward, type ClaimRewardParameters } from './lib/claim-reward';
@@ -0,0 +1,106 @@
1
+ import BigNumber from 'bignumber.js';
2
+ import axios from 'axios';
3
+ import { CommonWriteParameters } from '../../common/parameters';
4
+ import { SuiSignPersonalMessageFeature } from '@mysten/wallet-standard';
5
+ import {
6
+ getApiConfig,
7
+ getRewardSigningData,
8
+ getRewardWithdrawalFee,
9
+ isRewardTokenSupported,
10
+ RewardToken,
11
+ RewardWithdrawal,
12
+ RewardWithdrawalStatus,
13
+ } from '@lombard.finance/sdk';
14
+
15
+ type Response = {
16
+ withdrawal: {
17
+ account_id: string;
18
+ amount: string;
19
+ created_at: string;
20
+ fee: string;
21
+ id: string;
22
+ nonce: string;
23
+ signature: string;
24
+ status: RewardWithdrawalStatus;
25
+ to: string;
26
+ tx_hash?: string;
27
+ };
28
+ };
29
+
30
+ export type ClaimRewardParameters = {
31
+ /** The reward token. */
32
+ rewardToken: RewardToken;
33
+ /** The amount of reward to be withdrawn (claimed). */
34
+ amount: BigNumber.Value;
35
+ /** The destination address. */
36
+ to: string;
37
+ } & CommonWriteParameters<SuiSignPersonalMessageFeature>;
38
+
39
+ const REQUEST_WITHDRAW_URL =
40
+ '/api/v1/distribution/account/{from}/withdrawals/{to}';
41
+
42
+ /** Claims a reward */
43
+ export async function claimReward({
44
+ account: from,
45
+ rewardToken,
46
+ amount,
47
+ to,
48
+ walletClient,
49
+ env,
50
+ }: ClaimRewardParameters) {
51
+ if (!isRewardTokenSupported(rewardToken)) {
52
+ throw new Error(`Unknown reward token: ${RewardToken}`);
53
+ }
54
+
55
+ const withdrawalFee = await getRewardWithdrawalFee({
56
+ address: from.address,
57
+ rewardToken,
58
+ env,
59
+ });
60
+ const signingData = await getRewardSigningData({
61
+ from: from.address,
62
+ to,
63
+ amount,
64
+ fee: withdrawalFee,
65
+ rewardToken,
66
+ env,
67
+ });
68
+
69
+ const { signature } = await walletClient.features[
70
+ 'sui:signPersonalMessage'
71
+ ].signPersonalMessage({
72
+ account: from,
73
+ message: Buffer.from(signingData) as unknown as Uint8Array,
74
+ });
75
+
76
+ const payload = {
77
+ amount: BigNumber(amount).toFixed(),
78
+ fee: BigNumber(withdrawalFee).toFixed(),
79
+ signature,
80
+ };
81
+
82
+ const { baseApiUrl } = getApiConfig(env);
83
+ const { data: withdrawData } = await axios.post<Response>(
84
+ REQUEST_WITHDRAW_URL.replace('{from}', from.address).replace('{to}', to),
85
+ payload,
86
+ {
87
+ baseURL: baseApiUrl,
88
+ },
89
+ );
90
+
91
+ return mapDataToRewardWithdrawal(withdrawData.withdrawal);
92
+ }
93
+
94
+ function mapDataToRewardWithdrawal(data: Response['withdrawal']) {
95
+ const withdrawal: RewardWithdrawal = {
96
+ amount: BigNumber(data.amount),
97
+ rewardToken: RewardToken.BABY,
98
+ fee: BigNumber(data.fee),
99
+ to: data.to,
100
+ signature: data.signature,
101
+ status: data.status,
102
+ txHash: data.tx_hash,
103
+ timestamp: new Date(data.created_at),
104
+ };
105
+ return withdrawal;
106
+ }
@@ -0,0 +1 @@
1
+ /// <reference types="vite/client" />
@@ -0,0 +1,89 @@
1
+ import { Transaction } from '@mysten/sui/transactions';
2
+ import { SuiChain, SuiSignTransactionFeature } from '@mysten/wallet-standard';
3
+ import { WalletWithFeatures } from '@wallet-standard/base';
4
+ import type { WalletAccount } from '@wallet-standard/core';
5
+ import { DEFAULT_ENV, Env } from '@lombard.finance/sdk-common';
6
+ import { SuiClient } from '@mysten/sui/client';
7
+ import type { SuiTransactionBlockResponse } from '@mysten/sui/client';
8
+ import { getConfig } from '../../const';
9
+
10
+ type Not0xPrefixedHex = string;
11
+
12
+ interface IClaimLBTCParams {
13
+ chainId: SuiChain;
14
+ wallet: WalletWithFeatures<SuiSignTransactionFeature>;
15
+ payload: Not0xPrefixedHex;
16
+ proof: Not0xPrefixedHex;
17
+ walletAccount: WalletAccount;
18
+ client: SuiClient;
19
+ env?: Env;
20
+ }
21
+
22
+ const SIGN_TRANSACTION_V2_FEATURE = 'sui:signTransaction';
23
+
24
+ /**
25
+ * Claims LBTC.
26
+ */
27
+ export async function claimLBTC({
28
+ chainId,
29
+ wallet,
30
+ payload,
31
+ proof,
32
+ walletAccount,
33
+ client,
34
+ env = DEFAULT_ENV,
35
+ }: IClaimLBTCParams): Promise<SuiTransactionBlockResponse> {
36
+ const transaction = new Transaction();
37
+
38
+ const {
39
+ mint: { target, denyList },
40
+ treasuryAddress,
41
+ consortiumAddress,
42
+ bascule,
43
+ LBTC,
44
+ } = getConfig(env);
45
+
46
+ transaction.moveCall({
47
+ target,
48
+ arguments: [
49
+ transaction.object(treasuryAddress),
50
+ transaction.object(consortiumAddress),
51
+ transaction.object(denyList),
52
+ transaction.object(bascule),
53
+ transaction.pure.vector('u8', Array.from(Buffer.from(payload, 'hex'))),
54
+ transaction.pure.vector('u8', Array.from(Buffer.from(proof, 'hex'))),
55
+ ],
56
+ typeArguments: [LBTC],
57
+ });
58
+
59
+ if (wallet.features[SIGN_TRANSACTION_V2_FEATURE]) {
60
+ const signedTransaction = await wallet.features[
61
+ 'sui:signTransaction'
62
+ ].signTransaction({
63
+ chain: chainId,
64
+ transaction,
65
+ account: walletAccount,
66
+ });
67
+
68
+ return client.executeTransactionBlock({
69
+ transactionBlock: signedTransaction.bytes,
70
+ signature: signedTransaction.signature,
71
+ });
72
+ }
73
+
74
+ transaction.setSender(walletAccount.address);
75
+
76
+ const signedTransaction = await wallet.features[
77
+ // @ts-ignore The current wallet standard interface version doesn't support this type
78
+ 'sui:signTransactionBlock'
79
+ ].signTransactionBlock({
80
+ chain: chainId,
81
+ transactionBlock: transaction,
82
+ account: walletAccount,
83
+ });
84
+
85
+ return client.executeTransactionBlock({
86
+ transactionBlock: signedTransaction.transactionBlockBytes,
87
+ signature: signedTransaction.signature,
88
+ });
89
+ }
@@ -0,0 +1 @@
1
+ export * from './claimLBTC';
@@ -0,0 +1,32 @@
1
+ import type { WalletAccount } from '@wallet-standard/core';
2
+ import type { CoinStruct } from '@mysten/sui/client';
3
+ import { SuiClient } from '@mysten/sui/client';
4
+
5
+ interface IUnstakeLBTCParams {
6
+ walletAccount: WalletAccount;
7
+ client: SuiClient;
8
+ coinType: string;
9
+ }
10
+
11
+ export async function getAllCoinsOfType({
12
+ walletAccount,
13
+ client,
14
+ coinType,
15
+ }: IUnstakeLBTCParams) {
16
+ let cursor: string | null | undefined = undefined;
17
+ let coins: CoinStruct[] = [];
18
+
19
+ do {
20
+ const response = await client.getCoins({
21
+ owner: walletAccount.address,
22
+ coinType,
23
+ cursor,
24
+ limit: 50,
25
+ });
26
+
27
+ coins = coins.concat(response.data);
28
+ cursor = response.nextCursor;
29
+ } while (cursor);
30
+
31
+ return coins;
32
+ }
@@ -0,0 +1 @@
1
+ export * from './getAllCoinsOfType';
@@ -0,0 +1,41 @@
1
+ import type { WalletAccount } from '@wallet-standard/core';
2
+ import { Env } from '@lombard.finance/sdk-common';
3
+ import { SuiClient } from '@mysten/sui/client';
4
+ import BigNumber from 'bignumber.js';
5
+ import { ERROR_COIN_METADATA_NOT_FUND } from '../../const';
6
+
7
+ interface IGetBalanceParams {
8
+ walletAccount: WalletAccount;
9
+ client: SuiClient;
10
+ coinType: string;
11
+ env?: Env;
12
+ }
13
+
14
+ interface IGetBalanceResult {
15
+ total: BigNumber;
16
+ }
17
+
18
+ export async function getBalance({
19
+ walletAccount,
20
+ client,
21
+ coinType,
22
+ }: IGetBalanceParams): Promise<IGetBalanceResult> {
23
+ const coinBalance = await client.getBalance({
24
+ owner: walletAccount.address,
25
+ coinType,
26
+ });
27
+
28
+ const coinMetadata = await client.getCoinMetadata({
29
+ coinType,
30
+ });
31
+
32
+ if (!coinMetadata) {
33
+ throw ERROR_COIN_METADATA_NOT_FUND;
34
+ }
35
+
36
+ const total = new BigNumber(coinBalance.totalBalance).div(
37
+ new BigNumber(10).pow(coinMetadata.decimals),
38
+ );
39
+
40
+ return { total };
41
+ }
@@ -0,0 +1 @@
1
+ export * from './getBalance';
@@ -0,0 +1 @@
1
+ export * from './prepareCoinsTransaction';
@@ -0,0 +1,88 @@
1
+ import { Transaction } from '@mysten/sui/transactions';
2
+ import type { WalletAccount } from '@wallet-standard/core';
3
+ import type { CoinStruct } from '@mysten/sui/client';
4
+ import { SuiClient } from '@mysten/sui/client';
5
+ import BigNumber from 'bignumber.js';
6
+ import {
7
+ ERROR_COIN_METADATA_NOT_FUND,
8
+ ERROR_NOT_ENOUGH_BALANCE,
9
+ } from '../../const';
10
+ import { getAllCoinsOfType } from '../getAllCoinsOfType';
11
+
12
+ interface IUnstakeLBTCParams {
13
+ walletAccount: WalletAccount;
14
+ client: SuiClient;
15
+ amount: BigNumber;
16
+ coinType: string;
17
+ }
18
+
19
+ export async function prepareCoinsTransaction({
20
+ walletAccount,
21
+ client,
22
+ amount,
23
+ coinType,
24
+ }: IUnstakeLBTCParams) {
25
+ const coins = await getAllCoinsOfType({ walletAccount, client, coinType });
26
+
27
+ const transaction = new Transaction();
28
+
29
+ const preparedCoins = await (async () => {
30
+ const coinMetadata = await client.getCoinMetadata({
31
+ coinType,
32
+ });
33
+
34
+ if (!coinMetadata) {
35
+ throw ERROR_COIN_METADATA_NOT_FUND;
36
+ }
37
+
38
+ const unstakeAmount = BigInt(
39
+ amount
40
+ .multipliedBy(new BigNumber(10).pow(coinMetadata.decimals))
41
+ .toString(10),
42
+ );
43
+
44
+ const selectedCoins = [] as CoinStruct[];
45
+ let selectedAmount = BigInt(0);
46
+
47
+ for (const coin of coins) {
48
+ if (selectedAmount + BigInt(coin.balance) < unstakeAmount) {
49
+ selectedCoins.push(coin);
50
+ selectedAmount += BigInt(coin.balance);
51
+ } else if (selectedAmount + BigInt(coin.balance) === unstakeAmount) {
52
+ selectedCoins.push(coin);
53
+
54
+ const coinObjects = selectedCoins.map(coin =>
55
+ transaction.object(coin.coinObjectId),
56
+ );
57
+
58
+ if (coinObjects.length > 1) {
59
+ const [coin, ...rest] = coinObjects;
60
+ transaction.mergeCoins(coin, rest);
61
+ return coin;
62
+ }
63
+
64
+ return coinObjects[0];
65
+ } else if (selectedAmount + BigInt(coin.balance) > unstakeAmount) {
66
+ const remaining = unstakeAmount - selectedAmount;
67
+ const [splitCoin] = transaction.splitCoins(
68
+ transaction.object(coin.coinObjectId),
69
+ [transaction.pure.u64(remaining)],
70
+ );
71
+
72
+ if (selectedCoins.length === 0) {
73
+ return transaction.object(splitCoin);
74
+ }
75
+
76
+ transaction.mergeCoins(
77
+ splitCoin,
78
+ selectedCoins.map(coin => transaction.object(coin.coinObjectId)),
79
+ );
80
+
81
+ return transaction.object(splitCoin);
82
+ }
83
+ }
84
+ throw ERROR_NOT_ENOUGH_BALANCE;
85
+ })();
86
+
87
+ return { transaction, preparedCoins };
88
+ }
@@ -0,0 +1 @@
1
+ export * from './signLbtcDestinationAddrSui';
@@ -0,0 +1,44 @@
1
+ import {
2
+ SuiChain,
3
+ SuiSignPersonalMessageFeature,
4
+ } from '@mysten/wallet-standard';
5
+
6
+ import { WalletWithFeatures } from '@wallet-standard/base';
7
+ import type { WalletAccount } from '@wallet-standard/core';
8
+ import { getUnifiedChainId } from '../../getUnifiedChainId';
9
+
10
+ export const SIGNATURE_SIZE = -132;
11
+
12
+ interface SignLbtcDestinationAddrSuiParams {
13
+ chainId: SuiChain;
14
+ wallet: WalletWithFeatures<SuiSignPersonalMessageFeature>;
15
+ account: WalletAccount;
16
+ }
17
+
18
+ /**
19
+ * Signs the destination address for the LBTC in active chain
20
+ * in the current account. Signing is necessary for the
21
+ * generation of the deposit address.
22
+ *
23
+ * @param {SignLbtcDestinationAddrSuiParams} params
24
+ *
25
+ * @returns {Promise<{ bytes: string; signature: string }>} The signature and the message.
26
+ */
27
+ export async function signLbtcDestinationAddrSui({
28
+ chainId,
29
+ wallet,
30
+ account,
31
+ }: SignLbtcDestinationAddrSuiParams): Promise<{
32
+ bytes: string;
33
+ signature: string;
34
+ }> {
35
+ const message = Buffer.from(
36
+ `destination chain id is ${getUnifiedChainId(chainId)}`,
37
+ 'utf8',
38
+ ) as unknown as Uint8Array;
39
+
40
+ return wallet.features['sui:signPersonalMessage'].signPersonalMessage({
41
+ message,
42
+ account,
43
+ });
44
+ }
@@ -0,0 +1 @@
1
+ export * from './signTermsOfService';
@@ -0,0 +1,32 @@
1
+ import { SuiSignPersonalMessageFeature } from '@mysten/wallet-standard';
2
+
3
+ import { WalletWithFeatures } from '@wallet-standard/base';
4
+ import type { WalletAccount } from '@wallet-standard/core';
5
+
6
+ const SIGN_MESSAGE =
7
+ 'I have read and agreed to the terms of service: https://docs.lombard.finance/legals/terms-of-service';
8
+
9
+ interface SignTermsOfServiceParams {
10
+ wallet: WalletWithFeatures<SuiSignPersonalMessageFeature>;
11
+ account: WalletAccount;
12
+ }
13
+
14
+ /**
15
+ * Signs terms of service.
16
+ *
17
+ * @param {SignTermsOfServiceParams} params
18
+ *
19
+ * @returns {Promise<{ bytes: string; signature: string }>} The signature and the message.
20
+ */
21
+ export async function signTermsOfService({
22
+ wallet,
23
+ account,
24
+ }: SignTermsOfServiceParams): Promise<{
25
+ bytes: string;
26
+ signature: string;
27
+ }> {
28
+ return wallet.features['sui:signPersonalMessage'].signPersonalMessage({
29
+ message: Buffer.from(SIGN_MESSAGE, 'utf8') as unknown as Uint8Array,
30
+ account,
31
+ });
32
+ }
@@ -0,0 +1 @@
1
+ export * from './unstakeLBTC';
@@ -0,0 +1,69 @@
1
+ import { SuiChain, SuiSignTransactionFeature } from '@mysten/wallet-standard';
2
+ import { WalletWithFeatures } from '@wallet-standard/base';
3
+ import type { WalletAccount } from '@wallet-standard/core';
4
+ import { DEFAULT_ENV, Env, getOutputScript } from '@lombard.finance/sdk-common';
5
+ import type { SuiTransactionBlockResponse } from '@mysten/sui/client';
6
+ import { SuiClient } from '@mysten/sui/client';
7
+ import BigNumber from 'bignumber.js';
8
+ import { getConfig } from '../../const';
9
+ import { prepareCoinsTransaction } from '../prepareAmount';
10
+
11
+ interface IUnstakeLBTCParams {
12
+ chainId: SuiChain;
13
+ wallet: WalletWithFeatures<SuiSignTransactionFeature>;
14
+ walletAccount: WalletAccount;
15
+ client: SuiClient;
16
+ btcAddress: string;
17
+ amount: BigNumber;
18
+ env?: Env;
19
+ }
20
+
21
+ /**
22
+ * Unstake LBTC.
23
+ */
24
+ export async function unstakeLBTC({
25
+ chainId,
26
+ wallet,
27
+ walletAccount,
28
+ client,
29
+ btcAddress,
30
+ amount,
31
+ env = DEFAULT_ENV,
32
+ }: IUnstakeLBTCParams): Promise<SuiTransactionBlockResponse> {
33
+ const config = getConfig(env);
34
+
35
+ const { transaction, preparedCoins: unstakingCoins } =
36
+ await prepareCoinsTransaction({
37
+ walletAccount,
38
+ client,
39
+ amount,
40
+ coinType: config.LBTC,
41
+ });
42
+
43
+ const scriptPubKey = Array.from(
44
+ Buffer.from(getOutputScript(btcAddress, env).replace(/^0x/, ''), 'hex'),
45
+ );
46
+
47
+ transaction.moveCall({
48
+ target: config.redeem.target,
49
+ arguments: [
50
+ transaction.object(config.treasuryAddress),
51
+ unstakingCoins,
52
+ transaction.pure.vector('u8', scriptPubKey),
53
+ ],
54
+ typeArguments: [config.LBTC],
55
+ });
56
+
57
+ const signedTransaction = await wallet.features[
58
+ 'sui:signTransaction'
59
+ ].signTransaction({
60
+ chain: chainId,
61
+ transaction,
62
+ account: walletAccount,
63
+ });
64
+
65
+ return client.executeTransactionBlock({
66
+ transactionBlock: signedTransaction.bytes,
67
+ signature: signedTransaction.signature,
68
+ });
69
+ }