diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c93d8b..458fbd3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,15 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [0.46.58-alpha.1](https://github.com/scallop-io/sui-scallop-sdk/compare/v0.46.57...v0.46.58-alpha.1) (2024-09-19) + +### Adjustments + +- Increase `staleTime` to 2s ([608489c](https://github.com/scallop-io/sui-scallop-sdk/pull/161/commits/608489c60304e5c79b2377aebf8680ebfbbf91b1)) +- Limit 10 for owned objects query ([6d96fd6](https://github.com/scallop-io/sui-scallop-sdk/pull/161/commits/6d96fd6301e70448055526e98cd03e722bb4f005)) +- Increase token per interval to `50` and apply incremental delay time ([d04e04d](https://github.com/scallop-io/sui-scallop-sdk/pull/161/commits/d04e04dda690b21f01d63910a4cd6dda3c61a9fe)) +- Add `walletAddress` params to `ScallopCache` ([4e7f940](https://github.com/scallop-io/sui-scallop-sdk/pull/161/commits/4e7f94046cbfcfdc6b67921aeaeff94b5d457669)) + ### [0.46.57](https://github.com/scallop-io/sui-scallop-sdk/compare/v0.46.56...v0.46.57) (2024-09-13) ### Bugfixes diff --git a/package.json b/package.json index 003a55b..fab253b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@scallop-io/sui-scallop-sdk", - "version": "0.46.57", + "version": "0.46.58-alpha.1", "description": "Typescript sdk for interacting with Scallop contract on SUI", "keywords": [ "sui", diff --git a/src/constants/cache.ts b/src/constants/cache.ts index 148791a..4c3a67a 100644 --- a/src/constants/cache.ts +++ b/src/constants/cache.ts @@ -9,7 +9,7 @@ import { QueryClientConfig } from '@tanstack/query-core'; export const DEFAULT_CACHE_OPTIONS: QueryClientConfig = { defaultOptions: { queries: { - staleTime: 1500, + staleTime: 2000, }, }, }; diff --git a/src/constants/tokenBucket.ts b/src/constants/tokenBucket.ts index 40f1a98..5957114 100644 --- a/src/constants/tokenBucket.ts +++ b/src/constants/tokenBucket.ts @@ -1,2 +1,2 @@ -export const DEFAULT_TOKENS_PER_INTERVAL = 10; -export const DEFAULT_INTERVAL_IN_MS = 1000; +export const DEFAULT_TOKENS_PER_INTERVAL = 50; +export const DEFAULT_INTERVAL_IN_MS = 300; diff --git a/src/models/scallop.ts b/src/models/scallop.ts index 8d99d8f..bcb582f 100644 --- a/src/models/scallop.ts +++ b/src/models/scallop.ts @@ -49,6 +49,7 @@ export class Scallop { this.suiKit = new SuiKit(params); this.cache = new ScallopCache( this.suiKit, + params.walletAddress, cacheOptions ?? DEFAULT_CACHE_OPTIONS, tokenBucket ?? new TokenBucket(DEFAULT_TOKENS_PER_INTERVAL, DEFAULT_INTERVAL_IN_MS) diff --git a/src/models/scallopAddress.ts b/src/models/scallopAddress.ts index 662dd83..d2e59ca 100644 --- a/src/models/scallopAddress.ts +++ b/src/models/scallopAddress.ts @@ -382,6 +382,7 @@ export class ScallopAddress { instance?.cache ?? new ScallopCache( instance?.suiKit ?? new SuiKit({}), + undefined, DEFAULT_CACHE_OPTIONS ); diff --git a/src/models/scallopBuilder.ts b/src/models/scallopBuilder.ts index 6f9c3a0..d75091d 100644 --- a/src/models/scallopBuilder.ts +++ b/src/models/scallopBuilder.ts @@ -59,7 +59,11 @@ export class ScallopBuilder { this.address = this.utils.address; this.cache = this.address.cache; } else { - this.cache = new ScallopCache(this.suiKit, DEFAULT_CACHE_OPTIONS); + this.cache = new ScallopCache( + this.suiKit, + this.walletAddress, + DEFAULT_CACHE_OPTIONS + ); this.address = new ScallopAddress( { id: params?.addressesId || ADDRESSES_ID, diff --git a/src/models/scallopCache.ts b/src/models/scallopCache.ts index 7663188..68f28ec 100644 --- a/src/models/scallopCache.ts +++ b/src/models/scallopCache.ts @@ -48,9 +48,11 @@ export class ScallopCache { public readonly queryClient: QueryClient; public readonly _suiKit: SuiKit; private tokenBucket: TokenBucket; + public walletAddress: string; public constructor( suiKit: SuiKit, + walletAddress?: string, cacheOptions?: QueryClientConfig, tokenBucket?: TokenBucket ) { @@ -59,6 +61,7 @@ export class ScallopCache { this.tokenBucket = tokenBucket ?? new TokenBucket(DEFAULT_TOKENS_PER_INTERVAL, DEFAULT_INTERVAL_IN_MS); + this.walletAddress = walletAddress ?? suiKit.currentAddress(); } private get suiKit(): SuiKit { @@ -164,7 +167,7 @@ export class ScallopCache { objectId: string, options?: SuiObjectDataOptions ): Promise { - const queryKey = ['getObject', objectId, this.suiKit.currentAddress()]; + const queryKey = ['getObject', objectId, this.walletAddress]; if (options) { queryKey.push(JSON.stringify(options)); } @@ -188,13 +191,15 @@ export class ScallopCache { */ public async queryGetObjects( objectIds: string[], - options?: SuiObjectDataOptions + options: SuiObjectDataOptions = { + showContent: true, + } ): Promise { if (objectIds.length === 0) return []; const queryKey = [ 'getObjects', JSON.stringify(objectIds), - this.suiKit.currentAddress(), + this.walletAddress, ]; if (options) { queryKey.push(JSON.stringify(options)); diff --git a/src/models/scallopClient.ts b/src/models/scallopClient.ts index f3abcf8..5c9f8cf 100644 --- a/src/models/scallopClient.ts +++ b/src/models/scallopClient.ts @@ -76,7 +76,11 @@ export class ScallopClient { this.address = this.utils.address; this.cache = this.address.cache; } else { - this.cache = new ScallopCache(this.suiKit, DEFAULT_CACHE_OPTIONS); + this.cache = new ScallopCache( + this.suiKit, + this.walletAddress, + DEFAULT_CACHE_OPTIONS + ); this.address = new ScallopAddress( { id: params?.addressesId || ADDRESSES_ID, diff --git a/src/models/scallopIndexer.ts b/src/models/scallopIndexer.ts index a628f9d..7243647 100644 --- a/src/models/scallopIndexer.ts +++ b/src/models/scallopIndexer.ts @@ -49,7 +49,7 @@ export class ScallopIndexer { this.params = params; this.cache = instance?.cache ?? - new ScallopCache(new SuiKit({}), DEFAULT_CACHE_OPTIONS); + new ScallopCache(new SuiKit({}), undefined, DEFAULT_CACHE_OPTIONS); this._requestClient = axios.create({ baseURL: SDK_API_BASE_URL, headers: { diff --git a/src/models/scallopQuery.ts b/src/models/scallopQuery.ts index 2463705..112d1e5 100644 --- a/src/models/scallopQuery.ts +++ b/src/models/scallopQuery.ts @@ -90,12 +90,21 @@ export class ScallopQuery { this.params = params; this.suiKit = instance?.suiKit ?? instance?.utils?.suiKit ?? new SuiKit(params); + + this.walletAddress = normalizeSuiAddress( + params.walletAddress || this.suiKit.currentAddress() + ); + if (instance?.utils) { this.utils = instance.utils; this.address = instance.utils.address; this.cache = this.address.cache; } else { - this.cache = new ScallopCache(this.suiKit, DEFAULT_CACHE_OPTIONS); + this.cache = new ScallopCache( + this.suiKit, + this.walletAddress, + DEFAULT_CACHE_OPTIONS + ); this.address = new ScallopAddress( { id: params?.addressesId || ADDRESSES_ID, @@ -112,10 +121,6 @@ export class ScallopQuery { this.indexer = instance?.indexer ?? new ScallopIndexer(this.params, { cache: this.cache }); - - this.walletAddress = normalizeSuiAddress( - params.walletAddress || this.suiKit.currentAddress() - ); } /** diff --git a/src/models/scallopUtils.ts b/src/models/scallopUtils.ts index 5011b67..7163ecd 100644 --- a/src/models/scallopUtils.ts +++ b/src/models/scallopUtils.ts @@ -62,6 +62,7 @@ export class ScallopUtils { public suiKit: SuiKit; public address: ScallopAddress; public cache: ScallopCache; + public walletAddress: string; private _priceMap: PriceMap = new Map(); public constructor( @@ -77,12 +78,18 @@ export class ScallopUtils { instance?.address?.cache._suiKit ?? new SuiKit(params); + this.walletAddress = params.walletAddress ?? this.suiKit.currentAddress(); + if (instance?.address) { this.address = instance.address; this.cache = this.address.cache; this.suiKit = this.address.cache._suiKit; } else { - this.cache = new ScallopCache(this.suiKit, DEFAULT_CACHE_OPTIONS); + this.cache = new ScallopCache( + this.suiKit, + this.walletAddress, + DEFAULT_CACHE_OPTIONS + ); this.address = instance?.address ?? new ScallopAddress( @@ -409,7 +416,7 @@ export class ScallopUtils { txBlock: SuiTxBlock, dest: SuiTxArg, coinType: string, - sender: string + sender: string = this.walletAddress ): Promise { // merge to existing coins if exist try { diff --git a/src/queries/coreQuery.ts b/src/queries/coreQuery.ts index bda0ebe..fa8db72 100644 --- a/src/queries/coreQuery.ts +++ b/src/queries/coreQuery.ts @@ -709,6 +709,7 @@ export const getObligations = async ( StructType: `${protocolObjectId}::obligation::ObligationKey`, }, cursor: nextCursor, + limit: 10, }); if (!paginatedKeyObjectsResponse) break; diff --git a/src/queries/spoolQuery.ts b/src/queries/spoolQuery.ts index bb81d29..5bff5b3 100644 --- a/src/queries/spoolQuery.ts +++ b/src/queries/spoolQuery.ts @@ -251,9 +251,9 @@ export const getStakeAccounts = async ( filter: { StructType: stakeAccountType }, options: { showContent: true, - showType: true, }, cursor: nextCursor, + limit: 10, }); if (!paginatedStakeObjectsResponse) continue; @@ -299,7 +299,10 @@ export const getStakeAccounts = async ( const stakeObjectIds: string[] = stakeObjectsResponse .map((ref: any) => ref?.data?.objectId) .filter((id: any) => id !== undefined); - const stakeObjects = await utils.cache.queryGetObjects(stakeObjectIds); + const stakeObjects = await utils.cache.queryGetObjects(stakeObjectIds, { + showContent: true, + showType: true, + }); for (const stakeObject of stakeObjects) { const id = stakeObject.objectId; const type = stakeObject.type!; diff --git a/src/queries/vescaQuery.ts b/src/queries/vescaQuery.ts index bedf00b..473426a 100644 --- a/src/queries/vescaQuery.ts +++ b/src/queries/vescaQuery.ts @@ -34,6 +34,7 @@ export const getVescaKeys = async ( StructType: veScaKeyType, }, cursor: nextCursor, + limit: 10, }); if (!paginatedKeyObjectsResponse) continue; diff --git a/src/utils/tokenBucket.ts b/src/utils/tokenBucket.ts index d83814c..1002bd7 100644 --- a/src/utils/tokenBucket.ts +++ b/src/utils/tokenBucket.ts @@ -38,20 +38,44 @@ const callWithRateLimit = async ( tokenBucket: TokenBucket, fn: () => Promise, retryDelayInMs = DEFAULT_INTERVAL_IN_MS, - maxRetries = 5 // Adding a maximum retries limit, + maxRetries = 15, + backoffFactor = 1.25 // The factor by which to increase the delay ): Promise => { let retries = 0; const tryRequest = async (): Promise => { if (tokenBucket.removeTokens(1)) { - return await fn(); + try { + const result = await fn(); + + // Check if the result is an object with status code (assuming the response has a status property) + if (result && (result as any).status === 429) { + throw new Error('Unexpected status code: 429'); + } + + return result; + } catch (error: any) { + if ( + error.message === 'Unexpected status code: 429' && + retries < maxRetries + ) { + retries++; + const delay = retryDelayInMs * Math.pow(backoffFactor, retries); + // console.warn(`429 encountered, retrying in ${delay} ms`); + await new Promise((resolve) => setTimeout(resolve, delay)); + return tryRequest(); + } else { + console.error('An error occurred:', error); + return null; + } + } } else if (retries < maxRetries) { retries++; - // Use a Promise to correctly handle the async operation with setTimeout - await new Promise((resolve) => setTimeout(resolve, retryDelayInMs)); + const delay = retryDelayInMs * Math.pow(backoffFactor, retries); + // console.warn(`Rate limit exceeded, retrying in ${delay} ms`); + await new Promise((resolve) => setTimeout(resolve, delay)); return tryRequest(); } else { - // Optionally, handle the case where the maximum number of retries is reached console.error('Maximum retries reached'); return null; }