aiia-vault-sdk 1.1.0 → 1.1.2

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.
@@ -34,6 +34,13 @@ export interface UserContribution {
34
34
  contributedToken: string;
35
35
  contributedAmount: number;
36
36
  }
37
+ /**
38
+ * SDK for interacting with the SeedRoundFundraiser smart contract
39
+ *
40
+ * @remarks
41
+ * This SDK provides methods to interact with the SeedRoundFundraiser contract,
42
+ * including contributing tokens, managing rounds, and handling whitelisted tokens.
43
+ */
37
44
  export declare class SeedRoundFundraiserSDK {
38
45
  name: string;
39
46
  private contract;
@@ -43,14 +50,140 @@ export declare class SeedRoundFundraiserSDK {
43
50
  private PRICE_PRECISION;
44
51
  private whitelistedTokensArray;
45
52
  private networkName;
53
+ private projectToken;
54
+ private projectTokenDecimals;
55
+ /**
56
+ * Creates a new instance of the SeedRoundFundraiserSDK
57
+ *
58
+ * @param rpcUrls - Single RPC URL or array of RPC URLs for blockchain connection
59
+ * @param contractAddress - Optional contract address. If not provided, will be resolved from contracts.json
60
+ *
61
+ * @throws Will throw if no valid RPC providers are available
62
+ */
46
63
  constructor(rpcUrls: string | string[], contractAddress?: string);
64
+ /**
65
+ * Gets the network name from the RPC URL
66
+ *
67
+ * @param rpcUrl - The RPC URL to parse
68
+ * @returns The network name (e.g., 'sepolia', 'mainnet', 'base-sepolia')
69
+ * @private
70
+ */
47
71
  private getNetworkNameFromRpc;
72
+ /**
73
+ * Imports whitelisted tokens from configuration file
74
+ *
75
+ * @private
76
+ */
48
77
  private importWhitelistedTokens;
78
+ /**
79
+ * Gets detailed information about a whitelisted token
80
+ *
81
+ * @param tokenAddress - The address of the token to query
82
+ * @returns Token information including price, symbol, and contribution limits, or null if not whitelisted
83
+ *
84
+ * @example
85
+ * ```typescript
86
+ * const tokenInfo = await sdk.getWhitelistedTokenInfo("0x...");
87
+ * if (tokenInfo) {
88
+ * console.log(`Max contribution: ${tokenInfo.maxContribution} ${tokenInfo.symbol}`);
89
+ * }
90
+ * ```
91
+ */
49
92
  getWhitelistedTokenInfo(tokenAddress: string): Promise<WhitelistedTokenInfo | null>;
93
+ /**
94
+ * Gets information about all whitelisted tokens that are accepted for seed round participation.
95
+ *
96
+ * @remarks
97
+ * This function iterates through all whitelisted token addresses and fetches detailed information
98
+ * for each token that is actually whitelisted in the smart contract. The price and maxContribution
99
+ * values are calculated based on the current active round settings.
100
+ *
101
+ * @returns Promise<WhitelistedTokenInfo[]> Array of whitelisted token information with the following fields:
102
+ * - `address` (string): The token's contract address on the blockchain. For ETH, this will be the zero address (0x000...000)
103
+ * - `isWhitelisted` (boolean): Whether the token is currently whitelisted and accepted for contributions
104
+ * - `price` (number): Token price in USD with PRICE_PRECISION decimals (e.g., 1800.5 means 1 token = $1800.50)
105
+ * - `symbol` (string): Token symbol (e.g., "ETH", "USDC", "USDT")
106
+ * - `maxContribution` (number): Maximum amount of tokens a user can contribute in human-readable format,
107
+ * calculated as (maxFundPerAccount / tokenPrice)
108
+ * - `maxContributionRaw` (number): Maximum contribution amount adjusted with token decimals (maxContribution * 10^decimals),
109
+ * ready for contract interaction
110
+ * - `decimals` (number): Number of decimal places the token uses (e.g., 18 for ETH, 6 for USDC)
111
+ *
112
+ * @example
113
+ * ```typescript
114
+ * const sdk = new SeedRoundFundraiserSDK(rpcUrl);
115
+ * const whitelistedTokens = await sdk.getAllWhitelistedTokensInfo();
116
+ *
117
+ * // Example response:
118
+ * [
119
+ * {
120
+ * address: "0x0000000000000000000000000000000000000000",
121
+ * isWhitelisted: true,
122
+ * price: 1800.5, // 1 ETH = $1800.50
123
+ * symbol: "ETH",
124
+ * maxContribution: 5.55, // Can contribute up to 5.55 ETH
125
+ * maxContributionRaw: 5550000000000000000n, // 5.55 * 10^18
126
+ * decimals: 18
127
+ * },
128
+ * {
129
+ * address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
130
+ * isWhitelisted: true,
131
+ * price: 1.0, // 1 USDC = $1.00
132
+ * symbol: "USDC",
133
+ * maxContribution: 10000, // Can contribute up to 10000 USDC
134
+ * maxContributionRaw: 10000000000, // 10000 * 10^6
135
+ * decimals: 6
136
+ * }
137
+ * ]
138
+ * ```
139
+ *
140
+ * @notice
141
+ * - Token prices are in USD with PRICE_PRECISION (1e18) decimals
142
+ * - maxContribution is calculated based on the current round's maxFundPerAccount
143
+ * - For new rounds or if no active round exists, maxContribution will be 0
144
+ * - ETH is represented with the zero address and always has 18 decimals
145
+ *
146
+ * @see {@link getWhitelistedTokenInfo} For getting information about a single token
147
+ * @see {@link WhitelistedTokenInfo} For the interface definition
148
+ */
50
149
  getAllWhitelistedTokensInfo(): Promise<WhitelistedTokenInfo[]>;
150
+ /**
151
+ * Gets a random provider from the available providers
152
+ *
153
+ * @returns An ethers Provider instance
154
+ * @private
155
+ */
51
156
  private getRandomProvider;
157
+ /**
158
+ * Gets a contract instance with a random provider
159
+ *
160
+ * @returns Contract instance
161
+ * @private
162
+ */
52
163
  private getContractWithRandomProvider;
164
+ /**
165
+ * Bootstraps the SDK by checking RPC health and removing inactive providers
166
+ *
167
+ * @throws Will throw if no active RPC providers are available
168
+ */
53
169
  bootstrap(): Promise<void>;
170
+ /**
171
+ * Signs and sends a transaction to the blockchain
172
+ *
173
+ * @param tx - The transaction to send
174
+ * @param wallet - The wallet or transaction sender
175
+ * @param callbacks - Optional callbacks for transaction lifecycle events
176
+ * @returns Transaction result and status
177
+ *
178
+ * @example
179
+ * ```typescript
180
+ * const tx = await sdk.buildContributeTx(0, ethers.ZeroAddress, 1.5);
181
+ * const result = await sdk.signAndSendTransaction(tx, wallet, {
182
+ * onSubmit: (txHash) => console.log(`Submitted: ${txHash}`),
183
+ * onFinally: (status) => console.log(`Completed: ${status.status}`)
184
+ * });
185
+ * ```
186
+ */
54
187
  signAndSendTransaction(tx: ethers.ContractTransaction, wallet: ethers.Wallet | SendTransactionMutateAsync<Config, any>, callbacks?: {
55
188
  onSubmit?: (tx: string) => void | Promise<void>;
56
189
  onFinally?: (status: {
@@ -72,20 +205,154 @@ export declare class SeedRoundFundraiserSDK {
72
205
  attempts: number;
73
206
  };
74
207
  }>;
208
+ /**
209
+ * Builds a transaction to add a token to the whitelist
210
+ *
211
+ * @param token - The token address to whitelist
212
+ * @param price - The price of the token in USD (with PRICE_PRECISION decimals)
213
+ * @returns Populated transaction
214
+ *
215
+ * @example
216
+ * ```typescript
217
+ * const tx = await sdk.buildAddWhitelistedTokenTx("0x...", 1800.5);
218
+ * ```
219
+ */
75
220
  buildAddWhitelistedTokenTx(token: string, price: number): Promise<ethers.ContractTransaction>;
221
+ /**
222
+ * Builds a transaction to update a whitelisted token's price
223
+ *
224
+ * @param token - The token address
225
+ * @param newPrice - The new price in USD (with PRICE_PRECISION decimals)
226
+ * @returns Populated transaction
227
+ */
76
228
  buildUpdateTokenPriceTx(token: string, newPrice: number): Promise<ethers.ContractTransaction>;
229
+ /**
230
+ * Builds a transaction to remove a token from the whitelist
231
+ *
232
+ * @param token - The token address to remove
233
+ * @returns Populated transaction
234
+ */
77
235
  buildRemoveWhitelistedTokenTx(token: string): Promise<ethers.ContractTransaction>;
236
+ /**
237
+ * Builds a transaction to create a new fundraising round
238
+ *
239
+ * @param startTime - Round start time (Unix timestamp)
240
+ * @param endTime - Round end time (Unix timestamp)
241
+ * @param targetFund - Target funding amount in USD (with PRICE_PRECISION decimals)
242
+ * @param totalAllocation - Total tokens to allocate
243
+ * @param maxFundPerAccount - Maximum funding per account in USD
244
+ * @returns Populated transaction
245
+ *
246
+ * @example
247
+ * ```typescript
248
+ * const now = Math.floor(Date.now() / 1000);
249
+ * const tx = await sdk.buildCreateRoundTx(
250
+ * now,
251
+ * now + 86400, // 24 hours
252
+ * 1000000, // $1M target
253
+ * 1000000, // 1M tokens
254
+ * 10000 // $10k max per account
255
+ * );
256
+ * ```
257
+ */
78
258
  buildCreateRoundTx(startTime: number, endTime: number, targetFund: number, totalAllocation: number, maxFundPerAccount: number): Promise<ethers.ContractTransaction>;
259
+ /**
260
+ * Builds a transaction to update an existing round's parameters
261
+ *
262
+ * @param roundId - The ID of the round to update
263
+ * @param startTime - New start time
264
+ * @param endTime - New end time
265
+ * @param targetFund - New target fund amount
266
+ * @param totalAllocation - New total token allocation
267
+ * @param maxFundPerAccount - New maximum funding per account
268
+ * @returns Populated transaction
269
+ */
79
270
  buildUpdateRoundTx(roundId: number, startTime: number, endTime: number, targetFund: number, totalAllocation: number, maxFundPerAccount: number): Promise<ethers.ContractTransaction>;
271
+ /**
272
+ * Builds a transaction to end a round
273
+ *
274
+ * @param roundId - The ID of the round to end
275
+ * @returns Populated transaction
276
+ */
80
277
  buildEndRoundTx(roundId: number): Promise<ethers.ContractTransaction>;
278
+ /**
279
+ * Builds a transaction to enable/disable token claiming for a round
280
+ *
281
+ * @param roundId - The round ID
282
+ * @param enabled - Whether to enable or disable claiming
283
+ * @returns Populated transaction
284
+ */
81
285
  buildSetClaimingEnabledTx(roundId: number, enabled: boolean): Promise<ethers.ContractTransaction>;
286
+ /**
287
+ * Builds a transaction to enable/disable refunds for a round
288
+ *
289
+ * @param roundId - The round ID
290
+ * @param enabled - Whether to enable or disable refunds
291
+ * @returns Populated transaction
292
+ */
82
293
  buildSetRefundEnabledTx(roundId: number, enabled: boolean): Promise<ethers.ContractTransaction>;
294
+ /**
295
+ * Builds a transaction to contribute to a round
296
+ *
297
+ * @param roundId - The ID of the round to contribute to
298
+ * @param token - The token address (use ethers.ZeroAddress for ETH)
299
+ * @param amount - Amount to contribute in human-readable format
300
+ * @returns Populated transaction
301
+ *
302
+ * @example
303
+ * ```typescript
304
+ * // Contribute 1.5 ETH
305
+ * const tx = await sdk.buildContributeTx(0, ethers.ZeroAddress, 1.5);
306
+ *
307
+ * // Contribute 1000 USDC
308
+ * const tx = await sdk.buildContributeTx(0, "0x...", 1000);
309
+ * ```
310
+ *
311
+ * @notice For ERC20 tokens, ensure you have approved the contract first
312
+ */
83
313
  buildContributeTx(roundId: number, token: string, amount: number): Promise<ethers.ContractTransaction>;
314
+ /**
315
+ * Builds a transaction to claim allocated tokens
316
+ *
317
+ * @returns Populated transaction for claiming tokens from all eligible rounds
318
+ */
84
319
  buildClaimTokensTx(): Promise<ethers.ContractTransaction>;
320
+ /**
321
+ * Builds a transaction to request a refund
322
+ *
323
+ * @returns Populated transaction for requesting refund from eligible rounds
324
+ */
85
325
  buildRefundTx(): Promise<ethers.ContractTransaction>;
326
+ /**
327
+ * Builds a transaction to withdraw accumulated funds
328
+ *
329
+ * @param token - The token address to withdraw
330
+ * @param amount - Amount to withdraw in human-readable format
331
+ * @returns Populated transaction
332
+ *
333
+ * @notice Only callable by contract owner
334
+ */
86
335
  buildWithdrawFundsTx(token: string, amount: number): Promise<ethers.ContractTransaction>;
336
+ /**
337
+ * Builds a transaction to claim tokens from a specific round
338
+ *
339
+ * @param roundId - The round ID to claim tokens from
340
+ * @returns Populated transaction
341
+ */
87
342
  buildClaimTokensByRoundIdTx(roundId: number): Promise<ethers.ContractTransaction>;
343
+ /**
344
+ * Gets information about a whitelisted token
345
+ *
346
+ * @param token - The token address
347
+ * @returns Token whitelist status and price
348
+ */
88
349
  getWhitelistedToken(token: string): Promise<WhitelistedToken>;
350
+ /**
351
+ * Gets configuration of a specific round
352
+ *
353
+ * @param roundId - The round ID to query
354
+ * @returns Round configuration including times, targets, and status
355
+ */
89
356
  getRound(roundId: number): Promise<RoundConfig>;
90
357
  getUserContribution(roundId: number, user: string): Promise<UserContribution>;
91
358
  getRoundRaisedFunds(roundId: number): Promise<number>;
@@ -101,9 +368,63 @@ export declare class SeedRoundFundraiserSDK {
101
368
  */
102
369
  getLatestRoundId(): Promise<number>;
103
370
  /**
104
- * Get comprehensive information about a specific round
105
- * @param roundId The ID of the round to get information for
106
- * @returns An object containing all information about the specified round
371
+ * Gets comprehensive information about a specific fundraising round
372
+ *
373
+ * @param roundId - The ID of the round to query (0-based index)
374
+ * @returns Detailed round information with the following fields:
375
+ * ```typescript
376
+ * {
377
+ * roundId: number; // The queried round ID
378
+ * config: { // Round configuration and current state
379
+ * startTime: number; // Unix timestamp when the round starts
380
+ * endTime: number; // Unix timestamp when the round ends
381
+ * targetFund: number; // Target funding amount in USD (with PRICE_PRECISION)
382
+ * totalAllocation: number;// Total project tokens to be distributed in this round
383
+ * maxFundPerAccount: number; // Maximum USD value one account can contribute
384
+ * exists: boolean; // Whether this round has been created
385
+ * ended: boolean; // Whether this round has been manually ended
386
+ * claimingEnabled: boolean; // Whether participants can claim their tokens
387
+ * refundEnabled: boolean; // Whether refunds are enabled for this round
388
+ * };
389
+ * raisedFunds: number; // Total USD value raised in this round
390
+ * participants: number; // Number of unique participants
391
+ * isActive: boolean; // Whether the round is currently active
392
+ * }
393
+ * ```
394
+ *
395
+ * @example
396
+ * ```typescript
397
+ * const roundInfo = await sdk.getRoundInfo(0);
398
+ *
399
+ * // Check if round is active and accepting contributions
400
+ * if (roundInfo.isActive) {
401
+ * console.log(`Round 0 is active!`);
402
+ * console.log(`Progress: $${roundInfo.raisedFunds}/$${roundInfo.config.targetFund}`);
403
+ * console.log(`Participants: ${roundInfo.participants}`);
404
+ * }
405
+ *
406
+ * // Check if tokens can be claimed
407
+ * if (roundInfo.config.claimingEnabled) {
408
+ * console.log('Token claiming is enabled for this round');
409
+ * }
410
+ * ```
411
+ *
412
+ * @notice
413
+ * - All USD values (targetFund, maxFundPerAccount, raisedFunds) use PRICE_PRECISION (1e18) decimals
414
+ * - totalAllocation is in project token's decimals (e.g., usually 18 decimals)
415
+ * - A round is considered active if:
416
+ * 1. It exists
417
+ * 2. Current time is between startTime and endTime
418
+ * 3. It hasn't been manually ended
419
+ * - Rounds are 0-indexed, so first round has ID 0
420
+ *
421
+ * @throws Will throw an error if:
422
+ * - roundId is negative
423
+ * - roundId is greater than or equal to total number of rounds
424
+ *
425
+ * @see {@link getRound} For getting just the round configuration
426
+ * @see {@link getRoundRaisedFunds} For getting just the raised funds
427
+ * @see {@link getRoundParticipants} For getting just the participant count
107
428
  */
108
429
  getRoundInfo(roundId: number): Promise<{
109
430
  roundId: number;
@@ -127,4 +448,72 @@ export declare class SeedRoundFundraiserSDK {
127
448
  getAllEvents(fromBlock: number, toBlock: number): Promise<ParsedSeedRoundFundraiserEventRaw[]>;
128
449
  streamEvents(fromBlock: number, onEvent: (event: ParsedSeedRoundFundraiserEvent) => Promise<void>, saveLatestBlock: (blockNumber: number) => Promise<void>, batchSize?: number, sleepTime?: number): Promise<void>;
129
450
  formatEventArgs: (event: ParsedSeedRoundFundraiserEventRaw) => ParsedSeedRoundFundraiserEvent;
451
+ /**
452
+ * Gets detailed information about a user's contribution in a specific round
453
+ *
454
+ * @param roundId - The ID of the round to query
455
+ * @param user - The user's address to check contribution
456
+ * @returns Detailed contribution information with the following fields:
457
+ * ```typescript
458
+ * {
459
+ * contribution: {
460
+ * fundAmount: number; // Total USD value of contribution (with PRICE_PRECISION)
461
+ * tokenAllocation: number; // Amount of project tokens allocated
462
+ * claimed: boolean; // Whether allocated tokens have been claimed
463
+ * refunded: boolean; // Whether contribution has been refunded
464
+ * contributedToken: string;// Address of token used for contribution
465
+ * contributedAmount: number;// Actual amount of tokens contributed
466
+ * };
467
+ * roundInfo: {
468
+ * exists: boolean; // Whether the round exists
469
+ * isActive: boolean; // Whether the round is currently active
470
+ * claimingEnabled: boolean;// Whether token claiming is enabled
471
+ * refundEnabled: boolean; // Whether refunds are enabled
472
+ * };
473
+ * tokenInfo?: { // Only present if contribution exists
474
+ * symbol: string; // Symbol of contributed token
475
+ * decimals: number; // Decimals of contributed token
476
+ * };
477
+ * }
478
+ * ```
479
+ *
480
+ * @example
481
+ * ```typescript
482
+ * const userContrib = await sdk.getUserRoundContribution(0, "0x...");
483
+ *
484
+ * if (userContrib.contribution.fundAmount > 0) {
485
+ * console.log(`Contributed: ${userContrib.contribution.contributedAmount} ${userContrib.tokenInfo?.symbol}`);
486
+ * console.log(`Value: $${userContrib.contribution.fundAmount}`);
487
+ * console.log(`Allocated: ${userContrib.contribution.tokenAllocation} tokens`);
488
+ *
489
+ * if (userContrib.roundInfo.claimingEnabled && !userContrib.contribution.claimed) {
490
+ * console.log('Tokens are ready to claim!');
491
+ * }
492
+ * }
493
+ * ```
494
+ *
495
+ * @notice
496
+ * - All USD values use PRICE_PRECISION (1e18) decimals
497
+ * - Token amounts are in their native decimals (e.g., 18 for ETH, 6 for USDC)
498
+ * - For ETH contributions, contributedToken will be the zero address
499
+ * - tokenInfo will be undefined if user hasn't contributed to the round
500
+ *
501
+ * @throws Will throw if:
502
+ * - roundId is invalid
503
+ * - user address is invalid
504
+ * - Contract call fails
505
+ */
506
+ getUserRoundContribution(roundId: number, user: string): Promise<{
507
+ contribution: UserContribution;
508
+ roundInfo: {
509
+ exists: boolean;
510
+ isActive: boolean;
511
+ claimingEnabled: boolean;
512
+ refundEnabled: boolean;
513
+ };
514
+ tokenInfo?: {
515
+ symbol: string;
516
+ decimals: number;
517
+ };
518
+ }>;
130
519
  }
@@ -1 +1 @@
1
- "use strict";var t=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(exports,"__esModule",{value:!0}),exports.SeedRoundFundraiserSDK=void 0;const e=require("ethers"),n=t(require("./abis/SeedRoundFundraiser.json")),r=t(require("./contracts.json")),o=require("./utils"),a=t(require("./whitelist-tokens.json"));exports.SeedRoundFundraiserSDK=class{constructor(t,a){this.name="SeedRoundFundraiser",this.isBootstrapped=!1,this.PRICE_PRECISION=1e18,this.whitelistedTokensArray=[],this.formatEventArgs=t=>{const{eventName:e,args:n}=t;switch(e){case"TokenWhitelisted":return{...t,args:{...n,token:n.token.toLowerCase(),price:Number(n.price)/this.PRICE_PRECISION}};case"TokenPriceUpdated":return{...t,args:{...n,token:n.token.toLowerCase(),oldPrice:Number(n.oldPrice)/this.PRICE_PRECISION,newPrice:Number(n.newPrice)/this.PRICE_PRECISION}};case"TokenRemovedFromWhitelist":return{...t,args:{...n,token:n.token.toLowerCase()}};case"RoundCreated":case"RoundUpdated":return{...t,args:{...n,roundId:Number(n.roundId),startTime:Number(n.startTime),endTime:Number(n.endTime),targetFund:Number(n.targetFund)/this.PRICE_PRECISION,totalAllocation:Number(n.totalAllocation),maxFundPerAccount:Number(n.maxFundPerAccount)/this.PRICE_PRECISION}};case"RoundEnded":return{...t,args:{...n,roundId:Number(n.roundId),raisedFunds:Number(n.raisedFunds)/this.PRICE_PRECISION,participants:Number(n.participants)}};case"Contribution":return{...t,args:{...n,roundId:Number(n.roundId),contributor:n.contributor.toLowerCase(),token:n.token.toLowerCase(),amount:Number(n.amount),fundAmount:Number(n.fundAmount)/this.PRICE_PRECISION,tokenAllocation:Number(n.tokenAllocation)}};case"TokensClaimed":return{...t,args:{...n,roundId:Number(n.roundId),user:n.user.toLowerCase(),amount:Number(n.amount)}};case"ProjectTokenUpdated":return{...t,args:{...n,oldToken:n.oldToken.toLowerCase(),newToken:n.newToken.toLowerCase()}};case"ClaimingEnabledUpdated":case"RefundEnabledUpdated":return{...t,args:{...n,roundId:Number(n.roundId),enabled:n.enabled}};case"Refunded":return{...t,args:{...n,roundId:Number(n.roundId),user:n.user.toLowerCase(),token:n.token.toLowerCase(),amount:Number(n.amount)}};default:return t}};const s=Array.isArray(t)?t:[t];this.providers=s.map((t=>new e.ethers.JsonRpcProvider(t)));const i=(0,o.getRandomProvider)(this.providers);this.contractAddress=(0,o.resolveContractAddress)(s[0],this.name,r.default,a),this.contract=new e.ethers.Contract(this.contractAddress,n.default.abi,i),this.networkName=this.getNetworkNameFromRpc(s[0]),this.importWhitelistedTokens()}getNetworkNameFromRpc(t){const e=t.toLowerCase();return e.includes("sepolia.base")?"base-sepolia":e.includes("sepolia")?"sepolia":e.includes("mainnet")?"mainnet":e.includes("localhost")||e.includes("127.0.0.1")?"hardhat":"sepolia"}importWhitelistedTokens(){try{a.default[this.networkName]?(this.whitelistedTokensArray=a.default[this.networkName].map((t=>t.toLowerCase())),console.log(`Imported ${this.whitelistedTokensArray.length} whitelisted tokens for ${this.networkName} network`)):console.log(`No whitelisted tokens found for ${this.networkName} network`)}catch(t){console.error("Error importing whitelisted tokens:",t)}}async getWhitelistedTokenInfo(t){const n=t.toLowerCase();if(!this.whitelistedTokensArray.includes(n))return null;const r=await this.getWhitelistedToken(n);if(!r.isWhitelisted)return null;let a="ETH",s=18;n!==e.ethers.ZeroAddress&&([a,s]=await Promise.all([(0,o.getTokenSymbol)(n,this.getRandomProvider()),(0,o.getTokenDecimals)(n,this.getRandomProvider())]));const i=await this.getLatestRoundId();let d=0;if(i>=0){const t=await this.getRound(i);t.exists&&!t.ended&&(d=t.maxFundPerAccount/r.price)}return{address:n,isWhitelisted:r.isWhitelisted,price:r.price,symbol:a,maxContribution:d,maxContributionRaw:Math.floor(d*Math.pow(10,s)),decimals:s}}async getAllWhitelistedTokensInfo(){const t=[];for(const e of this.whitelistedTokensArray){const n=await this.getWhitelistedTokenInfo(e);n&&t.push(n)}return t}getRandomProvider(){return(0,o.getRandomProvider)(this.providers)}getContractWithRandomProvider(){return new e.ethers.Contract(this.contractAddress,n.default.abi,this.getRandomProvider())}async bootstrap(){if(this.isBootstrapped)return;const t=await Promise.all(this.providers.map(((t,e)=>(0,o.checkRpcHealth)(t,e))));if(this.providers=this.providers.filter(((e,n)=>t[n])),0===this.providers.length)throw new Error("No active RPC providers available");this.isBootstrapped=!0}async signAndSendTransaction(t,e,n={}){return(0,o.signAndSendTransaction)(t,e,(()=>this.getRandomProvider()),n,this.contract)}async buildAddWhitelistedTokenTx(t,e){const n=BigInt(Math.floor(e*this.PRICE_PRECISION));return await this.contract.addWhitelistedToken.populateTransaction(t,n)}async buildUpdateTokenPriceTx(t,e){const n=BigInt(Math.floor(e*this.PRICE_PRECISION));return await this.contract.updateTokenPrice.populateTransaction(t,n)}async buildRemoveWhitelistedTokenTx(t){return await this.contract.removeWhitelistedToken.populateTransaction(t)}async buildCreateRoundTx(t,e,n,r,a){const s=BigInt(Math.floor(n*this.PRICE_PRECISION)),i=BigInt(Math.floor(a*this.PRICE_PRECISION)),d=await(0,o.getTokenDecimals)(await this.getProjectToken(),this.getRandomProvider()),u=BigInt(Math.floor(r*Math.pow(10,d)));return await this.contract.createRound.populateTransaction(t,e,s,u,i)}async buildUpdateRoundTx(t,e,n,r,o,a){const s=BigInt(Math.floor(r*this.PRICE_PRECISION)),i=BigInt(Math.floor(a*this.PRICE_PRECISION));return await this.contract.updateRound.populateTransaction(t,e,n,s,o,i)}async buildEndRoundTx(t){return await this.contract.endRound.populateTransaction(t)}async buildSetClaimingEnabledTx(t,e){return await this.contract.setClaimingEnabled.populateTransaction(t,e)}async buildSetRefundEnabledTx(t,e){return await this.contract.setRefundEnabled.populateTransaction(t,e)}async buildContributeTx(t,n,r){let a=18;n!==e.ethers.ZeroAddress&&(a=await(0,o.getTokenDecimals)(n,this.getRandomProvider()));const s=e.ethers.parseUnits(r.toString(),a),i=await this.contract.contribute.populateTransaction(t,n,n===e.ethers.ZeroAddress?0:s);return n===e.ethers.ZeroAddress&&(i.value=s),i}async buildClaimTokensTx(){return await this.contract.claimTokens.populateTransaction()}async buildRefundTx(){return await this.contract.refund.populateTransaction()}async buildWithdrawFundsTx(t,e){const n=await(0,o.getTokenDecimals)(t,this.getRandomProvider()),r=BigInt(Math.floor(e*Math.pow(10,n)));return await this.contract.withdrawFunds.populateTransaction(t,r)}async buildClaimTokensByRoundIdTx(t){return await this.contract.claimTokensByRoundId.populateTransaction(t)}async getWhitelistedToken(t){const e=await this.contract.whitelistedTokens(t);return{isWhitelisted:e.isWhitelisted,price:Number(e.price)/this.PRICE_PRECISION}}async getRound(t){const e=await this.contract.rounds(t);return{startTime:Number(e.startTime),endTime:Number(e.endTime),targetFund:Number(e.targetFund)/this.PRICE_PRECISION,totalAllocation:Number(e.totalAllocation),maxFundPerAccount:Number(e.maxFundPerAccount)/this.PRICE_PRECISION,exists:e.exists,ended:e.ended,claimingEnabled:e.claimingEnabled,refundEnabled:e.refundEnabled}}async getUserContribution(t,e){const n=await this.contract.userContributions(t,e);return{fundAmount:Number(n.fundAmount)/this.PRICE_PRECISION,tokenAllocation:Number(n.tokenAllocation),claimed:n.claimed,refunded:n.refunded,contributedToken:n.contributedToken,contributedAmount:Number(n.contributedAmount)}}async getRoundRaisedFunds(t){const e=await this.contract.roundRaisedFunds(t);return Number(e)/this.PRICE_PRECISION}async getRoundParticipants(t){const e=await this.contract.roundParticipants(t);return Number(e)}async getUserParticipatedRound(t){const e=await this.contract.userParticipatedRound(t);return Number(e)}async getProjectToken(){return await this.contract.projectToken()}async getTotalRounds(){const t=await this.contract.totalRounds();return Number(t)}async getTotalRaisedFunds(){const t=await this.contract.totalRaisedFunds();return Number(t)/this.PRICE_PRECISION}async isRoundActive(t){return await this.contract.isRoundActive(t)}async getLatestRoundId(){const t=await this.getTotalRounds();return 0===t?-1:t-1}async getRoundInfo(t){const e=await this.getTotalRounds();if(t<0||t>=e)throw new Error(`Invalid round ID: ${t}`);return{roundId:t,config:await this.getRound(t),raisedFunds:await this.getRoundRaisedFunds(t),participants:await this.getRoundParticipants(t),isActive:await this.isRoundActive(t)}}async getUserTotalContribution(t){const e=await this.contract.getUserTotalContribution(t);return{totalFundAmount:Number(e.totalFundAmount)/this.PRICE_PRECISION,totalTokenAllocation:Number(e.totalTokenAllocation)}}async getTransactionStatus(t,e=10){return await(0,o.getTransactionStatus)(this.getRandomProvider(),t,e)}getContractAddress(){return this.contractAddress}async getAllEvents(t,e){return await this.bootstrap(),(0,o.getAllEvents)(this.contract,(()=>this.getRandomProvider()),(()=>this.getContractWithRandomProvider()),t,e)}async streamEvents(t,e,n,r=1e3,a=5e3){return await this.bootstrap(),(0,o.streamEvents)({getProvider:()=>this.getRandomProvider(),getAllEvents:(t,e)=>this.getAllEvents(t,e),formatEvent:t=>this.formatEventArgs(t),onEvent:e,saveLatestBlock:n,fromBlock:t,batchSize:r,sleepTime:a})}};
1
+ "use strict";var t=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(exports,"__esModule",{value:!0}),exports.SeedRoundFundraiserSDK=void 0;const e=require("ethers"),n=t(require("./abis/SeedRoundFundraiser.json")),o=t(require("./contracts.json")),r=require("./utils"),i=t(require("./whitelist-tokens.json"));exports.SeedRoundFundraiserSDK=class{constructor(t,i){this.name="SeedRoundFundraiser",this.isBootstrapped=!1,this.PRICE_PRECISION=1e18,this.whitelistedTokensArray=[],this.projectToken="",this.projectTokenDecimals=0,this.formatEventArgs=t=>{const{eventName:e,args:n}=t;switch(e){case"TokenWhitelisted":return{...t,args:{...n,token:n.token.toLowerCase(),price:Number(n.price)/this.PRICE_PRECISION}};case"TokenPriceUpdated":return{...t,args:{...n,token:n.token.toLowerCase(),oldPrice:Number(n.oldPrice)/this.PRICE_PRECISION,newPrice:Number(n.newPrice)/this.PRICE_PRECISION}};case"TokenRemovedFromWhitelist":return{...t,args:{...n,token:n.token.toLowerCase()}};case"RoundCreated":case"RoundUpdated":return{...t,args:{...n,roundId:Number(n.roundId),startTime:Number(n.startTime),endTime:Number(n.endTime),targetFund:Number(n.targetFund)/this.PRICE_PRECISION,totalAllocation:Number(n.totalAllocation),maxFundPerAccount:Number(n.maxFundPerAccount)/this.PRICE_PRECISION}};case"RoundEnded":return{...t,args:{...n,roundId:Number(n.roundId),raisedFunds:Number(n.raisedFunds)/this.PRICE_PRECISION,participants:Number(n.participants)}};case"Contribution":return{...t,args:{...n,roundId:Number(n.roundId),contributor:n.contributor.toLowerCase(),token:n.token.toLowerCase(),amount:Number(n.amount),fundAmount:Number(n.fundAmount)/this.PRICE_PRECISION,tokenAllocation:Number(n.tokenAllocation)}};case"TokensClaimed":return{...t,args:{...n,roundId:Number(n.roundId),user:n.user.toLowerCase(),amount:Number(n.amount)}};case"ProjectTokenUpdated":return{...t,args:{...n,oldToken:n.oldToken.toLowerCase(),newToken:n.newToken.toLowerCase()}};case"ClaimingEnabledUpdated":case"RefundEnabledUpdated":return{...t,args:{...n,roundId:Number(n.roundId),enabled:n.enabled}};case"Refunded":return{...t,args:{...n,roundId:Number(n.roundId),user:n.user.toLowerCase(),token:n.token.toLowerCase(),amount:Number(n.amount)}};default:return t}};const a=Array.isArray(t)?t:[t];this.providers=a.map((t=>new e.ethers.JsonRpcProvider(t)));const s=(0,r.getRandomProvider)(this.providers);this.contractAddress=(0,r.resolveContractAddress)(a[0],this.name,o.default,i),this.contract=new e.ethers.Contract(this.contractAddress,n.default.abi,s),this.networkName=this.getNetworkNameFromRpc(a[0]),this.importWhitelistedTokens()}getNetworkNameFromRpc(t){const e=t.toLowerCase();return e.includes("sepolia.base")?"base-sepolia":e.includes("sepolia")?"sepolia":e.includes("mainnet")?"mainnet":e.includes("localhost")||e.includes("127.0.0.1")?"hardhat":"sepolia"}importWhitelistedTokens(){try{i.default[this.networkName]?(this.whitelistedTokensArray=i.default[this.networkName].map((t=>t.toLowerCase())),console.log(`Imported ${this.whitelistedTokensArray.length} whitelisted tokens for ${this.networkName} network`)):console.log(`No whitelisted tokens found for ${this.networkName} network`)}catch(t){console.error("Error importing whitelisted tokens:",t)}}async getWhitelistedTokenInfo(t){const n=t.toLowerCase();if(!this.whitelistedTokensArray.includes(n))return null;const o=await this.getWhitelistedToken(n);if(!o.isWhitelisted)return null;let i="ETH",a=18;n!==e.ethers.ZeroAddress&&([i,a]=await Promise.all([(0,r.getTokenSymbol)(n,this.getRandomProvider()),(0,r.getTokenDecimals)(n,this.getRandomProvider())]));const s=await this.getLatestRoundId();let d=0;if(s>=0){const t=await this.getRound(s);t.exists&&!t.ended&&(d=t.maxFundPerAccount/o.price)}return{address:n,isWhitelisted:o.isWhitelisted,price:o.price,symbol:i,maxContribution:d,maxContributionRaw:Math.floor(d*Math.pow(10,a)),decimals:a}}async getAllWhitelistedTokensInfo(){const t=[];for(const e of this.whitelistedTokensArray){const n=await this.getWhitelistedTokenInfo(e);n&&t.push(n)}return t}getRandomProvider(){return(0,r.getRandomProvider)(this.providers)}getContractWithRandomProvider(){return new e.ethers.Contract(this.contractAddress,n.default.abi,this.getRandomProvider())}async bootstrap(){if(this.isBootstrapped)return;const t=await Promise.all(this.providers.map(((t,e)=>(0,r.checkRpcHealth)(t,e))));if(this.providers=this.providers.filter(((e,n)=>t[n])),0===this.providers.length)throw new Error("No active RPC providers available");this.projectToken=await this.getProjectToken(),this.projectTokenDecimals=await(0,r.getTokenDecimals)(this.projectToken,this.getRandomProvider()),this.isBootstrapped=!0}async signAndSendTransaction(t,e,n={}){return(0,r.signAndSendTransaction)(t,e,(()=>this.getRandomProvider()),n,this.contract)}async buildAddWhitelistedTokenTx(t,e){const n=BigInt(Math.floor(e*this.PRICE_PRECISION));return await this.contract.addWhitelistedToken.populateTransaction(t,n)}async buildUpdateTokenPriceTx(t,e){const n=BigInt(Math.floor(e*this.PRICE_PRECISION));return await this.contract.updateTokenPrice.populateTransaction(t,n)}async buildRemoveWhitelistedTokenTx(t){return await this.contract.removeWhitelistedToken.populateTransaction(t)}async buildCreateRoundTx(t,e,n,o,i){const a=BigInt(Math.floor(n*this.PRICE_PRECISION)),s=BigInt(Math.floor(i*this.PRICE_PRECISION)),d=await(0,r.getTokenDecimals)(await this.getProjectToken(),this.getRandomProvider()),u=BigInt(Math.floor(o*Math.pow(10,d)));return await this.contract.createRound.populateTransaction(t,e,a,u,s)}async buildUpdateRoundTx(t,e,n,o,r,i){const a=BigInt(Math.floor(o*this.PRICE_PRECISION)),s=BigInt(Math.floor(i*this.PRICE_PRECISION));return await this.contract.updateRound.populateTransaction(t,e,n,a,r,s)}async buildEndRoundTx(t){return await this.contract.endRound.populateTransaction(t)}async buildSetClaimingEnabledTx(t,e){return await this.contract.setClaimingEnabled.populateTransaction(t,e)}async buildSetRefundEnabledTx(t,e){return await this.contract.setRefundEnabled.populateTransaction(t,e)}async buildContributeTx(t,n,o){let i=18;n!==e.ethers.ZeroAddress&&(i=await(0,r.getTokenDecimals)(n,this.getRandomProvider()));const a=e.ethers.parseUnits(o.toString(),i),s=await this.contract.contribute.populateTransaction(t,n,n===e.ethers.ZeroAddress?0:a);return n===e.ethers.ZeroAddress&&(s.value=a),s}async buildClaimTokensTx(){return await this.contract.claimTokens.populateTransaction()}async buildRefundTx(){return await this.contract.refund.populateTransaction()}async buildWithdrawFundsTx(t,e){const n=await(0,r.getTokenDecimals)(t,this.getRandomProvider()),o=BigInt(Math.floor(e*Math.pow(10,n)));return await this.contract.withdrawFunds.populateTransaction(t,o)}async buildClaimTokensByRoundIdTx(t){return await this.contract.claimTokensByRoundId.populateTransaction(t)}async getWhitelistedToken(t){const e=await this.contract.whitelistedTokens(t);return{isWhitelisted:e.isWhitelisted,price:Number(e.price)/this.PRICE_PRECISION}}async getRound(t){const e=await this.contract.rounds(t);return{startTime:Number(e.startTime),endTime:Number(e.endTime),targetFund:Number(e.targetFund)/this.PRICE_PRECISION,totalAllocation:Number(e.totalAllocation)/this.projectTokenDecimals,maxFundPerAccount:Number(e.maxFundPerAccount)/this.PRICE_PRECISION,exists:e.exists,ended:e.ended,claimingEnabled:e.claimingEnabled,refundEnabled:e.refundEnabled}}async getUserContribution(t,e){const n=await this.contract.userContributions(t,e);return{fundAmount:Number(n.fundAmount)/this.PRICE_PRECISION,tokenAllocation:Number(n.tokenAllocation),claimed:n.claimed,refunded:n.refunded,contributedToken:n.contributedToken,contributedAmount:Number(n.contributedAmount)}}async getRoundRaisedFunds(t){const e=await this.contract.roundRaisedFunds(t);return Number(e)/this.PRICE_PRECISION}async getRoundParticipants(t){const e=await this.contract.roundParticipants(t);return Number(e)}async getUserParticipatedRound(t){const e=await this.contract.userParticipatedRound(t);return Number(e)}async getProjectToken(){return await this.contract.projectToken()}async getTotalRounds(){const t=await this.contract.totalRounds();return Number(t)}async getTotalRaisedFunds(){const t=await this.contract.totalRaisedFunds();return Number(t)/this.PRICE_PRECISION}async isRoundActive(t){return await this.contract.isRoundActive(t)}async getLatestRoundId(){const t=await this.getTotalRounds();return 0===t?-1:t-1}async getRoundInfo(t){const e=await this.getTotalRounds();if(t<0||t>=e)throw new Error(`Invalid round ID: ${t}`);return{roundId:t,config:await this.getRound(t),raisedFunds:await this.getRoundRaisedFunds(t),participants:await this.getRoundParticipants(t),isActive:await this.isRoundActive(t)}}async getUserTotalContribution(t){const e=await this.contract.getUserTotalContribution(t);return{totalFundAmount:Number(e.totalFundAmount)/this.PRICE_PRECISION,totalTokenAllocation:Number(e.totalTokenAllocation)}}async getTransactionStatus(t,e=10){return await(0,r.getTransactionStatus)(this.getRandomProvider(),t,e)}getContractAddress(){return this.contractAddress}async getAllEvents(t,e){return await this.bootstrap(),(0,r.getAllEvents)(this.contract,(()=>this.getRandomProvider()),(()=>this.getContractWithRandomProvider()),t,e)}async streamEvents(t,e,n,o=1e3,i=5e3){return await this.bootstrap(),(0,r.streamEvents)({getProvider:()=>this.getRandomProvider(),getAllEvents:(t,e)=>this.getAllEvents(t,e),formatEvent:t=>this.formatEventArgs(t),onEvent:e,saveLatestBlock:n,fromBlock:t,batchSize:o,sleepTime:i})}async getUserRoundContribution(t,n){const[o,i]=await Promise.all([this.contract.getUserRoundContribution(t,n),this.contract.rounds(t)]),a={fundAmount:Number(o.fundAmount)/this.PRICE_PRECISION,tokenAllocation:Number(o.tokenAllocation),claimed:o.claimed,refunded:o.refunded,contributedToken:o.contributedToken,contributedAmount:Number(o.contributedAmount)},s=Math.floor(Date.now()/1e3),d=i.exists&&!i.ended&&s>=Number(i.startTime)&&s<=Number(i.endTime),u={contribution:a,roundInfo:{exists:i.exists,isActive:d,claimingEnabled:i.claimingEnabled,refundEnabled:i.refundEnabled}};if(a.fundAmount>0){const t=a.contributedToken;let n="ETH",o=18;return t!==e.ethers.ZeroAddress&&([n,o]=await Promise.all([(0,r.getTokenSymbol)(t,this.getRandomProvider()),(0,r.getTokenDecimals)(t,this.getRandomProvider())])),{...u,tokenInfo:{symbol:n,decimals:o}}}return u}};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aiia-vault-sdk",
3
- "version": "1.1.0",
3
+ "version": "1.1.2",
4
4
  "description": "SDK for AIIA Vault Contract",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",