@obscura-fhe/sdk 1.0.0 → 1.0.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.
- package/CHANGELOG.md +25 -0
- package/README.md +163 -31
- package/dist/index.cjs +140 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +112 -2
- package/dist/index.d.ts +112 -2
- package/dist/index.js +140 -3
- package/dist/index.js.map +1 -1
- package/package.json +7 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,31 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `@obscura-fhe/sdk` are documented in this file.
|
|
4
4
|
|
|
5
|
+
## [1.0.2] - 2026-05-30
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- **Credit module:** `getMarketUtilization()` — public pool aggregates (`utilizationBps`, `totalSupplyAssets`, `totalBorrowAssets`)
|
|
10
|
+
- **Credit module:** `getPositionHandles()` — encrypted position handles as opaque hex; optional plaintext shadows with explicit warning
|
|
11
|
+
- Exported types: `CreditMarketUtilization`, `CreditPositionHandles`
|
|
12
|
+
|
|
13
|
+
## [1.0.1] - 2026-05-29
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
|
|
17
|
+
- **Vote module:** `getProposalCount()` now reads on-chain `nextProposalId()` instead of non-existent `proposalCount()` (verified against Arbitrum Sepolia ObscuraVote `0xe358…1730`)
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- `ActivityModule.isConfigured()` — check Supabase credentials before querying
|
|
22
|
+
- Clearer activity error messages with default Supabase URL and setup instructions
|
|
23
|
+
- Module examples: `reputation`, `activity`, `notifications`, `pay`, `credit`, `vote`
|
|
24
|
+
- README: requirements matrix, viem rpcUrl/transport examples, TypeScript `verbatimModuleSyntax` guidance
|
|
25
|
+
|
|
26
|
+
### Docs
|
|
27
|
+
|
|
28
|
+
- Developer portal quick-start, SDK onboarding, and SDK reference updated with hidden requirements
|
|
29
|
+
|
|
5
30
|
## [1.0.0] - 2026-05-29
|
|
6
31
|
|
|
7
32
|
### Added
|
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# @obscura-fhe/sdk
|
|
2
2
|
|
|
3
|
-
Official TypeScript SDK for **Obscura Pay**, **Credit**, and Vote on Arbitrum Sepolia.
|
|
3
|
+
Official TypeScript SDK for **Obscura Pay**, **Credit**, and **Vote** on Arbitrum Sepolia.
|
|
4
4
|
|
|
5
|
-
Privacy-first DeFi with FHE (Fully Homomorphic Encryption). Framework-agnostic — works in Node.js, browsers, and automation scripts.
|
|
5
|
+
Privacy-first DeFi with FHE (Fully Homomorphic Encryption). Framework-agnostic — works in Node.js, browsers, Vite, Next.js, and automation scripts.
|
|
6
6
|
|
|
7
7
|
## Install
|
|
8
8
|
|
|
@@ -10,7 +10,22 @@ Privacy-first DeFi with FHE (Fully Homomorphic Encryption). Framework-agnostic
|
|
|
10
10
|
npm install @obscura-fhe/sdk viem
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
`viem` is a peer dependency (v2+).
|
|
13
|
+
`viem` is a **peer dependency** (v2+). You must install it alongside the SDK.
|
|
14
|
+
|
|
15
|
+
## Requirements at a glance
|
|
16
|
+
|
|
17
|
+
| Module | Wallet | RPC / chain | Supabase | FHE provider |
|
|
18
|
+
|--------|--------|-------------|----------|--------------|
|
|
19
|
+
| `reputation` | No | No | No | No |
|
|
20
|
+
| `notifications` | No | No | No | No |
|
|
21
|
+
| `activity` | No | No | **Yes** (URL + anon key) | No |
|
|
22
|
+
| `pay` / `credit` / `vote` reads | No | **Yes** (default RPC) | No | No |
|
|
23
|
+
| Encrypted writes (`buildShield`, etc.) | Optional* | Yes | No | **Yes** (or pre-encrypted input) |
|
|
24
|
+
| `sendCall()` | **Yes** (`walletClient`) | Yes | No | If write needs FHE |
|
|
25
|
+
|
|
26
|
+
\*Use `encodeCall()` and sign externally if you do not inject `walletClient`.
|
|
27
|
+
|
|
28
|
+
**Network:** Arbitrum Sepolia (`chainId` **421614**) by default.
|
|
14
29
|
|
|
15
30
|
## Quick start
|
|
16
31
|
|
|
@@ -18,49 +33,153 @@ npm install @obscura-fhe/sdk viem
|
|
|
18
33
|
import { ObscuraSDK } from "@obscura-fhe/sdk";
|
|
19
34
|
|
|
20
35
|
const sdk = ObscuraSDK.create({
|
|
21
|
-
|
|
36
|
+
// Required for activity feed only:
|
|
37
|
+
supabaseAnonKey: process.env.OBSCURA_SUPABASE_ANON_KEY,
|
|
38
|
+
// supabaseUrl defaults to Obscura production project
|
|
22
39
|
});
|
|
23
40
|
|
|
24
|
-
// Reputation
|
|
41
|
+
// Reputation — no wallet, no Supabase
|
|
25
42
|
const summary = await sdk.reputation.getSummary("0xYourWallet...");
|
|
26
43
|
console.log(summary.tier, summary.totalCappedWeight);
|
|
27
44
|
|
|
28
|
-
// Activity
|
|
29
|
-
|
|
30
|
-
filter: "credit"
|
|
45
|
+
// Activity — requires supabaseAnonKey
|
|
46
|
+
if (sdk.activity.isConfigured()) {
|
|
47
|
+
const { items } = await sdk.activity.listForWallet("0xYourWallet...", { filter: "credit" });
|
|
48
|
+
console.log(items.length);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// On-chain read — uses default Arbitrum Sepolia RPC
|
|
52
|
+
const proposalCount = await sdk.vote.getProposalCount(); // reads nextProposalId()
|
|
53
|
+
const balanceCt = await sdk.pay.getShieldedBalance("0xYourWallet...");
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## viem integration (recommended)
|
|
57
|
+
|
|
58
|
+
Pass an explicit RPC URL and viem clients when you need custom transport, account abstraction, or `sendCall()`:
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
import { ObscuraSDK } from "@obscura-fhe/sdk";
|
|
62
|
+
import { createPublicClient, createWalletClient, http, custom } from "viem";
|
|
63
|
+
import { arbitrumSepolia } from "viem/chains";
|
|
64
|
+
import { privateKeyToAccount } from "viem/accounts";
|
|
65
|
+
|
|
66
|
+
const rpcUrl = process.env.ARB_SEPOLIA_RPC_URL ?? "https://sepolia-rollup.arbitrum.io/rpc";
|
|
67
|
+
|
|
68
|
+
const publicClient = createPublicClient({
|
|
69
|
+
chain: arbitrumSepolia,
|
|
70
|
+
transport: http(rpcUrl),
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// Browser wallet (MetaMask, etc.)
|
|
74
|
+
const walletClient = createWalletClient({
|
|
75
|
+
chain: arbitrumSepolia,
|
|
76
|
+
transport: custom(window.ethereum),
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// Or Node with private key
|
|
80
|
+
// const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);
|
|
81
|
+
// const walletClient = createWalletClient({ account, chain: arbitrumSepolia, transport: http(rpcUrl) });
|
|
82
|
+
|
|
83
|
+
const sdk = ObscuraSDK.create({
|
|
84
|
+
chainId: 421614,
|
|
85
|
+
rpcUrl,
|
|
86
|
+
publicClient,
|
|
87
|
+
walletClient,
|
|
88
|
+
supabaseUrl: process.env.OBSCURA_SUPABASE_URL,
|
|
89
|
+
supabaseAnonKey: process.env.OBSCURA_SUPABASE_ANON_KEY,
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
// Shorthand — SDK creates publicClient from rpcUrl when publicClient omitted:
|
|
93
|
+
const sdkMinimal = ObscuraSDK.create({ rpcUrl: "https://sepolia-rollup.arbitrum.io/rpc" });
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Activity module — Supabase setup
|
|
97
|
+
|
|
98
|
+
The activity feed reads indexed on-chain events from Supabase (`obscura_activity`). **Both** credentials are required:
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
import { ObscuraSDK, DEFAULT_SUPABASE_URL } from "@obscura-fhe/sdk";
|
|
102
|
+
|
|
103
|
+
const sdk = ObscuraSDK.create({
|
|
104
|
+
supabaseUrl: process.env.OBSCURA_SUPABASE_URL ?? DEFAULT_SUPABASE_URL,
|
|
105
|
+
supabaseAnonKey: process.env.OBSCURA_SUPABASE_ANON_KEY!, // required
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
if (!sdk.activity.isConfigured()) {
|
|
109
|
+
throw new Error("Set OBSCURA_SUPABASE_ANON_KEY for activity queries");
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const { items, hasMore } = await sdk.activity.listForWallet(wallet, {
|
|
113
|
+
filter: "vote", // all | pay | credit | vote | stream | ...
|
|
31
114
|
page: 0,
|
|
115
|
+
pageSize: 20,
|
|
32
116
|
});
|
|
117
|
+
```
|
|
33
118
|
|
|
34
|
-
|
|
35
|
-
const vapidKey = await sdk.notifications.getVapidPublicKey();
|
|
36
|
-
const prefs = await sdk.notifications.getPrefs("0xYourWallet...");
|
|
119
|
+
**Environment variables:**
|
|
37
120
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
121
|
+
```bash
|
|
122
|
+
OBSCURA_SUPABASE_URL=https://quoovjkjwgtdqwdofubh.supabase.co # optional — this is the default
|
|
123
|
+
OBSCURA_SUPABASE_ANON_KEY=eyJ... # required for activity
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Get the anon key from Supabase → Project Settings → API → `anon` `public` key.
|
|
127
|
+
|
|
128
|
+
## TypeScript setup
|
|
129
|
+
|
|
130
|
+
The SDK ships ESM + CJS with `.d.ts` types. Recommended `tsconfig.json`:
|
|
41
131
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
132
|
+
```json
|
|
133
|
+
{
|
|
134
|
+
"compilerOptions": {
|
|
135
|
+
"target": "ES2022",
|
|
136
|
+
"module": "ESNext",
|
|
137
|
+
"moduleResolution": "bundler",
|
|
138
|
+
"strict": true,
|
|
139
|
+
"skipLibCheck": true,
|
|
140
|
+
"esModuleInterop": true,
|
|
141
|
+
"verbatimModuleSyntax": true
|
|
142
|
+
}
|
|
143
|
+
}
|
|
45
144
|
```
|
|
46
145
|
|
|
47
|
-
|
|
146
|
+
### `verbatimModuleSyntax`
|
|
48
147
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
148
|
+
With `verbatimModuleSyntax: true`, TypeScript requires **type-only imports** for types:
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
// Correct
|
|
152
|
+
import { ObscuraSDK } from "@obscura-fhe/sdk";
|
|
153
|
+
import type { FheProvider, ReputationSummary, ContractCall } from "@obscura-fhe/sdk";
|
|
154
|
+
|
|
155
|
+
// Wrong — TS1363 error under verbatimModuleSyntax
|
|
156
|
+
import { FheProvider, ReputationSummary } from "@obscura-fhe/sdk";
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
If you cannot use type-only imports, set `"verbatimModuleSyntax": false` or use `"isolatedModules": true` without verbatim (Vite/Next default).
|
|
160
|
+
|
|
161
|
+
## Module examples
|
|
162
|
+
|
|
163
|
+
See [`examples/`](./examples/) for runnable scripts:
|
|
57
164
|
|
|
58
|
-
|
|
165
|
+
| File | Module |
|
|
166
|
+
|------|--------|
|
|
167
|
+
| `examples/reputation.ts` | Reputation summary |
|
|
168
|
+
| `examples/activity.ts` | Activity feed (Supabase) |
|
|
169
|
+
| `examples/notifications.ts` | VAPID + prefs |
|
|
170
|
+
| `examples/pay.ts` | Shielded balance + transfer builder |
|
|
171
|
+
| `examples/credit.ts` | Market address + borrow builder |
|
|
172
|
+
| `examples/vote.ts` | Proposal count + delegate |
|
|
173
|
+
| `examples/basic-usage.ts` | Combined smoke test |
|
|
174
|
+
|
|
175
|
+
Run: `npm run example:basic` or `npx tsx examples/reputation.ts`
|
|
176
|
+
|
|
177
|
+
## Configuration reference
|
|
59
178
|
|
|
60
179
|
```typescript
|
|
61
180
|
ObscuraSDK.create({
|
|
62
181
|
chainId: 421614, // default: Arbitrum Sepolia
|
|
63
|
-
rpcUrl: "https://...", // default: Arbitrum Sepolia RPC
|
|
182
|
+
rpcUrl: "https://...", // default: Arbitrum Sepolia public RPC
|
|
64
183
|
apiUrl: "https://...", // default: obscura-api production
|
|
65
184
|
supabaseUrl: "https://...", // default: Obscura Supabase project
|
|
66
185
|
supabaseAnonKey: "...", // required for activity module
|
|
@@ -73,14 +192,14 @@ ObscuraSDK.create({
|
|
|
73
192
|
|
|
74
193
|
## FHE (encrypted writes)
|
|
75
194
|
|
|
76
|
-
Encrypted contract inputs require a host-supplied `FheProvider` (typically wrapping `@cofhe
|
|
195
|
+
Encrypted contract inputs require a host-supplied `FheProvider` (typically wrapping `@fhenixprotocol/cofhe-sdk`):
|
|
77
196
|
|
|
78
197
|
```typescript
|
|
79
198
|
import type { FheProvider } from "@obscura-fhe/sdk";
|
|
80
199
|
|
|
81
200
|
const fhe: FheProvider = {
|
|
82
201
|
async encryptUint64(value, { contractAddress }) {
|
|
83
|
-
// wrap
|
|
202
|
+
// wrap CoFHE encrypt — user-triggered only
|
|
84
203
|
return { ctHash, securityZone, utype, signature };
|
|
85
204
|
},
|
|
86
205
|
};
|
|
@@ -99,11 +218,24 @@ const call = sdk.vote.buildDelegate("0xDelegatee...");
|
|
|
99
218
|
const hash = await sdk.sendCall(call, account); // requires walletClient
|
|
100
219
|
```
|
|
101
220
|
|
|
221
|
+
## Modules
|
|
222
|
+
|
|
223
|
+
| Module | Methods | Backend |
|
|
224
|
+
|--------|---------|---------|
|
|
225
|
+
| `pay` | `getShieldedBalance`, `buildShield`, `buildUnshield`, `buildTransfer` | On-chain (ocUSDC_Pay) |
|
|
226
|
+
| `credit` | `getMarketAddress`, `buildSupplyCollateral`, `buildBorrow`, `buildRepay` | On-chain (credit market) |
|
|
227
|
+
| `vote` | `getProposalCount`, `getProposal`, `buildCastVote`, `buildDelegate` | On-chain (ObscuraVote) |
|
|
228
|
+
| `reputation` | `getSummary` | obscura-api REST |
|
|
229
|
+
| `activity` | `listForWallet`, `getEventFilters`, `isConfigured` | Supabase |
|
|
230
|
+
| `notifications` | `getVapidPublicKey`, `getPrefs`, `savePrefs`, `subscribe`, `unsubscribe` | obscura-api REST |
|
|
231
|
+
|
|
102
232
|
## Defaults (Arbitrum Sepolia)
|
|
103
233
|
|
|
104
234
|
| Setting | Value |
|
|
105
235
|
|---------|-------|
|
|
106
236
|
| Chain ID | `421614` |
|
|
237
|
+
| RPC | `https://sepolia-rollup.arbitrum.io/rpc` |
|
|
238
|
+
| Supabase URL | `https://quoovjkjwgtdqwdofubh.supabase.co` |
|
|
107
239
|
| ocUSDC_Pay | `0xEd46020Df8abe7BB1E096f27d089F4326D223a53` |
|
|
108
240
|
| Vote | `0xe358776AfdbA95d7c9F040e6ef1f5A021aF91730` |
|
|
109
241
|
| Credit market | `0x1Ec113297c7F9516A6604aa3b18C180559a6f551` |
|
|
@@ -115,7 +247,7 @@ Core: `ObscuraSDK`, `ObscuraSDKConfig`, `ContractCall`, `InEuint64`, `FheProvide
|
|
|
115
247
|
|
|
116
248
|
Types: `ReputationSummary`, `ActivityItem`, `NotificationPrefs`, `ProposalState`, …
|
|
117
249
|
|
|
118
|
-
Constants: `DEFAULT_ADDRESSES`, `ARBITRUM_SEPOLIA_CHAIN_ID`, `ACTIVITY_EVENT_FILTERS`
|
|
250
|
+
Constants: `DEFAULT_ADDRESSES`, `DEFAULT_SUPABASE_URL`, `ARBITRUM_SEPOLIA_CHAIN_ID`, `ACTIVITY_EVENT_FILTERS`
|
|
119
251
|
|
|
120
252
|
Utilities: `encodeCall`, `normalizeWallet`, `toContractInEuint64`, `HttpError`
|
|
121
253
|
|
package/dist/index.cjs
CHANGED
|
@@ -222,16 +222,30 @@ var ACTIVITY_EVENT_FILTERS = {
|
|
|
222
222
|
var DEFAULT_PAGE_SIZE = 20;
|
|
223
223
|
var ActivityModule = class {
|
|
224
224
|
client;
|
|
225
|
+
supabaseUrl;
|
|
226
|
+
supabaseAnonKey;
|
|
225
227
|
constructor(supabaseUrl, supabaseAnonKey) {
|
|
228
|
+
this.supabaseUrl = supabaseUrl;
|
|
229
|
+
this.supabaseAnonKey = supabaseAnonKey;
|
|
226
230
|
this.client = supabaseUrl && supabaseAnonKey ? supabaseJs.createClient(supabaseUrl, supabaseAnonKey) : null;
|
|
227
231
|
}
|
|
232
|
+
/** True when both Supabase URL and anon key were supplied at SDK init. */
|
|
233
|
+
isConfigured() {
|
|
234
|
+
return this.client !== null;
|
|
235
|
+
}
|
|
228
236
|
getEventFilters() {
|
|
229
237
|
return ACTIVITY_EVENT_FILTERS;
|
|
230
238
|
}
|
|
231
239
|
async listForWallet(wallet, options = {}) {
|
|
232
240
|
if (!this.client) {
|
|
233
241
|
throw new Error(
|
|
234
|
-
|
|
242
|
+
[
|
|
243
|
+
"Activity module requires Supabase credentials.",
|
|
244
|
+
`Pass supabaseAnonKey (and optionally supabaseUrl) to ObscuraSDK.create().`,
|
|
245
|
+
`Default URL: ${DEFAULT_SUPABASE_URL}`,
|
|
246
|
+
"Get the anon key from your Supabase project \u2192 Settings \u2192 API \u2192 anon public.",
|
|
247
|
+
"Reputation and notifications work without Supabase; activity does not."
|
|
248
|
+
].join(" ")
|
|
235
249
|
);
|
|
236
250
|
}
|
|
237
251
|
const normalized = normalizeWallet(wallet);
|
|
@@ -303,6 +317,53 @@ var OC_USDC_PAY_ABI = [
|
|
|
303
317
|
}
|
|
304
318
|
];
|
|
305
319
|
var CREDIT_MARKET_ABI = [
|
|
320
|
+
{
|
|
321
|
+
name: "utilizationBps",
|
|
322
|
+
type: "function",
|
|
323
|
+
stateMutability: "view",
|
|
324
|
+
inputs: [],
|
|
325
|
+
outputs: [{ name: "", type: "uint256" }]
|
|
326
|
+
},
|
|
327
|
+
{
|
|
328
|
+
name: "totalSupplyAssets",
|
|
329
|
+
type: "function",
|
|
330
|
+
stateMutability: "view",
|
|
331
|
+
inputs: [],
|
|
332
|
+
outputs: [{ name: "", type: "uint128" }]
|
|
333
|
+
},
|
|
334
|
+
{
|
|
335
|
+
name: "totalBorrowAssets",
|
|
336
|
+
type: "function",
|
|
337
|
+
stateMutability: "view",
|
|
338
|
+
inputs: [],
|
|
339
|
+
outputs: [{ name: "", type: "uint128" }]
|
|
340
|
+
},
|
|
341
|
+
{
|
|
342
|
+
name: "getPosition",
|
|
343
|
+
type: "function",
|
|
344
|
+
stateMutability: "view",
|
|
345
|
+
inputs: [{ name: "user", type: "address" }],
|
|
346
|
+
outputs: [
|
|
347
|
+
{ name: "encSupplyShares", type: "uint256" },
|
|
348
|
+
{ name: "borrowShares", type: "uint256" },
|
|
349
|
+
{ name: "collateral", type: "uint256" },
|
|
350
|
+
{ name: "disburseTo", type: "uint256" }
|
|
351
|
+
]
|
|
352
|
+
},
|
|
353
|
+
{
|
|
354
|
+
name: "getPlainCollateral",
|
|
355
|
+
type: "function",
|
|
356
|
+
stateMutability: "view",
|
|
357
|
+
inputs: [{ name: "user", type: "address" }],
|
|
358
|
+
outputs: [{ name: "", type: "uint128" }]
|
|
359
|
+
},
|
|
360
|
+
{
|
|
361
|
+
name: "getPlainBorrow",
|
|
362
|
+
type: "function",
|
|
363
|
+
stateMutability: "view",
|
|
364
|
+
inputs: [{ name: "user", type: "address" }],
|
|
365
|
+
outputs: [{ name: "", type: "uint128" }]
|
|
366
|
+
},
|
|
306
367
|
{
|
|
307
368
|
name: "supplyCollateral",
|
|
308
369
|
type: "function",
|
|
@@ -333,7 +394,7 @@ var CREDIT_MARKET_ABI = [
|
|
|
333
394
|
];
|
|
334
395
|
var OBSCURA_VOTE_ABI = [
|
|
335
396
|
{
|
|
336
|
-
name: "
|
|
397
|
+
name: "nextProposalId",
|
|
337
398
|
type: "function",
|
|
338
399
|
stateMutability: "view",
|
|
339
400
|
inputs: [],
|
|
@@ -375,6 +436,11 @@ var OBSCURA_VOTE_ABI = [
|
|
|
375
436
|
];
|
|
376
437
|
|
|
377
438
|
// src/modules/credit.ts
|
|
439
|
+
var PLAINTEXT_SHADOW_WARNING = "Plaintext shadows are public testnet UI hints only \u2014 not encrypted balances. Do not treat as private position size. Omit on mainnet strict privacy mode.";
|
|
440
|
+
function bigintToHandleHex(value) {
|
|
441
|
+
const hex = value.toString(16).padStart(64, "0");
|
|
442
|
+
return `0x${hex}`;
|
|
443
|
+
}
|
|
378
444
|
var CreditModule = class {
|
|
379
445
|
constructor(deps) {
|
|
380
446
|
this.deps = deps;
|
|
@@ -383,6 +449,75 @@ var CreditModule = class {
|
|
|
383
449
|
getMarketAddress(override) {
|
|
384
450
|
return override ?? this.deps.addresses.CreditCanonicalPayOcUSDCMarket;
|
|
385
451
|
}
|
|
452
|
+
/** Public pool aggregates — no wallet required */
|
|
453
|
+
async getMarketUtilization(marketAddress) {
|
|
454
|
+
const market = this.getMarketAddress(marketAddress);
|
|
455
|
+
const [utilizationBps, totalSupplyAssets, totalBorrowAssets] = await Promise.all([
|
|
456
|
+
this.deps.publicClient.readContract({
|
|
457
|
+
address: market,
|
|
458
|
+
abi: CREDIT_MARKET_ABI,
|
|
459
|
+
functionName: "utilizationBps"
|
|
460
|
+
}),
|
|
461
|
+
this.deps.publicClient.readContract({
|
|
462
|
+
address: market,
|
|
463
|
+
abi: CREDIT_MARKET_ABI,
|
|
464
|
+
functionName: "totalSupplyAssets"
|
|
465
|
+
}),
|
|
466
|
+
this.deps.publicClient.readContract({
|
|
467
|
+
address: market,
|
|
468
|
+
abi: CREDIT_MARKET_ABI,
|
|
469
|
+
functionName: "totalBorrowAssets"
|
|
470
|
+
})
|
|
471
|
+
]);
|
|
472
|
+
return {
|
|
473
|
+
marketAddress: market,
|
|
474
|
+
utilizationBps,
|
|
475
|
+
totalSupplyAssets,
|
|
476
|
+
totalBorrowAssets
|
|
477
|
+
};
|
|
478
|
+
}
|
|
479
|
+
/**
|
|
480
|
+
* Returns encrypted position handles as opaque hex strings.
|
|
481
|
+
* Plaintext shadows are optional and labeled with an explicit warning.
|
|
482
|
+
*/
|
|
483
|
+
async getPositionHandles(wallet, options = {}) {
|
|
484
|
+
const normalized = normalizeWallet(wallet);
|
|
485
|
+
if (!normalized) throw new Error("Invalid wallet address");
|
|
486
|
+
const market = this.getMarketAddress(options.marketAddress);
|
|
487
|
+
const position = await this.deps.publicClient.readContract({
|
|
488
|
+
address: market,
|
|
489
|
+
abi: CREDIT_MARKET_ABI,
|
|
490
|
+
functionName: "getPosition",
|
|
491
|
+
args: [normalized]
|
|
492
|
+
});
|
|
493
|
+
const result = {
|
|
494
|
+
marketAddress: market,
|
|
495
|
+
wallet: normalized,
|
|
496
|
+
encryptedSupplySharesHandle: bigintToHandleHex(position[0]),
|
|
497
|
+
encryptedBorrowSharesHandle: bigintToHandleHex(position[1]),
|
|
498
|
+
encryptedCollateralHandle: bigintToHandleHex(position[2])
|
|
499
|
+
};
|
|
500
|
+
if (options.includePlaintextShadows) {
|
|
501
|
+
const [plainCollateral, plainBorrow] = await Promise.all([
|
|
502
|
+
this.deps.publicClient.readContract({
|
|
503
|
+
address: market,
|
|
504
|
+
abi: CREDIT_MARKET_ABI,
|
|
505
|
+
functionName: "getPlainCollateral",
|
|
506
|
+
args: [normalized]
|
|
507
|
+
}),
|
|
508
|
+
this.deps.publicClient.readContract({
|
|
509
|
+
address: market,
|
|
510
|
+
abi: CREDIT_MARKET_ABI,
|
|
511
|
+
functionName: "getPlainBorrow",
|
|
512
|
+
args: [normalized]
|
|
513
|
+
})
|
|
514
|
+
]);
|
|
515
|
+
result.plaintextShadowWarning = PLAINTEXT_SHADOW_WARNING;
|
|
516
|
+
result.plainCollateral = plainCollateral;
|
|
517
|
+
result.plainBorrow = plainBorrow;
|
|
518
|
+
}
|
|
519
|
+
return result;
|
|
520
|
+
}
|
|
386
521
|
async buildSupplyCollateral(amount, encryptedAmount, marketAddress) {
|
|
387
522
|
const market = this.getMarketAddress(marketAddress);
|
|
388
523
|
const enc = await resolveInEuint64(amount, market, this.deps.fhe, encryptedAmount);
|
|
@@ -536,11 +671,12 @@ var VoteModule = class {
|
|
|
536
671
|
get voteAddress() {
|
|
537
672
|
return this.deps.addresses.ObscuraVote;
|
|
538
673
|
}
|
|
674
|
+
/** Returns total proposals created (= public `nextProposalId` on ObscuraVote). */
|
|
539
675
|
async getProposalCount() {
|
|
540
676
|
return this.deps.publicClient.readContract({
|
|
541
677
|
address: this.deps.addresses.ObscuraVote,
|
|
542
678
|
abi: OBSCURA_VOTE_ABI,
|
|
543
|
-
functionName: "
|
|
679
|
+
functionName: "nextProposalId"
|
|
544
680
|
});
|
|
545
681
|
}
|
|
546
682
|
async getProposal(id) {
|
|
@@ -620,6 +756,7 @@ var ObscuraSDK = class _ObscuraSDK {
|
|
|
620
756
|
this.credit = new CreditModule({
|
|
621
757
|
chainId: this.chainId,
|
|
622
758
|
addresses: this.addresses,
|
|
759
|
+
publicClient: this.publicClient,
|
|
623
760
|
fhe: this.fhe
|
|
624
761
|
});
|
|
625
762
|
this.vote = new VoteModule(moduleDeps);
|