@scallop-io/sui-scallop-sdk 2.2.3-pyth-sponsored-transaction-alpha.2 → 2.2.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scallop-io/sui-scallop-sdk",
3
- "version": "2.2.3-pyth-sponsored-transaction-alpha.2",
3
+ "version": "2.2.3",
4
4
  "description": "Typescript sdk for interacting with Scallop contract on SUI",
5
5
  "keywords": [
6
6
  "sui",
@@ -39,7 +39,7 @@
39
39
  ],
40
40
  "dependencies": {
41
41
  "@mysten/sui": "1.28.2",
42
- "@pythnetwork/pyth-sui-js": "2.1.0",
42
+ "@pythnetwork/pyth-sui-js": "2.2.0",
43
43
  "@scallop-io/sui-kit": "1.4.1",
44
44
  "@tanstack/query-core": "5.59.16",
45
45
  "axios": "^1.9.0",
@@ -146,6 +146,7 @@
146
146
  "scripts": {
147
147
  "clean": "rm -rf tsconfig.tsbuildinfo ./dist",
148
148
  "build": "pnpm run build:tsup",
149
+ "build:sourcemap": "tsup ./src/index.ts --format esm,cjs --sourcemap --dts",
149
150
  "build:tsup": "tsup ./src/index.ts --format esm,cjs --splitting --minify --treeshake --dts",
150
151
  "watch:tsup": "tsup ./src/index.ts --format esm,cjs --clean --splitting --watch",
151
152
  "watch:types": "tsc --watch",
@@ -313,7 +313,8 @@ const generateCoreQuickMethod: GenerateCoreQuickMethod = ({
313
313
  amount,
314
314
  collateralCoinName,
315
315
  obligationId,
316
- obligationKey
316
+ obligationKey,
317
+ updateOracleOptions
317
318
  ) => {
318
319
  const obligationInfo = await requireObligationInfo(
319
320
  builder,
@@ -324,7 +325,12 @@ const generateCoreQuickMethod: GenerateCoreQuickMethod = ({
324
325
  const updateCoinNames = await builder.utils.getObligationCoinNames(
325
326
  obligationInfo.obligationId
326
327
  );
327
- await updateOracles(builder, txBlock, updateCoinNames);
328
+ await updateOracles(
329
+ builder,
330
+ txBlock,
331
+ updateCoinNames,
332
+ updateOracleOptions
333
+ );
328
334
  return txBlock.takeCollateral(
329
335
  obligationInfo.obligationId,
330
336
  obligationInfo.obligationKey as SuiObjectArg,
@@ -387,7 +393,7 @@ const generateCoreQuickMethod: GenerateCoreQuickMethod = ({
387
393
  poolCoinName,
388
394
  obligationId,
389
395
  obligationKey,
390
- isSponsoredTx = false
396
+ updateOracleOptions
391
397
  ) => {
392
398
  const obligationInfo = await requireObligationInfo(
393
399
  builder,
@@ -400,7 +406,12 @@ const generateCoreQuickMethod: GenerateCoreQuickMethod = ({
400
406
  obligationInfo.obligationId
401
407
  )) ?? [];
402
408
  const updateCoinNames = [...obligationCoinNames, poolCoinName];
403
- await updateOracles(builder, txBlock, updateCoinNames, { isSponsoredTx });
409
+ await updateOracles(
410
+ builder,
411
+ txBlock,
412
+ updateCoinNames,
413
+ updateOracleOptions
414
+ );
404
415
  return txBlock.borrow(
405
416
  obligationInfo.obligationId,
406
417
  obligationInfo.obligationKey as SuiObjectArg,
@@ -414,7 +425,7 @@ const generateCoreQuickMethod: GenerateCoreQuickMethod = ({
414
425
  borrowReferral,
415
426
  obligationId,
416
427
  obligationKey,
417
- isSponsoredTx = false
428
+ updateOracleOptions
418
429
  ) => {
419
430
  const obligationInfo = await requireObligationInfo(
420
431
  builder,
@@ -427,9 +438,12 @@ const generateCoreQuickMethod: GenerateCoreQuickMethod = ({
427
438
  obligationInfo.obligationId
428
439
  )) ?? [];
429
440
  const updateCoinNames = [...obligationCoinNames, poolCoinName];
430
- await updateOracles(builder, txBlock, updateCoinNames, {
431
- isSponsoredTx,
432
- });
441
+ await updateOracles(
442
+ builder,
443
+ txBlock,
444
+ updateCoinNames,
445
+ updateOracleOptions
446
+ );
433
447
  return txBlock.borrowWithReferral(
434
448
  obligationInfo.obligationId,
435
449
  obligationInfo.obligationKey as SuiObjectArg,
@@ -461,8 +475,13 @@ const generateCoreQuickMethod: GenerateCoreQuickMethod = ({
461
475
  if (leftCoin) txBlock.transferObjects([leftCoin], sender);
462
476
  return txBlock.repay(obligationInfo.obligationId, takeCoin, poolCoinName);
463
477
  },
464
- updateAssetPricesQuick: async (assetCoinNames) => {
465
- return await updateOracles(builder, txBlock, assetCoinNames);
478
+ updateAssetPricesQuick: async (assetCoinNames, updateOracleOptions) => {
479
+ return await updateOracles(
480
+ builder,
481
+ txBlock,
482
+ assetCoinNames,
483
+ updateOracleOptions
484
+ );
466
485
  },
467
486
  };
468
487
  };
@@ -1,9 +1,82 @@
1
1
  import {
2
+ HexString,
2
3
  SuiPriceServiceConnection,
3
4
  SuiPythClient,
4
5
  } from '@pythnetwork/pyth-sui-js';
5
6
  import { ScallopBuilder } from 'src/models';
6
- import type { SuiTxBlock as SuiKitTxBlock } from '@scallop-io/sui-kit';
7
+ import {
8
+ SUI_CLOCK_OBJECT_ID,
9
+ type SuiTxBlock as SuiKitTxBlock,
10
+ type Transaction,
11
+ } from '@scallop-io/sui-kit';
12
+ import { SuiClient } from '@mysten/sui/client';
13
+
14
+ type ObjectId = string;
15
+ class ScallopPythClient extends SuiPythClient {
16
+ constructor(
17
+ provider: SuiClient,
18
+ pythStateId: ObjectId,
19
+ wormholeStateId: ObjectId,
20
+ private params: {
21
+ // addressId?: string;
22
+ defaultPackageId: ObjectId;
23
+ gasStationId: ObjectId;
24
+ }
25
+ ) {
26
+ super(provider, pythStateId, wormholeStateId);
27
+ }
28
+
29
+ async updatePriceFeedsWithSponsoredBaseUpdateFee(
30
+ tx: Transaction,
31
+ updates: Buffer[],
32
+ feedIds: HexString[]
33
+ ) {
34
+ if (!this.params) throw new Error('Please provide params');
35
+ const { defaultPackageId: scallopSponsorPackage, gasStationId } =
36
+ this.params;
37
+ const packageId = await this.getPythPackageId();
38
+ let priceUpdatesHotPotato = await this.verifyVaasAndGetHotPotato(
39
+ tx,
40
+ updates,
41
+ packageId
42
+ );
43
+
44
+ const priceInfoObjects = [];
45
+ for (const feedId of feedIds) {
46
+ const priceInfoObjectId = await this.getPriceFeedObjectId(feedId);
47
+ if (!priceInfoObjectId) {
48
+ throw new Error(`Price feed object not found for ID: ${feedId}`);
49
+ }
50
+ priceInfoObjects.push(priceInfoObjectId);
51
+ }
52
+
53
+ const clockObjectRef = tx.sharedObjectRef({
54
+ objectId: SUI_CLOCK_OBJECT_ID,
55
+ mutable: false,
56
+ initialSharedVersion: '1',
57
+ });
58
+
59
+ for (let i = 0; i < priceInfoObjects.length; i++) {
60
+ const priceInfoObjectId = priceInfoObjects[i];
61
+ [priceUpdatesHotPotato] = tx.moveCall({
62
+ target: `${scallopSponsorPackage}::pyth_sponsor::update_single_price_feed_with_sponsor`,
63
+ arguments: [
64
+ tx.object(this.pythStateId),
65
+ priceUpdatesHotPotato,
66
+ tx.object(priceInfoObjectId),
67
+ tx.object(gasStationId),
68
+ clockObjectRef,
69
+ ],
70
+ });
71
+ }
72
+
73
+ tx.moveCall({
74
+ target: `${packageId}::hot_potato_vector::destroy`,
75
+ arguments: [priceUpdatesHotPotato],
76
+ typeArguments: [`${packageId}::price_info::PriceInfo`],
77
+ });
78
+ }
79
+ }
7
80
 
8
81
  export const updatePythPriceFeeds = async (
9
82
  builder: ScallopBuilder,
@@ -11,7 +84,7 @@ export const updatePythPriceFeeds = async (
11
84
  txBlock: SuiKitTxBlock,
12
85
  isSponsoredTx: boolean = false
13
86
  ) => {
14
- const pythClient = new SuiPythClient(
87
+ const pythClient = new ScallopPythClient(
15
88
  builder.suiKit.client,
16
89
  builder.address.get('core.oracles.pyth.state'),
17
90
  builder.address.get('core.oracles.pyth.wormholeState'),
@@ -26,23 +99,33 @@ export const updatePythPriceFeeds = async (
26
99
  builder.address.get(`core.coins.${assetCoinName}.oracle.pyth.feed`)
27
100
  );
28
101
 
29
- // iterate through the endpoints
30
102
  const endpoints = builder.utils.pythEndpoints ?? [
31
103
  ...builder.constants.whitelist.pythEndpoints,
32
104
  ];
105
+
106
+ // iterate through the endpoints
33
107
  for (const endpoint of endpoints) {
34
108
  try {
35
109
  const pythConnection = new SuiPriceServiceConnection(endpoint);
36
110
  const priceUpdateData =
37
111
  await pythConnection.getPriceFeedsUpdateData(priceIds);
38
- await pythClient.updatePriceFeeds(
39
- txBlock.txBlock,
40
- priceUpdateData,
41
- priceIds,
42
- isSponsoredTx
43
- );
44
112
 
45
- break;
113
+ if (isSponsoredTx) {
114
+ // Use gas station to sponsor the baseFeeUpdate
115
+ await pythClient.updatePriceFeedsWithSponsoredBaseUpdateFee(
116
+ txBlock.txBlock,
117
+ priceUpdateData,
118
+ priceIds
119
+ );
120
+ } else {
121
+ await pythClient.updatePriceFeeds(
122
+ txBlock.txBlock,
123
+ priceUpdateData,
124
+ priceIds
125
+ );
126
+ }
127
+
128
+ return;
46
129
  } catch (e) {
47
130
  console.warn(
48
131
  `Failed to update price feeds with endpoint ${endpoint}: ${e}`
@@ -534,10 +534,7 @@ export const WHITELIST = {
534
534
  suiBridge: new Set(['sbeth', 'sbusdt', 'sbwbtc']),
535
535
  wormhole: new Set(['wusdc', 'wusdt', 'weth', 'wbtc', 'wapt', 'wsol']),
536
536
  oracles: new Set(['pyth', 'supra', 'switchboard']),
537
- pythEndpoints: new Set([
538
- 'https://hermes.pyth.network',
539
- 'https://scallop.rpc.p2p.world',
540
- ]),
537
+ pythEndpoints: new Set(['https://hermes.pyth.network']),
541
538
  deprecated: new Set(['wapt', 'wusdc', 'wusdt', 'weth', 'wbtc']),
542
539
  borrowIncentiveRewards: new Set(['mpoints']),
543
540
  rewardsAsPoint: new Set(['mpoints']),
@@ -96,6 +96,7 @@ class ScallopBuilder implements ScallopBuilderInterface {
96
96
  * @param assetCoinName - Specific support asset coin name.
97
97
  * @param amount - Amount of coins to be selected.
98
98
  * @param sender - Sender address.
99
+ * @param isSponsored - Whether the transaction is a sponsored transaction.
99
100
  * @return Take coin and left coin.
100
101
  */
101
102
  async selectCoin(
@@ -31,6 +31,7 @@ class ScallopUtils implements ScallopUtilsInterface {
31
31
  public pythEndpoints: string[];
32
32
  public readonly scallopSuiKit: ScallopSuiKit;
33
33
  public readonly constants: ScallopConstants;
34
+ public readonly timeout: number;
34
35
 
35
36
  constructor(params: ScallopUtilsParams = {}) {
36
37
  this.constants = params.scallopConstants ?? new ScallopConstants(params);
@@ -43,8 +44,9 @@ class ScallopUtils implements ScallopUtilsInterface {
43
44
 
44
45
  this.pythEndpoints = params.pythEndpoints ?? [
45
46
  'https://hermes.pyth.network',
46
- 'https://scallop.rpc.p2p.world',
47
47
  ];
48
+
49
+ this.timeout = params.axiosTimeout ?? 4000;
48
50
  }
49
51
 
50
52
  get walletAddress() {
@@ -539,7 +541,7 @@ class ScallopUtils implements ScallopUtilsInterface {
539
541
 
540
542
  const priceIds = priceIdPairs.map(([_, priceId]) => priceId);
541
543
  const pythConnection = new SuiPriceServiceConnection(endpoint, {
542
- timeout: 4000,
544
+ timeout: this.timeout,
543
545
  });
544
546
 
545
547
  try {
@@ -93,14 +93,25 @@ export type CoreQuickMethods = {
93
93
  amount: number,
94
94
  collateralCoinName: string,
95
95
  obligationId?: SuiObjectArg,
96
- obligationKey?: SuiObjectArg
96
+ obligationKey?: SuiObjectArg,
97
+ updateOracleOptions?: {
98
+ usePythPullModel?: boolean;
99
+ useOnChainXOracleList?: boolean;
100
+ sponsoredFeeds?: string[];
101
+ isSponsoredTx?: boolean;
102
+ }
97
103
  ) => Promise<TransactionResult>;
98
104
  borrowQuick: (
99
105
  amount: number,
100
106
  poolCoinName: string,
101
107
  obligationId?: SuiObjectArg,
102
108
  obligationKey?: SuiObjectArg,
103
- isSponsoredTx?: boolean
109
+ updateOracleOptions?: {
110
+ usePythPullModel?: boolean;
111
+ useOnChainXOracleList?: boolean;
112
+ sponsoredFeeds?: string[];
113
+ isSponsoredTx?: boolean;
114
+ }
104
115
  ) => Promise<TransactionResult>;
105
116
  borrowWithReferralQuick: (
106
117
  amount: number,
@@ -108,7 +119,12 @@ export type CoreQuickMethods = {
108
119
  borrowReferral: SuiObjectArg,
109
120
  obligationId?: SuiObjectArg,
110
121
  obligationKey?: SuiObjectArg,
111
- isSponsoredTx?: boolean
122
+ updateOracleOptions?: {
123
+ usePythPullModel?: boolean;
124
+ useOnChainXOracleList?: boolean;
125
+ sponsoredFeeds?: string[];
126
+ isSponsoredTx?: boolean;
127
+ }
112
128
  ) => Promise<TransactionResult>;
113
129
  depositQuick: (
114
130
  amount: number,
@@ -125,7 +141,15 @@ export type CoreQuickMethods = {
125
141
  obligationId?: SuiObjectArg,
126
142
  isSponsoredTx?: boolean
127
143
  ) => Promise<void>;
128
- updateAssetPricesQuick: (assetCoinNames?: string[]) => Promise<void>;
144
+ updateAssetPricesQuick: (
145
+ assetCoinNames?: string[],
146
+ updateOracleOptions?: {
147
+ usePythPullModel?: boolean;
148
+ useOnChainXOracleList?: boolean;
149
+ sponsoredFeeds?: string[];
150
+ isSponsoredTx?: boolean;
151
+ }
152
+ ) => Promise<void>;
129
153
  };
130
154
 
131
155
  export type SuiTxBlockWithCoreNormalMethods = SuiKitTxBlock &