@glamsystems/glam-cli 1.0.3-alpha.4 → 1.0.3-alpha.6

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.
Files changed (2) hide show
  1. package/main.js +119 -57
  2. package/package.json +2 -2
package/main.js CHANGED
@@ -5240,6 +5240,9 @@ async function fetchTokenPrices(pubkeys) {
5240
5240
  async function fetchTokensList() {
5241
5241
  const response = await fetch(`${JUPITER_API}/tokens/v2/tag?query=verified`);
5242
5242
  const data = await response.json();
5243
+ if (!response.ok) {
5244
+ throw new Error(`Failed to fetch tokens list and prices from Jupiter: ${response.status} ${data?.message}`);
5245
+ }
5243
5246
  const tokenList = data?.map((t) => ({
5244
5247
  address: t.id,
5245
5248
  name: t.name,
@@ -5248,6 +5251,7 @@ async function fetchTokensList() {
5248
5251
  logoURI: t.icon,
5249
5252
  tags: t.tags,
5250
5253
  usdPrice: t.usdPrice,
5254
+ slot: t.priceBlockId,
5251
5255
  }));
5252
5256
  return tokenList;
5253
5257
  }
@@ -8363,11 +8367,12 @@ const spl_token_1 = __webpack_require__(17);
8363
8367
  const constants_1 = __webpack_require__(25);
8364
8368
  const jupiter_1 = __webpack_require__(57);
8365
8369
  class Holding {
8366
- constructor(mintAddress, decimals, amount, price, protocol, protocolMeta = {}) {
8370
+ constructor(mintAddress, decimals, amount, price, priceMeta = {}, protocol, protocolMeta = {}) {
8367
8371
  this.mintAddress = mintAddress;
8368
8372
  this.decimals = decimals;
8369
8373
  this.amount = amount;
8370
8374
  this.price = price;
8375
+ this.priceMeta = priceMeta;
8371
8376
  this.protocol = protocol;
8372
8377
  this.protocolMeta = protocolMeta;
8373
8378
  this.uiAmount = (0, utils_1.toUiAmount)(this.amount, this.decimals);
@@ -8481,7 +8486,7 @@ class PriceClient {
8481
8486
  .map((v) => Array.from(v.pkValues()))
8482
8487
  .flat();
8483
8488
  // Dedupe keys and fetch all accounts in a single RPC call
8484
- const pubkeys = Array.from(new utils_1.PkSet(tokenPubkeys.concat(...driftUsers, ...driftSpotMarkets, ...kaminoObligations, ...kaminoReserves)));
8489
+ const pubkeys = Array.from(new utils_1.PkSet(tokenPubkeys.concat(...driftUsers, ...driftSpotMarkets, ...kaminoObligations, ...kaminoReserves, web3_js_1.SYSVAR_CLOCK_PUBKEY)));
8485
8490
  const { context: { slot }, value: accountsInfo, } = await this.base.provider.connection.getMultipleAccountsInfoAndContext(pubkeys, commitment);
8486
8491
  // Build a map of pubkey to account data for quick lookup
8487
8492
  const accountsDataMap = new utils_1.PkMap();
@@ -8506,10 +8511,12 @@ class PriceClient {
8506
8511
  const tokenMint = new web3_js_1.PublicKey(item.address);
8507
8512
  tokenPricesMap.set(tokenMint, item);
8508
8513
  });
8509
- const tokenHoldings = this.getTokenHoldings(tokenPubkeys, accountsDataMap, tokenPricesMap);
8510
- const driftSpotHoldings = this.getDriftSpotHoldings(driftPubkeys.pkKeys(), driftSpotMarketsMap, accountsDataMap, tokenPricesMap);
8511
- const kaminoLendHoldings = this.getKaminoLendHoldings(kaminoPubkeys.pkKeys(), kaminoReservesMap, accountsDataMap, tokenPricesMap);
8512
- const timestamp = await this.base.connection.getBlockTime(slot);
8514
+ const tokenHoldings = this.getTokenHoldings(tokenPubkeys, accountsDataMap, tokenPricesMap, "Jupiter");
8515
+ const driftSpotHoldings = this.getDriftSpotHoldings(driftPubkeys.pkKeys(), driftSpotMarketsMap, accountsDataMap, tokenPricesMap, "Jupiter");
8516
+ const kaminoLendHoldings = this.getKaminoLendHoldings(kaminoPubkeys.pkKeys(), kaminoReservesMap, accountsDataMap, tokenPricesMap, "Jupiter");
8517
+ const timestamp = accountsDataMap
8518
+ .get(web3_js_1.SYSVAR_CLOCK_PUBKEY)
8519
+ .readUInt32LE(32);
8513
8520
  const ret = new VaultHoldings(this.base.statePda, this.base.vaultPda, priceBaseAssetMint, slot, timestamp, commitment);
8514
8521
  tokenHoldings.forEach((holding) => ret.add(holding));
8515
8522
  driftSpotHoldings.forEach((holding) => ret.add(holding));
@@ -8567,7 +8574,7 @@ class PriceClient {
8567
8574
  }
8568
8575
  return obligationReservesMap;
8569
8576
  }
8570
- getTokenHoldings(tokenAccountPubkeys, accountsDataMap, tokenPricesMap) {
8577
+ getTokenHoldings(tokenAccountPubkeys, accountsDataMap, tokenPricesMap, priceSource) {
8571
8578
  const holdings = [];
8572
8579
  if (tokenAccountPubkeys.length === 0) {
8573
8580
  return holdings;
@@ -8577,7 +8584,10 @@ class PriceClient {
8577
8584
  const tokenInfo = tokenPricesMap.get(mint);
8578
8585
  if (tokenInfo) {
8579
8586
  const { decimals, usdPrice } = tokenInfo;
8580
- const holding = new Holding(mint, decimals, new anchor_1.BN(amount), usdPrice, "Token", {
8587
+ const holding = new Holding(mint, decimals, new anchor_1.BN(amount), usdPrice, {
8588
+ slot: tokenInfo.slot,
8589
+ source: priceSource,
8590
+ }, "Token", {
8581
8591
  tokenAccount: pubkey,
8582
8592
  });
8583
8593
  holdings.push(holding);
@@ -8585,7 +8595,7 @@ class PriceClient {
8585
8595
  }
8586
8596
  return holdings;
8587
8597
  }
8588
- getDriftSpotHoldings(userPubkeys, spotMarketsMap, accountsDataMap, tokenPricesMap) {
8598
+ getDriftSpotHoldings(userPubkeys, spotMarketsMap, accountsDataMap, tokenPricesMap, priceSource) {
8589
8599
  const holdings = [];
8590
8600
  for (const userPda of userPubkeys) {
8591
8601
  const { spotPositions } = (0, utils_1.decodeUser)(accountsDataMap.get(userPda));
@@ -8597,7 +8607,10 @@ class PriceClient {
8597
8607
  : cumulativeDepositInterest;
8598
8608
  const amount = this.drift.calcSpotBalanceBn(scaledBalance, decimals, interest);
8599
8609
  const direction = Object.keys(balanceType)[0];
8600
- const holding = new Holding(mint, decimals, amount, tokenPricesMap.get(mint).usdPrice, "DriftProtocol", {
8610
+ const holding = new Holding(mint, decimals, amount, tokenPricesMap.get(mint).usdPrice, {
8611
+ slot: tokenPricesMap.get(mint).slot,
8612
+ source: priceSource,
8613
+ }, "DriftProtocol", {
8601
8614
  user: userPda,
8602
8615
  marketIndex: marketIndex,
8603
8616
  direction: direction,
@@ -8607,7 +8620,7 @@ class PriceClient {
8607
8620
  }
8608
8621
  return holdings;
8609
8622
  }
8610
- getKaminoLendHoldings(obligationPubkeys, reservesMap, accountsDataMap, tokenPricesMap) {
8623
+ getKaminoLendHoldings(obligationPubkeys, reservesMap, accountsDataMap, tokenPricesMap, priceSource) {
8611
8624
  const holdings = [];
8612
8625
  for (const obligation of obligationPubkeys) {
8613
8626
  const { deposits, borrows } = this.klend.parseObligation(obligation, accountsDataMap.get(obligation));
@@ -8617,7 +8630,10 @@ class PriceClient {
8617
8630
  .div(parsedReserve.collateralExchangeRate)
8618
8631
  .floor();
8619
8632
  const amount = new anchor_1.BN(supplyAmount.toString());
8620
- const holding = new Holding(parsedReserve.liquidityMint, parsedReserve.liquidityMintDecimals, amount, tokenPricesMap.get(parsedReserve.liquidityMint).usdPrice, "KaminoLend", {
8633
+ const holding = new Holding(parsedReserve.liquidityMint, parsedReserve.liquidityMintDecimals, amount, tokenPricesMap.get(parsedReserve.liquidityMint).usdPrice, {
8634
+ slot: tokenPricesMap.get(parsedReserve.liquidityMint).slot,
8635
+ source: priceSource,
8636
+ }, "KaminoLend", {
8621
8637
  obligation,
8622
8638
  market: parsedReserve.market,
8623
8639
  reserve,
@@ -8634,7 +8650,10 @@ class PriceClient {
8634
8650
  .div(obligationCumulativeBorrowRate)
8635
8651
  .ceil();
8636
8652
  const amount = new anchor_1.BN(borrowAmount.toString());
8637
- const holding = new Holding(parsedReserve.liquidityMint, parsedReserve.liquidityMintDecimals, amount, tokenPricesMap.get(parsedReserve.liquidityMint).usdPrice, "KaminoLend", {
8653
+ const holding = new Holding(parsedReserve.liquidityMint, parsedReserve.liquidityMintDecimals, amount, tokenPricesMap.get(parsedReserve.liquidityMint).usdPrice, {
8654
+ slot: tokenPricesMap.get(parsedReserve.liquidityMint).slot,
8655
+ source: priceSource,
8656
+ }, "KaminoLend", {
8638
8657
  obligation,
8639
8658
  market: parsedReserve.market,
8640
8659
  reserve,
@@ -10416,7 +10435,8 @@ class CctpClient {
10416
10435
  const ix = await this.buildReceiveMessageIx(sourceDomain, message);
10417
10436
  receiveMessageIxs.push(ix);
10418
10437
  }
10419
- const tx = new web3_js_1.Transaction().add(...receiveMessageIxs);
10438
+ const createUsdcAtaIx = (0, spl_token_1.createAssociatedTokenAccountIdempotentInstruction)(this.base.signer, this.base.getVaultAta(constants_1.USDC), this.base.vaultPda, constants_1.USDC);
10439
+ const tx = new web3_js_1.Transaction().add(createUsdcAtaIx, ...receiveMessageIxs);
10420
10440
  const vTx = await this.base.intoVersionedTransaction(tx, txOptions);
10421
10441
  return await this.base.sendAndConfirm(vTx);
10422
10442
  }
@@ -10468,9 +10488,17 @@ class CctpClient {
10468
10488
  ];
10469
10489
  }
10470
10490
  async buildReceiveMessageIx(sourceDomain, messageObj) {
10471
- const { message, attestation, eventNonce, decodedMessage: { decodedMessageBody: { burnToken }, }, } = messageObj;
10491
+ const { message, attestation, eventNonce, decodedMessage, status } = messageObj;
10492
+ if (status !== "complete") {
10493
+ throw new Error(`Attestation status is ${status}, expected "complete"`);
10494
+ }
10495
+ if (!decodedMessage ||
10496
+ !decodedMessage?.decodedMessageBody ||
10497
+ !decodedMessage?.decodedMessageBody?.burnToken) {
10498
+ throw new Error("Invalid message object: missing burnToken in decodedMessage");
10499
+ }
10472
10500
  // message, attestation, eventNonce, burnToken are hex strings
10473
- const pdas = await this.getReceiveMessagePdas(constants_1.MESSAGE_TRANSMITTER_V2, constants_1.TOKEN_MESSENGER_MINTER_V2, constants_1.USDC, burnToken, sourceDomain.toString(), eventNonce);
10501
+ const pdas = await this.getReceiveMessagePdas(constants_1.MESSAGE_TRANSMITTER_V2, constants_1.TOKEN_MESSENGER_MINTER_V2, constants_1.USDC, decodedMessage.decodedMessageBody.burnToken, sourceDomain.toString(), eventNonce);
10474
10502
  // raw ix data: [discriminator][message][attestation]
10475
10503
  const messageBuffer = Buffer.from(message.replace("0x", ""), "hex");
10476
10504
  const attestationBuffer = Buffer.from(attestation.replace("0x", ""), "hex");
@@ -10674,7 +10702,14 @@ class CctpClient {
10674
10702
  queryParams.set("transactionHash", txHash);
10675
10703
  }
10676
10704
  const resonse = await fetch(`https://iris-api.circle.com/v2/messages/${sourceDomain}?${queryParams}`);
10705
+ if (resonse.status !== 200) {
10706
+ const { error } = await resonse.json();
10707
+ throw new Error(`Failed to fetch messages from Circle API: ${resonse.status} ${error}`);
10708
+ }
10677
10709
  const { messages } = await resonse.json();
10710
+ if (!(messages instanceof Array)) {
10711
+ throw new Error("Invalid response from Circle API: messages not found");
10712
+ }
10678
10713
  return messages;
10679
10714
  }
10680
10715
  /**
@@ -13067,37 +13102,6 @@ function installVaultCommands(program, context) {
13067
13102
  process.exit(1);
13068
13103
  }
13069
13104
  });
13070
- program
13071
- .command("add-asset")
13072
- .argument("<asset>", "Asset mint public key", utils_1.validatePublicKey)
13073
- .description("Add a new asset to allowlist")
13074
- .action(async (asset) => {
13075
- const stateModel = await context.glamClient.fetchStateModel();
13076
- const assetsSet = new Set([...stateModel.assets, asset].map((a) => a.toBase58()));
13077
- const assets = Array.from(assetsSet).map((a) => new web3_js_1.PublicKey(a));
13078
- const txSig = await context.glamClient.state.update({ assets }, context.txOptions);
13079
- console.log(`Added asset ${asset}: ${txSig}`);
13080
- });
13081
- program
13082
- .command("delete-asset")
13083
- .argument("<asset>", "Asset mint public key", utils_1.validatePublicKey)
13084
- .description("Delete an asset from allowlist")
13085
- .action(async (asset) => {
13086
- const stateModel = await context.glamClient.fetchStateModel();
13087
- if (asset.equals(stateModel.baseAssetMint)) {
13088
- console.error("Base asset cannot be deleted from allowlist");
13089
- process.exit(1);
13090
- }
13091
- const assetsSet = new Set(stateModel.assets.map((a) => a.toBase58()));
13092
- let removed = assetsSet.delete(asset.toBase58());
13093
- if (!removed) {
13094
- console.error("Asset not found in allowlist, nothing to delete");
13095
- process.exit(1);
13096
- }
13097
- const assets = Array.from(assetsSet).map((a) => new web3_js_1.PublicKey(a));
13098
- const txSig = await context.glamClient.state.update({ assets }, context.txOptions);
13099
- console.log(`Deleted asset ${asset}: ${txSig}`);
13100
- });
13101
13105
  program
13102
13106
  .command("set-enabled <enabled>")
13103
13107
  .description("Set GLAM state enabled or disabled")
@@ -13319,6 +13323,58 @@ function installVaultCommands(program, context) {
13319
13323
  }
13320
13324
  });
13321
13325
  });
13326
+ program
13327
+ .command("asset-allowlist")
13328
+ .description("Get asset allowlist and corresponding token account")
13329
+ .action(async () => {
13330
+ const state = await context.glamClient.fetchStateAccount();
13331
+ const mints = await (0, glam_sdk_1.fetchMintsAndTokenPrograms)(context.glamClient.connection, state.assets);
13332
+ const data = mints.map(({ mint: { address, decimals }, tokenProgram }) => {
13333
+ const tokenAccount = context.glamClient.getVaultAta(address, tokenProgram);
13334
+ return {
13335
+ assetMint: address,
13336
+ decimals,
13337
+ tokenAccount,
13338
+ tokenProgram,
13339
+ };
13340
+ });
13341
+ console.log(JSON.stringify(data, null, 2));
13342
+ });
13343
+ program
13344
+ .command("add-asset")
13345
+ .argument("<asset>", "Asset mint public key", utils_1.validatePublicKey)
13346
+ .description("Add a new asset to allowlist")
13347
+ .action(async (asset) => {
13348
+ const state = await context.glamClient.fetchStateAccount();
13349
+ const assetsSet = new glam_sdk_1.PkSet(state.assets);
13350
+ if (assetsSet.has(asset)) {
13351
+ console.error(`Asset ${asset} already allowlisted`);
13352
+ process.exit(1);
13353
+ }
13354
+ const assets = Array.from(assetsSet.add(asset));
13355
+ const txSig = await context.glamClient.state.update({ assets }, context.txOptions);
13356
+ console.log(`Allowlisted asset ${asset}: ${txSig}`);
13357
+ });
13358
+ program
13359
+ .command("delete-asset")
13360
+ .argument("<asset>", "Asset mint public key", utils_1.validatePublicKey)
13361
+ .description("Delete an asset from allowlist")
13362
+ .action(async (asset) => {
13363
+ const state = await context.glamClient.fetchStateAccount();
13364
+ if (asset.equals(state.baseAssetMint)) {
13365
+ console.error("Base asset should not be deleted from allowlist");
13366
+ process.exit(1);
13367
+ }
13368
+ const assetsSet = new glam_sdk_1.PkSet(state.assets);
13369
+ let removed = assetsSet.delete(asset);
13370
+ if (!removed) {
13371
+ console.error(`${asset} not found in allowlist, nothing to delete`);
13372
+ process.exit(1);
13373
+ }
13374
+ const assets = Array.from(assetsSet);
13375
+ const txSig = await context.glamClient.state.update({ assets }, context.txOptions);
13376
+ console.log(`Deleted asset ${asset} from allowlist: ${txSig}`);
13377
+ });
13322
13378
  program
13323
13379
  .command("holdings")
13324
13380
  .description("Get vault holdings")
@@ -13666,15 +13722,21 @@ function installCctpCommands(program, context) {
13666
13722
  .option("-n, --nonce <nonce>", "Nonce hex string (start with 0x)")
13667
13723
  .description("Receive USDC from an EVM chain. Either txHash or nonce is required.")
13668
13724
  .action(async (sourceDomain, { txHash, nonce }) => {
13669
- await context.glamClient.cctp.receiveUsdc(sourceDomain, {
13670
- txHash,
13671
- nonce,
13672
- }, {
13673
- ...context.txOptions,
13674
- lookupTables: [
13675
- new web3_js_1.PublicKey("qj4EYgsGpnRdt9rvQW3wWZR8JVaKPg9rG9EB8DNgfz8"), // CCTP lookup table
13676
- ],
13677
- });
13725
+ try {
13726
+ await context.glamClient.cctp.receiveUsdc(sourceDomain, {
13727
+ txHash,
13728
+ nonce,
13729
+ }, {
13730
+ ...context.txOptions,
13731
+ lookupTables: [
13732
+ new web3_js_1.PublicKey("qj4EYgsGpnRdt9rvQW3wWZR8JVaKPg9rG9EB8DNgfz8"), // CCTP lookup table
13733
+ ],
13734
+ });
13735
+ }
13736
+ catch (e) {
13737
+ console.error((0, utils_1.parseTxError)(e));
13738
+ process.exit(1);
13739
+ }
13678
13740
  });
13679
13741
  program
13680
13742
  .command("list")
@@ -14106,7 +14168,7 @@ program
14106
14168
  initialize(config, skipSimulation);
14107
14169
  await (0, idl_1.idlCheck)(context.glamClient);
14108
14170
  })
14109
- .version("1.0.3-alpha.4");
14171
+ .version("1.0.3-alpha.6");
14110
14172
  program
14111
14173
  .command("env")
14112
14174
  .description("Display current environment setup")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glamsystems/glam-cli",
3
- "version": "1.0.3-alpha.4",
3
+ "version": "1.0.3-alpha.6",
4
4
  "description": "CLI for interacting with the GLAM Protocol",
5
5
  "main": "./main.js",
6
6
  "bin": {
@@ -21,7 +21,7 @@
21
21
  "node": ">=20.18.0"
22
22
  },
23
23
  "dependencies": {
24
- "@glamsystems/glam-sdk": "1.0.3-alpha.4",
24
+ "@glamsystems/glam-sdk": "1.0.3-alpha.6",
25
25
  "@switchboard-xyz/common": "^3.0.0",
26
26
  "commander": "^11.1.0",
27
27
  "decimal.js": "^10.6.0",