atfi 1.0.0

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/README.md ADDED
@@ -0,0 +1,453 @@
1
+ # ATFi SDK
2
+
3
+ TypeScript SDK for interacting with ATFi commitment vaults on Base.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install atfi viem
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```typescript
14
+ import { ATFiSDK } from 'atfi';
15
+ import { createPublicClient, createWalletClient, http, custom } from 'viem';
16
+ import { base } from 'viem/chains';
17
+
18
+ // Setup clients
19
+ const publicClient = createPublicClient({
20
+ chain: base,
21
+ transport: http(),
22
+ });
23
+
24
+ const walletClient = createWalletClient({
25
+ chain: base,
26
+ transport: custom(window.ethereum),
27
+ });
28
+
29
+ // Initialize SDK
30
+ const sdk = new ATFiSDK(publicClient, walletClient);
31
+ ```
32
+
33
+ ## How It Works
34
+
35
+ **Every write function returns `{ simulation, execute() }`** - one call gives you everything:
36
+
37
+ ```typescript
38
+ const action = await sdk.register({ vaultAddress: '0x...' });
39
+
40
+ // 1. Check simulation result (NO wallet popup yet!)
41
+ if (!action.simulation.success) {
42
+ console.error(action.simulation.error.message);
43
+ return;
44
+ }
45
+
46
+ // 2. Show user what will happen
47
+ console.log(`Stake: ${action.simulation.stakeAmount} ${action.simulation.tokenSymbol}`);
48
+ console.log(`Your balance: ${action.simulation.userBalance}`);
49
+ console.log(`Gas estimate: ${action.simulation.gasEstimate}`);
50
+
51
+ // 3. User confirms → execute with loading callbacks
52
+ const result = await action.execute({
53
+ onApproving: () => setStatus('Approving token...'),
54
+ onApproved: (hash) => setStatus('Token approved!'),
55
+ onSubmitting: () => setStatus('Submitting...'),
56
+ onSubmitted: (hash) => setStatus(`TX: ${hash}`),
57
+ onConfirming: () => setStatus('Confirming...'),
58
+ });
59
+ console.log('Done!', result.txHash);
60
+ ```
61
+
62
+ ---
63
+
64
+ ## Read-Only Mode
65
+
66
+ Show data before user connects wallet:
67
+
68
+ ```typescript
69
+ import { ATFiSDK } from 'atfi';
70
+ import { createPublicClient, http } from 'viem';
71
+ import { base } from 'viem/chains';
72
+
73
+ // No wallet needed!
74
+ const publicClient = createPublicClient({
75
+ chain: base,
76
+ transport: http(),
77
+ });
78
+
79
+ const sdk = ATFiSDK.readOnly(publicClient);
80
+
81
+ // All read functions work
82
+ const events = await sdk.getAllEvents();
83
+ const info = await sdk.getEventInfo('0x...');
84
+
85
+ // Write functions throw helpful error
86
+ await sdk.register({ vaultAddress: '0x...' });
87
+ // Error: "SDK is in read-only mode. Initialize with a walletClient to perform write operations."
88
+ ```
89
+
90
+ ---
91
+
92
+ ## API Reference
93
+
94
+ ### Create Event (Organizer)
95
+
96
+ ```typescript
97
+ const action = await sdk.createEvent({
98
+ stakeAmount: '10', // 10 USDC
99
+ maxParticipants: 50,
100
+ useYield: true, // Enable Morpho yield
101
+ token: 'USDC', // 'USDC' or 'IDRX'
102
+ });
103
+
104
+ if (action.simulation.success) {
105
+ console.log('Expected vault ID:', action.simulation.expectedVaultId);
106
+ console.log('Token:', action.simulation.token.symbol);
107
+ console.log('Gas:', action.simulation.gasEstimate);
108
+
109
+ const result = await action.execute({
110
+ onSubmitting: () => showLoader('Creating event...'),
111
+ onConfirming: () => showLoader('Confirming...'),
112
+ });
113
+ console.log('Created:', result.vaultAddress);
114
+ }
115
+ ```
116
+
117
+ **Simulation returns:**
118
+ | Field | Type | Description |
119
+ |-------|------|-------------|
120
+ | `expectedVaultId` | bigint | Next vault ID |
121
+ | `token` | object | { address, symbol, decimals } |
122
+ | `stakeAmount` | string | Human readable stake |
123
+ | `maxParticipants` | number | Max allowed |
124
+ | `useYield` | boolean | Yield enabled |
125
+ | `gasEstimate` | bigint | Estimated gas |
126
+
127
+ ---
128
+
129
+ ### Register (Participant)
130
+
131
+ ```typescript
132
+ const action = await sdk.register({ vaultAddress: '0x...' });
133
+
134
+ if (action.simulation.success) {
135
+ console.log(`Stake: ${action.simulation.stakeAmount} ${action.simulation.tokenSymbol}`);
136
+ console.log(`Your balance: ${action.simulation.userBalance}`);
137
+ console.log(`Needs approval: ${action.simulation.needsApproval}`);
138
+ console.log(`Spots left: ${action.simulation.maxParticipants - action.simulation.currentParticipants}`);
139
+
140
+ // Callbacks for loading states (approval + stake transaction)
141
+ const result = await action.execute({
142
+ onApproving: () => showLoader('Approving USDC...'),
143
+ onApproved: (hash) => showToast(`Approved! ${hash}`),
144
+ onSubmitting: () => showLoader('Staking...'),
145
+ onConfirming: () => showLoader('Confirming...'),
146
+ });
147
+ }
148
+ ```
149
+
150
+ **Simulation returns:**
151
+ | Field | Type | Description |
152
+ |-------|------|-------------|
153
+ | `stakeAmount` | string | Amount to stake |
154
+ | `tokenSymbol` | string | USDC or IDRX |
155
+ | `userBalance` | string | Your token balance |
156
+ | `currentAllowance` | string | Current approval |
157
+ | `needsApproval` | boolean | Need approve TX first |
158
+ | `currentParticipants` | number | Current count |
159
+ | `maxParticipants` | number | Max allowed |
160
+
161
+ ---
162
+
163
+ ### Start Event (Organizer)
164
+
165
+ ```typescript
166
+ const action = await sdk.startEvent({ vaultAddress: '0x...' });
167
+
168
+ if (action.simulation.success) {
169
+ console.log(`Total staked: ${action.simulation.totalStaked}`);
170
+ console.log(`Participants: ${action.simulation.participantCount}`);
171
+ console.log(`Has yield: ${action.simulation.hasYield}`);
172
+
173
+ const result = await action.execute();
174
+ }
175
+ ```
176
+
177
+ ---
178
+
179
+ ### Verify Participants (Organizer)
180
+
181
+ ```typescript
182
+ const action = await sdk.verifyParticipant({
183
+ vaultAddress: '0x...',
184
+ participants: ['0xAddr1', '0xAddr2', '0xAddr3'],
185
+ });
186
+
187
+ if (action.simulation.success) {
188
+ console.log(`Will verify: ${action.simulation.toVerify.length}`);
189
+ console.log(`Already verified: ${action.simulation.alreadyVerified.length}`);
190
+ console.log(`Not staked: ${action.simulation.notStaked.length}`);
191
+
192
+ const result = await action.execute();
193
+ }
194
+ ```
195
+
196
+ **Simulation returns:**
197
+ | Field | Type | Description |
198
+ |-------|------|-------------|
199
+ | `toVerify` | Address[] | Will be verified |
200
+ | `alreadyVerified` | Address[] | Already done |
201
+ | `notStaked` | Address[] | Not registered (will fail) |
202
+ | `currentVerified` | number | Current count |
203
+ | `newVerifiedCount` | number | Count after |
204
+
205
+ ---
206
+
207
+ ### Settle Event (Organizer)
208
+
209
+ ```typescript
210
+ const action = await sdk.settleEvent({ vaultAddress: '0x...' });
211
+
212
+ if (action.simulation.success) {
213
+ console.log(`Verified: ${action.simulation.verifiedCount}`);
214
+ console.log(`No-shows: ${action.simulation.noShowCount}`);
215
+ console.log(`Yield earned: ${action.simulation.estimatedYield}`);
216
+ console.log(`Protocol fees: ${action.simulation.estimatedProtocolFees}`);
217
+ console.log(`Reward per attendee: ${action.simulation.estimatedRewardPerParticipant}`);
218
+
219
+ const result = await action.execute();
220
+ }
221
+ ```
222
+
223
+ **Simulation returns:**
224
+ | Field | Type | Description |
225
+ |-------|------|-------------|
226
+ | `totalStaked` | string | Total staked |
227
+ | `verifiedCount` | number | Attendees |
228
+ | `noShowCount` | number | No-shows |
229
+ | `estimatedYield` | string | Yield earned |
230
+ | `estimatedProtocolFees` | string | Protocol fees |
231
+ | `estimatedNoShowFees` | string | No-show fees |
232
+ | `estimatedRewardPerParticipant` | string | Reward each |
233
+
234
+ ---
235
+
236
+ ### Claim Rewards (Participant)
237
+
238
+ ```typescript
239
+ const action = await sdk.claim({ vaultAddress: '0x...' });
240
+
241
+ if (action.simulation.success) {
242
+ console.log(`Total: ${action.simulation.claimableAmount} ${action.simulation.tokenSymbol}`);
243
+ console.log(`Your stake: ${action.simulation.stakeAmount}`);
244
+ console.log(`Bonus: ${action.simulation.bonusShare}`);
245
+
246
+ const result = await action.execute();
247
+ }
248
+ ```
249
+
250
+ **Simulation returns:**
251
+ | Field | Type | Description |
252
+ |-------|------|-------------|
253
+ | `claimableAmount` | string | Total to claim |
254
+ | `tokenSymbol` | string | Token symbol |
255
+ | `stakeAmount` | string | Original stake |
256
+ | `bonusShare` | string | Bonus from no-shows + yield |
257
+
258
+ ---
259
+
260
+ ## Read Functions
261
+
262
+ ```typescript
263
+ // Get event details
264
+ const info = await sdk.getEventInfo('0xVaultAddress');
265
+
266
+ // Get participant status
267
+ const status = await sdk.getParticipantStatus('0xVault', '0xParticipant');
268
+
269
+ // Get all events (batched for performance)
270
+ const events = await sdk.getAllEvents();
271
+
272
+ // Get vault by ID
273
+ const vault = await sdk.getVaultAddress(1);
274
+ ```
275
+
276
+ ---
277
+
278
+ ## Token Balance Helpers
279
+
280
+ ```typescript
281
+ // Get single token balance
282
+ const usdcBalance = await sdk.getTokenBalance('0xUserAddress', 'USDC');
283
+ console.log(`USDC: ${usdcBalance}`); // "125.50"
284
+
285
+ // Get all supported token balances
286
+ const balances = await sdk.getAllTokenBalances('0xUserAddress');
287
+ console.log(balances);
288
+ // { USDC: "125.50", IDRX: "1000000.00" }
289
+ ```
290
+
291
+ ---
292
+
293
+ ## User-Centric Queries
294
+
295
+ Get events filtered by user:
296
+
297
+ ```typescript
298
+ // Events created by user
299
+ const myEvents = await sdk.getEventsByOwner('0xUserAddress');
300
+
301
+ // Events user registered for
302
+ const registered = await sdk.getRegisteredEvents('0xUserAddress');
303
+
304
+ // Events with unclaimed rewards
305
+ const claimable = await sdk.getClaimableEvents('0xUserAddress');
306
+
307
+ // Complete dashboard data (all in one call)
308
+ const dashboard = await sdk.getUserDashboard('0xUserAddress');
309
+ console.log(dashboard);
310
+ // {
311
+ // asOrganizer: [...], // Events user created
312
+ // asParticipant: [...], // Events user joined
313
+ // claimable: [...], // Ready to claim
314
+ // balances: { USDC: "125.50", IDRX: "1000000.00" }
315
+ // }
316
+ ```
317
+
318
+ ---
319
+
320
+ ## Transaction Callbacks
321
+
322
+ All write functions accept callbacks for loading states:
323
+
324
+ ```typescript
325
+ interface TransactionCallbacks {
326
+ onApproving?: () => void; // Starting token approval
327
+ onApproved?: (txHash: Hash) => void; // Approval submitted
328
+ onSubmitting?: () => void; // Starting main transaction
329
+ onSubmitted?: (txHash: Hash) => void; // Transaction submitted
330
+ onConfirming?: () => void; // Waiting for confirmation
331
+ }
332
+
333
+ // Example: Full loading state management
334
+ const result = await action.execute({
335
+ onApproving: () => {
336
+ setStatus('approving');
337
+ setMessage('Please approve token in wallet...');
338
+ },
339
+ onApproved: (hash) => {
340
+ setMessage(`Approved! TX: ${hash.slice(0, 10)}...`);
341
+ },
342
+ onSubmitting: () => {
343
+ setStatus('submitting');
344
+ setMessage('Please confirm transaction in wallet...');
345
+ },
346
+ onSubmitted: (hash) => {
347
+ setMessage(`Submitted! TX: ${hash.slice(0, 10)}...`);
348
+ setTxHash(hash);
349
+ },
350
+ onConfirming: () => {
351
+ setStatus('confirming');
352
+ setMessage('Waiting for blockchain confirmation...');
353
+ },
354
+ });
355
+ setStatus('success');
356
+ ```
357
+
358
+ ---
359
+
360
+ ## Real-Time Event Watching
361
+
362
+ Subscribe to vault events for live UI updates:
363
+
364
+ ```typescript
365
+ const unwatch = sdk.watchVault('0xVaultAddress', {
366
+ onParticipantJoined: (address, total) => {
367
+ console.log(`${address} joined! Total: ${total}`);
368
+ updateParticipantList();
369
+ },
370
+ onParticipantVerified: (address, totalVerified) => {
371
+ console.log(`${address} verified!`);
372
+ updateVerifiedCount(totalVerified);
373
+ },
374
+ onSettled: (totalYield, protocolFee) => {
375
+ console.log(`Event settled! Yield: ${totalYield}`);
376
+ showClaimButton();
377
+ },
378
+ onClaimed: (address, amount) => {
379
+ console.log(`${address} claimed ${amount}`);
380
+ },
381
+ onStakingStatusChanged: (isOpen) => {
382
+ updateRegistrationStatus(isOpen);
383
+ },
384
+ onError: (error) => {
385
+ console.error('Watch error:', error);
386
+ },
387
+ });
388
+
389
+ // Stop watching when done
390
+ unwatch();
391
+ ```
392
+
393
+ ---
394
+
395
+ ## Error Handling
396
+
397
+ Errors are returned in simulation, not thrown:
398
+
399
+ ```typescript
400
+ const action = await sdk.register({ vaultAddress: '0x...' });
401
+
402
+ if (!action.simulation.success) {
403
+ switch (action.simulation.error.code) {
404
+ case 'STAKING_CLOSED':
405
+ showMessage('Registration ended');
406
+ break;
407
+ case 'ALREADY_STAKED':
408
+ showMessage('Already registered');
409
+ break;
410
+ case 'INSUFFICIENT_BALANCE':
411
+ showMessage(`Need ${action.simulation.stakeAmount} ${action.simulation.tokenSymbol}`);
412
+ break;
413
+ case 'MAX_PARTICIPANTS_REACHED':
414
+ showMessage('Event is full');
415
+ break;
416
+ default:
417
+ showMessage(action.simulation.error.message);
418
+ }
419
+ return;
420
+ }
421
+ ```
422
+
423
+ **Error Codes:**
424
+ - `STAKING_CLOSED` - Registration ended
425
+ - `ALREADY_STAKED` - Already registered
426
+ - `INSUFFICIENT_BALANCE` - Not enough tokens
427
+ - `MAX_PARTICIPANTS_REACHED` - Event full
428
+ - `NOT_OWNER` - Not event owner
429
+ - `EVENT_ALREADY_STARTED` - Already started
430
+ - `VAULT_ALREADY_SETTLED` - Already settled
431
+ - `VAULT_NOT_SETTLED` - Not settled yet
432
+ - `NOT_VERIFIED` - Not verified for attendance
433
+ - `ALREADY_CLAIMED` - Already claimed
434
+
435
+ ---
436
+
437
+ ## Supported Tokens
438
+
439
+ | Token | Address | Decimals | Yield |
440
+ |-------|---------|----------|-------|
441
+ | USDC | `0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913` | 6 | Yes |
442
+ | IDRX | `0x18Bc5bcC660cf2B9cE3cd51a404aFe1a0cBD3C22` | 2 | No |
443
+
444
+ ## Contract Addresses (Base Mainnet)
445
+
446
+ | Contract | Address |
447
+ |----------|---------|
448
+ | FactoryATFi | `0x0be05a5fa7116c1b33f2b0036eb0d9690db9075f` |
449
+ | Morpho Vault | `0x050cE30b927Da55177A4914EC73480238BAD56f0` |
450
+
451
+ ## License
452
+
453
+ MIT