@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.
@@ -0,0 +1,208 @@
1
+ import {
2
+ BUILD,
3
+ DOCUMENT_TIMEOUT_MS,
4
+ compact
5
+ } from "./chunk-DQCX2GYT.mjs";
6
+ import {
7
+ ValidationError,
8
+ isSignOptions,
9
+ optionalBoolean,
10
+ optionalOneOf,
11
+ preflightChain,
12
+ requireOneOf,
13
+ requireSigner,
14
+ requireString,
15
+ requireWallet,
16
+ signMessage,
17
+ signerAddress
18
+ } from "./chunk-3YF42MHV.mjs";
19
+
20
+ // src/modules/tokens/index.ts
21
+ var TOKENS_BASE = "/external-tokens/api";
22
+ var INSTRUMENTS_BASE = "/instruments/api";
23
+ var ASSET_TYPES = [
24
+ "PUBLIC_EQUITY",
25
+ "PRIVATE_EQUITY",
26
+ "REAL_ESTATE",
27
+ "COMMODITY",
28
+ "ART",
29
+ "WATCH",
30
+ "INFRASTRUCTURE",
31
+ "BOND",
32
+ "CRYPTO_ASSET"
33
+ ];
34
+ var ASSET_STANDARDS = ["ERC721", "ERC1155"];
35
+ var PRESENTATION_KEYS = ["description", "issuerName", "sector", "website", "ammAddress", "reserveURI"];
36
+ var INSTRUMENT_KEYS = ["instrument", "documents", "presentation", "takeOver"];
37
+ function requireImageUri(value, field) {
38
+ const uri = requireString(value, field);
39
+ if (uri.length > 1024) throw new ValidationError(`${field} must be at most 1024 characters`);
40
+ if (uri.startsWith("ipfs://")) {
41
+ if (!/^ipfs:\/\/[A-Za-z0-9]{10,}([/?#].*)?$/.test(uri)) throw new ValidationError(`${field} must name an IPFS content identifier, such as ipfs://Qm...`);
42
+ return uri;
43
+ }
44
+ let parsed;
45
+ try {
46
+ parsed = new URL(uri);
47
+ } catch {
48
+ throw new ValidationError(`${field} must be an https or ipfs URI`);
49
+ }
50
+ if (parsed.protocol !== "https:") throw new ValidationError(`${field} must be an https or ipfs URI`);
51
+ return uri;
52
+ }
53
+ function checkPresentation(value, field) {
54
+ if (value === void 0 || value === null) return value;
55
+ if (typeof value !== "object" || Array.isArray(value)) throw new ValidationError(`${field} must be an object with the presentation fields, or null to clear them`);
56
+ for (const key of Object.keys(value)) {
57
+ if (!PRESENTATION_KEYS.includes(key)) {
58
+ throw new ValidationError(`Unknown ${field} field: ${key}. The presentation fields are ${PRESENTATION_KEYS.join(", ")}`);
59
+ }
60
+ }
61
+ if (value.ammAddress !== void 0 && value.ammAddress !== null && value.ammAddress !== "") requireWallet(value.ammAddress, `${field}.ammAddress`);
62
+ return value;
63
+ }
64
+ function instrumentBody(input) {
65
+ if (!input || typeof input !== "object" || Array.isArray(input)) {
66
+ throw new ValidationError("The instrument update must be an object with instrument, documents, presentation or takeOver");
67
+ }
68
+ for (const key of Object.keys(input)) {
69
+ if (key === "issuerApproval") continue;
70
+ if (!INSTRUMENT_KEYS.includes(key)) {
71
+ throw new ValidationError(`Unknown field: ${key}. An instrument update takes ${INSTRUMENT_KEYS.join(", ")}`);
72
+ }
73
+ }
74
+ if (input.instrument !== void 0 && (typeof input.instrument !== "object" || input.instrument === null || Array.isArray(input.instrument))) {
75
+ throw new ValidationError("instrument must be an object of instrument fields");
76
+ }
77
+ if (input.documents !== void 0 && !Array.isArray(input.documents)) {
78
+ throw new ValidationError("documents must be an array");
79
+ }
80
+ return compact({
81
+ instrument: input.instrument,
82
+ documents: input.documents,
83
+ presentation: checkPresentation(input.presentation, "presentation"),
84
+ takeOver: optionalBoolean(input.takeOver, "takeOver")
85
+ });
86
+ }
87
+ var Tokens = class {
88
+ constructor(ctx) {
89
+ this.ctx = ctx;
90
+ }
91
+ tokenPath(tokenAddress, rest = "") {
92
+ return `${TOKENS_BASE}/${requireWallet(tokenAddress, "tokenAddress")}${rest}`;
93
+ }
94
+ instrumentPath(tokenAddress, rest = "") {
95
+ return `${INSTRUMENTS_BASE}/${requireWallet(tokenAddress, "tokenAddress")}${rest}`;
96
+ }
97
+ async detect(input) {
98
+ const body = compact({
99
+ tokenAddress: requireWallet(input?.tokenAddress, "tokenAddress"),
100
+ assetStandard: optionalOneOf(input?.assetStandard, "assetStandard", ASSET_STANDARDS)
101
+ });
102
+ return this.ctx.http.post(`${TOKENS_BASE}/detect`, body, BUILD);
103
+ }
104
+ async import(input) {
105
+ const body = compact({
106
+ tokenAddress: requireWallet(input?.tokenAddress, "tokenAddress"),
107
+ assetType: requireOneOf(input?.assetType, "assetType", ASSET_TYPES),
108
+ imageURI: input?.imageURI === void 0 || input.imageURI === null || input.imageURI === "" ? void 0 : requireImageUri(input.imageURI, "imageURI"),
109
+ assetStandard: optionalOneOf(input?.assetStandard, "assetStandard", ASSET_STANDARDS)
110
+ });
111
+ return this.ctx.http.post(`${TOKENS_BASE}/import`, body, BUILD);
112
+ }
113
+ async upload(file, fileName, options = {}) {
114
+ const name = requireString(fileName, "fileName");
115
+ const purpose = optionalOneOf(options.purpose, "purpose", ["image"]);
116
+ let blob;
117
+ if (typeof Blob !== "undefined" && file instanceof Blob) blob = file;
118
+ else if (file instanceof Uint8Array) blob = new Blob([Uint8Array.from(file)]);
119
+ else throw new ValidationError("file must be a Blob or a Uint8Array of the file bytes");
120
+ if (blob.size === 0) throw new ValidationError("file is empty");
121
+ const form = new FormData();
122
+ form.append("file", blob, name);
123
+ return this.ctx.http.postForm(`${TOKENS_BASE}/upload`, form, { purpose }, { timeoutMs: DOCUMENT_TIMEOUT_MS });
124
+ }
125
+ async list(options = {}) {
126
+ const withEligibility = optionalBoolean(options.withLendingEligibility, "withLendingEligibility");
127
+ const rows = await this.ctx.http.get(`${TOKENS_BASE}/list`, { withLendingEligibility: withEligibility ? "1" : void 0 });
128
+ return Array.isArray(rows) ? rows : [];
129
+ }
130
+ async holders() {
131
+ return this.ctx.http.get(`${TOKENS_BASE}/holders`);
132
+ }
133
+ async get(tokenAddress) {
134
+ return this.ctx.http.get(this.tokenPath(tokenAddress));
135
+ }
136
+ async refresh(tokenAddress) {
137
+ return this.ctx.http.get(this.tokenPath(tokenAddress, "/onchain"), void 0, BUILD);
138
+ }
139
+ async redetect(tokenAddress, assetStandard) {
140
+ const body = compact({ assetStandard: optionalOneOf(assetStandard, "assetStandard", ASSET_STANDARDS) });
141
+ return this.ctx.http.post(this.tokenPath(tokenAddress, "/redetect"), body, BUILD);
142
+ }
143
+ async setAssetType(tokenAddress, assetType) {
144
+ return this.ctx.http.put(this.tokenPath(tokenAddress, "/asset-type"), { assetType: requireOneOf(assetType, "assetType", ASSET_TYPES) }, BUILD);
145
+ }
146
+ async setProfile(tokenAddress, presentation) {
147
+ if (presentation === void 0) throw new ValidationError("presentation is required: send the presentation fields, or null to clear them");
148
+ return this.ctx.http.put(this.tokenPath(tokenAddress, "/profile"), { profile: checkPresentation(presentation, "presentation") }, BUILD);
149
+ }
150
+ async setImage(tokenAddress, imageURI) {
151
+ const uri = imageURI === null ? null : requireImageUri(imageURI, "imageURI");
152
+ return this.ctx.http.put(this.tokenPath(tokenAddress, "/image"), { imageURI: uri }, BUILD);
153
+ }
154
+ async remove(tokenAddress) {
155
+ return this.ctx.http.delete(this.tokenPath(tokenAddress), BUILD);
156
+ }
157
+ async instrumentSchema() {
158
+ return this.ctx.http.get(`${INSTRUMENTS_BASE}/schema`);
159
+ }
160
+ async instrument(tokenAddress) {
161
+ return this.ctx.http.get(this.instrumentPath(tokenAddress));
162
+ }
163
+ async requestApproval(tokenAddress, input) {
164
+ return this.ctx.http.post(this.instrumentPath(tokenAddress, "/approval-request"), instrumentBody(input), BUILD);
165
+ }
166
+ async saveInstrument(tokenAddress, input, options) {
167
+ const path = this.instrumentPath(tokenAddress);
168
+ const body = instrumentBody(input);
169
+ if (!isSignOptions(options)) {
170
+ if (options !== void 0) throw new ValidationError("Pass { signer } to have the token controller sign the approval, or no options");
171
+ if (input.issuerApproval !== void 0) {
172
+ const approval2 = input.issuerApproval;
173
+ if (!approval2 || typeof approval2 !== "object") throw new ValidationError("issuerApproval must be { signer, signature, recordVersion, signedAt }");
174
+ body.issuerApproval = {
175
+ signer: requireWallet(approval2.signer, "issuerApproval.signer"),
176
+ signature: requireString(approval2.signature, "issuerApproval.signature"),
177
+ recordVersion: approval2.recordVersion,
178
+ signedAt: requireString(approval2.signedAt, "issuerApproval.signedAt")
179
+ };
180
+ }
181
+ return this.ctx.http.put(path, body, BUILD);
182
+ }
183
+ if (input.issuerApproval !== void 0) {
184
+ throw new ValidationError("Pass either issuerApproval or { signer }, not both: with a signer the SDK requests and signs the approval itself");
185
+ }
186
+ const signer = requireSigner(options.signer);
187
+ await preflightChain(this.ctx, options);
188
+ const request = await this.ctx.http.post(this.instrumentPath(tokenAddress, "/approval-request"), body, BUILD);
189
+ if (request.takeOverRequired && body.takeOver !== true) {
190
+ throw new ValidationError("Another instance asserts this instrument record. Send takeOver: true to replace it with the token controller's signed record");
191
+ }
192
+ const signature = await signMessage(this.ctx, options, request.message);
193
+ const approval = {
194
+ signer: await signerAddress(signer),
195
+ signature,
196
+ recordVersion: request.recordVersion,
197
+ signedAt: request.signedAt
198
+ };
199
+ return this.ctx.http.put(path, { ...body, issuerApproval: approval }, BUILD);
200
+ }
201
+ async releaseInstrument(tokenAddress) {
202
+ return this.ctx.http.delete(this.instrumentPath(tokenAddress), BUILD);
203
+ }
204
+ };
205
+
206
+ export {
207
+ Tokens
208
+ };
@@ -0,0 +1,107 @@
1
+ import {
2
+ InstanceChain,
3
+ TrussetError,
4
+ ValidationError,
5
+ attachTransactions,
6
+ confirmExecuted,
7
+ confirmHashOf,
8
+ execute,
9
+ isConfirmOptions,
10
+ isSignOptions,
11
+ planOf,
12
+ preflightChain,
13
+ requireSigner,
14
+ signerAddress
15
+ } from "./chunk-3YF42MHV.mjs";
16
+
17
+ // src/modules/lending/base.ts
18
+ var LENDING_BASE = "/lending-external-securities-v2/api";
19
+ var WRITE_TIMEOUT_MS = 6e4;
20
+ var DOCUMENT_TIMEOUT_MS = 12e4;
21
+ var BUILD = { timeoutMs: WRITE_TIMEOUT_MS };
22
+ var CONFIRM = { timeoutMs: WRITE_TIMEOUT_MS, retry: "confirm" };
23
+ var CONFIRM_ONCE = { timeoutMs: WRITE_TIMEOUT_MS, retry: "write" };
24
+ var LendingContext = class extends InstanceChain {
25
+ };
26
+ var LendingArea = class {
27
+ constructor(ctx) {
28
+ this.ctx = ctx;
29
+ }
30
+ get http() {
31
+ return this.ctx.http;
32
+ }
33
+ async twoLeg(options, spec) {
34
+ if (options === void 0) return spec.build();
35
+ if (isConfirmOptions(options)) return spec.confirm(confirmHashOf(options), null);
36
+ if (!isSignOptions(options)) {
37
+ throw new ValidationError("Pass { signer } to sign and confirm, or { txHash } to confirm a transaction you broadcast yourself");
38
+ }
39
+ await preflightChain(this.ctx, options);
40
+ const prepared = await spec.build();
41
+ const plan = planOf(prepared, spec.plan);
42
+ if (!plan) return attachTransactions(prepared, []);
43
+ if (spec.check) await spec.check(prepared, await signerAddress(requireSigner(options.signer)));
44
+ const executed = await execute(this.ctx, plan, options);
45
+ return confirmExecuted(executed, (hash) => spec.confirm(hash, prepared));
46
+ }
47
+ async oneLeg(options, build, plan) {
48
+ if (options === void 0) return build();
49
+ if (isConfirmOptions(options)) {
50
+ throw new ValidationError("This route has no confirm leg: the chain state it changes is read back from the chain on the next read");
51
+ }
52
+ if (!isSignOptions(options)) {
53
+ throw new ValidationError("Pass { signer } to sign, or no options to get the unsigned transaction");
54
+ }
55
+ await preflightChain(this.ctx, options);
56
+ const prepared = await build();
57
+ const resolved = planOf(prepared, { ...plan, confirmIndex: null });
58
+ if (!resolved) return { transactions: [] };
59
+ const executed = await execute(this.ctx, resolved, options);
60
+ return { transactions: executed.transactions };
61
+ }
62
+ async assertSignerRoles(marketId, address, roles) {
63
+ for (const role of roles) {
64
+ const status = await this.http.get(`${LENDING_BASE}/markets/${enc(marketId)}/access-role/${address}`, { role });
65
+ if (status.failed || typeof status.granted !== "boolean") {
66
+ throw new TrussetError(`Whether ${address} holds ${role} on this market could not be read just now, so nothing was signed. Retry shortly`, "ROLE_UNREADABLE", 503);
67
+ }
68
+ if (!status.granted) {
69
+ throw new ValidationError(`${address} does not hold ${role} on this market, and a step of this plan needs it. Prepare without a signer and sign that step from the wallet that holds ${role}`);
70
+ }
71
+ }
72
+ }
73
+ async assertSignerHoldsAny(marketId, address, roles) {
74
+ let unreadable = false;
75
+ for (const role of roles) {
76
+ const status = await this.http.get(`${LENDING_BASE}/markets/${enc(marketId)}/access-role/${address}`, { role });
77
+ if (status.granted === true) return;
78
+ if (status.failed || typeof status.granted !== "boolean") unreadable = true;
79
+ }
80
+ if (unreadable) {
81
+ throw new TrussetError(`Whether ${address} holds ${roles.join(" or ")} on this market could not be read just now, so nothing was signed. Retry shortly`, "ROLE_UNREADABLE", 503);
82
+ }
83
+ throw new ValidationError(`${address} holds none of ${roles.join(", ")} on this market, and this transaction needs one. Prepare without a signer and sign from the wallet that holds it`);
84
+ }
85
+ };
86
+ function enc(value) {
87
+ return encodeURIComponent(value);
88
+ }
89
+ function compact(body) {
90
+ const out = {};
91
+ for (const [k, v] of Object.entries(body)) {
92
+ if (v !== void 0) out[k] = v;
93
+ }
94
+ return out;
95
+ }
96
+
97
+ export {
98
+ LENDING_BASE,
99
+ DOCUMENT_TIMEOUT_MS,
100
+ BUILD,
101
+ CONFIRM,
102
+ CONFIRM_ONCE,
103
+ LendingContext,
104
+ LendingArea,
105
+ enc,
106
+ compact
107
+ };
@@ -0,0 +1,208 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
2
+
3
+
4
+
5
+ var _chunk7HFMHYRAjs = require('./chunk-7HFMHYRA.js');
6
+
7
+
8
+
9
+
10
+
11
+
12
+
13
+
14
+
15
+
16
+
17
+
18
+ var _chunkAI4ZNJLRjs = require('./chunk-AI4ZNJLR.js');
19
+
20
+ // src/modules/tokens/index.ts
21
+ var TOKENS_BASE = "/external-tokens/api";
22
+ var INSTRUMENTS_BASE = "/instruments/api";
23
+ var ASSET_TYPES = [
24
+ "PUBLIC_EQUITY",
25
+ "PRIVATE_EQUITY",
26
+ "REAL_ESTATE",
27
+ "COMMODITY",
28
+ "ART",
29
+ "WATCH",
30
+ "INFRASTRUCTURE",
31
+ "BOND",
32
+ "CRYPTO_ASSET"
33
+ ];
34
+ var ASSET_STANDARDS = ["ERC721", "ERC1155"];
35
+ var PRESENTATION_KEYS = ["description", "issuerName", "sector", "website", "ammAddress", "reserveURI"];
36
+ var INSTRUMENT_KEYS = ["instrument", "documents", "presentation", "takeOver"];
37
+ function requireImageUri(value, field) {
38
+ const uri = _chunkAI4ZNJLRjs.requireString.call(void 0, value, field);
39
+ if (uri.length > 1024) throw new (0, _chunkAI4ZNJLRjs.ValidationError)(`${field} must be at most 1024 characters`);
40
+ if (uri.startsWith("ipfs://")) {
41
+ if (!/^ipfs:\/\/[A-Za-z0-9]{10,}([/?#].*)?$/.test(uri)) throw new (0, _chunkAI4ZNJLRjs.ValidationError)(`${field} must name an IPFS content identifier, such as ipfs://Qm...`);
42
+ return uri;
43
+ }
44
+ let parsed;
45
+ try {
46
+ parsed = new URL(uri);
47
+ } catch (e) {
48
+ throw new (0, _chunkAI4ZNJLRjs.ValidationError)(`${field} must be an https or ipfs URI`);
49
+ }
50
+ if (parsed.protocol !== "https:") throw new (0, _chunkAI4ZNJLRjs.ValidationError)(`${field} must be an https or ipfs URI`);
51
+ return uri;
52
+ }
53
+ function checkPresentation(value, field) {
54
+ if (value === void 0 || value === null) return value;
55
+ if (typeof value !== "object" || Array.isArray(value)) throw new (0, _chunkAI4ZNJLRjs.ValidationError)(`${field} must be an object with the presentation fields, or null to clear them`);
56
+ for (const key of Object.keys(value)) {
57
+ if (!PRESENTATION_KEYS.includes(key)) {
58
+ throw new (0, _chunkAI4ZNJLRjs.ValidationError)(`Unknown ${field} field: ${key}. The presentation fields are ${PRESENTATION_KEYS.join(", ")}`);
59
+ }
60
+ }
61
+ if (value.ammAddress !== void 0 && value.ammAddress !== null && value.ammAddress !== "") _chunkAI4ZNJLRjs.requireWallet.call(void 0, value.ammAddress, `${field}.ammAddress`);
62
+ return value;
63
+ }
64
+ function instrumentBody(input) {
65
+ if (!input || typeof input !== "object" || Array.isArray(input)) {
66
+ throw new (0, _chunkAI4ZNJLRjs.ValidationError)("The instrument update must be an object with instrument, documents, presentation or takeOver");
67
+ }
68
+ for (const key of Object.keys(input)) {
69
+ if (key === "issuerApproval") continue;
70
+ if (!INSTRUMENT_KEYS.includes(key)) {
71
+ throw new (0, _chunkAI4ZNJLRjs.ValidationError)(`Unknown field: ${key}. An instrument update takes ${INSTRUMENT_KEYS.join(", ")}`);
72
+ }
73
+ }
74
+ if (input.instrument !== void 0 && (typeof input.instrument !== "object" || input.instrument === null || Array.isArray(input.instrument))) {
75
+ throw new (0, _chunkAI4ZNJLRjs.ValidationError)("instrument must be an object of instrument fields");
76
+ }
77
+ if (input.documents !== void 0 && !Array.isArray(input.documents)) {
78
+ throw new (0, _chunkAI4ZNJLRjs.ValidationError)("documents must be an array");
79
+ }
80
+ return _chunk7HFMHYRAjs.compact.call(void 0, {
81
+ instrument: input.instrument,
82
+ documents: input.documents,
83
+ presentation: checkPresentation(input.presentation, "presentation"),
84
+ takeOver: _chunkAI4ZNJLRjs.optionalBoolean.call(void 0, input.takeOver, "takeOver")
85
+ });
86
+ }
87
+ var Tokens = class {
88
+ constructor(ctx) {
89
+ this.ctx = ctx;
90
+ }
91
+ tokenPath(tokenAddress, rest = "") {
92
+ return `${TOKENS_BASE}/${_chunkAI4ZNJLRjs.requireWallet.call(void 0, tokenAddress, "tokenAddress")}${rest}`;
93
+ }
94
+ instrumentPath(tokenAddress, rest = "") {
95
+ return `${INSTRUMENTS_BASE}/${_chunkAI4ZNJLRjs.requireWallet.call(void 0, tokenAddress, "tokenAddress")}${rest}`;
96
+ }
97
+ async detect(input) {
98
+ const body = _chunk7HFMHYRAjs.compact.call(void 0, {
99
+ tokenAddress: _chunkAI4ZNJLRjs.requireWallet.call(void 0, _optionalChain([input, 'optionalAccess', _ => _.tokenAddress]), "tokenAddress"),
100
+ assetStandard: _chunkAI4ZNJLRjs.optionalOneOf.call(void 0, _optionalChain([input, 'optionalAccess', _2 => _2.assetStandard]), "assetStandard", ASSET_STANDARDS)
101
+ });
102
+ return this.ctx.http.post(`${TOKENS_BASE}/detect`, body, _chunk7HFMHYRAjs.BUILD);
103
+ }
104
+ async import(input) {
105
+ const body = _chunk7HFMHYRAjs.compact.call(void 0, {
106
+ tokenAddress: _chunkAI4ZNJLRjs.requireWallet.call(void 0, _optionalChain([input, 'optionalAccess', _3 => _3.tokenAddress]), "tokenAddress"),
107
+ assetType: _chunkAI4ZNJLRjs.requireOneOf.call(void 0, _optionalChain([input, 'optionalAccess', _4 => _4.assetType]), "assetType", ASSET_TYPES),
108
+ imageURI: _optionalChain([input, 'optionalAccess', _5 => _5.imageURI]) === void 0 || input.imageURI === null || input.imageURI === "" ? void 0 : requireImageUri(input.imageURI, "imageURI"),
109
+ assetStandard: _chunkAI4ZNJLRjs.optionalOneOf.call(void 0, _optionalChain([input, 'optionalAccess', _6 => _6.assetStandard]), "assetStandard", ASSET_STANDARDS)
110
+ });
111
+ return this.ctx.http.post(`${TOKENS_BASE}/import`, body, _chunk7HFMHYRAjs.BUILD);
112
+ }
113
+ async upload(file, fileName, options = {}) {
114
+ const name = _chunkAI4ZNJLRjs.requireString.call(void 0, fileName, "fileName");
115
+ const purpose = _chunkAI4ZNJLRjs.optionalOneOf.call(void 0, options.purpose, "purpose", ["image"]);
116
+ let blob;
117
+ if (typeof Blob !== "undefined" && file instanceof Blob) blob = file;
118
+ else if (file instanceof Uint8Array) blob = new Blob([Uint8Array.from(file)]);
119
+ else throw new (0, _chunkAI4ZNJLRjs.ValidationError)("file must be a Blob or a Uint8Array of the file bytes");
120
+ if (blob.size === 0) throw new (0, _chunkAI4ZNJLRjs.ValidationError)("file is empty");
121
+ const form = new FormData();
122
+ form.append("file", blob, name);
123
+ return this.ctx.http.postForm(`${TOKENS_BASE}/upload`, form, { purpose }, { timeoutMs: _chunk7HFMHYRAjs.DOCUMENT_TIMEOUT_MS });
124
+ }
125
+ async list(options = {}) {
126
+ const withEligibility = _chunkAI4ZNJLRjs.optionalBoolean.call(void 0, options.withLendingEligibility, "withLendingEligibility");
127
+ const rows = await this.ctx.http.get(`${TOKENS_BASE}/list`, { withLendingEligibility: withEligibility ? "1" : void 0 });
128
+ return Array.isArray(rows) ? rows : [];
129
+ }
130
+ async holders() {
131
+ return this.ctx.http.get(`${TOKENS_BASE}/holders`);
132
+ }
133
+ async get(tokenAddress) {
134
+ return this.ctx.http.get(this.tokenPath(tokenAddress));
135
+ }
136
+ async refresh(tokenAddress) {
137
+ return this.ctx.http.get(this.tokenPath(tokenAddress, "/onchain"), void 0, _chunk7HFMHYRAjs.BUILD);
138
+ }
139
+ async redetect(tokenAddress, assetStandard) {
140
+ const body = _chunk7HFMHYRAjs.compact.call(void 0, { assetStandard: _chunkAI4ZNJLRjs.optionalOneOf.call(void 0, assetStandard, "assetStandard", ASSET_STANDARDS) });
141
+ return this.ctx.http.post(this.tokenPath(tokenAddress, "/redetect"), body, _chunk7HFMHYRAjs.BUILD);
142
+ }
143
+ async setAssetType(tokenAddress, assetType) {
144
+ return this.ctx.http.put(this.tokenPath(tokenAddress, "/asset-type"), { assetType: _chunkAI4ZNJLRjs.requireOneOf.call(void 0, assetType, "assetType", ASSET_TYPES) }, _chunk7HFMHYRAjs.BUILD);
145
+ }
146
+ async setProfile(tokenAddress, presentation) {
147
+ if (presentation === void 0) throw new (0, _chunkAI4ZNJLRjs.ValidationError)("presentation is required: send the presentation fields, or null to clear them");
148
+ return this.ctx.http.put(this.tokenPath(tokenAddress, "/profile"), { profile: checkPresentation(presentation, "presentation") }, _chunk7HFMHYRAjs.BUILD);
149
+ }
150
+ async setImage(tokenAddress, imageURI) {
151
+ const uri = imageURI === null ? null : requireImageUri(imageURI, "imageURI");
152
+ return this.ctx.http.put(this.tokenPath(tokenAddress, "/image"), { imageURI: uri }, _chunk7HFMHYRAjs.BUILD);
153
+ }
154
+ async remove(tokenAddress) {
155
+ return this.ctx.http.delete(this.tokenPath(tokenAddress), _chunk7HFMHYRAjs.BUILD);
156
+ }
157
+ async instrumentSchema() {
158
+ return this.ctx.http.get(`${INSTRUMENTS_BASE}/schema`);
159
+ }
160
+ async instrument(tokenAddress) {
161
+ return this.ctx.http.get(this.instrumentPath(tokenAddress));
162
+ }
163
+ async requestApproval(tokenAddress, input) {
164
+ return this.ctx.http.post(this.instrumentPath(tokenAddress, "/approval-request"), instrumentBody(input), _chunk7HFMHYRAjs.BUILD);
165
+ }
166
+ async saveInstrument(tokenAddress, input, options) {
167
+ const path = this.instrumentPath(tokenAddress);
168
+ const body = instrumentBody(input);
169
+ if (!_chunkAI4ZNJLRjs.isSignOptions.call(void 0, options)) {
170
+ if (options !== void 0) throw new (0, _chunkAI4ZNJLRjs.ValidationError)("Pass { signer } to have the token controller sign the approval, or no options");
171
+ if (input.issuerApproval !== void 0) {
172
+ const approval2 = input.issuerApproval;
173
+ if (!approval2 || typeof approval2 !== "object") throw new (0, _chunkAI4ZNJLRjs.ValidationError)("issuerApproval must be { signer, signature, recordVersion, signedAt }");
174
+ body.issuerApproval = {
175
+ signer: _chunkAI4ZNJLRjs.requireWallet.call(void 0, approval2.signer, "issuerApproval.signer"),
176
+ signature: _chunkAI4ZNJLRjs.requireString.call(void 0, approval2.signature, "issuerApproval.signature"),
177
+ recordVersion: approval2.recordVersion,
178
+ signedAt: _chunkAI4ZNJLRjs.requireString.call(void 0, approval2.signedAt, "issuerApproval.signedAt")
179
+ };
180
+ }
181
+ return this.ctx.http.put(path, body, _chunk7HFMHYRAjs.BUILD);
182
+ }
183
+ if (input.issuerApproval !== void 0) {
184
+ throw new (0, _chunkAI4ZNJLRjs.ValidationError)("Pass either issuerApproval or { signer }, not both: with a signer the SDK requests and signs the approval itself");
185
+ }
186
+ const signer = _chunkAI4ZNJLRjs.requireSigner.call(void 0, options.signer);
187
+ await _chunkAI4ZNJLRjs.preflightChain.call(void 0, this.ctx, options);
188
+ const request = await this.ctx.http.post(this.instrumentPath(tokenAddress, "/approval-request"), body, _chunk7HFMHYRAjs.BUILD);
189
+ if (request.takeOverRequired && body.takeOver !== true) {
190
+ throw new (0, _chunkAI4ZNJLRjs.ValidationError)("Another instance asserts this instrument record. Send takeOver: true to replace it with the token controller's signed record");
191
+ }
192
+ const signature = await _chunkAI4ZNJLRjs.signMessage.call(void 0, this.ctx, options, request.message);
193
+ const approval = {
194
+ signer: await _chunkAI4ZNJLRjs.signerAddress.call(void 0, signer),
195
+ signature,
196
+ recordVersion: request.recordVersion,
197
+ signedAt: request.signedAt
198
+ };
199
+ return this.ctx.http.put(path, { ...body, issuerApproval: approval }, _chunk7HFMHYRAjs.BUILD);
200
+ }
201
+ async releaseInstrument(tokenAddress) {
202
+ return this.ctx.http.delete(this.instrumentPath(tokenAddress), _chunk7HFMHYRAjs.BUILD);
203
+ }
204
+ };
205
+
206
+
207
+
208
+ exports.Tokens = Tokens;