@lombard.finance/sdk-solana 1.2.2 → 2.0.0
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 +48 -15
- package/dist/index.cjs +1 -1
- package/dist/index.js +37 -31
- package/dist/index2.cjs +57 -54
- package/dist/index2.js +7608 -7206
- package/package.json +2 -2
- package/src/const/errors.ts +0 -4
- package/src/const/getConfig.ts +43 -20
- package/src/const/rpcUrls.ts +2 -2
- package/src/idl/asset_router.json +548 -179
- package/src/idl/consortium.json +24 -43
- package/src/idl/mailbox.json +118 -107
- package/src/index.ts +1 -3
- package/src/services/SolanaServiceImpl.test.ts +123 -0
- package/src/services/SolanaServiceImpl.ts +53 -17
- package/src/stories/components/OutputSelector/OutputSelector.tsx +1 -0
- package/src/types/errors.ts +2 -0
- package/src/utils/createDebugLogger.ts +6 -13
- package/src/utils/errors.ts +2 -0
- package/src/utils/tokenAccount.ts +3 -1
- package/src/utils/transactions.ts +1 -1
- package/src/web3Sdk/claimToken/claimBtcb.ts +37 -28
- package/src/web3Sdk/claimToken/claimLbtcGmp.ts +66 -8
- package/src/web3Sdk/claimToken/claimToken.stories.tsx +2 -2
- package/src/web3Sdk/claimToken/claimToken.ts +20 -16
- package/src/web3Sdk/claimToken/constants.ts +5 -0
- package/src/web3Sdk/claimToken/index.ts +1 -0
- package/src/web3Sdk/claimToken/shared.ts +88 -80
- package/src/web3Sdk/deposit/deposit.stories.tsx +240 -0
- package/src/web3Sdk/deposit/deposit.test.ts +327 -0
- package/src/web3Sdk/deposit/deposit.ts +339 -0
- package/src/web3Sdk/deposit/index.ts +1 -0
- package/src/web3Sdk/getTokenFeeConfig/getTokenFeeConfig.stories.tsx +166 -0
- package/src/web3Sdk/getTokenFeeConfig/getTokenFeeConfig.test.ts +224 -0
- package/src/web3Sdk/getTokenFeeConfig/getTokenFeeConfig.ts +154 -0
- package/src/web3Sdk/getTokenFeeConfig/index.ts +11 -0
- package/src/web3Sdk/index.ts +3 -4
- package/src/web3Sdk/redeem/index.ts +1 -0
- package/src/web3Sdk/redeem/redeem.stories.tsx +226 -0
- package/src/web3Sdk/redeem/redeem.test.ts +327 -0
- package/src/web3Sdk/redeem/redeem.ts +352 -0
- package/src/web3Sdk/redeemToken/redeemBtcb.ts +174 -0
- package/src/web3Sdk/redeemToken/redeemForBtc.stories.tsx +35 -21
- package/src/web3Sdk/redeemToken/redeemForBtc.test.ts +306 -0
- package/src/web3Sdk/redeemToken/redeemForBtc.ts +54 -215
- package/src/web3Sdk/redeemToken/redeemLbtc.ts +174 -0
- package/src/web3Sdk/redeemToken/shared.test.ts +45 -0
- package/src/web3Sdk/redeemToken/shared.ts +97 -0
- package/src/web3Sdk/claimLBTC/claimLBTC.stories.tsx +0 -189
- package/src/web3Sdk/claimLBTC/claimLBTC.ts +0 -225
- package/src/web3Sdk/claimLBTC/index.ts +0 -1
- package/src/web3Sdk/claimLBTC/utils/generateDepositId.ts +0 -75
- package/src/web3Sdk/claimLBTC/utils/index.ts +0 -2
- package/src/web3Sdk/claimLBTC/utils/parseTransactionLogs.ts +0 -44
- package/src/web3Sdk/claimLBTC/utils/payloadUtils.ts +0 -58
- package/src/web3Sdk/claimLBTC/utils/postMintSignatures.ts +0 -50
- package/src/web3Sdk/unstakeLBTC/index.ts +0 -1
- package/src/web3Sdk/unstakeLBTC/unstakeLBTC.stories.tsx +0 -141
- package/src/web3Sdk/unstakeLBTC/unstakeLBTC.ts +0 -140
- /package/src/web3Sdk/{claimLBTC → claimToken}/utils/__tests__/signatureUtils.test.ts +0 -0
- /package/src/web3Sdk/{claimLBTC → claimToken}/utils/signatureUtils.ts +0 -0
|
@@ -1,225 +0,0 @@
|
|
|
1
|
-
import { AnchorProvider, Program, setProvider } from '@coral-xyz/anchor';
|
|
2
|
-
import { getAssociatedTokenAddress, TOKEN_PROGRAM_ID } from '@solana/spl-token';
|
|
3
|
-
import { PublicKey, SystemProgram } from '@solana/web3.js';
|
|
4
|
-
|
|
5
|
-
import { MintPayload } from '../../common/mintPayload';
|
|
6
|
-
import { getConfig, networkToEnv } from '../../const/getConfig';
|
|
7
|
-
import { getConnection } from '../../const/rpcUrls';
|
|
8
|
-
import { getLbtcIdl } from '../../idl/getLbtcIdl';
|
|
9
|
-
import { ISolanaWalletProvider, SolanaNetwork } from '../../types';
|
|
10
|
-
import { sendAndConfirmTransaction } from '../../utils';
|
|
11
|
-
import { createDebugLogger } from '../../utils/createDebugLogger';
|
|
12
|
-
import { verifyMatchingRecipient } from '../../utils/recipients';
|
|
13
|
-
import { createOrGetAssociatedTokenAccount } from '../../utils/tokenAccount';
|
|
14
|
-
import { checkPayloadStatus } from './utils';
|
|
15
|
-
import { generateDepositId } from './utils/generateDepositId';
|
|
16
|
-
import { postMintSignatures } from './utils/postMintSignatures';
|
|
17
|
-
|
|
18
|
-
export const ALREADY_MINTED_TX_HASH = 'ALREADY_MINTED';
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Parameters for claiming LBTC tokens on Solana
|
|
22
|
-
*/
|
|
23
|
-
export interface ClaimLBTCParams {
|
|
24
|
-
/**
|
|
25
|
-
* Address to receive the LBTC tokens
|
|
26
|
-
*/
|
|
27
|
-
recipientAddress: string;
|
|
28
|
-
/**
|
|
29
|
-
* Amount of LBTC to claim in base units
|
|
30
|
-
*/
|
|
31
|
-
amount: string;
|
|
32
|
-
/**
|
|
33
|
-
* Network to use
|
|
34
|
-
*/
|
|
35
|
-
network: SolanaNetwork;
|
|
36
|
-
/**
|
|
37
|
-
* Proof signature from the backend
|
|
38
|
-
*/
|
|
39
|
-
proofSignature: string;
|
|
40
|
-
/**
|
|
41
|
-
* Raw payload data
|
|
42
|
-
*/
|
|
43
|
-
rawPayload: string;
|
|
44
|
-
/**
|
|
45
|
-
* Optional RPC endpoint to use
|
|
46
|
-
*/
|
|
47
|
-
rpcUrl?: string;
|
|
48
|
-
/**
|
|
49
|
-
* Enable verbose debug logging
|
|
50
|
-
* @default false
|
|
51
|
-
*/
|
|
52
|
-
debug?: boolean;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Claim LBTC tokens on Solana using a three-step process:
|
|
57
|
-
* 1. Create mint payload
|
|
58
|
-
* 2. Post mint signatures
|
|
59
|
-
* 3. Mint from payload
|
|
60
|
-
*
|
|
61
|
-
* @param provider Solana wallet provider
|
|
62
|
-
* @param params Claim parameters
|
|
63
|
-
* @returns Transaction signature
|
|
64
|
-
*/
|
|
65
|
-
export async function claimLBTC(
|
|
66
|
-
provider: ISolanaWalletProvider,
|
|
67
|
-
params: ClaimLBTCParams,
|
|
68
|
-
): Promise<string> {
|
|
69
|
-
const {
|
|
70
|
-
recipientAddress,
|
|
71
|
-
network,
|
|
72
|
-
proofSignature,
|
|
73
|
-
rawPayload,
|
|
74
|
-
rpcUrl,
|
|
75
|
-
debug = false,
|
|
76
|
-
} = params;
|
|
77
|
-
const { debugLog, printLogs } = createDebugLogger({ debug });
|
|
78
|
-
|
|
79
|
-
try {
|
|
80
|
-
if (!provider.publicKey) {
|
|
81
|
-
throw new Error('Wallet not found');
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const config = getConfig(networkToEnv[network]);
|
|
85
|
-
const connection = getConnection(network, rpcUrl);
|
|
86
|
-
|
|
87
|
-
const wallet = {
|
|
88
|
-
publicKey: new PublicKey(provider.publicKey),
|
|
89
|
-
signTransaction: provider.signTransaction,
|
|
90
|
-
signAllTransactions: provider.signAllTransactions,
|
|
91
|
-
};
|
|
92
|
-
const anchorProvider = new AnchorProvider(connection, wallet, {});
|
|
93
|
-
setProvider(anchorProvider);
|
|
94
|
-
const program = new Program(getLbtcIdl(network), anchorProvider);
|
|
95
|
-
|
|
96
|
-
const mint = new PublicKey(config.lbtcTokenMint);
|
|
97
|
-
const programId = new PublicKey(config.lbtcProgramId);
|
|
98
|
-
const lzMultisig = new PublicKey(config.lzMultisig);
|
|
99
|
-
const mintPayload = new MintPayload(rawPayload);
|
|
100
|
-
const [mintPayloadPDA] = PublicKey.findProgramAddressSync(
|
|
101
|
-
[mintPayload.hashAsBytes()],
|
|
102
|
-
programId,
|
|
103
|
-
);
|
|
104
|
-
const [configPDA] = PublicKey.findProgramAddressSync(
|
|
105
|
-
[Buffer.from('lbtc_config')],
|
|
106
|
-
programId,
|
|
107
|
-
);
|
|
108
|
-
const [tokenAuth] = PublicKey.findProgramAddressSync(
|
|
109
|
-
[Buffer.from('token_authority')],
|
|
110
|
-
programId,
|
|
111
|
-
);
|
|
112
|
-
const payloadHashArray = Array.from(mintPayload.hashAsBytes());
|
|
113
|
-
|
|
114
|
-
await verifyMatchingRecipient(mint, mintPayload, recipientAddress);
|
|
115
|
-
|
|
116
|
-
const payloadStatus = await checkPayloadStatus(
|
|
117
|
-
program,
|
|
118
|
-
mintPayloadPDA,
|
|
119
|
-
debugLog,
|
|
120
|
-
);
|
|
121
|
-
|
|
122
|
-
if (payloadStatus.isMinted) {
|
|
123
|
-
return ALREADY_MINTED_TX_HASH;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
await createOrGetAssociatedTokenAccount({
|
|
127
|
-
provider,
|
|
128
|
-
connection,
|
|
129
|
-
ownerAddress: recipientAddress,
|
|
130
|
-
mintAddress: config.lbtcTokenMint,
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
// Step 1: Create Mint Payload (if it doesn't exist)
|
|
134
|
-
if (!payloadStatus.exists) {
|
|
135
|
-
debugLog('Adding Create Mint Payload instruction...');
|
|
136
|
-
const createPayloadIx = await program.methods
|
|
137
|
-
.createMintPayload(payloadHashArray, Array.from(mintPayload.bytes()))
|
|
138
|
-
.accounts({
|
|
139
|
-
payer: provider.publicKey,
|
|
140
|
-
config: configPDA,
|
|
141
|
-
// @ts-ignore -- type error from idl even though payload is required
|
|
142
|
-
payload: mintPayloadPDA,
|
|
143
|
-
systemProgram: SystemProgram.programId,
|
|
144
|
-
})
|
|
145
|
-
.transaction();
|
|
146
|
-
await sendAndConfirmTransaction({
|
|
147
|
-
instruction: createPayloadIx,
|
|
148
|
-
connection,
|
|
149
|
-
provider,
|
|
150
|
-
debugLabel: 'Create Mint Payload',
|
|
151
|
-
});
|
|
152
|
-
} else {
|
|
153
|
-
debugLog('Mint payload already exists, skipping create instruction.');
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
// Step 2: Post Mint Signatures (if not already signed)
|
|
157
|
-
if (!payloadStatus.isSigned) {
|
|
158
|
-
await postMintSignatures({
|
|
159
|
-
connection,
|
|
160
|
-
provider,
|
|
161
|
-
program,
|
|
162
|
-
configPDA,
|
|
163
|
-
mintPayloadPDA,
|
|
164
|
-
payloadHashArray,
|
|
165
|
-
proofSignature,
|
|
166
|
-
});
|
|
167
|
-
} else {
|
|
168
|
-
debugLog('Payload already signed, skipping post signatures instruction.');
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
// Extract necessary data from the payload
|
|
172
|
-
const recipient = new PublicKey(recipientAddress);
|
|
173
|
-
const recipientATA = await getAssociatedTokenAddress(mint, recipient);
|
|
174
|
-
const amount = mintPayload.amount.startsWith('0x')
|
|
175
|
-
? BigInt(mintPayload.amount)
|
|
176
|
-
: BigInt(`0x${mintPayload.amount}`);
|
|
177
|
-
const depositId = generateDepositId(
|
|
178
|
-
recipientATA,
|
|
179
|
-
amount,
|
|
180
|
-
mintPayload.txId,
|
|
181
|
-
Number(mintPayload.vout),
|
|
182
|
-
);
|
|
183
|
-
const DEPOSIT_SEED = Buffer.from('deposit');
|
|
184
|
-
const [depositPDA] = config.bascule
|
|
185
|
-
? PublicKey.findProgramAddressSync(
|
|
186
|
-
[DEPOSIT_SEED, depositId],
|
|
187
|
-
new PublicKey(config.bascule),
|
|
188
|
-
)
|
|
189
|
-
: [];
|
|
190
|
-
|
|
191
|
-
// Step 3: Mint From Payload (Always add if not already minted)
|
|
192
|
-
const mintTx = await program.methods
|
|
193
|
-
.mintFromPayload(payloadHashArray)
|
|
194
|
-
.accounts({
|
|
195
|
-
config: configPDA,
|
|
196
|
-
tokenProgram: TOKEN_PROGRAM_ID,
|
|
197
|
-
recipient: recipientATA,
|
|
198
|
-
mint,
|
|
199
|
-
mintAuthority: lzMultisig,
|
|
200
|
-
tokenAuthority: tokenAuth,
|
|
201
|
-
payload: mintPayloadPDA,
|
|
202
|
-
// @ts-ignore -- type error from idl even though payload is required
|
|
203
|
-
bascule: config.bascule,
|
|
204
|
-
basculeData: config.basculeData,
|
|
205
|
-
deposit: depositPDA,
|
|
206
|
-
systemProgram: SystemProgram.programId,
|
|
207
|
-
signer: provider.publicKey,
|
|
208
|
-
})
|
|
209
|
-
.transaction();
|
|
210
|
-
|
|
211
|
-
const { signature } = await sendAndConfirmTransaction({
|
|
212
|
-
instruction: mintTx,
|
|
213
|
-
connection,
|
|
214
|
-
provider,
|
|
215
|
-
debugLabel: 'Mint From Payload',
|
|
216
|
-
});
|
|
217
|
-
|
|
218
|
-
return signature;
|
|
219
|
-
} catch (error: unknown) {
|
|
220
|
-
if (error instanceof Error) {
|
|
221
|
-
error.message = `${error.message}\n\nDebug logs:\n${printLogs()}`;
|
|
222
|
-
}
|
|
223
|
-
throw error;
|
|
224
|
-
}
|
|
225
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './claimLBTC';
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import { Buffer } from 'node:buffer'; // Use buffer package for cross-platform compatibility
|
|
2
|
-
|
|
3
|
-
import { PublicKey } from '@solana/web3.js';
|
|
4
|
-
import { keccak256 } from 'js-sha3';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Represents the unique identifier for a deposit, derived from transaction details.
|
|
8
|
-
* It's a 32-byte array, typically the result of a Keccak-256 hash.
|
|
9
|
-
*/
|
|
10
|
-
export type DepositId = Uint8Array;
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Generates a unique deposit ID (address) based on transaction details, mirroring
|
|
14
|
-
* the logic used in the corresponding Solana smart contract.
|
|
15
|
-
*
|
|
16
|
-
* The ID is computed using the following formula:
|
|
17
|
-
* keccak256(
|
|
18
|
-
* [0u8; 32] // 32-byte zero prefix
|
|
19
|
-
* || [0x03, 0x53, 0x4f, 0x4c] // 4-byte chain ID ("\x03SOL")
|
|
20
|
-
* || recipient (32 bytes)
|
|
21
|
-
* || amount (u64, 8 bytes, big-endian)
|
|
22
|
-
* || tx_id (32 bytes)
|
|
23
|
-
* || tx_vout (u32, 4 bytes, big-endian)
|
|
24
|
-
* )
|
|
25
|
-
*
|
|
26
|
-
* Adapted from: https://github.com/lombard-finance/sol-contracts/blob/632491cb92fd2f206b0e563b1e72e4b2ae2eadf5/programs/bascule/src/instructions/validator.rs#L118-L138
|
|
27
|
-
*
|
|
28
|
-
* @param recipient - The recipient's Solana public key.
|
|
29
|
-
* @param amount - The amount of the transaction (as a bigint, representing u64).
|
|
30
|
-
* @param txId - The transaction ID (as a 32-byte Uint8Array or Buffer).
|
|
31
|
-
* @param txVout - The transaction output index (as a number, representing u32).
|
|
32
|
-
* @returns A 32-byte Uint8Array representing the calculated deposit ID.
|
|
33
|
-
* @throws Error if txId is not 32 bytes long.
|
|
34
|
-
*/
|
|
35
|
-
export function generateDepositId(
|
|
36
|
-
recipient: PublicKey,
|
|
37
|
-
amount: bigint,
|
|
38
|
-
txId: string,
|
|
39
|
-
txVout: number,
|
|
40
|
-
): DepositId {
|
|
41
|
-
const txIdBuffer = Buffer.from(txId, 'hex');
|
|
42
|
-
const reversedTxIdBuffer = txIdBuffer.reverse();
|
|
43
|
-
|
|
44
|
-
if (reversedTxIdBuffer.length !== 32) {
|
|
45
|
-
throw new Error('txId must be a 32-byte array.');
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const prefix = Buffer.alloc(32, 0);
|
|
49
|
-
const chainId = Buffer.from([0x03, 0x53, 0x4f, 0x4c]);
|
|
50
|
-
const recipientBuffer = recipient.toBuffer();
|
|
51
|
-
const amountBuffer = Buffer.alloc(8);
|
|
52
|
-
amountBuffer.writeBigUInt64BE(amount);
|
|
53
|
-
|
|
54
|
-
const txVoutBuffer = Buffer.alloc(4);
|
|
55
|
-
txVoutBuffer.writeUInt32BE(txVout);
|
|
56
|
-
|
|
57
|
-
const dataToHash = Buffer.concat([
|
|
58
|
-
new Uint8Array(prefix),
|
|
59
|
-
new Uint8Array(chainId),
|
|
60
|
-
new Uint8Array(recipientBuffer),
|
|
61
|
-
new Uint8Array(amountBuffer),
|
|
62
|
-
new Uint8Array(reversedTxIdBuffer),
|
|
63
|
-
new Uint8Array(txVoutBuffer),
|
|
64
|
-
]);
|
|
65
|
-
|
|
66
|
-
const dataToHashUint8Array = new Uint8Array(
|
|
67
|
-
dataToHash.buffer,
|
|
68
|
-
dataToHash.byteOffset,
|
|
69
|
-
dataToHash.byteLength,
|
|
70
|
-
);
|
|
71
|
-
const hashString = keccak256(dataToHashUint8Array);
|
|
72
|
-
const hashBuffer = Buffer.from(hashString, 'hex');
|
|
73
|
-
|
|
74
|
-
return new Uint8Array(hashBuffer);
|
|
75
|
-
}
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
export const parseTransactionLogs = (
|
|
2
|
-
err: unknown,
|
|
3
|
-
): { errorMessage: string; errorLogs: string[] } => {
|
|
4
|
-
console.error('Error claiming LBTC:', err);
|
|
5
|
-
let errorMessage =
|
|
6
|
-
typeof err === 'object' && err !== null && 'message' in err
|
|
7
|
-
? (err.message as string)
|
|
8
|
-
: String(err);
|
|
9
|
-
let errorLogs: string[] = [];
|
|
10
|
-
|
|
11
|
-
if (typeof errorMessage === 'string') {
|
|
12
|
-
const logParts = errorMessage.split('Logs:');
|
|
13
|
-
if (logParts.length > 1) {
|
|
14
|
-
errorMessage = logParts[0].trim();
|
|
15
|
-
try {
|
|
16
|
-
let logsText = logParts[1].trim();
|
|
17
|
-
|
|
18
|
-
if (logsText.startsWith('[') && logsText.endsWith(']')) {
|
|
19
|
-
try {
|
|
20
|
-
errorLogs = JSON.parse(logsText);
|
|
21
|
-
|
|
22
|
-
return { errorMessage, errorLogs };
|
|
23
|
-
} catch {
|
|
24
|
-
logsText = logsText.replace(/^\[|\]$/g, '');
|
|
25
|
-
errorLogs = logsText
|
|
26
|
-
.split(/",?\s*"/)
|
|
27
|
-
.map(line => line.replace(/^"|"$/g, '')); // Remove quotes
|
|
28
|
-
|
|
29
|
-
return { errorMessage, errorLogs };
|
|
30
|
-
}
|
|
31
|
-
} else {
|
|
32
|
-
errorLogs = logsText.split('\n').filter(line => line.trim() !== '');
|
|
33
|
-
return { errorMessage, errorLogs };
|
|
34
|
-
}
|
|
35
|
-
} catch (parseError) {
|
|
36
|
-
console.error('Failed to parse logs:', parseError);
|
|
37
|
-
errorMessage = err instanceof Error ? err.message : String(err);
|
|
38
|
-
return { errorMessage, errorLogs: [] };
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
return { errorMessage, errorLogs };
|
|
44
|
-
};
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import { Program } from '@coral-xyz/anchor';
|
|
2
|
-
import { PublicKey } from '@solana/web3.js';
|
|
3
|
-
|
|
4
|
-
import type { Lbtc } from '../../../idl/lbtc';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Status of a mint payload on-chain
|
|
8
|
-
*/
|
|
9
|
-
export interface PayloadStatus {
|
|
10
|
-
/**
|
|
11
|
-
* Whether the payload exists on-chain
|
|
12
|
-
*/
|
|
13
|
-
exists: boolean;
|
|
14
|
-
/**
|
|
15
|
-
* Whether the payload has been signed (signatures posted)
|
|
16
|
-
*/
|
|
17
|
-
isSigned: boolean;
|
|
18
|
-
/**
|
|
19
|
-
* Whether the LBTC tokens have been minted
|
|
20
|
-
*/
|
|
21
|
-
isMinted: boolean;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Checks the status of a mint payload on the Solana blockchain
|
|
26
|
-
*
|
|
27
|
-
* @param program Anchor program instance
|
|
28
|
-
* @param mintPayloadPDA The PDA address where the mint payload is stored
|
|
29
|
-
* @param debugLog Debug logging function
|
|
30
|
-
* @returns The status of the payload
|
|
31
|
-
*/
|
|
32
|
-
export async function checkPayloadStatus(
|
|
33
|
-
program: Program<Lbtc>,
|
|
34
|
-
mintPayloadPDA: PublicKey,
|
|
35
|
-
debugLog: (...args: unknown[]) => void,
|
|
36
|
-
): Promise<PayloadStatus> {
|
|
37
|
-
try {
|
|
38
|
-
const payloadAccount =
|
|
39
|
-
await program.account.mintPayload.fetch(mintPayloadPDA);
|
|
40
|
-
|
|
41
|
-
if (!payloadAccount) {
|
|
42
|
-
return { exists: false, isSigned: false, isMinted: false };
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const isSigned = Array.isArray(payloadAccount.signed)
|
|
46
|
-
? payloadAccount.signed.every((signed: boolean) => signed === true)
|
|
47
|
-
: false;
|
|
48
|
-
|
|
49
|
-
return {
|
|
50
|
-
exists: true,
|
|
51
|
-
isSigned,
|
|
52
|
-
isMinted: !!payloadAccount.minted,
|
|
53
|
-
};
|
|
54
|
-
} catch (error) {
|
|
55
|
-
debugLog('Error checking payload status:', error);
|
|
56
|
-
return { exists: false, isSigned: false, isMinted: false };
|
|
57
|
-
}
|
|
58
|
-
}
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { Program } from '@coral-xyz/anchor';
|
|
2
|
-
import { Connection, PublicKey } from '@solana/web3.js';
|
|
3
|
-
|
|
4
|
-
import { Lbtc } from '../../../idl/lbtc';
|
|
5
|
-
import { ISolanaWalletProvider } from '../../../types';
|
|
6
|
-
import { sendAndConfirmTransaction } from '../../../utils';
|
|
7
|
-
import { parseSignaturesFromProof } from './signatureUtils';
|
|
8
|
-
|
|
9
|
-
export const postMintSignatures = async ({
|
|
10
|
-
connection,
|
|
11
|
-
provider,
|
|
12
|
-
program,
|
|
13
|
-
configPDA,
|
|
14
|
-
mintPayloadPDA,
|
|
15
|
-
payloadHashArray,
|
|
16
|
-
proofSignature,
|
|
17
|
-
}: {
|
|
18
|
-
connection: Connection;
|
|
19
|
-
provider: ISolanaWalletProvider;
|
|
20
|
-
program: Program<Lbtc>;
|
|
21
|
-
configPDA: PublicKey;
|
|
22
|
-
mintPayloadPDA: PublicKey;
|
|
23
|
-
payloadHashArray: number[];
|
|
24
|
-
proofSignature: string;
|
|
25
|
-
}) => {
|
|
26
|
-
const { signatures: parsedSignaturesUint8, indices } =
|
|
27
|
-
parseSignaturesFromProof(proofSignature);
|
|
28
|
-
|
|
29
|
-
if (parsedSignaturesUint8.length === 0 || indices.length === 0) {
|
|
30
|
-
throw new Error('No valid signatures found in the proof');
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// Convert Uint8Array[] to number[][]
|
|
34
|
-
const signatures = parsedSignaturesUint8.map(sig => Array.from(sig));
|
|
35
|
-
|
|
36
|
-
const postSignaturesIx = await program.methods
|
|
37
|
-
.postMintSignatures(payloadHashArray, signatures, indices)
|
|
38
|
-
.accounts({
|
|
39
|
-
config: configPDA,
|
|
40
|
-
// @ts-ignore -- type error from idl even though payload is required
|
|
41
|
-
payload: mintPayloadPDA,
|
|
42
|
-
})
|
|
43
|
-
.transaction();
|
|
44
|
-
return await sendAndConfirmTransaction({
|
|
45
|
-
instruction: postSignaturesIx,
|
|
46
|
-
connection,
|
|
47
|
-
provider,
|
|
48
|
-
debugLabel: 'Post Mint Signatures',
|
|
49
|
-
});
|
|
50
|
-
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './unstakeLBTC';
|
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
Button,
|
|
5
|
-
ConnectButton,
|
|
6
|
-
ErrorDisplay,
|
|
7
|
-
ResultDisplay,
|
|
8
|
-
} from '../../stories/components';
|
|
9
|
-
import { functionType } from '../../stories/decorators/function-type';
|
|
10
|
-
import { useConnect } from '../../stories/hooks/useConnect';
|
|
11
|
-
import useQuery from '../../stories/hooks/useQuery';
|
|
12
|
-
import { SolanaNetwork } from '../../types';
|
|
13
|
-
import { unstakeLBTC } from './unstakeLBTC';
|
|
14
|
-
|
|
15
|
-
interface UnstakeLbtcStoryArgs {
|
|
16
|
-
network: SolanaNetwork;
|
|
17
|
-
amountSats: string;
|
|
18
|
-
btcAddress: string;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const DEFAULT_AMOUNT_SATS = '22000';
|
|
22
|
-
|
|
23
|
-
export const StoryView = ({
|
|
24
|
-
network,
|
|
25
|
-
amountSats,
|
|
26
|
-
btcAddress,
|
|
27
|
-
}: UnstakeLbtcStoryArgs) => {
|
|
28
|
-
const {
|
|
29
|
-
data: connectionData,
|
|
30
|
-
error: connectError,
|
|
31
|
-
isLoading: isConnecting,
|
|
32
|
-
connect,
|
|
33
|
-
disconnect,
|
|
34
|
-
} = useConnect();
|
|
35
|
-
const isConnected = !!connectionData;
|
|
36
|
-
const address = connectionData?.address;
|
|
37
|
-
const provider = connectionData?.provider;
|
|
38
|
-
|
|
39
|
-
const request = async () => {
|
|
40
|
-
if (!provider || !address) throw new Error('Wallet not connected.');
|
|
41
|
-
if (!btcAddress)
|
|
42
|
-
throw new Error('Destination Bitcoin address is required (set in args).');
|
|
43
|
-
if (!amountSats || !/^[1-9]\d*$/.test(amountSats))
|
|
44
|
-
throw new Error(
|
|
45
|
-
'Amount must be a positive integer in satoshis (set in args).',
|
|
46
|
-
);
|
|
47
|
-
|
|
48
|
-
const result = await unstakeLBTC(provider, {
|
|
49
|
-
amount: amountSats,
|
|
50
|
-
btcAddress,
|
|
51
|
-
network: network,
|
|
52
|
-
});
|
|
53
|
-
return result;
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
const {
|
|
57
|
-
data: txHash,
|
|
58
|
-
error,
|
|
59
|
-
isLoading,
|
|
60
|
-
refetch: handleUnstake,
|
|
61
|
-
} = useQuery(
|
|
62
|
-
request,
|
|
63
|
-
[provider, address, amountSats, btcAddress, network],
|
|
64
|
-
false,
|
|
65
|
-
);
|
|
66
|
-
|
|
67
|
-
return (
|
|
68
|
-
<>
|
|
69
|
-
<ConnectButton
|
|
70
|
-
connect={connect}
|
|
71
|
-
disconnect={disconnect}
|
|
72
|
-
isConnected={isConnected}
|
|
73
|
-
isLoading={isConnecting}
|
|
74
|
-
error={connectError}
|
|
75
|
-
walletName={connectionData?.walletName}
|
|
76
|
-
address={connectionData?.address}
|
|
77
|
-
network={network}
|
|
78
|
-
/>
|
|
79
|
-
|
|
80
|
-
{isConnected && (
|
|
81
|
-
<>
|
|
82
|
-
<div className="d-grid gap-2 my-4">
|
|
83
|
-
<Button
|
|
84
|
-
primary
|
|
85
|
-
size="large"
|
|
86
|
-
onClick={handleUnstake}
|
|
87
|
-
isLoading={isLoading}
|
|
88
|
-
actionName={unstakeLBTC.name}
|
|
89
|
-
/>
|
|
90
|
-
</div>
|
|
91
|
-
|
|
92
|
-
{txHash && (
|
|
93
|
-
<ResultDisplay
|
|
94
|
-
result={txHash}
|
|
95
|
-
title="Unstake Transaction Hash"
|
|
96
|
-
successMessage="Success! Unstake transaction submitted."
|
|
97
|
-
/>
|
|
98
|
-
)}
|
|
99
|
-
{(error || connectError) && (
|
|
100
|
-
<ErrorDisplay error={error || connectError} title="Unstake Error" />
|
|
101
|
-
)}
|
|
102
|
-
</>
|
|
103
|
-
)}
|
|
104
|
-
</>
|
|
105
|
-
);
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
const meta: Meta<typeof StoryView> = {
|
|
109
|
-
title: 'write/unstakeLBTC',
|
|
110
|
-
component: StoryView,
|
|
111
|
-
tags: ['autodocs'],
|
|
112
|
-
decorators: [functionType('write')],
|
|
113
|
-
parameters: {
|
|
114
|
-
docs: {
|
|
115
|
-
description: {
|
|
116
|
-
component:
|
|
117
|
-
'Demonstrates unstaking LBTC from Solana back to a Bitcoin address using the `unstakeLBTC` SDK function. Requires the amount in satoshis and the destination Bitcoin address.',
|
|
118
|
-
},
|
|
119
|
-
},
|
|
120
|
-
},
|
|
121
|
-
args: {
|
|
122
|
-
network: SolanaNetwork.devnet,
|
|
123
|
-
amountSats: DEFAULT_AMOUNT_SATS,
|
|
124
|
-
btcAddress: '',
|
|
125
|
-
},
|
|
126
|
-
argTypes: {
|
|
127
|
-
network: {
|
|
128
|
-
control: { type: 'select' },
|
|
129
|
-
options: Object.values(SolanaNetwork),
|
|
130
|
-
},
|
|
131
|
-
amountSats: {
|
|
132
|
-
control: { type: 'text' },
|
|
133
|
-
},
|
|
134
|
-
btcAddress: {
|
|
135
|
-
control: { type: 'text' },
|
|
136
|
-
},
|
|
137
|
-
},
|
|
138
|
-
};
|
|
139
|
-
|
|
140
|
-
export default meta;
|
|
141
|
-
type Story = StoryObj<typeof meta>;
|