@agentlayer.tech/wallet 0.1.101 → 0.1.102
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/.openclaw/extensions/agent-wallet/dist/index.js +46 -1
- package/.openclaw/extensions/agent-wallet/index.ts +46 -1
- package/.openclaw/extensions/agent-wallet/openclaw.plugin.json +1 -1
- package/.openclaw/extensions/agent-wallet/package.json +1 -1
- package/README.md +18 -0
- package/VERSION +1 -1
- package/agent-wallet/agent_wallet/__init__.py +1 -1
- package/agent-wallet/agent_wallet/connector_cli.py +198 -0
- package/agent-wallet/agent_wallet/connectors/__init__.py +28 -0
- package/agent-wallet/agent_wallet/connectors/catalog.py +68 -0
- package/agent-wallet/agent_wallet/connectors/client.py +308 -0
- package/agent-wallet/agent_wallet/connectors/intent_policy.py +243 -0
- package/agent-wallet/agent_wallet/connectors/manifest.py +192 -0
- package/agent-wallet/agent_wallet/connectors/registry.py +341 -0
- package/agent-wallet/agent_wallet/openclaw_adapter.py +56 -5
- package/agent-wallet/openclaw.plugin.json +1 -1
- package/agent-wallet/pyproject.toml +4 -2
- package/agent-wallet/scripts/build_release_bundle.py +1 -0
- package/agent-wallet/scripts/install_agent_wallet.py +1 -1
- package/bin/openclaw-agent-wallet.mjs +38 -0
- package/claude-code/plugins/agent-wallet/.claude-plugin/plugin.json +1 -1
- package/codex/plugins/agent-wallet/.codex-plugin/plugin.json +1 -1
- package/codex/plugins/agent-wallet/server.py +4 -1
- package/connectors/AGENTS.md +37 -0
- package/connectors/DEVELOPER_GUIDE.md +131 -0
- package/connectors/README.md +139 -0
- package/connectors/READ_ONLY_BETA.md +54 -0
- package/connectors/RELEASING.md +48 -0
- package/connectors/conformance/README.md +31 -0
- package/connectors/conformance/package.json +54 -0
- package/connectors/conformance/scripts/sync-license.mjs +3 -0
- package/connectors/conformance/scripts/sync-spec.mjs +16 -0
- package/connectors/conformance/src/cli.ts +43 -0
- package/connectors/conformance/src/index.ts +7 -0
- package/connectors/conformance/src/runner.ts +314 -0
- package/connectors/conformance/src/types.ts +27 -0
- package/connectors/conformance/test/fixtures/invalid-response-identity.json +14 -0
- package/connectors/conformance/test/fixtures/missing-tool-fixture.json +4 -0
- package/connectors/conformance/test/runner.test.mjs +151 -0
- package/connectors/conformance/tsconfig.json +17 -0
- package/connectors/examples/reference-crypto-data/Dockerfile +21 -0
- package/connectors/examples/reference-crypto-data/README.md +51 -0
- package/connectors/examples/reference-crypto-data/conformance.json +11 -0
- package/connectors/examples/reference-crypto-data/connector.json +95 -0
- package/connectors/examples/reference-crypto-data/package.json +21 -0
- package/connectors/examples/reference-crypto-data/railway.toml +9 -0
- package/connectors/examples/reference-crypto-data/src/connector.ts +137 -0
- package/connectors/examples/reference-crypto-data/src/server.ts +13 -0
- package/connectors/examples/reference-crypto-data/test/connector.test.mjs +97 -0
- package/connectors/examples/reference-crypto-data/tsconfig.json +17 -0
- package/connectors/package-lock.json +561 -0
- package/connectors/package.json +19 -0
- package/connectors/scripts/smoke-packed-packages.mjs +121 -0
- package/connectors/sdk-typescript/README.md +47 -0
- package/connectors/sdk-typescript/package.json +49 -0
- package/connectors/sdk-typescript/scripts/sync-license.mjs +3 -0
- package/connectors/sdk-typescript/src/connector.ts +204 -0
- package/connectors/sdk-typescript/src/errors.ts +11 -0
- package/connectors/sdk-typescript/src/http.ts +116 -0
- package/connectors/sdk-typescript/src/index.ts +26 -0
- package/connectors/sdk-typescript/src/types.ts +101 -0
- package/connectors/sdk-typescript/test/sdk.test.mjs +181 -0
- package/connectors/sdk-typescript/tsconfig.json +21 -0
- package/connectors/spec/connector-manifest.schema.json +340 -0
- package/connectors/spec/connector-protocol.md +159 -0
- package/connectors/spec/transaction-intent.schema.json +281 -0
- package/connectors/templates/read-only/.env.example +1 -0
- package/connectors/templates/read-only/Dockerfile +11 -0
- package/connectors/templates/read-only/README.md +33 -0
- package/connectors/templates/read-only/conformance.json +11 -0
- package/connectors/templates/read-only/connector.json +64 -0
- package/connectors/templates/read-only/package.json +21 -0
- package/connectors/templates/read-only/railway.toml +9 -0
- package/connectors/templates/read-only/src/connector.ts +61 -0
- package/connectors/templates/read-only/src/server.ts +14 -0
- package/connectors/templates/read-only/test/connector.test.mjs +62 -0
- package/connectors/templates/read-only/tsconfig.json +17 -0
- package/hermes/plugins/agent_wallet/plugin.yaml +1 -1
- package/package.json +2 -1
- package/wdk-btc-wallet/package.json +1 -1
- package/wdk-evm-wallet/package.json +1 -1
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema_version": 1,
|
|
3
|
+
"id": "tech.agentlayer.crypto-data",
|
|
4
|
+
"name": "AgentLayer Crypto Data Reference",
|
|
5
|
+
"version": "0.1.0-beta.1",
|
|
6
|
+
"publisher": {
|
|
7
|
+
"id": "agentlayer",
|
|
8
|
+
"name": "AgentLayer",
|
|
9
|
+
"url": "https://agentlayer.tech"
|
|
10
|
+
},
|
|
11
|
+
"agentlayer": {
|
|
12
|
+
"protocol_version": 1,
|
|
13
|
+
"runtime_range": ">=0.1.101"
|
|
14
|
+
},
|
|
15
|
+
"trust": "community_read_only",
|
|
16
|
+
"transport": {
|
|
17
|
+
"type": "https",
|
|
18
|
+
"url": "https://reference-crypto-data-production.up.railway.app",
|
|
19
|
+
"timeout_ms": 10000
|
|
20
|
+
},
|
|
21
|
+
"permissions": {
|
|
22
|
+
"wallet_address": false,
|
|
23
|
+
"transaction_intents": false,
|
|
24
|
+
"network_hosts": ["api.exchange.coinbase.com"]
|
|
25
|
+
},
|
|
26
|
+
"tools": [
|
|
27
|
+
{
|
|
28
|
+
"name": "get_spot_price",
|
|
29
|
+
"description": "Get a public spot ticker snapshot for a crypto/fiat or crypto/crypto product.",
|
|
30
|
+
"read_only": true,
|
|
31
|
+
"risk_level": "low",
|
|
32
|
+
"input_schema": {
|
|
33
|
+
"type": "object",
|
|
34
|
+
"properties": {
|
|
35
|
+
"base": { "type": "string", "pattern": "^[A-Za-z0-9]{2,12}$" },
|
|
36
|
+
"quote": { "type": "string", "pattern": "^[A-Za-z0-9]{2,12}$" }
|
|
37
|
+
},
|
|
38
|
+
"required": ["base", "quote"],
|
|
39
|
+
"additionalProperties": false
|
|
40
|
+
},
|
|
41
|
+
"output_schema": {
|
|
42
|
+
"type": "object",
|
|
43
|
+
"properties": {
|
|
44
|
+
"product_id": { "type": "string", "minLength": 5, "maxLength": 25 },
|
|
45
|
+
"base_currency": { "type": "string", "minLength": 2, "maxLength": 12 },
|
|
46
|
+
"quote_currency": { "type": "string", "minLength": 2, "maxLength": 12 },
|
|
47
|
+
"price": { "type": "string", "minLength": 1, "maxLength": 80 },
|
|
48
|
+
"bid": { "type": "string", "minLength": 1, "maxLength": 80 },
|
|
49
|
+
"ask": { "type": "string", "minLength": 1, "maxLength": 80 },
|
|
50
|
+
"last_size": { "type": "string", "minLength": 1, "maxLength": 80 },
|
|
51
|
+
"volume_24h": { "type": "string", "minLength": 1, "maxLength": 80 },
|
|
52
|
+
"observed_at": { "type": "string", "minLength": 10, "maxLength": 64 },
|
|
53
|
+
"source": { "const": "coinbase_exchange" }
|
|
54
|
+
},
|
|
55
|
+
"required": [
|
|
56
|
+
"product_id", "base_currency", "quote_currency", "price", "bid", "ask",
|
|
57
|
+
"last_size", "volume_24h", "observed_at", "source"
|
|
58
|
+
],
|
|
59
|
+
"additionalProperties": false
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"name": "get_asset_metadata",
|
|
64
|
+
"description": "Get public metadata and network status for a currency code.",
|
|
65
|
+
"read_only": true,
|
|
66
|
+
"risk_level": "low",
|
|
67
|
+
"input_schema": {
|
|
68
|
+
"type": "object",
|
|
69
|
+
"properties": {
|
|
70
|
+
"asset": { "type": "string", "pattern": "^[A-Za-z0-9]{2,12}$" }
|
|
71
|
+
},
|
|
72
|
+
"required": ["asset"],
|
|
73
|
+
"additionalProperties": false
|
|
74
|
+
},
|
|
75
|
+
"output_schema": {
|
|
76
|
+
"type": "object",
|
|
77
|
+
"properties": {
|
|
78
|
+
"asset": { "type": "string", "minLength": 2, "maxLength": 12 },
|
|
79
|
+
"name": { "type": "string", "minLength": 1, "maxLength": 120 },
|
|
80
|
+
"status": { "type": "string", "minLength": 1, "maxLength": 40 },
|
|
81
|
+
"type": { "type": ["string", "null"], "maxLength": 40 },
|
|
82
|
+
"min_size": { "type": "string", "minLength": 1, "maxLength": 80 },
|
|
83
|
+
"max_precision": { "type": "string", "minLength": 1, "maxLength": 80 },
|
|
84
|
+
"default_network": { "type": ["string", "null"], "maxLength": 80 },
|
|
85
|
+
"source": { "const": "coinbase_exchange" }
|
|
86
|
+
},
|
|
87
|
+
"required": [
|
|
88
|
+
"asset", "name", "status", "type", "min_size", "max_precision",
|
|
89
|
+
"default_network", "source"
|
|
90
|
+
],
|
|
91
|
+
"additionalProperties": false
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
]
|
|
95
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@agentlayer.tech/reference-crypto-data-connector",
|
|
3
|
+
"version": "0.1.0-beta.1",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"engines": {
|
|
7
|
+
"node": ">=24"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "tsc -p tsconfig.json",
|
|
11
|
+
"start": "node dist/server.js",
|
|
12
|
+
"check": "npm run build && node --test test/*.test.mjs"
|
|
13
|
+
},
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"@agentlayer.tech/connector-sdk": "0.1.0-beta.1"
|
|
16
|
+
},
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"@types/node": "^24.0.0",
|
|
19
|
+
"typescript": "^7.0.2"
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
ConnectorSdkError,
|
|
5
|
+
defineReadOnlyConnector,
|
|
6
|
+
type ConnectorManifest,
|
|
7
|
+
type JsonObject,
|
|
8
|
+
} from "@agentlayer.tech/connector-sdk";
|
|
9
|
+
|
|
10
|
+
const manifest = JSON.parse(
|
|
11
|
+
readFileSync(new URL("../connector.json", import.meta.url), "utf8")
|
|
12
|
+
) as ConnectorManifest;
|
|
13
|
+
const UPSTREAM_ORIGIN = "https://api.exchange.coinbase.com";
|
|
14
|
+
const MAX_UPSTREAM_BYTES = 256 * 1024;
|
|
15
|
+
const ASSET_PATTERN = /^[A-Z0-9]{2,12}$/;
|
|
16
|
+
|
|
17
|
+
function assetCode(value: unknown, field: string): string {
|
|
18
|
+
const normalized = String(value ?? "").trim().toUpperCase();
|
|
19
|
+
if (!ASSET_PATTERN.test(normalized)) {
|
|
20
|
+
throw new ConnectorSdkError("invalid_arguments", `${field} must be a 2-12 character asset code.`);
|
|
21
|
+
}
|
|
22
|
+
return normalized;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function requiredString(value: unknown, field: string, maxLength = 120): string {
|
|
26
|
+
if (typeof value !== "string" || value.length === 0 || value.length > maxLength) {
|
|
27
|
+
throw new ConnectorSdkError("invalid_upstream", `Upstream ${field} is invalid.`, 502);
|
|
28
|
+
}
|
|
29
|
+
return value;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function optionalString(value: unknown, maxLength = 80): string | null {
|
|
33
|
+
return typeof value === "string" && value.length > 0 && value.length <= maxLength ? value : null;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async function readObject(response: Response): Promise<Record<string, unknown>> {
|
|
37
|
+
const contentLength = Number(response.headers.get("content-length") ?? 0);
|
|
38
|
+
if (Number.isFinite(contentLength) && contentLength > MAX_UPSTREAM_BYTES) {
|
|
39
|
+
throw new ConnectorSdkError("upstream_too_large", "Upstream response exceeds the size limit.", 502);
|
|
40
|
+
}
|
|
41
|
+
if (!response.body) {
|
|
42
|
+
throw new ConnectorSdkError("invalid_upstream", "Upstream response body is missing.", 502);
|
|
43
|
+
}
|
|
44
|
+
const reader = response.body.getReader();
|
|
45
|
+
const chunks: Uint8Array[] = [];
|
|
46
|
+
let size = 0;
|
|
47
|
+
while (true) {
|
|
48
|
+
const { done, value } = await reader.read();
|
|
49
|
+
if (done) break;
|
|
50
|
+
size += value.byteLength;
|
|
51
|
+
if (size > MAX_UPSTREAM_BYTES) {
|
|
52
|
+
await reader.cancel();
|
|
53
|
+
throw new ConnectorSdkError("upstream_too_large", "Upstream response exceeds the size limit.", 502);
|
|
54
|
+
}
|
|
55
|
+
chunks.push(value);
|
|
56
|
+
}
|
|
57
|
+
let payload: unknown;
|
|
58
|
+
try {
|
|
59
|
+
payload = JSON.parse(Buffer.concat(chunks).toString("utf8"));
|
|
60
|
+
} catch {
|
|
61
|
+
throw new ConnectorSdkError("invalid_upstream", "Upstream response is not valid JSON.", 502);
|
|
62
|
+
}
|
|
63
|
+
if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
|
|
64
|
+
throw new ConnectorSdkError("invalid_upstream", "Upstream response root is invalid.", 502);
|
|
65
|
+
}
|
|
66
|
+
return payload as Record<string, unknown>;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async function fetchObject(
|
|
70
|
+
path: string,
|
|
71
|
+
fetchImpl: typeof fetch
|
|
72
|
+
): Promise<Record<string, unknown>> {
|
|
73
|
+
const url = new URL(path, UPSTREAM_ORIGIN);
|
|
74
|
+
if (url.origin !== UPSTREAM_ORIGIN || !manifest.permissions.network_hosts.includes(url.hostname)) {
|
|
75
|
+
throw new ConnectorSdkError("upstream_not_allowed", "Upstream host is not allowlisted.", 500);
|
|
76
|
+
}
|
|
77
|
+
const response = await fetchImpl(url, {
|
|
78
|
+
headers: {
|
|
79
|
+
accept: "application/json",
|
|
80
|
+
"cache-control": "no-cache",
|
|
81
|
+
"user-agent": "AgentLayer-Reference-Connector/0.1",
|
|
82
|
+
},
|
|
83
|
+
redirect: "error",
|
|
84
|
+
signal: AbortSignal.timeout(5000),
|
|
85
|
+
});
|
|
86
|
+
if (!response.ok) {
|
|
87
|
+
throw new ConnectorSdkError("upstream_http_error", `Upstream returned HTTP ${response.status}.`, 502);
|
|
88
|
+
}
|
|
89
|
+
return readObject(response);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function createCryptoDataConnector(fetchImpl: typeof fetch = fetch) {
|
|
93
|
+
return defineReadOnlyConnector({
|
|
94
|
+
manifest,
|
|
95
|
+
responseTtlSeconds: 30,
|
|
96
|
+
handlers: {
|
|
97
|
+
async get_spot_price(arguments_: JsonObject): Promise<JsonObject> {
|
|
98
|
+
const base = assetCode(arguments_.base, "base");
|
|
99
|
+
const quote = assetCode(arguments_.quote, "quote");
|
|
100
|
+
const productId = `${base}-${quote}`;
|
|
101
|
+
const ticker = await fetchObject(`/products/${encodeURIComponent(productId)}/ticker`, fetchImpl);
|
|
102
|
+
return {
|
|
103
|
+
product_id: productId,
|
|
104
|
+
base_currency: base,
|
|
105
|
+
quote_currency: quote,
|
|
106
|
+
price: requiredString(ticker.price, "price", 80),
|
|
107
|
+
bid: requiredString(ticker.bid, "bid", 80),
|
|
108
|
+
ask: requiredString(ticker.ask, "ask", 80),
|
|
109
|
+
last_size: requiredString(ticker.size, "size", 80),
|
|
110
|
+
volume_24h: requiredString(ticker.volume, "volume", 80),
|
|
111
|
+
observed_at: requiredString(ticker.time, "time", 64),
|
|
112
|
+
source: "coinbase_exchange",
|
|
113
|
+
};
|
|
114
|
+
},
|
|
115
|
+
async get_asset_metadata(arguments_: JsonObject): Promise<JsonObject> {
|
|
116
|
+
const asset = assetCode(arguments_.asset, "asset");
|
|
117
|
+
const currency = await fetchObject(`/currencies/${encodeURIComponent(asset)}`, fetchImpl);
|
|
118
|
+
const details =
|
|
119
|
+
currency.details && typeof currency.details === "object" && !Array.isArray(currency.details)
|
|
120
|
+
? (currency.details as Record<string, unknown>)
|
|
121
|
+
: {};
|
|
122
|
+
return {
|
|
123
|
+
asset: requiredString(currency.id, "id", 12),
|
|
124
|
+
name: requiredString(currency.name, "name"),
|
|
125
|
+
status: requiredString(currency.status, "status", 40),
|
|
126
|
+
type: optionalString(details.type, 40),
|
|
127
|
+
min_size: requiredString(currency.min_size, "min_size", 80),
|
|
128
|
+
max_precision: requiredString(currency.max_precision, "max_precision", 80),
|
|
129
|
+
default_network: optionalString(currency.default_network, 80),
|
|
130
|
+
source: "coinbase_exchange",
|
|
131
|
+
};
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export const connector = createCryptoDataConnector();
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { startConnectorServer } from "@agentlayer.tech/connector-sdk";
|
|
2
|
+
|
|
3
|
+
import { connector } from "./connector.js";
|
|
4
|
+
|
|
5
|
+
const server = await startConnectorServer(connector);
|
|
6
|
+
console.log(
|
|
7
|
+
JSON.stringify({
|
|
8
|
+
event: "connector_started",
|
|
9
|
+
connector_id: connector.manifest.id,
|
|
10
|
+
connector_version: connector.manifest.version,
|
|
11
|
+
address: server.address(),
|
|
12
|
+
})
|
|
13
|
+
);
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import test from "node:test";
|
|
3
|
+
|
|
4
|
+
import { createCryptoDataConnector } from "../dist/connector.js";
|
|
5
|
+
|
|
6
|
+
function request(connector, tool, arguments_) {
|
|
7
|
+
return {
|
|
8
|
+
protocol_version: 1,
|
|
9
|
+
request_id: `reference-${tool}`,
|
|
10
|
+
connector: { id: connector.manifest.id, version: connector.manifest.version },
|
|
11
|
+
tool,
|
|
12
|
+
arguments: arguments_,
|
|
13
|
+
context: {},
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
test("normalizes public ticker data without wallet context", async () => {
|
|
18
|
+
const connector = createCryptoDataConnector(async (url, options) => {
|
|
19
|
+
assert.equal(url.href, "https://api.exchange.coinbase.com/products/BTC-USD/ticker");
|
|
20
|
+
assert.equal(options.redirect, "error");
|
|
21
|
+
assert.equal(options.headers["cache-control"], "no-cache");
|
|
22
|
+
return new Response(
|
|
23
|
+
JSON.stringify({
|
|
24
|
+
price: "78000.12",
|
|
25
|
+
bid: "78000.11",
|
|
26
|
+
ask: "78000.13",
|
|
27
|
+
size: "0.01",
|
|
28
|
+
volume: "1234.5",
|
|
29
|
+
time: "2026-08-27T00:00:00Z",
|
|
30
|
+
}),
|
|
31
|
+
{ status: 200, headers: { "content-type": "application/json" } }
|
|
32
|
+
);
|
|
33
|
+
});
|
|
34
|
+
const response = await connector.invoke(request(connector, "get_spot_price", {
|
|
35
|
+
base: "btc",
|
|
36
|
+
quote: "usd",
|
|
37
|
+
}));
|
|
38
|
+
assert.deepEqual(response.result, {
|
|
39
|
+
product_id: "BTC-USD",
|
|
40
|
+
base_currency: "BTC",
|
|
41
|
+
quote_currency: "USD",
|
|
42
|
+
price: "78000.12",
|
|
43
|
+
bid: "78000.11",
|
|
44
|
+
ask: "78000.13",
|
|
45
|
+
last_size: "0.01",
|
|
46
|
+
volume_24h: "1234.5",
|
|
47
|
+
observed_at: "2026-08-27T00:00:00Z",
|
|
48
|
+
source: "coinbase_exchange",
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test("normalizes public asset metadata", async () => {
|
|
53
|
+
const connector = createCryptoDataConnector(async (url) => {
|
|
54
|
+
assert.equal(url.href, "https://api.exchange.coinbase.com/currencies/BTC");
|
|
55
|
+
return new Response(
|
|
56
|
+
JSON.stringify({
|
|
57
|
+
id: "BTC",
|
|
58
|
+
name: "Bitcoin",
|
|
59
|
+
min_size: "0.00000001",
|
|
60
|
+
max_precision: "0.00000001",
|
|
61
|
+
status: "online",
|
|
62
|
+
default_network: "bitcoin",
|
|
63
|
+
details: { type: "crypto" },
|
|
64
|
+
}),
|
|
65
|
+
{ status: 200, headers: { "content-type": "application/json" } }
|
|
66
|
+
);
|
|
67
|
+
});
|
|
68
|
+
const response = await connector.invoke(request(connector, "get_asset_metadata", { asset: "btc" }));
|
|
69
|
+
assert.deepEqual(response.result, {
|
|
70
|
+
asset: "BTC",
|
|
71
|
+
name: "Bitcoin",
|
|
72
|
+
status: "online",
|
|
73
|
+
type: "crypto",
|
|
74
|
+
min_size: "0.00000001",
|
|
75
|
+
max_precision: "0.00000001",
|
|
76
|
+
default_network: "bitcoin",
|
|
77
|
+
source: "coinbase_exchange",
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test("rejects oversized and malformed upstream responses", async () => {
|
|
82
|
+
const oversized = createCryptoDataConnector(async () =>
|
|
83
|
+
new Response("{}", { status: 200, headers: { "content-length": "999999" } })
|
|
84
|
+
);
|
|
85
|
+
await assert.rejects(
|
|
86
|
+
oversized.invoke(request(oversized, "get_asset_metadata", { asset: "BTC" })),
|
|
87
|
+
/size limit/
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
const malformed = createCryptoDataConnector(async () =>
|
|
91
|
+
new Response("not-json", { status: 200, headers: { "content-type": "application/json" } })
|
|
92
|
+
);
|
|
93
|
+
await assert.rejects(
|
|
94
|
+
malformed.invoke(request(malformed, "get_asset_metadata", { asset: "BTC" })),
|
|
95
|
+
/not valid JSON/
|
|
96
|
+
);
|
|
97
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2023",
|
|
4
|
+
"module": "NodeNext",
|
|
5
|
+
"moduleResolution": "NodeNext",
|
|
6
|
+
"rootDir": "src",
|
|
7
|
+
"outDir": "dist",
|
|
8
|
+
"declaration": true,
|
|
9
|
+
"strict": true,
|
|
10
|
+
"noUncheckedIndexedAccess": true,
|
|
11
|
+
"exactOptionalPropertyTypes": true,
|
|
12
|
+
"verbatimModuleSyntax": true,
|
|
13
|
+
"types": ["node"],
|
|
14
|
+
"skipLibCheck": true
|
|
15
|
+
},
|
|
16
|
+
"include": ["src/**/*.ts"]
|
|
17
|
+
}
|