@trusset/sdk 0.1.0 → 0.5.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 +175 -171
- package/dist/base-BYEauvBZ.d.mts +111 -0
- package/dist/base-zODt0Kf5.d.ts +111 -0
- package/dist/chunk-2KHUPARH.js +2260 -0
- package/dist/chunk-3YF42MHV.mjs +678 -0
- package/dist/chunk-4MNJZAXE.mjs +2260 -0
- package/dist/chunk-7HFMHYRA.js +107 -0
- package/dist/chunk-ACXAKW5E.js +916 -0
- package/dist/chunk-AI4ZNJLR.js +678 -0
- package/dist/chunk-C7CANC53.mjs +208 -0
- package/dist/chunk-DQCX2GYT.mjs +107 -0
- package/dist/chunk-GWMT6UU7.js +208 -0
- package/dist/chunk-OQG3PEF3.mjs +916 -0
- package/dist/flow-Cz8A09rn.d.mts +171 -0
- package/dist/flow-Cz8A09rn.d.ts +171 -0
- package/dist/index-DKUSzkBN.d.ts +956 -0
- package/dist/index-Dl4U8vUM.d.mts +956 -0
- package/dist/index.d.mts +39 -448
- package/dist/index.d.ts +39 -448
- package/dist/index.js +264 -534
- package/dist/index.mjs +249 -483
- package/dist/modules/customers/index.d.mts +2 -0
- package/dist/modules/customers/index.d.ts +2 -0
- package/dist/modules/customers/index.js +17 -0
- package/dist/modules/customers/index.mjs +17 -0
- package/dist/modules/lending/index.d.mts +6768 -0
- package/dist/modules/lending/index.d.ts +6768 -0
- package/dist/modules/lending/index.js +44 -0
- package/dist/modules/lending/index.mjs +44 -0
- package/dist/modules/tokens/index.d.mts +476 -0
- package/dist/modules/tokens/index.d.ts +476 -0
- package/dist/modules/tokens/index.js +8 -0
- package/dist/modules/tokens/index.mjs +8 -0
- package/package.json +71 -35
package/README.md
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
# @trusset/sdk
|
|
2
2
|
|
|
3
|
-
TypeScript SDK for the Trusset
|
|
3
|
+
TypeScript SDK for the Trusset API, built for banks, exchanges and fintechs that integrate tokenized securities. It ships three modules:
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
- `customers`: customer records, on-chain identity verification and claims, KYC links, verification profiles, database sync.
|
|
6
|
+
- `lending`: external securities lending (markets, the lender of record, loans, liquidations, vaults, whitelists, bots, hooks, asset data).
|
|
7
|
+
- `tokens`: importing an existing security token and publishing its profile and instrument record, which a lending market needs.
|
|
8
|
+
|
|
9
|
+
The SDK has no runtime dependencies and runs on Node.js 22 or later. It is non-custodial: Trusset never holds, asks for or uses a private key. Every on-chain write is signed by a wallet you control, and you can pass any ethers v5 `Signer` or sign the returned calldata somewhere else entirely.
|
|
6
10
|
|
|
7
11
|
## Setup
|
|
8
12
|
|
|
@@ -10,237 +14,237 @@ Zero dependencies. Works in Node.js 18+ and modern runtimes with native `fetch`.
|
|
|
10
14
|
npm install @trusset/sdk
|
|
11
15
|
```
|
|
12
16
|
|
|
13
|
-
|
|
17
|
+
Each API key belongs to one instance. Development instances run on Sepolia, production instances on Ethereum mainnet, and lending also runs on Polygon for production instances that use it. The backend picks the network from the key; the SDK never chooses one.
|
|
14
18
|
|
|
15
19
|
```ts
|
|
16
20
|
import { TrussetClient } from '@trusset/sdk'
|
|
17
21
|
|
|
18
|
-
const trusset = new TrussetClient({
|
|
19
|
-
apiKey: 'tsk_live_...',
|
|
20
|
-
// baseUrl defaults to https://api.trusset.org
|
|
21
|
-
})
|
|
22
|
+
const trusset = new TrussetClient({ apiKey: process.env.TRUSSET_API_KEY! })
|
|
22
23
|
```
|
|
23
24
|
|
|
24
|
-
##
|
|
25
|
+
## How writes are signed
|
|
25
26
|
|
|
26
|
-
|
|
27
|
+
Every write that changes chain state has two legs: the API returns unsigned calldata, your wallet signs and broadcasts it, and a confirm call posts the transaction hash so the backend verifies the mined receipt and records it. Each write method covers both legs in one of three ways.
|
|
27
28
|
|
|
28
|
-
|
|
29
|
+
Call it with its input alone to get the unsigned transaction or plan. Nothing is signed and nothing is recorded.
|
|
29
30
|
|
|
30
31
|
```ts
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
investorType: 'PROFESSIONAL',
|
|
36
|
-
externalId: 'your-internal-id-123',
|
|
32
|
+
const prepared = await trusset.lending.loans.open(marketId, {
|
|
33
|
+
collateralAmount: '1000',
|
|
34
|
+
borrowAmount: '500',
|
|
35
|
+
borrowerAddress: '0x7451D81d7C1639c14B041Ba65e11378146d19a86',
|
|
37
36
|
})
|
|
37
|
+
```
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
// Link a wallet later:
|
|
41
|
-
await trusset.customers.manage.linkWallet({
|
|
42
|
-
referenceKey: customer.referenceKey!,
|
|
43
|
-
walletAddress: '0x...',
|
|
44
|
-
})
|
|
39
|
+
Pass `{ signer }` and the SDK signs every step in order, waits for each to mine on the signer's own provider, confirms with the hash of the step the API names, and returns the recorded result together with every transaction it sent.
|
|
45
40
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
const byWallet = await trusset.customers.manage.searchByWallet('0x...')
|
|
49
|
-
const byExtId = await trusset.customers.manage.searchByExternalId('your-internal-id-123')
|
|
41
|
+
```ts
|
|
42
|
+
import { Wallet, providers } from 'ethers'
|
|
50
43
|
|
|
51
|
-
|
|
52
|
-
const
|
|
44
|
+
const borrower = new Wallet(process.env.BORROWER_KEY!, new providers.JsonRpcProvider(process.env.RPC_URL))
|
|
45
|
+
const loan = await trusset.lending.loans.open(marketId, { collateralAmount: '1000', borrowAmount: '500' }, { signer: borrower })
|
|
46
|
+
console.log(loan.loanId, loan.transactions)
|
|
47
|
+
```
|
|
53
48
|
|
|
54
|
-
|
|
55
|
-
await trusset.customers.manage.update(customer.id, { country: 'AT' })
|
|
49
|
+
Pass `{ txHash }` to confirm a transaction you broadcast yourself, for example from a hardware wallet, an MPC system, a Safe or another smart-contract wallet. Send the hash of the mined outer transaction; the API resolves Safe, ERC-4337 and EIP-7702 calls.
|
|
56
50
|
|
|
57
|
-
|
|
58
|
-
await trusset.
|
|
51
|
+
```ts
|
|
52
|
+
const recorded = await trusset.lending.loans.open(marketId, {}, { txHash: '0x9f2c41d8b7e05a3164c2870fbd935e1a4c7802db6135ea9048f7c21b5d3ea41b' })
|
|
59
53
|
```
|
|
60
54
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
55
|
+
What the SDK guarantees when it signs:
|
|
56
|
+
|
|
57
|
+
- It reads the instance's chain from the API and refuses a signer connected to another chain before it sends any request.
|
|
58
|
+
- It forwards `to`, `data`, `value`, `chainId` and the API's `gasLimit` exactly. Where the API sends no `gasLimit` and the signer can estimate, it sets the limit to 1.5 times the signer's own estimate. It adds nothing else.
|
|
59
|
+
- It runs plan steps strictly in order. An optional trailing step, such as clearing a leftover allowance after a full repayment, never blocks the confirm; its outcome is reported in `transactions`.
|
|
60
|
+
- A field that names the signing wallet (`payer`, `borrowerAddress`, `provider`, `holderAddress`, `signerAddress`, `fromAddress`, `bidder`) is filled from the signer when omitted and refused when it names another wallet.
|
|
61
|
+
- Where a write needs a role or an owner the market can report (role changes, rate settings and extensions, bot connections, auction wiring, insurance withdrawals), it reads that authority for the signer first and refuses before signing when the signer lacks it. An authority it cannot read stops the write with a `503`, never a blind signature.
|
|
62
|
+
- If a step fails after an earlier one went out, or the confirm cannot be recorded, it throws `ConfirmationError` with every hash sent, so you can finish with `{ txHash }`.
|
|
63
|
+
- A repayment in `mode: 'batch'` is meant for a wallet that bundles calls (`wallet_sendCalls`); the SDK refuses it with a signer and returns the plan without one.
|
|
64
|
+
|
|
65
|
+
The SDK broadcasts the calldata the API returned without decoding it. If your controls require it, prepare without a signer and validate `to` and `data` in your own pinned code before signing.
|
|
66
|
+
|
|
67
|
+
## Lending
|
|
68
|
+
|
|
69
|
+
`trusset.lending` mirrors the API Reference groups.
|
|
70
|
+
|
|
71
|
+
| Namespace | Covers |
|
|
72
|
+
|---|---|
|
|
73
|
+
| `markets` | Market reads, deployment, setup and wiring, upgrades with their seven-day notice, risk configuration, identity gates, guardians, price halt, pause, borrow assets |
|
|
74
|
+
| `operators` | The lender-of-record queue and adoption, nominations, roles, handover, admin handover plans |
|
|
75
|
+
| `assetData` | Asset data preview, attestation and acknowledgement |
|
|
76
|
+
| `accessLists` | Whitelists: creation, members, managers, ownership |
|
|
77
|
+
| `rates` | Rate mode, loan terms, extensions, exit liquidity, reserve ratio |
|
|
78
|
+
| `terms` | Terms of use |
|
|
79
|
+
| `oracle` | Price status, signing, attestations, on-chain price updates |
|
|
80
|
+
| `liquidity` | Direct liquidity and vault liquidity on a market |
|
|
81
|
+
| `loans` | Borrowing, collateral, repayment (sequential, permit, batch), escrow and surplus, position reads |
|
|
82
|
+
| `fees` | Fee split, cashflows, sweeps, operator wallet |
|
|
83
|
+
| `insurance` | The insurance fund and its withdrawal notice |
|
|
84
|
+
| `liquidations` | Liquidation, the atomic sale and router settlement |
|
|
85
|
+
| `auctions` | The Dutch auction venue, bids and expiry |
|
|
86
|
+
| `hooks` | Risk monitors and liquidation hooks |
|
|
87
|
+
| `bots` | Liquidation bots |
|
|
88
|
+
| `vaults` | Vault deposits, redemptions and distributor fees |
|
|
89
|
+
| `pledges` | The pledge record of a market |
|
|
90
|
+
| `documents` | Legal documents of a market and its loans on the document registry |
|
|
91
|
+
|
|
92
|
+
A market needs an imported collateral token with a published profile. The journey below is the one the rig suite runs end to end.
|
|
64
93
|
|
|
65
94
|
```ts
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
})
|
|
97
|
-
|
|
95
|
+
await trusset.tokens.import({ tokenAddress: collateral, assetType: 'BOND' })
|
|
96
|
+
await trusset.tokens.setProfile(collateral, { description: 'Senior bond, series A', issuerName: 'Example Issuer AG' })
|
|
97
|
+
|
|
98
|
+
const deployed = await trusset.lending.markets.deploy({
|
|
99
|
+
collateralTokenAddress: collateral,
|
|
100
|
+
mode: 'CUSTODY',
|
|
101
|
+
priceSource: 'NAV',
|
|
102
|
+
initialPrice: '1',
|
|
103
|
+
candidates: [await lender.getAddress()],
|
|
104
|
+
}, { signer: deployer })
|
|
105
|
+
const marketId = deployed.market.id
|
|
106
|
+
const marketAddress = deployed.market.marketAddress!
|
|
107
|
+
|
|
108
|
+
const assetData = await trusset.lending.assetData.get(marketAddress)
|
|
109
|
+
await trusset.lending.operators.accept(marketAddress, {
|
|
110
|
+
admin: lenderAddress,
|
|
111
|
+
issuer: lenderAddress,
|
|
112
|
+
collateralAgent: lenderAddress,
|
|
113
|
+
saleRecipient: lenderAddress,
|
|
114
|
+
liquidationOperator: operatorAddress,
|
|
115
|
+
oracleOwner: lenderAddress,
|
|
116
|
+
priceSigner: lenderAddress,
|
|
117
|
+
realizationMode: 'ISSUER_REDEMPTION',
|
|
118
|
+
liquidator: keeperAddress,
|
|
119
|
+
assetDataHash: assetData.attested?.contentHash,
|
|
120
|
+
}, { signer: lender })
|
|
121
|
+
|
|
122
|
+
await trusset.lending.oracle.sync(marketId, { price: '1' }, { signer: lender })
|
|
123
|
+
await trusset.lending.liquidity.add(marketId, { amount: '100000' }, { signer: lender })
|
|
124
|
+
|
|
125
|
+
const loan = await trusset.lending.loans.open(marketId, { collateralAmount: '1000', borrowAmount: '500' }, { signer: borrower })
|
|
126
|
+
await trusset.lending.loans.repay(marketId, { loanId: loan.loanId!, amount: '100' }, { signer: borrower })
|
|
127
|
+
await trusset.lending.loans.repay(marketId, { loanId: loan.loanId!, all: true }, { signer: payer })
|
|
98
128
|
```
|
|
99
129
|
|
|
100
|
-
|
|
130
|
+
Amounts are always decimal strings in the asset's own units (`'100'`, `'12.5'`). The SDK refuses JavaScript numbers for token amounts. Addresses are checked like the backend checks them: 0x plus 40 hex characters, and a valid EIP-55 checksum when mixed case.
|
|
101
131
|
|
|
102
|
-
|
|
132
|
+
Older markets run older contract implementations. Read what a market supports from the API (`markets.upgradeStatus`, `markets.config` and its `thresholdStep`, `markets.identityGates`, `payToSupported` on market reads) instead of assuming a feature.
|
|
103
133
|
|
|
104
|
-
|
|
105
|
-
const link = await trusset.customers.idLinks.create({
|
|
106
|
-
recipientEmail: 'investor@example.com',
|
|
107
|
-
investorType: 'RETAIL',
|
|
108
|
-
country: 'DE',
|
|
109
|
-
expiryDays: 30,
|
|
110
|
-
sendVia: ['email'],
|
|
111
|
-
})
|
|
112
|
-
// link.verificationUrl, link.token
|
|
134
|
+
## Tokens
|
|
113
135
|
|
|
114
|
-
|
|
115
|
-
await trusset.
|
|
116
|
-
await trusset.
|
|
136
|
+
```ts
|
|
137
|
+
const detected = await trusset.tokens.detect({ tokenAddress })
|
|
138
|
+
await trusset.tokens.import({ tokenAddress, assetType: 'BOND' })
|
|
139
|
+
await trusset.tokens.setProfile(tokenAddress, { description: 'Senior bond, series A' })
|
|
140
|
+
await trusset.tokens.saveInstrument(tokenAddress, { instrument: { instrumentName: 'Senior bond, series A', jurisdiction: 'Germany' } }, { signer: tokenController })
|
|
117
141
|
```
|
|
118
142
|
|
|
119
|
-
|
|
143
|
+
`saveInstrument` with `{ signer }` requests the issuer approval message from the API and signs it with the token controller's wallet; without a signer you pass `issuerApproval` yourself or rely on the instance's verified wallets.
|
|
120
144
|
|
|
121
|
-
|
|
145
|
+
## Customers
|
|
122
146
|
|
|
123
147
|
```ts
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
// Map your existing database rows to SyncRecord
|
|
127
|
-
const records: SyncRecord[] = existingCustomers.map(row => ({
|
|
128
|
-
externalId: row.id, // Your system's unique ID
|
|
129
|
-
name: row.fullName,
|
|
130
|
-
walletAddress: row.ethAddress, // Optional
|
|
131
|
-
country: row.countryCode,
|
|
132
|
-
investorType: 'RETAIL',
|
|
133
|
-
metadata: { source: 'legacy-crm' },
|
|
134
|
-
}))
|
|
135
|
-
|
|
136
|
-
const result = await trusset.customers.sync.importRecords(records, {
|
|
137
|
-
batchSize: 50,
|
|
138
|
-
onConflict: 'update', // 'skip' or 'update'
|
|
139
|
-
verifyOnChain: true, // Also verify wallets on IdentityRegistry
|
|
140
|
-
verificationDefaults: {
|
|
141
|
-
softExpiryDays: 365,
|
|
142
|
-
hardExpiryDays: 730,
|
|
143
|
-
},
|
|
144
|
-
onProgress: (done, total) => {
|
|
145
|
-
console.log(`Synced ${done}/${total}`)
|
|
146
|
-
},
|
|
147
|
-
})
|
|
148
|
+
const customer = await trusset.customers.manage.create({ name: 'Acme GmbH', country: 'DEU', customerType: 'COMPANY' })
|
|
148
149
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
150
|
+
const verified = await trusset.customers.identity.verify({
|
|
151
|
+
walletAddress: '0x7451D81d7C1639c14B041Ba65e11378146d19a86',
|
|
152
|
+
country: 'DEU',
|
|
153
|
+
investorType: 'PROFESSIONAL',
|
|
154
|
+
kycHash: manifest.kycHash,
|
|
155
|
+
}, { signer: issuerWallet })
|
|
153
156
|
```
|
|
154
157
|
|
|
155
|
-
|
|
158
|
+
Identity writes follow the same three call shapes as lending writes, with the same signing guarantees. KYC hashing happens in the [trusset-kyc-zk-proofs](https://github.com/Trusset/trusset-kyc-zk-proofs) tool you run locally; only the root hash and the proof manifest reach Trusset. Pass the bundle's `manifest.sig` to `addClaimsFromProof` as its raw bytes (`readFileSync(path)`); the SDK sends them base64-encoded.
|
|
159
|
+
|
|
160
|
+
On an instance bound to its own ERC-3643 register, an identity write is phased: an ONCHAINID deployment for a wallet without one, claim messages signed by a claim key of the register's trusted issuer, then the claim and registration transactions. With `{ signer }` the SDK runs every phase and confirms the registration; without one it returns the current phase, which carries no single `transaction`, so check `action` before broadcasting.
|
|
161
|
+
|
|
162
|
+
## Errors and retries
|
|
156
163
|
|
|
157
|
-
|
|
164
|
+
Every error extends `TrussetError` and carries the API's `code`, `statusCode`, `requestId`, plus `details`, `data` (any other field the API sent) and `retryAfter`.
|
|
158
165
|
|
|
159
166
|
```ts
|
|
160
|
-
import { TrussetError,
|
|
167
|
+
import { TrussetError, ValidationError, AuthError, ConfirmationError } from '@trusset/sdk'
|
|
161
168
|
|
|
162
169
|
try {
|
|
163
|
-
await trusset.
|
|
170
|
+
await trusset.lending.loans.repay(marketId, { loanId, all: true }, { signer: payer })
|
|
164
171
|
} catch (err) {
|
|
165
|
-
if (err instanceof
|
|
166
|
-
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
if (err instanceof TrussetError) {
|
|
172
|
-
// err.code, err.statusCode, err.requestId
|
|
172
|
+
if (err instanceof ConfirmationError) {
|
|
173
|
+
console.error(err.code, err.txHash, err.transactions)
|
|
174
|
+
} else if (err instanceof ValidationError) {
|
|
175
|
+
console.error(err.message)
|
|
176
|
+
} else if (err instanceof TrussetError && err.statusCode === 503) {
|
|
177
|
+
console.error('the chain could not be read; nothing was decided', err.code)
|
|
173
178
|
}
|
|
174
179
|
}
|
|
175
180
|
```
|
|
176
181
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
timeoutMs: 60_000,
|
|
183
|
-
maxRetries: 5,
|
|
184
|
-
})
|
|
185
|
-
```
|
|
182
|
+
- Reads (GET) retry 408, 429, 500, 502, 503, 504 and network errors with exponential backoff.
|
|
183
|
+
- Builds are never retried, except after a 429, which the server answers before doing any work.
|
|
184
|
+
- A 429 waits for the server's `Retry-After` (up to 60 seconds) before the next attempt. Writes share a limit of 10 per minute per API key.
|
|
185
|
+
- Lending confirms retry 503, 502, 504, 408 and network errors, since the backend records one transaction once. Every confirm retries `TX_NOT_FOUND` three times (3, 6 and 12 seconds) when the backend's node has not seen a receipt yet. Liquidation bot deployment is the exception and is never retried; customer identity confirms otherwise keep the build rules.
|
|
186
|
+
- A 503 means the chain or a record could not be read, never a verdict.
|
|
186
187
|
|
|
187
188
|
## Configuration
|
|
188
189
|
|
|
189
190
|
| Option | Type | Default | Description |
|
|
190
191
|
|---|---|---|---|
|
|
191
|
-
| `apiKey` | `string` | required | Instance API key
|
|
192
|
+
| `apiKey` | `string` | required | Instance API key (`trusset_...`) |
|
|
192
193
|
| `baseUrl` | `string` | `https://api.trusset.org` | API base URL |
|
|
193
|
-
| `timeoutMs` | `number` | `30000` | Request timeout
|
|
194
|
-
| `maxRetries` | `number` | `3` | Retries
|
|
195
|
-
| `logger` | `Logger` | silent |
|
|
194
|
+
| `timeoutMs` | `number` | `30000` | Request timeout; builds and confirms use at least 60 seconds, documents 120 seconds, proof claims 180 seconds |
|
|
195
|
+
| `maxRetries` | `number` | `3` | Retries for the cases listed above |
|
|
196
|
+
| `logger` | `Logger` | silent | Receives the request path on retries, never a body, a signature or the key |
|
|
197
|
+
|
|
198
|
+
## Imports
|
|
199
|
+
|
|
200
|
+
The root export holds everything. Each module also has its own entry point.
|
|
201
|
+
|
|
202
|
+
```ts
|
|
203
|
+
import { TrussetClient } from '@trusset/sdk'
|
|
204
|
+
import type { PreparedRepay, RepayResult } from '@trusset/sdk/lending'
|
|
205
|
+
import { Tokens } from '@trusset/sdk/tokens'
|
|
206
|
+
```
|
|
196
207
|
|
|
197
208
|
## Architecture
|
|
198
209
|
|
|
199
210
|
```
|
|
200
211
|
src/
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
common.ts Shared types (config, API envelope, pagination)
|
|
205
|
-
customers.ts All customer-related types and interfaces
|
|
212
|
+
client.ts TrussetClient
|
|
213
|
+
index.ts Public exports
|
|
214
|
+
version.ts SDK version
|
|
206
215
|
modules/
|
|
207
|
-
customers/
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
id-links.ts KYC verification link management
|
|
212
|
-
sync.ts Bulk database import/export
|
|
216
|
+
customers/ Customer records, identity, links, profiles, sync
|
|
217
|
+
lending/ Lending facade and its 18 namespaces
|
|
218
|
+
tokens/ Token import, profile and instrument record
|
|
219
|
+
types/ Request and response types per module
|
|
213
220
|
utils/
|
|
214
|
-
http.ts
|
|
215
|
-
|
|
216
|
-
|
|
221
|
+
http.ts HTTP client, envelope handling, retry classes, Retry-After
|
|
222
|
+
flow.ts Shared signing flow: plans, chain checks, typed data, confirms
|
|
223
|
+
register.ts Phased identity plans of own ERC-3643 registers
|
|
224
|
+
chain.ts The instance's chain id, read once per client
|
|
225
|
+
sign.ts Signer checks
|
|
226
|
+
validation.ts Input validation mirroring the backend
|
|
227
|
+
keccak.ts Keccak-256 for EIP-55 checksums
|
|
228
|
+
errors.ts Error classes
|
|
217
229
|
```
|
|
218
230
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
## Compatibility
|
|
222
|
-
|
|
223
|
-
- **TypeScript / ESM** - primary target, full type safety
|
|
224
|
-
- **Node.js / CommonJS** - dual CJS/ESM build via tsup
|
|
225
|
-
- **Java / Python** - the SDK calls a standard REST API with JSON over HTTPS. Any HTTP client in any language works. Typed wrappers for Java and Python are planned.
|
|
226
|
-
|
|
227
|
-
## Build
|
|
231
|
+
## Build and test
|
|
228
232
|
|
|
229
233
|
```bash
|
|
230
234
|
npm install
|
|
231
|
-
npm run build
|
|
232
|
-
npm run typecheck
|
|
233
|
-
npm run
|
|
235
|
+
npm run build
|
|
236
|
+
npm run typecheck
|
|
237
|
+
npm run lint
|
|
238
|
+
npm run test:unit
|
|
239
|
+
npm test
|
|
240
|
+
npm run test:rig
|
|
234
241
|
```
|
|
235
242
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
243
|
+
- `test:unit` runs without a network. Its fixtures are responses recorded verbatim from the rig or from a live run, never hand-written. The customers signing tests build the later phases of a captured own-register plan with the contract encodings the backend uses.
|
|
244
|
+
- `npm test` runs the integration suites against a DEVELOPMENT instance. They need `TRUSSET_TEST_API_KEY` (see `tests/integration/env.ts`). The lending suites call every read and every build leg and sign nothing; they pace themselves on the write limit and take about 20 minutes.
|
|
245
|
+
- `test:rig` runs the full write lifecycle with zero broadcast against `tests/rig/server.mjs`. That server combines a scratch Postgres on 127.0.0.1:55432, an anvil fork of Sepolia on 127.0.0.1:8545 and the real backend routers from `RIG_BACKEND_DIR`. It refuses to start with Doppler configured, with any other database or with any other RPC, and it blanks every variable named in the backend's `.env` before importing it. Point `RIG_STATE` at the file the server writes. Reset the scratch database (`prisma db push --force-reset` against 127.0.0.1:55432) whenever you restart the fork: a fresh fork reuses contract addresses that the old records still claim. `tests/rig/capture.test.ts` stops the fork when it finishes, so run it last and on its own.
|
|
246
|
+
- `TRUSSET_TEST_ONCHAIN=1` enables the Sepolia identity journey and spends Sepolia gas.
|
|
239
247
|
|
|
248
|
+
## License
|
|
240
249
|
|
|
241
|
-
|
|
242
|
-
└── modules/
|
|
243
|
-
├── customers/
|
|
244
|
-
├── tokenization/ # next
|
|
245
|
-
├── trading/ # next
|
|
246
|
-
└── lending/ # next
|
|
250
|
+
MIT, Trusset UG
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { S as SignedStep, e as ChainSource, H as HttpClient, b as SignOptions, C as ConfirmOptions, f as PlanOptions } from './flow-Cz8A09rn.mjs';
|
|
2
|
+
|
|
3
|
+
type Decimal = string;
|
|
4
|
+
type RawAmount = string;
|
|
5
|
+
type UnixSeconds = string;
|
|
6
|
+
type IsoDate = string;
|
|
7
|
+
interface LendingTransaction {
|
|
8
|
+
to: string;
|
|
9
|
+
data: string;
|
|
10
|
+
chainId?: number;
|
|
11
|
+
value?: string;
|
|
12
|
+
gasLimit?: string;
|
|
13
|
+
}
|
|
14
|
+
interface LendingConfirmWith {
|
|
15
|
+
endpoint: string;
|
|
16
|
+
field: 'txHash';
|
|
17
|
+
body?: Record<string, unknown>;
|
|
18
|
+
}
|
|
19
|
+
interface TransactionPayload<F extends string = string> {
|
|
20
|
+
action: 'SIGN_TRANSACTION';
|
|
21
|
+
transaction: LendingTransaction;
|
|
22
|
+
functionName: F;
|
|
23
|
+
description?: string;
|
|
24
|
+
}
|
|
25
|
+
interface TransactionStep<F extends string = string> {
|
|
26
|
+
action: 'SIGN_TRANSACTION';
|
|
27
|
+
transaction: LendingTransaction;
|
|
28
|
+
functionName: F;
|
|
29
|
+
description?: string;
|
|
30
|
+
optional?: true;
|
|
31
|
+
}
|
|
32
|
+
interface StepsPayload<S = TransactionStep> {
|
|
33
|
+
action: 'SIGN_TRANSACTIONS';
|
|
34
|
+
steps: S[];
|
|
35
|
+
confirmStepIndex?: number;
|
|
36
|
+
}
|
|
37
|
+
interface TypedDataField {
|
|
38
|
+
name: string;
|
|
39
|
+
type: string;
|
|
40
|
+
}
|
|
41
|
+
interface TypedDataDomain {
|
|
42
|
+
name: string;
|
|
43
|
+
version: string;
|
|
44
|
+
chainId: number;
|
|
45
|
+
verifyingContract: string;
|
|
46
|
+
}
|
|
47
|
+
interface TypedData<M extends object = Record<string, unknown>> {
|
|
48
|
+
domain: TypedDataDomain;
|
|
49
|
+
types: Record<string, TypedDataField[]>;
|
|
50
|
+
primaryType: string;
|
|
51
|
+
message: M;
|
|
52
|
+
}
|
|
53
|
+
interface SignedPrice {
|
|
54
|
+
price: string;
|
|
55
|
+
timestamp: number;
|
|
56
|
+
validUntil: number;
|
|
57
|
+
signature: string;
|
|
58
|
+
}
|
|
59
|
+
interface SignerDisclosure {
|
|
60
|
+
requiredSigner?: string | null;
|
|
61
|
+
heldByThisInstance?: boolean | null;
|
|
62
|
+
signerAddress?: string | null;
|
|
63
|
+
note?: string | null;
|
|
64
|
+
}
|
|
65
|
+
type Signed<T> = T & {
|
|
66
|
+
transactions: SignedStep[];
|
|
67
|
+
};
|
|
68
|
+
interface SubmittedTransactions {
|
|
69
|
+
transactions: SignedStep[];
|
|
70
|
+
}
|
|
71
|
+
interface LendingDocument {
|
|
72
|
+
filename: string | null;
|
|
73
|
+
contentType: string;
|
|
74
|
+
bytes: Uint8Array;
|
|
75
|
+
}
|
|
76
|
+
interface ApprovalStep extends TransactionStep<'approve'> {
|
|
77
|
+
stepKind?: 'approve' | 'approveZeroFirst' | 'clearAllowance';
|
|
78
|
+
approval?: {
|
|
79
|
+
token: string;
|
|
80
|
+
spender: string;
|
|
81
|
+
amount: Decimal;
|
|
82
|
+
amountRaw: RawAmount;
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
declare class InstanceChain implements ChainSource {
|
|
87
|
+
readonly http: HttpClient;
|
|
88
|
+
private chain;
|
|
89
|
+
constructor(http: HttpClient);
|
|
90
|
+
instanceChainId(): Promise<number>;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
declare class LendingContext extends InstanceChain implements ChainSource {
|
|
94
|
+
}
|
|
95
|
+
interface TwoLegSpec<P, R> {
|
|
96
|
+
build: () => Promise<P>;
|
|
97
|
+
confirm: (txHash: string, prepared: P | null) => Promise<R>;
|
|
98
|
+
check?: (prepared: P, signer: string) => Promise<void>;
|
|
99
|
+
plan?: PlanOptions;
|
|
100
|
+
}
|
|
101
|
+
declare abstract class LendingArea {
|
|
102
|
+
protected readonly ctx: LendingContext;
|
|
103
|
+
constructor(ctx: LendingContext);
|
|
104
|
+
protected get http(): HttpClient;
|
|
105
|
+
protected twoLeg<P, R>(options: SignOptions | ConfirmOptions | undefined, spec: TwoLegSpec<P, R>): Promise<P | R | Signed<R>>;
|
|
106
|
+
protected oneLeg<P>(options: SignOptions | undefined, build: () => Promise<P>, plan?: PlanOptions): Promise<P | SubmittedTransactions>;
|
|
107
|
+
protected assertSignerRoles(marketId: string, address: string, roles: string[]): Promise<void>;
|
|
108
|
+
protected assertSignerHoldsAny(marketId: string, address: string, roles: string[]): Promise<void>;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export { type ApprovalStep as A, type Decimal as D, type IsoDate as I, type LendingConfirmWith as L, type RawAmount as R, type Signed as S, type TransactionPayload as T, type UnixSeconds as U, type LendingDocument as a, type LendingTransaction as b, type SignedPrice as c, type SignerDisclosure as d, type StepsPayload as e, type SubmittedTransactions as f, type TransactionStep as g, type TypedData as h, type TypedDataDomain as i, type TypedDataField as j, LendingArea as k, LendingContext as l };
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { S as SignedStep, e as ChainSource, H as HttpClient, b as SignOptions, C as ConfirmOptions, f as PlanOptions } from './flow-Cz8A09rn.js';
|
|
2
|
+
|
|
3
|
+
type Decimal = string;
|
|
4
|
+
type RawAmount = string;
|
|
5
|
+
type UnixSeconds = string;
|
|
6
|
+
type IsoDate = string;
|
|
7
|
+
interface LendingTransaction {
|
|
8
|
+
to: string;
|
|
9
|
+
data: string;
|
|
10
|
+
chainId?: number;
|
|
11
|
+
value?: string;
|
|
12
|
+
gasLimit?: string;
|
|
13
|
+
}
|
|
14
|
+
interface LendingConfirmWith {
|
|
15
|
+
endpoint: string;
|
|
16
|
+
field: 'txHash';
|
|
17
|
+
body?: Record<string, unknown>;
|
|
18
|
+
}
|
|
19
|
+
interface TransactionPayload<F extends string = string> {
|
|
20
|
+
action: 'SIGN_TRANSACTION';
|
|
21
|
+
transaction: LendingTransaction;
|
|
22
|
+
functionName: F;
|
|
23
|
+
description?: string;
|
|
24
|
+
}
|
|
25
|
+
interface TransactionStep<F extends string = string> {
|
|
26
|
+
action: 'SIGN_TRANSACTION';
|
|
27
|
+
transaction: LendingTransaction;
|
|
28
|
+
functionName: F;
|
|
29
|
+
description?: string;
|
|
30
|
+
optional?: true;
|
|
31
|
+
}
|
|
32
|
+
interface StepsPayload<S = TransactionStep> {
|
|
33
|
+
action: 'SIGN_TRANSACTIONS';
|
|
34
|
+
steps: S[];
|
|
35
|
+
confirmStepIndex?: number;
|
|
36
|
+
}
|
|
37
|
+
interface TypedDataField {
|
|
38
|
+
name: string;
|
|
39
|
+
type: string;
|
|
40
|
+
}
|
|
41
|
+
interface TypedDataDomain {
|
|
42
|
+
name: string;
|
|
43
|
+
version: string;
|
|
44
|
+
chainId: number;
|
|
45
|
+
verifyingContract: string;
|
|
46
|
+
}
|
|
47
|
+
interface TypedData<M extends object = Record<string, unknown>> {
|
|
48
|
+
domain: TypedDataDomain;
|
|
49
|
+
types: Record<string, TypedDataField[]>;
|
|
50
|
+
primaryType: string;
|
|
51
|
+
message: M;
|
|
52
|
+
}
|
|
53
|
+
interface SignedPrice {
|
|
54
|
+
price: string;
|
|
55
|
+
timestamp: number;
|
|
56
|
+
validUntil: number;
|
|
57
|
+
signature: string;
|
|
58
|
+
}
|
|
59
|
+
interface SignerDisclosure {
|
|
60
|
+
requiredSigner?: string | null;
|
|
61
|
+
heldByThisInstance?: boolean | null;
|
|
62
|
+
signerAddress?: string | null;
|
|
63
|
+
note?: string | null;
|
|
64
|
+
}
|
|
65
|
+
type Signed<T> = T & {
|
|
66
|
+
transactions: SignedStep[];
|
|
67
|
+
};
|
|
68
|
+
interface SubmittedTransactions {
|
|
69
|
+
transactions: SignedStep[];
|
|
70
|
+
}
|
|
71
|
+
interface LendingDocument {
|
|
72
|
+
filename: string | null;
|
|
73
|
+
contentType: string;
|
|
74
|
+
bytes: Uint8Array;
|
|
75
|
+
}
|
|
76
|
+
interface ApprovalStep extends TransactionStep<'approve'> {
|
|
77
|
+
stepKind?: 'approve' | 'approveZeroFirst' | 'clearAllowance';
|
|
78
|
+
approval?: {
|
|
79
|
+
token: string;
|
|
80
|
+
spender: string;
|
|
81
|
+
amount: Decimal;
|
|
82
|
+
amountRaw: RawAmount;
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
declare class InstanceChain implements ChainSource {
|
|
87
|
+
readonly http: HttpClient;
|
|
88
|
+
private chain;
|
|
89
|
+
constructor(http: HttpClient);
|
|
90
|
+
instanceChainId(): Promise<number>;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
declare class LendingContext extends InstanceChain implements ChainSource {
|
|
94
|
+
}
|
|
95
|
+
interface TwoLegSpec<P, R> {
|
|
96
|
+
build: () => Promise<P>;
|
|
97
|
+
confirm: (txHash: string, prepared: P | null) => Promise<R>;
|
|
98
|
+
check?: (prepared: P, signer: string) => Promise<void>;
|
|
99
|
+
plan?: PlanOptions;
|
|
100
|
+
}
|
|
101
|
+
declare abstract class LendingArea {
|
|
102
|
+
protected readonly ctx: LendingContext;
|
|
103
|
+
constructor(ctx: LendingContext);
|
|
104
|
+
protected get http(): HttpClient;
|
|
105
|
+
protected twoLeg<P, R>(options: SignOptions | ConfirmOptions | undefined, spec: TwoLegSpec<P, R>): Promise<P | R | Signed<R>>;
|
|
106
|
+
protected oneLeg<P>(options: SignOptions | undefined, build: () => Promise<P>, plan?: PlanOptions): Promise<P | SubmittedTransactions>;
|
|
107
|
+
protected assertSignerRoles(marketId: string, address: string, roles: string[]): Promise<void>;
|
|
108
|
+
protected assertSignerHoldsAny(marketId: string, address: string, roles: string[]): Promise<void>;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export { type ApprovalStep as A, type Decimal as D, type IsoDate as I, type LendingConfirmWith as L, type RawAmount as R, type Signed as S, type TransactionPayload as T, type UnixSeconds as U, type LendingDocument as a, type LendingTransaction as b, type SignedPrice as c, type SignerDisclosure as d, type StepsPayload as e, type SubmittedTransactions as f, type TransactionStep as g, type TypedData as h, type TypedDataDomain as i, type TypedDataField as j, LendingArea as k, LendingContext as l };
|