@wireio/stake 1.5.69 → 1.6.69

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/lib/stake.m.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { SolChainID, PublicKey as PublicKey$1, KeyType, EvmChainID } from '@wireio/core';
2
2
  import { PublicKey, StakeProgram, Keypair, SystemProgram, SYSVAR_INSTRUCTIONS_PUBKEY, SYSVAR_CLOCK_PUBKEY, SYSVAR_STAKE_HISTORY_PUBKEY, SYSVAR_RENT_PUBKEY, ComputeBudgetProgram, Connection, TransactionMessage, VersionedTransaction, Transaction, SendTransactionError } from '@solana/web3.js';
3
3
  import { BN, Program, AnchorProvider } from '@coral-xyz/anchor';
4
- import { getAssociatedTokenAddress, TOKEN_2022_PROGRAM_ID, getAssociatedTokenAddressSync, ASSOCIATED_TOKEN_PROGRAM_ID } from '@solana/spl-token';
4
+ import { getAssociatedTokenAddress, TOKEN_2022_PROGRAM_ID, getAssociatedTokenAddressSync, ASSOCIATED_TOKEN_PROGRAM_ID, createAssociatedTokenAccountInstruction } from '@solana/spl-token';
5
5
  import * as multisig from '@sqds/multisig';
6
6
  import bs58 from 'bs58';
7
7
  import { ethers, Contract, BigNumber } from 'ethers';
@@ -18318,7 +18318,7 @@ const DEVNET_PROGRAM_IDS = {
18318
18318
  LIQSOL_TOKEN: new PublicKey(liqsolTokenDevnetJson.address),
18319
18319
  VALIDATOR_LEADERBOARD: new PublicKey(validatorLeaderboardDevnetJson.address),
18320
18320
  TRANSFER_HOOK: new PublicKey(devnetTransferHookIDL.address),
18321
- ALT: new PublicKey("3dm6p83nqBTLnbJBFEfbHJ988y6cfKtrGSoKJbGD3hqp")
18321
+ ALT: new PublicKey("EG5pouZneDQxfw5coaWkkv5qeoJkRsgyMiq4r6bw7K2F")
18322
18322
  };
18323
18323
  const PROGRAM_IDS_BY_CHAIN = {
18324
18324
  [SolChainID.Mainnet]: MAINNET_PROGRAM_IDS,
@@ -19666,8 +19666,21 @@ class OutpostClient {
19666
19666
  return buildOutpostAccounts(this.connection, userPk, this.pgs);
19667
19667
  }
19668
19668
  async getTokenBalance(ata) {
19669
- const bal = await this.connection.getTokenAccountBalance(ata);
19670
- return new BN(bal.value.amount);
19669
+ try {
19670
+ const bal = await this.connection.getTokenAccountBalance(ata);
19671
+ return new BN(bal.value.amount);
19672
+ } catch (error) {
19673
+ if (this.isMissingTokenAccountError(error)) {
19674
+ return new BN(0);
19675
+ }
19676
+ throw error;
19677
+ }
19678
+ }
19679
+ isMissingTokenAccountError(error) {
19680
+ const message = String(
19681
+ error?.message ?? ""
19682
+ ).toLowerCase();
19683
+ return message.includes("failed to get token account balance") && message.includes("could not find account");
19671
19684
  }
19672
19685
  async fetchOutpostAccount(address) {
19673
19686
  const program = this.program;
@@ -20390,12 +20403,73 @@ const _SolanaStakingClient = class _SolanaStakingClient {
20390
20403
  throw err;
20391
20404
  }
20392
20405
  }
20406
+ getLiqsolDestinationOwner(owner) {
20407
+ return owner ?? this.squadsVaultPDA ?? this.anchor.wallet.publicKey;
20408
+ }
20409
+ getLiqsolDestinationAta(owner) {
20410
+ const destinationOwner = this.getLiqsolDestinationOwner(owner);
20411
+ const mint = this.program.deriveLiqsolMintPda();
20412
+ return getAssociatedTokenAddressSync(
20413
+ mint,
20414
+ destinationOwner,
20415
+ true,
20416
+ TOKEN_2022_PROGRAM_ID,
20417
+ ASSOCIATED_TOKEN_PROGRAM_ID
20418
+ );
20419
+ }
20420
+ async getLiqsolDestinationAtaState(owner) {
20421
+ const destinationOwner = this.getLiqsolDestinationOwner(owner);
20422
+ const mint = this.program.deriveLiqsolMintPda();
20423
+ const ata = this.getLiqsolDestinationAta(destinationOwner);
20424
+ const accountInfo = await this.connection.getAccountInfo(ata, "confirmed");
20425
+ return {
20426
+ owner: destinationOwner,
20427
+ mint,
20428
+ ata,
20429
+ exists: !!accountInfo
20430
+ };
20431
+ }
20432
+ async maybeBuildCreateLiqsolDestinationAtaIx(owner) {
20433
+ const state = await this.getLiqsolDestinationAtaState(owner);
20434
+ if (state.exists) {
20435
+ return null;
20436
+ }
20437
+ return createAssociatedTokenAccountInstruction(
20438
+ this.feePayer,
20439
+ state.ata,
20440
+ state.owner,
20441
+ state.mint,
20442
+ TOKEN_2022_PROGRAM_ID,
20443
+ ASSOCIATED_TOKEN_PROGRAM_ID
20444
+ );
20445
+ }
20446
+ async ensureLiqsolDestinationAta(owner) {
20447
+ this.ensureUser();
20448
+ const createAtaIx = await this.maybeBuildCreateLiqsolDestinationAtaIx(owner);
20449
+ if (!createAtaIx) {
20450
+ return null;
20451
+ }
20452
+ try {
20453
+ return await this.buildAndSendIx(createAtaIx);
20454
+ } catch (error) {
20455
+ if (!this.isAtaAlreadyCreatedError(error)) {
20456
+ throw error;
20457
+ }
20458
+ return null;
20459
+ }
20460
+ }
20461
+ async prependLiqsolDestinationAtaIx(ix, owner) {
20462
+ const ixs = Array.isArray(ix) ? [...ix] : [ix];
20463
+ const createAtaIx = await this.maybeBuildCreateLiqsolDestinationAtaIx(owner);
20464
+ return createAtaIx ? [createAtaIx, ...ixs] : ixs;
20465
+ }
20393
20466
  async claimLiqsolRewards() {
20394
20467
  this.ensureUser();
20395
20468
  const owner = this.squadsVaultPDA ?? this.anchor.wallet.publicKey;
20396
20469
  try {
20397
20470
  const ix = await this.distributionClient.buildClaimRewardsIx(owner);
20398
- return !!this.squadsX ? await this.sendSquadsIxs(ix) : await this.buildAndSendIx(ix);
20471
+ const ixs = await this.prependLiqsolDestinationAtaIx(ix, owner);
20472
+ return !!this.squadsX ? await this.sendSquadsIxs(ixs) : await this.buildAndSendIx(ixs);
20399
20473
  } catch (err) {
20400
20474
  console.log(`Failed to claim liqSOL rewards on Solana: ${err}`);
20401
20475
  throw err;
@@ -20422,8 +20496,10 @@ const _SolanaStakingClient = class _SolanaStakingClient {
20422
20496
  if (!amountLamports || amountLamports <= BigInt(0))
20423
20497
  throw new Error("Unstake amount must be greater than zero.");
20424
20498
  try {
20499
+ const owner = this.squadsVaultPDA ?? this.anchor.wallet.publicKey;
20425
20500
  const ix = await this.outpostClient.buildUnstakeIx(amountLamports, this.squadsVaultPDA);
20426
- return !!this.squadsX ? await this.sendSquadsIxs(ix) : await this.buildAndSendIx(ix);
20501
+ const ixs = await this.prependLiqsolDestinationAtaIx(ix, owner);
20502
+ return !!this.squadsX ? await this.sendSquadsIxs(ixs) : await this.buildAndSendIx(ixs);
20427
20503
  } catch (err) {
20428
20504
  console.log(`Failed to unstake Solana: ${err}`);
20429
20505
  throw err;
@@ -20481,7 +20557,8 @@ const _SolanaStakingClient = class _SolanaStakingClient {
20481
20557
  const user = this.squadsVaultPDA ?? this.anchor.wallet.publicKey;
20482
20558
  const unstakeIx = await this.outpostClient.buildUnstakeIx(amountLamports, user);
20483
20559
  const withdrawIx = await this.convertClient.buildWithdrawTx(amountLamports, user);
20484
- return !!this.squadsX ? await this.sendSquadsIxs([unstakeIx, withdrawIx]) : await this.buildAndSendIx([unstakeIx, withdrawIx]);
20560
+ const ixs = await this.prependLiqsolDestinationAtaIx([unstakeIx, withdrawIx], user);
20561
+ return !!this.squadsX ? await this.sendSquadsIxs(ixs) : await this.buildAndSendIx(ixs);
20485
20562
  } catch (err) {
20486
20563
  console.log(`Failed to unstake and withdraw: ${err}`);
20487
20564
  throw err;
@@ -20713,6 +20790,11 @@ const _SolanaStakingClient = class _SolanaStakingClient {
20713
20790
  const normalized = message.toLowerCase();
20714
20791
  return normalized.includes("legacyuserrecordmigrationrequired") || normalized.includes("legacy user record must be migrated") || normalized.includes("custom program error: 0x1784");
20715
20792
  }
20793
+ isAtaAlreadyCreatedError(error) {
20794
+ const message = error instanceof Error ? error.message : String(error ?? "");
20795
+ const normalized = message.toLowerCase();
20796
+ return normalized.includes("already in use") || normalized.includes("already exists");
20797
+ }
20716
20798
  async getTrancheSnapshot(chainID) {
20717
20799
  try {
20718
20800
  const [globalState, trancheState] = await Promise.all([
@@ -74167,6 +74249,198 @@ class Staker {
74167
74249
  }
74168
74250
  }
74169
74251
 
74252
+ async function getEthereumTransactionStatus(source, txId) {
74253
+ const provider = isEthereumStakingClient(source) ? getEthereumProvider(source) : source;
74254
+ const tx = await provider.getTransaction(txId).catch(() => null);
74255
+ const receipt = await provider.getTransactionReceipt(txId).catch(() => null);
74256
+ if (!tx && !receipt) {
74257
+ return {
74258
+ chain: "eth",
74259
+ txId,
74260
+ state: "not_found",
74261
+ timestampMs: null
74262
+ };
74263
+ }
74264
+ if (!receipt) {
74265
+ return {
74266
+ chain: "eth",
74267
+ txId,
74268
+ state: "pending",
74269
+ timestampMs: null,
74270
+ confirmations: tx?.confirmations ?? null
74271
+ };
74272
+ }
74273
+ const block = receipt.blockNumber != null ? await provider.getBlock(receipt.blockNumber).catch(() => null) : null;
74274
+ return {
74275
+ chain: "eth",
74276
+ txId,
74277
+ state: receipt.status === 0 ? "failed" : "confirmed",
74278
+ timestampMs: block?.timestamp ? block.timestamp * 1e3 : null,
74279
+ blockNumber: receipt.blockNumber,
74280
+ confirmations: tx?.confirmations ?? null
74281
+ };
74282
+ }
74283
+ async function getSolanaTransactionStatus(source, txId) {
74284
+ const connection = isSolanaStakingClient(source) ? source.connection : source;
74285
+ const statusResponse = await connection.getSignatureStatuses(
74286
+ [txId],
74287
+ { searchTransactionHistory: true }
74288
+ ).catch(() => ({ value: [null] }));
74289
+ const status = statusResponse.value[0];
74290
+ const transaction = await connection.getTransaction(txId, {
74291
+ commitment: "confirmed",
74292
+ maxSupportedTransactionVersion: 0
74293
+ }).catch(() => null);
74294
+ if (!status && !transaction) {
74295
+ return {
74296
+ chain: "sol",
74297
+ txId,
74298
+ state: "not_found",
74299
+ timestampMs: null
74300
+ };
74301
+ }
74302
+ const errorMessage = status?.err ? JSON.stringify(status.err) : void 0;
74303
+ const isConfirmed = !!transaction || status?.confirmationStatus === "confirmed" || status?.confirmationStatus === "finalized";
74304
+ return {
74305
+ chain: "sol",
74306
+ txId,
74307
+ state: status?.err ? "failed" : isConfirmed ? "confirmed" : "pending",
74308
+ timestampMs: transaction?.blockTime ? transaction.blockTime * 1e3 : null,
74309
+ slot: transaction?.slot ?? status?.slot,
74310
+ confirmations: status?.confirmations ?? null,
74311
+ errorMessage
74312
+ };
74313
+ }
74314
+ async function getStakingClientTransactionStatus(client, txId) {
74315
+ if (isEthereumStakingClient(client)) {
74316
+ return getEthereumTransactionStatus(client, txId);
74317
+ }
74318
+ return getSolanaTransactionStatus(client, txId);
74319
+ }
74320
+ async function submitEthereumStakeToWireFlow(client, amount, wireAccount) {
74321
+ ensureEthereumUser(client);
74322
+ const amountWei = BigNumber.isBigNumber(amount) ? amount : BigNumber.from(amount);
74323
+ const signerAddress = await client.address;
74324
+ if (!signerAddress) {
74325
+ throw new Error("Ethereum signer address is unavailable.");
74326
+ }
74327
+ const contractService = getEthereumContractService(client);
74328
+ const depositor = client.contract.Depositor.address;
74329
+ const liqRead = client.contract.LiqEthToken;
74330
+ const liqWrite = contractService.getWrite("LiqEthToken");
74331
+ const steps = [];
74332
+ const [balance, allowance, paused] = await Promise.all([
74333
+ liqRead.balanceOf(signerAddress),
74334
+ liqRead.allowance(signerAddress, depositor),
74335
+ client.contract.Depositor.paused()
74336
+ ]);
74337
+ if (paused) {
74338
+ throw new Error("StakeClient.performStakeToWire: Depositor is in a paused state");
74339
+ }
74340
+ if (!wireAccount?.trim()) {
74341
+ throw new Error("StakeClient.performStakeToWire: wireAccount is required");
74342
+ }
74343
+ if (balance.lt(amountWei)) {
74344
+ throw new Error("StakeClient.performStakeToWire: Insufficient LiqETH balance");
74345
+ }
74346
+ if (allowance.lt(amountWei)) {
74347
+ const approveTx = await liqWrite.approve(depositor, amountWei);
74348
+ const approveReceipt = await approveTx.wait(1);
74349
+ const updatedAllowance = await liqRead.allowance(signerAddress, depositor);
74350
+ if (updatedAllowance.lt(amountWei)) {
74351
+ throw new Error("StakeClient.performStakeToWire: Liq allowance approval failed or allowance still insufficient after approve");
74352
+ }
74353
+ steps.push({
74354
+ stepId: "approve",
74355
+ label: "Approve LIQETH spend",
74356
+ txId: approveTx.hash,
74357
+ timestampMs: approveReceipt?.blockNumber != null ? await getEthereumBlockTimestampMs(getEthereumProvider(client), approveReceipt.blockNumber) : null
74358
+ });
74359
+ }
74360
+ try {
74361
+ await client.contract.Depositor.callStatic.stakeLiqETHToWire(amountWei, wireAccount);
74362
+ } catch (error) {
74363
+ const formatted = formatContractErrors(error);
74364
+ throw new Error(`StakeClient.performStakeToWire: ${formatted.name ?? formatted.raw}`);
74365
+ }
74366
+ const txOverrides = await resolveContractWriteOverrides(
74367
+ client.contract.Depositor,
74368
+ "stakeLiqETHToWire",
74369
+ [amountWei, wireAccount]
74370
+ );
74371
+ const stakeTx = await client.contract.Depositor.stakeLiqETHToWire(
74372
+ amountWei,
74373
+ wireAccount,
74374
+ txOverrides
74375
+ );
74376
+ const stakeReceipt = await stakeTx.wait(1);
74377
+ steps.push({
74378
+ stepId: "source",
74379
+ label: "Stake LIQETH to Wire",
74380
+ txId: stakeTx.hash,
74381
+ timestampMs: stakeReceipt?.blockNumber != null ? await getEthereumBlockTimestampMs(getEthereumProvider(client), stakeReceipt.blockNumber) : null
74382
+ });
74383
+ return {
74384
+ finalTxId: stakeTx.hash,
74385
+ steps
74386
+ };
74387
+ }
74388
+ async function submitEthereumDepositAndStakeToWireFlow(client, amount, wireAccount) {
74389
+ ensureEthereumUser(client);
74390
+ const amountWei = BigNumber.isBigNumber(amount) ? amount : BigNumber.from(amount);
74391
+ if (amountWei.lte(0)) {
74392
+ throw new Error("Amount must be greater than zero.");
74393
+ }
74394
+ const convertClient = getEthereumConvertClient(client);
74395
+ const depositResult = await convertClient.performDeposit(amountWei);
74396
+ const steps = [{
74397
+ stepId: "deposit",
74398
+ label: "Deposit native ETH",
74399
+ txId: depositResult.txHash,
74400
+ timestampMs: depositResult.receipt?.blockNumber != null ? await getEthereumBlockTimestampMs(getEthereumProvider(client), depositResult.receipt.blockNumber) : null
74401
+ }];
74402
+ const stake = await submitEthereumStakeToWireFlow(client, amountWei, wireAccount);
74403
+ return {
74404
+ finalTxId: stake.finalTxId,
74405
+ steps: [...steps, ...stake.steps]
74406
+ };
74407
+ }
74408
+ function isEthereumStakingClient(value) {
74409
+ return value instanceof EthereumStakingClient;
74410
+ }
74411
+ function isSolanaStakingClient(value) {
74412
+ return value instanceof SolanaStakingClient;
74413
+ }
74414
+ function getEthereumProvider(client) {
74415
+ const provider = client.provider;
74416
+ if (!provider) {
74417
+ throw new Error("Ethereum provider is unavailable.");
74418
+ }
74419
+ return provider;
74420
+ }
74421
+ function getEthereumContractService(client) {
74422
+ const contractService = client.contractService;
74423
+ if (!contractService) {
74424
+ throw new Error("Ethereum contract service is unavailable.");
74425
+ }
74426
+ return contractService;
74427
+ }
74428
+ function getEthereumConvertClient(client) {
74429
+ const convertClient = client.convertClient;
74430
+ if (!convertClient?.performDeposit) {
74431
+ throw new Error("Ethereum convert client is unavailable.");
74432
+ }
74433
+ return convertClient;
74434
+ }
74435
+ function ensureEthereumUser(client) {
74436
+ const ensureUser = client.ensureUser;
74437
+ ensureUser?.call(client);
74438
+ }
74439
+ async function getEthereumBlockTimestampMs(provider, blockNumber) {
74440
+ const block = await provider.getBlock(blockNumber).catch(() => null);
74441
+ return block?.timestamp ? block.timestamp * 1e3 : null;
74442
+ }
74443
+
74170
74444
  const CONTRACT_NAMES = [
74171
74445
  "LiqEthAuthority",
74172
74446
  "BeaconState",
@@ -74202,5 +74476,5 @@ var types = /*#__PURE__*/Object.freeze({
74202
74476
  __proto__: null
74203
74477
  });
74204
74478
 
74205
- export { ADDRESSES, ADDRESS_BOOK_BY_CHAIN, CHAINLINK_FEED, CHAINLINK_PROGRAM, CONTRACTS_BY_CHAIN, ConvertClient$1 as ConvertClient, DEFAULT_AVERAGE_PAY_RATE, DEFAULT_PAY_RATE_LOOKBACK, DistributionClient, EPHEMERAL_RENT_EXEMPTION, ERC1155Abi, ERC20Abi, ERC721Abi, types$1 as ETH, EthereumContractService, EthereumInstaswapClient, EthereumStakingClient, HOODI_ADDRESSES, INDEX_SCALE$1 as INDEX_SCALE, INITIAL_TRANCHE_SUPPLY, LAMPORTS_PER_SOL, LeaderboardClient, MAINNET_ADDRESSES, OutpostClient, PAY_RATE_SCALE_FACTOR, PDA_SEEDS, PROGRAM_IDS_BY_CHAIN, PurchaseAsset, ReceiptNFTKind, SCALE, types as SOL, SolanaInstaswapClient, SolanaStakingClient, Staker, SupportedEvmChainID, SupportedSolChainID, TokenClient, airdropSol, buildOutpostAccounts, buildSolanaInstaswapCrossChainAccounts, buildSolanaSyndicateAccounts, buildSolanaTrancheLadder, buildSolanaTrancheSnapshot, ceilDiv, deriveEphemeralStakeAddress, generateRandomDepositAmount, generateTestKeypair, getEpochSnapshot, getErrorMessage, getProgramIds, lamportsToSol, msToEpochEnd, normalizeToBigInt, safeFetch, scheduledInstruction, sleep, solToLamports, toBigint, tokensToShares, waitForConfirmation, waitUntilSafeToExecuteFunction };
74479
+ export { ADDRESSES, ADDRESS_BOOK_BY_CHAIN, CHAINLINK_FEED, CHAINLINK_PROGRAM, CONTRACTS_BY_CHAIN, ConvertClient$1 as ConvertClient, DEFAULT_AVERAGE_PAY_RATE, DEFAULT_PAY_RATE_LOOKBACK, DistributionClient, EPHEMERAL_RENT_EXEMPTION, ERC1155Abi, ERC20Abi, ERC721Abi, types$1 as ETH, EthereumContractService, EthereumInstaswapClient, EthereumStakingClient, HOODI_ADDRESSES, INDEX_SCALE$1 as INDEX_SCALE, INITIAL_TRANCHE_SUPPLY, LAMPORTS_PER_SOL, LeaderboardClient, MAINNET_ADDRESSES, OutpostClient, PAY_RATE_SCALE_FACTOR, PDA_SEEDS, PROGRAM_IDS_BY_CHAIN, PurchaseAsset, ReceiptNFTKind, SCALE, types as SOL, SolanaInstaswapClient, SolanaStakingClient, Staker, SupportedEvmChainID, SupportedSolChainID, TokenClient, airdropSol, buildOutpostAccounts, buildSolanaInstaswapCrossChainAccounts, buildSolanaSyndicateAccounts, buildSolanaTrancheLadder, buildSolanaTrancheSnapshot, ceilDiv, deriveEphemeralStakeAddress, generateRandomDepositAmount, generateTestKeypair, getEpochSnapshot, getErrorMessage, getEthereumTransactionStatus, getProgramIds, getSolanaTransactionStatus, getStakingClientTransactionStatus, lamportsToSol, msToEpochEnd, normalizeToBigInt, safeFetch, scheduledInstruction, sleep, solToLamports, submitEthereumDepositAndStakeToWireFlow, submitEthereumStakeToWireFlow, toBigint, tokensToShares, waitForConfirmation, waitUntilSafeToExecuteFunction };
74206
74480
  //# sourceMappingURL=stake.m.js.map