@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/dist/index.d.mts +26 -4
- package/dist/index.d.ts +26 -4
- package/dist/index.js +17 -17
- package/dist/index.mjs +4 -4
- package/package.json +3 -2
- package/src/builders/coreBuilder.ts +29 -10
- package/src/builders/oracles/pyth.ts +93 -10
- package/src/constants/testAddress.ts +1 -4
- package/src/models/scallopBuilder.ts +1 -0
- package/src/models/scallopUtils.ts +4 -2
- package/src/types/builder/core.ts +28 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scallop-io/sui-scallop-sdk",
|
|
3
|
-
"version": "2.2.3
|
|
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.
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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(
|
|
431
|
-
|
|
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(
|
|
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
|
|
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
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
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: (
|
|
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 &
|