@across-protocol/sdk 4.3.143-alpha.0 → 4.3.143-alpha.1
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/dist/cjs/src/caching/Arweave/ArweaveClient.d.ts +11 -6
- package/dist/cjs/src/caching/Arweave/ArweaveClient.js +102 -79
- package/dist/cjs/src/caching/Arweave/ArweaveClient.js.map +1 -1
- package/dist/esm/src/caching/Arweave/ArweaveClient.d.ts +21 -8
- package/dist/esm/src/caching/Arweave/ArweaveClient.js +119 -89
- package/dist/esm/src/caching/Arweave/ArweaveClient.js.map +1 -1
- package/dist/types/src/caching/Arweave/ArweaveClient.d.ts +21 -8
- package/dist/types/src/caching/Arweave/ArweaveClient.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/caching/Arweave/ArweaveClient.ts +134 -88
|
@@ -2,16 +2,22 @@ import { JWKInterface } from "arweave/node/lib/wallet";
|
|
|
2
2
|
import { Struct } from "superstruct";
|
|
3
3
|
import winston from "winston";
|
|
4
4
|
import { BigNumber } from "../../utils";
|
|
5
|
+
export interface ArweaveGatewayConfig {
|
|
6
|
+
host: string;
|
|
7
|
+
protocol?: string;
|
|
8
|
+
port?: number;
|
|
9
|
+
}
|
|
10
|
+
export declare const DEFAULT_ARWEAVE_GATEWAYS: ArweaveGatewayConfig[];
|
|
5
11
|
export declare class ArweaveClient {
|
|
6
12
|
private arweaveJWT;
|
|
7
13
|
private logger;
|
|
8
|
-
gatewayURL: string;
|
|
9
|
-
protocol: string;
|
|
10
14
|
private readonly retries;
|
|
11
15
|
private readonly retryDelaySeconds;
|
|
12
|
-
private
|
|
13
|
-
|
|
14
|
-
|
|
16
|
+
private gateways;
|
|
17
|
+
constructor(arweaveJWT: JWKInterface, logger: winston.Logger, gateways?: ArweaveGatewayConfig[], retries?: number, retryDelaySeconds?: number);
|
|
18
|
+
private _raceGateways;
|
|
19
|
+
private _failoverGateways;
|
|
20
|
+
private _retryRequest;
|
|
15
21
|
set(value: Record<string, unknown>, topicTag?: string | undefined): Promise<string | undefined>;
|
|
16
22
|
get<T>(transactionID: string, validator: Struct<T>): Promise<T | null>;
|
|
17
23
|
getByTopic<T>(tag: string, validator: Struct<T>, originQueryAddress?: string): Promise<{
|
|
@@ -20,6 +26,5 @@ export declare class ArweaveClient {
|
|
|
20
26
|
}[]>;
|
|
21
27
|
getMetadata(transactionID: string): Promise<Record<string, string> | null>;
|
|
22
28
|
getAddress(): Promise<string>;
|
|
23
|
-
private _retryRequest;
|
|
24
29
|
getBalance(): Promise<BigNumber>;
|
|
25
30
|
}
|
|
@@ -1,83 +1,126 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ArweaveClient = void 0;
|
|
3
|
+
exports.ArweaveClient = exports.DEFAULT_ARWEAVE_GATEWAYS = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const arweave_1 = tslib_1.__importDefault(require("arweave"));
|
|
6
6
|
const superstruct_1 = require("superstruct");
|
|
7
7
|
const constants_1 = require("../../constants");
|
|
8
8
|
const utils_1 = require("../../utils");
|
|
9
|
+
exports.DEFAULT_ARWEAVE_GATEWAYS = [{ host: "arweave.net" }, { host: "ar-io.net" }];
|
|
9
10
|
class ArweaveClient {
|
|
10
11
|
arweaveJWT;
|
|
11
12
|
logger;
|
|
12
|
-
gatewayURL;
|
|
13
|
-
protocol;
|
|
14
13
|
retries;
|
|
15
14
|
retryDelaySeconds;
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
constructor(arweaveJWT, logger, gatewayURL = "arweave.net", protocol = "https", port = 443, retries = 2, retryDelaySeconds = 1) {
|
|
15
|
+
gateways;
|
|
16
|
+
constructor(arweaveJWT, logger, gateways = exports.DEFAULT_ARWEAVE_GATEWAYS, retries = 2, retryDelaySeconds = 1) {
|
|
19
17
|
this.arweaveJWT = arweaveJWT;
|
|
20
18
|
this.logger = logger;
|
|
21
|
-
this.gatewayURL = gatewayURL;
|
|
22
|
-
this.protocol = protocol;
|
|
23
19
|
this.retries = retries;
|
|
24
20
|
this.retryDelaySeconds = retryDelaySeconds;
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
port,
|
|
29
|
-
protocol,
|
|
30
|
-
timeout: 20000,
|
|
31
|
-
logging: false,
|
|
32
|
-
});
|
|
33
|
-
this.logger.debug({
|
|
34
|
-
at: "ArweaveClient:constructor",
|
|
35
|
-
message: "Arweave client initialized",
|
|
36
|
-
gateway: this.gatewayUrl,
|
|
37
|
-
});
|
|
21
|
+
if (gateways.length === 0) {
|
|
22
|
+
throw new Error("At least one gateway must be provided");
|
|
23
|
+
}
|
|
38
24
|
if (this.retries < 0) {
|
|
39
25
|
throw new Error(`retries cannot be < 0 and must be an integer. Currently set to ${this.retries}`);
|
|
40
26
|
}
|
|
41
27
|
if (this.retryDelaySeconds < 0) {
|
|
42
28
|
throw new Error(`delay cannot be < 0. Currently set to ${this.retryDelaySeconds}`);
|
|
43
29
|
}
|
|
30
|
+
this.gateways = gateways.map(({ host, protocol = "https", port = 443 }) => ({
|
|
31
|
+
client: new arweave_1.default({ host, port, protocol, timeout: 20000, logging: false }),
|
|
32
|
+
url: `${protocol}://${host}:${port}`,
|
|
33
|
+
}));
|
|
34
|
+
this.logger.debug({
|
|
35
|
+
at: "ArweaveClient:constructor",
|
|
36
|
+
message: "Arweave client initialized",
|
|
37
|
+
gateways: this.gateways.map((g) => g.url),
|
|
38
|
+
});
|
|
44
39
|
}
|
|
45
|
-
async
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
transaction.addTag("App-Name", constants_1.ARWEAVE_TAG_APP_NAME);
|
|
49
|
-
transaction.addTag("App-Version", constants_1.ARWEAVE_TAG_APP_VERSION.toString());
|
|
50
|
-
if ((0, utils_1.isDefined)(topicTag)) {
|
|
51
|
-
transaction.addTag("Topic", topicTag);
|
|
40
|
+
async _raceGateways(label, fn) {
|
|
41
|
+
try {
|
|
42
|
+
return await Promise.any(this.gateways.map((gw) => this._retryRequest(() => fn(gw), 0)));
|
|
52
43
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
44
|
+
catch (e) {
|
|
45
|
+
if (e instanceof AggregateError) {
|
|
46
|
+
const details = this.gateways.map((gw, i) => `${gw.url}: ${e.errors[i]}`).join("; ");
|
|
47
|
+
throw new Error(`All Arweave gateways failed for ${label}: ${details}`);
|
|
48
|
+
}
|
|
49
|
+
throw e;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
async _failoverGateways(label, fn) {
|
|
53
|
+
const errors = [];
|
|
54
|
+
for (const gw of this.gateways) {
|
|
55
|
+
try {
|
|
56
|
+
return await this._retryRequest(() => fn(gw), 0);
|
|
57
|
+
}
|
|
58
|
+
catch (e) {
|
|
59
|
+
errors.push(e);
|
|
60
|
+
this.logger.debug({
|
|
61
|
+
at: "ArweaveClient:failoverGateways",
|
|
62
|
+
message: `Gateway ${gw.url} failed for ${label}, trying next: ${e}`,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
const details = this.gateways.map((gw, i) => `${gw.url}: ${errors[i]}`).join("; ");
|
|
67
|
+
throw new Error(`All Arweave gateways failed for ${label}: ${details}`);
|
|
68
|
+
}
|
|
69
|
+
async _retryRequest(request, retryCount) {
|
|
70
|
+
try {
|
|
71
|
+
return await request();
|
|
72
|
+
}
|
|
73
|
+
catch (e) {
|
|
74
|
+
if (retryCount < this.retries) {
|
|
75
|
+
const baseDelay = this.retryDelaySeconds * Math.pow(2, retryCount);
|
|
76
|
+
const delayS = baseDelay + baseDelay * Math.random();
|
|
77
|
+
this.logger.debug({
|
|
78
|
+
at: "ArweaveClient:retryRequest",
|
|
79
|
+
message: `Arweave request failed, retrying after waiting ${delayS} seconds: ${e}`,
|
|
80
|
+
retryCount,
|
|
81
|
+
});
|
|
82
|
+
await (0, utils_1.delay)(delayS);
|
|
83
|
+
return this._retryRequest(request, retryCount + 1);
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
throw e;
|
|
87
|
+
}
|
|
66
88
|
}
|
|
67
|
-
|
|
89
|
+
}
|
|
90
|
+
async set(value, topicTag) {
|
|
91
|
+
return await this._failoverGateways("set", async ({ client }) => {
|
|
92
|
+
const transaction = await client.createTransaction({ data: JSON.stringify(value, utils_1.jsonReplacerWithBigNumbers) }, this.arweaveJWT);
|
|
93
|
+
transaction.addTag("Content-Type", "application/json");
|
|
94
|
+
transaction.addTag("App-Name", constants_1.ARWEAVE_TAG_APP_NAME);
|
|
95
|
+
transaction.addTag("App-Version", constants_1.ARWEAVE_TAG_APP_VERSION.toString());
|
|
96
|
+
if ((0, utils_1.isDefined)(topicTag)) {
|
|
97
|
+
transaction.addTag("Topic", topicTag);
|
|
98
|
+
}
|
|
99
|
+
await client.transactions.sign(transaction, this.arweaveJWT);
|
|
100
|
+
const result = await client.transactions.post(transaction);
|
|
101
|
+
if (result.status !== 200) {
|
|
102
|
+
const message = result?.data?.error?.msg ?? "Unknown error";
|
|
103
|
+
this.logger.error({
|
|
104
|
+
at: "ArweaveClient:set",
|
|
105
|
+
message,
|
|
106
|
+
result,
|
|
107
|
+
txn: transaction.id,
|
|
108
|
+
address: await this.getAddress(),
|
|
109
|
+
balance: (await this.getBalance()).toString(),
|
|
110
|
+
});
|
|
111
|
+
throw new Error(message);
|
|
112
|
+
}
|
|
68
113
|
this.logger.debug({
|
|
69
114
|
at: "ArweaveClient:set",
|
|
70
115
|
message: `Arweave transaction posted with ${transaction.id}`,
|
|
71
116
|
});
|
|
72
|
-
|
|
73
|
-
|
|
117
|
+
return transaction.id;
|
|
118
|
+
});
|
|
74
119
|
}
|
|
75
120
|
async get(transactionID, validator) {
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
};
|
|
80
|
-
const data = await this._retryRequest(request, 0);
|
|
121
|
+
const data = await this._raceGateways("get", async ({ url }) => {
|
|
122
|
+
return await (0, utils_1.fetchWithTimeout)(`${url}/${transactionID}`, {}, {}, 20_000);
|
|
123
|
+
});
|
|
81
124
|
try {
|
|
82
125
|
return (0, superstruct_1.create)(data, validator);
|
|
83
126
|
}
|
|
@@ -102,13 +145,13 @@ class ArweaveClient {
|
|
|
102
145
|
]
|
|
103
146
|
) { edges { node { id } } }
|
|
104
147
|
}`;
|
|
105
|
-
const response = await this.
|
|
106
|
-
const response = await
|
|
148
|
+
const response = await this._raceGateways("getByTopic", async ({ client }) => {
|
|
149
|
+
const response = await client.api.post("/graphql", { query });
|
|
107
150
|
if (!response.ok) {
|
|
108
151
|
throw new Error(`Arweave GraphQL request failed with status ${response.status}`);
|
|
109
152
|
}
|
|
110
153
|
return response;
|
|
111
|
-
}
|
|
154
|
+
});
|
|
112
155
|
const entries = response?.data?.data?.transactions?.edges ?? [];
|
|
113
156
|
this.logger.debug({
|
|
114
157
|
at: "ArweaveClient:getByTopic",
|
|
@@ -141,7 +184,9 @@ class ArweaveClient {
|
|
|
141
184
|
return results.filter(utils_1.isDefined);
|
|
142
185
|
}
|
|
143
186
|
async getMetadata(transactionID) {
|
|
144
|
-
const transaction = await this.client
|
|
187
|
+
const transaction = await this._raceGateways("getMetadata", async ({ client }) => {
|
|
188
|
+
return await client.transactions.get(transactionID);
|
|
189
|
+
});
|
|
145
190
|
if (!(0, utils_1.isDefined)(transaction)) {
|
|
146
191
|
return null;
|
|
147
192
|
}
|
|
@@ -156,33 +201,12 @@ class ArweaveClient {
|
|
|
156
201
|
};
|
|
157
202
|
}
|
|
158
203
|
getAddress() {
|
|
159
|
-
return this.client.wallets.jwkToAddress(this.arweaveJWT);
|
|
160
|
-
}
|
|
161
|
-
async _retryRequest(request, retryCount) {
|
|
162
|
-
try {
|
|
163
|
-
return await request();
|
|
164
|
-
}
|
|
165
|
-
catch (e) {
|
|
166
|
-
if (retryCount < this.retries) {
|
|
167
|
-
const baseDelay = this.retryDelaySeconds * Math.pow(2, retryCount);
|
|
168
|
-
const delayS = baseDelay + baseDelay * Math.random();
|
|
169
|
-
this.logger.debug({
|
|
170
|
-
at: "ArweaveClient:retryRequest",
|
|
171
|
-
message: `Arweave request failed, retrying after waiting ${delayS} seconds: ${e}`,
|
|
172
|
-
retryCount,
|
|
173
|
-
});
|
|
174
|
-
await (0, utils_1.delay)(delayS);
|
|
175
|
-
return this._retryRequest(request, retryCount + 1);
|
|
176
|
-
}
|
|
177
|
-
else {
|
|
178
|
-
throw e;
|
|
179
|
-
}
|
|
180
|
-
}
|
|
204
|
+
return this.gateways[0].client.wallets.jwkToAddress(this.arweaveJWT);
|
|
181
205
|
}
|
|
182
206
|
async getBalance() {
|
|
183
207
|
const address = await this.getAddress();
|
|
184
|
-
|
|
185
|
-
const balanceInFloat = await
|
|
208
|
+
return this._raceGateways("getBalance", async ({ client }) => {
|
|
209
|
+
const balanceInFloat = await client.wallets.getBalance(address);
|
|
186
210
|
if (balanceInFloat.includes("e")) {
|
|
187
211
|
const [balance, exponent] = balanceInFloat.split("e");
|
|
188
212
|
const resultingBN = utils_1.BigNumber.from(balance).mul((0, utils_1.toBN)(10).pow(exponent.replace("+", "")));
|
|
@@ -191,8 +215,7 @@ class ArweaveClient {
|
|
|
191
215
|
else {
|
|
192
216
|
return utils_1.BigNumber.from(balanceInFloat);
|
|
193
217
|
}
|
|
194
|
-
};
|
|
195
|
-
return await this._retryRequest(request, 0);
|
|
218
|
+
});
|
|
196
219
|
}
|
|
197
220
|
}
|
|
198
221
|
exports.ArweaveClient = ArweaveClient;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ArweaveClient.js","sourceRoot":"","sources":["../../../../../src/caching/Arweave/ArweaveClient.ts"],"names":[],"mappings":";;;;AAAA,8DAA8B;AAG9B,6CAA6C;AAE7C,+CAAiH;AACjH,uCAA8G;
|
|
1
|
+
{"version":3,"file":"ArweaveClient.js","sourceRoot":"","sources":["../../../../../src/caching/Arweave/ArweaveClient.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,16 +2,30 @@ import { JWKInterface } from "arweave/node/lib/wallet";
|
|
|
2
2
|
import { Struct } from "superstruct";
|
|
3
3
|
import winston from "winston";
|
|
4
4
|
import { BigNumber } from "../../utils";
|
|
5
|
+
export interface ArweaveGatewayConfig {
|
|
6
|
+
host: string;
|
|
7
|
+
protocol?: string;
|
|
8
|
+
port?: number;
|
|
9
|
+
}
|
|
10
|
+
export declare const DEFAULT_ARWEAVE_GATEWAYS: ArweaveGatewayConfig[];
|
|
5
11
|
export declare class ArweaveClient {
|
|
6
12
|
private arweaveJWT;
|
|
7
13
|
private logger;
|
|
8
|
-
gatewayURL: string;
|
|
9
|
-
protocol: string;
|
|
10
14
|
private readonly retries;
|
|
11
15
|
private readonly retryDelaySeconds;
|
|
12
|
-
private
|
|
13
|
-
|
|
14
|
-
|
|
16
|
+
private gateways;
|
|
17
|
+
constructor(arweaveJWT: JWKInterface, logger: winston.Logger, gateways?: ArweaveGatewayConfig[], retries?: number, retryDelaySeconds?: number);
|
|
18
|
+
/**
|
|
19
|
+
* Races a request across all gateways, returning the first successful response.
|
|
20
|
+
* If all gateways fail, throws an error with details from each gateway.
|
|
21
|
+
*/
|
|
22
|
+
private _raceGateways;
|
|
23
|
+
/**
|
|
24
|
+
* Tries gateways sequentially, returning the first successful response.
|
|
25
|
+
* Used for write operations where we want exactly one successful submission.
|
|
26
|
+
*/
|
|
27
|
+
private _failoverGateways;
|
|
28
|
+
private _retryRequest;
|
|
15
29
|
/**
|
|
16
30
|
* Stores an arbitrary record in the Arweave network. The record is stored as a JSON string and uses
|
|
17
31
|
* JSON.stringify to convert the record to a string. The record has all of its big numbers converted
|
|
@@ -19,7 +33,6 @@ export declare class ArweaveClient {
|
|
|
19
33
|
* @param value The value to store
|
|
20
34
|
* @param topicTag An optional topic tag to add to the transaction
|
|
21
35
|
* @returns The transaction ID of the stored value
|
|
22
|
-
* @
|
|
23
36
|
*/
|
|
24
37
|
set(value: Record<string, unknown>, topicTag?: string | undefined): Promise<string | undefined>;
|
|
25
38
|
/**
|
|
@@ -53,11 +66,11 @@ export declare class ArweaveClient {
|
|
|
53
66
|
*/
|
|
54
67
|
getMetadata(transactionID: string): Promise<Record<string, string> | null>;
|
|
55
68
|
/**
|
|
56
|
-
* Returns the address of the signer of the JWT
|
|
69
|
+
* Returns the address of the signer of the JWT. This is a local crypto
|
|
70
|
+
* operation and does not require a network call.
|
|
57
71
|
* @returns The address of the signer in this client
|
|
58
72
|
*/
|
|
59
73
|
getAddress(): Promise<string>;
|
|
60
|
-
private _retryRequest;
|
|
61
74
|
/**
|
|
62
75
|
* The balance of the signer
|
|
63
76
|
* @returns The balance of the signer in winston units
|
|
@@ -2,41 +2,95 @@ import Arweave from "arweave";
|
|
|
2
2
|
import { create } from "superstruct";
|
|
3
3
|
import { ARWEAVE_TAG_APP_NAME, ARWEAVE_TAG_APP_VERSION, DEFAULT_ARWEAVE_STORAGE_ADDRESS } from "../../constants";
|
|
4
4
|
import { BigNumber, delay, fetchWithTimeout, isDefined, jsonReplacerWithBigNumbers, toBN } from "../../utils";
|
|
5
|
+
export const DEFAULT_ARWEAVE_GATEWAYS = [{ host: "arweave.net" }, { host: "ar-io.net" }];
|
|
5
6
|
export class ArweaveClient {
|
|
6
7
|
arweaveJWT;
|
|
7
8
|
logger;
|
|
8
|
-
gatewayURL;
|
|
9
|
-
protocol;
|
|
10
9
|
retries;
|
|
11
10
|
retryDelaySeconds;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
constructor(arweaveJWT, logger, gatewayURL = "arweave.net", protocol = "https", port = 443, retries = 2, retryDelaySeconds = 1) {
|
|
11
|
+
gateways;
|
|
12
|
+
constructor(arweaveJWT, logger, gateways = DEFAULT_ARWEAVE_GATEWAYS, retries = 2, retryDelaySeconds = 1) {
|
|
15
13
|
this.arweaveJWT = arweaveJWT;
|
|
16
14
|
this.logger = logger;
|
|
17
|
-
this.gatewayURL = gatewayURL;
|
|
18
|
-
this.protocol = protocol;
|
|
19
15
|
this.retries = retries;
|
|
20
16
|
this.retryDelaySeconds = retryDelaySeconds;
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
port,
|
|
25
|
-
protocol,
|
|
26
|
-
timeout: 20000,
|
|
27
|
-
logging: false,
|
|
28
|
-
});
|
|
29
|
-
this.logger.debug({
|
|
30
|
-
at: "ArweaveClient:constructor",
|
|
31
|
-
message: "Arweave client initialized",
|
|
32
|
-
gateway: this.gatewayUrl,
|
|
33
|
-
});
|
|
17
|
+
if (gateways.length === 0) {
|
|
18
|
+
throw new Error("At least one gateway must be provided");
|
|
19
|
+
}
|
|
34
20
|
if (this.retries < 0) {
|
|
35
21
|
throw new Error(`retries cannot be < 0 and must be an integer. Currently set to ${this.retries}`);
|
|
36
22
|
}
|
|
37
23
|
if (this.retryDelaySeconds < 0) {
|
|
38
24
|
throw new Error(`delay cannot be < 0. Currently set to ${this.retryDelaySeconds}`);
|
|
39
25
|
}
|
|
26
|
+
this.gateways = gateways.map(({ host, protocol = "https", port = 443 }) => ({
|
|
27
|
+
client: new Arweave({ host, port, protocol, timeout: 20000, logging: false }),
|
|
28
|
+
url: `${protocol}://${host}:${port}`,
|
|
29
|
+
}));
|
|
30
|
+
this.logger.debug({
|
|
31
|
+
at: "ArweaveClient:constructor",
|
|
32
|
+
message: "Arweave client initialized",
|
|
33
|
+
gateways: this.gateways.map((g) => g.url),
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Races a request across all gateways, returning the first successful response.
|
|
38
|
+
* If all gateways fail, throws an error with details from each gateway.
|
|
39
|
+
*/
|
|
40
|
+
async _raceGateways(label, fn) {
|
|
41
|
+
try {
|
|
42
|
+
return await Promise.any(this.gateways.map((gw) => this._retryRequest(() => fn(gw), 0)));
|
|
43
|
+
}
|
|
44
|
+
catch (e) {
|
|
45
|
+
if (e instanceof AggregateError) {
|
|
46
|
+
const details = this.gateways.map((gw, i) => `${gw.url}: ${e.errors[i]}`).join("; ");
|
|
47
|
+
throw new Error(`All Arweave gateways failed for ${label}: ${details}`);
|
|
48
|
+
}
|
|
49
|
+
throw e;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Tries gateways sequentially, returning the first successful response.
|
|
54
|
+
* Used for write operations where we want exactly one successful submission.
|
|
55
|
+
*/
|
|
56
|
+
async _failoverGateways(label, fn) {
|
|
57
|
+
const errors = [];
|
|
58
|
+
for (const gw of this.gateways) {
|
|
59
|
+
try {
|
|
60
|
+
return await this._retryRequest(() => fn(gw), 0);
|
|
61
|
+
}
|
|
62
|
+
catch (e) {
|
|
63
|
+
errors.push(e);
|
|
64
|
+
this.logger.debug({
|
|
65
|
+
at: "ArweaveClient:failoverGateways",
|
|
66
|
+
message: `Gateway ${gw.url} failed for ${label}, trying next: ${e}`,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
const details = this.gateways.map((gw, i) => `${gw.url}: ${errors[i]}`).join("; ");
|
|
71
|
+
throw new Error(`All Arweave gateways failed for ${label}: ${details}`);
|
|
72
|
+
}
|
|
73
|
+
async _retryRequest(request, retryCount) {
|
|
74
|
+
try {
|
|
75
|
+
return await request();
|
|
76
|
+
}
|
|
77
|
+
catch (e) {
|
|
78
|
+
if (retryCount < this.retries) {
|
|
79
|
+
// Implement a slightly aggressive exponential backoff to account for fierce parallelism.
|
|
80
|
+
const baseDelay = this.retryDelaySeconds * Math.pow(2, retryCount);
|
|
81
|
+
const delayS = baseDelay + baseDelay * Math.random();
|
|
82
|
+
this.logger.debug({
|
|
83
|
+
at: "ArweaveClient:retryRequest",
|
|
84
|
+
message: `Arweave request failed, retrying after waiting ${delayS} seconds: ${e}`,
|
|
85
|
+
retryCount,
|
|
86
|
+
});
|
|
87
|
+
await delay(delayS);
|
|
88
|
+
return this._retryRequest(request, retryCount + 1);
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
throw e;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
40
94
|
}
|
|
41
95
|
/**
|
|
42
96
|
* Stores an arbitrary record in the Arweave network. The record is stored as a JSON string and uses
|
|
@@ -45,41 +99,40 @@ export class ArweaveClient {
|
|
|
45
99
|
* @param value The value to store
|
|
46
100
|
* @param topicTag An optional topic tag to add to the transaction
|
|
47
101
|
* @returns The transaction ID of the stored value
|
|
48
|
-
* @
|
|
49
102
|
*/
|
|
50
103
|
async set(value, topicTag) {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
104
|
+
return await this._failoverGateways("set", async ({ client }) => {
|
|
105
|
+
const transaction = await client.createTransaction({ data: JSON.stringify(value, jsonReplacerWithBigNumbers) }, this.arweaveJWT);
|
|
106
|
+
// Add tags to the transaction
|
|
107
|
+
transaction.addTag("Content-Type", "application/json");
|
|
108
|
+
transaction.addTag("App-Name", ARWEAVE_TAG_APP_NAME);
|
|
109
|
+
transaction.addTag("App-Version", ARWEAVE_TAG_APP_VERSION.toString());
|
|
110
|
+
if (isDefined(topicTag)) {
|
|
111
|
+
transaction.addTag("Topic", topicTag);
|
|
112
|
+
}
|
|
113
|
+
// Sign the transaction
|
|
114
|
+
await client.transactions.sign(transaction, this.arweaveJWT);
|
|
115
|
+
// Send the transaction
|
|
116
|
+
const result = await client.transactions.post(transaction);
|
|
117
|
+
// Ensure that the result is successful
|
|
118
|
+
if (result.status !== 200) {
|
|
119
|
+
const message = result?.data?.error?.msg ?? "Unknown error";
|
|
120
|
+
this.logger.error({
|
|
121
|
+
at: "ArweaveClient:set",
|
|
122
|
+
message,
|
|
123
|
+
result,
|
|
124
|
+
txn: transaction.id,
|
|
125
|
+
address: await this.getAddress(),
|
|
126
|
+
balance: (await this.getBalance()).toString(),
|
|
127
|
+
});
|
|
128
|
+
throw new Error(message);
|
|
129
|
+
}
|
|
77
130
|
this.logger.debug({
|
|
78
131
|
at: "ArweaveClient:set",
|
|
79
132
|
message: `Arweave transaction posted with ${transaction.id}`,
|
|
80
133
|
});
|
|
81
|
-
|
|
82
|
-
|
|
134
|
+
return transaction.id;
|
|
135
|
+
});
|
|
83
136
|
}
|
|
84
137
|
/**
|
|
85
138
|
* Retrieves a record from the Arweave network. The record is expected to be a JSON string and is
|
|
@@ -89,15 +142,12 @@ export class ArweaveClient {
|
|
|
89
142
|
* @returns The record if it exists, otherwise null
|
|
90
143
|
*/
|
|
91
144
|
async get(transactionID, validator) {
|
|
92
|
-
//
|
|
93
|
-
const transactionUrl = `${this.gatewayUrl}/${transactionID}`;
|
|
94
|
-
// We should query in via Axios directly to the gateway URL. The reasoning behind this is
|
|
145
|
+
// We query via fetchWithTimeout directly to the gateway URL. The reasoning behind this is
|
|
95
146
|
// that the Arweave SDK's `getData` method is too slow and does not provide a way to set a timeout.
|
|
96
147
|
// Therefore, something that could take milliseconds to complete could take tens of minutes.
|
|
97
|
-
const
|
|
98
|
-
return await fetchWithTimeout(
|
|
99
|
-
};
|
|
100
|
-
const data = await this._retryRequest(request, 0);
|
|
148
|
+
const data = await this._raceGateways("get", async ({ url }) => {
|
|
149
|
+
return await fetchWithTimeout(`${url}/${transactionID}`, {}, {}, 20_000);
|
|
150
|
+
});
|
|
101
151
|
try {
|
|
102
152
|
// We should validate the data and perform any logical coercion here.
|
|
103
153
|
return create(data, validator);
|
|
@@ -136,13 +186,13 @@ export class ArweaveClient {
|
|
|
136
186
|
]
|
|
137
187
|
) { edges { node { id } } }
|
|
138
188
|
}`;
|
|
139
|
-
const response = await this.
|
|
140
|
-
const response = await
|
|
189
|
+
const response = await this._raceGateways("getByTopic", async ({ client }) => {
|
|
190
|
+
const response = await client.api.post("/graphql", { query });
|
|
141
191
|
if (!response.ok) {
|
|
142
192
|
throw new Error(`Arweave GraphQL request failed with status ${response.status}`);
|
|
143
193
|
}
|
|
144
194
|
return response;
|
|
145
|
-
}
|
|
195
|
+
});
|
|
146
196
|
const entries = response?.data?.data?.transactions?.edges ?? [];
|
|
147
197
|
this.logger.debug({
|
|
148
198
|
at: "ArweaveClient:getByTopic",
|
|
@@ -180,7 +230,9 @@ export class ArweaveClient {
|
|
|
180
230
|
* @returns The metadata of the transaction if it exists, otherwise null
|
|
181
231
|
*/
|
|
182
232
|
async getMetadata(transactionID) {
|
|
183
|
-
const transaction = await this.client
|
|
233
|
+
const transaction = await this._raceGateways("getMetadata", async ({ client }) => {
|
|
234
|
+
return await client.transactions.get(transactionID);
|
|
235
|
+
});
|
|
184
236
|
if (!isDefined(transaction)) {
|
|
185
237
|
return null;
|
|
186
238
|
}
|
|
@@ -195,33 +247,12 @@ export class ArweaveClient {
|
|
|
195
247
|
};
|
|
196
248
|
}
|
|
197
249
|
/**
|
|
198
|
-
* Returns the address of the signer of the JWT
|
|
250
|
+
* Returns the address of the signer of the JWT. This is a local crypto
|
|
251
|
+
* operation and does not require a network call.
|
|
199
252
|
* @returns The address of the signer in this client
|
|
200
253
|
*/
|
|
201
254
|
getAddress() {
|
|
202
|
-
return this.client.wallets.jwkToAddress(this.arweaveJWT);
|
|
203
|
-
}
|
|
204
|
-
async _retryRequest(request, retryCount) {
|
|
205
|
-
try {
|
|
206
|
-
return await request();
|
|
207
|
-
}
|
|
208
|
-
catch (e) {
|
|
209
|
-
if (retryCount < this.retries) {
|
|
210
|
-
// Implement a slightly aggressive exponential backoff to account for fierce parallelism.
|
|
211
|
-
const baseDelay = this.retryDelaySeconds * Math.pow(2, retryCount); // ms; attempt = [0, 1, 2, ...]
|
|
212
|
-
const delayS = baseDelay + baseDelay * Math.random();
|
|
213
|
-
this.logger.debug({
|
|
214
|
-
at: "ArweaveClient:retryRequest",
|
|
215
|
-
message: `Arweave request failed, retrying after waiting ${delayS} seconds: ${e}`,
|
|
216
|
-
retryCount,
|
|
217
|
-
});
|
|
218
|
-
await delay(delayS);
|
|
219
|
-
return this._retryRequest(request, retryCount + 1);
|
|
220
|
-
}
|
|
221
|
-
else {
|
|
222
|
-
throw e;
|
|
223
|
-
}
|
|
224
|
-
}
|
|
255
|
+
return this.gateways[0].client.wallets.jwkToAddress(this.arweaveJWT);
|
|
225
256
|
}
|
|
226
257
|
/**
|
|
227
258
|
* The balance of the signer
|
|
@@ -229,9 +260,9 @@ export class ArweaveClient {
|
|
|
229
260
|
*/
|
|
230
261
|
async getBalance() {
|
|
231
262
|
const address = await this.getAddress();
|
|
232
|
-
|
|
233
|
-
const balanceInFloat = await
|
|
234
|
-
// @dev The reason we add in the BN.from
|
|
263
|
+
return this._raceGateways("getBalance", async ({ client }) => {
|
|
264
|
+
const balanceInFloat = await client.wallets.getBalance(address);
|
|
265
|
+
// @dev The reason we add in the BN.from here is because the client.getBalance call
|
|
235
266
|
// does not correctly throw an error if the request fails, instead it will return the error string as the
|
|
236
267
|
// balanceInFloat.
|
|
237
268
|
// Sometimes the balance is returned in scientific notation, so we need to
|
|
@@ -244,8 +275,7 @@ export class ArweaveClient {
|
|
|
244
275
|
else {
|
|
245
276
|
return BigNumber.from(balanceInFloat);
|
|
246
277
|
}
|
|
247
|
-
};
|
|
248
|
-
return await this._retryRequest(request, 0);
|
|
278
|
+
});
|
|
249
279
|
}
|
|
250
280
|
}
|
|
251
281
|
//# sourceMappingURL=ArweaveClient.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ArweaveClient.js","sourceRoot":"","sources":["../../../../../src/caching/Arweave/ArweaveClient.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;AAG9B,OAAO,EAAU,MAAM,EAAE,MAAM,aAAa,CAAC;AAE7C,OAAO,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,+BAA+B,EAAE,MAAM,iBAAiB,CAAC;AACjH,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,gBAAgB,EAAE,SAAS,EAAE,0BAA0B,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"ArweaveClient.js","sourceRoot":"","sources":["../../../../../src/caching/Arweave/ArweaveClient.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,16 +2,30 @@ import { JWKInterface } from "arweave/node/lib/wallet";
|
|
|
2
2
|
import { Struct } from "superstruct";
|
|
3
3
|
import winston from "winston";
|
|
4
4
|
import { BigNumber } from "../../utils";
|
|
5
|
+
export interface ArweaveGatewayConfig {
|
|
6
|
+
host: string;
|
|
7
|
+
protocol?: string;
|
|
8
|
+
port?: number;
|
|
9
|
+
}
|
|
10
|
+
export declare const DEFAULT_ARWEAVE_GATEWAYS: ArweaveGatewayConfig[];
|
|
5
11
|
export declare class ArweaveClient {
|
|
6
12
|
private arweaveJWT;
|
|
7
13
|
private logger;
|
|
8
|
-
gatewayURL: string;
|
|
9
|
-
protocol: string;
|
|
10
14
|
private readonly retries;
|
|
11
15
|
private readonly retryDelaySeconds;
|
|
12
|
-
private
|
|
13
|
-
|
|
14
|
-
|
|
16
|
+
private gateways;
|
|
17
|
+
constructor(arweaveJWT: JWKInterface, logger: winston.Logger, gateways?: ArweaveGatewayConfig[], retries?: number, retryDelaySeconds?: number);
|
|
18
|
+
/**
|
|
19
|
+
* Races a request across all gateways, returning the first successful response.
|
|
20
|
+
* If all gateways fail, throws an error with details from each gateway.
|
|
21
|
+
*/
|
|
22
|
+
private _raceGateways;
|
|
23
|
+
/**
|
|
24
|
+
* Tries gateways sequentially, returning the first successful response.
|
|
25
|
+
* Used for write operations where we want exactly one successful submission.
|
|
26
|
+
*/
|
|
27
|
+
private _failoverGateways;
|
|
28
|
+
private _retryRequest;
|
|
15
29
|
/**
|
|
16
30
|
* Stores an arbitrary record in the Arweave network. The record is stored as a JSON string and uses
|
|
17
31
|
* JSON.stringify to convert the record to a string. The record has all of its big numbers converted
|
|
@@ -19,7 +33,6 @@ export declare class ArweaveClient {
|
|
|
19
33
|
* @param value The value to store
|
|
20
34
|
* @param topicTag An optional topic tag to add to the transaction
|
|
21
35
|
* @returns The transaction ID of the stored value
|
|
22
|
-
* @
|
|
23
36
|
*/
|
|
24
37
|
set(value: Record<string, unknown>, topicTag?: string | undefined): Promise<string | undefined>;
|
|
25
38
|
/**
|
|
@@ -53,11 +66,11 @@ export declare class ArweaveClient {
|
|
|
53
66
|
*/
|
|
54
67
|
getMetadata(transactionID: string): Promise<Record<string, string> | null>;
|
|
55
68
|
/**
|
|
56
|
-
* Returns the address of the signer of the JWT
|
|
69
|
+
* Returns the address of the signer of the JWT. This is a local crypto
|
|
70
|
+
* operation and does not require a network call.
|
|
57
71
|
* @returns The address of the signer in this client
|
|
58
72
|
*/
|
|
59
73
|
getAddress(): Promise<string>;
|
|
60
|
-
private _retryRequest;
|
|
61
74
|
/**
|
|
62
75
|
* The balance of the signer
|
|
63
76
|
* @returns The balance of the signer in winston units
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ArweaveClient.d.ts","sourceRoot":"","sources":["../../../../../src/caching/Arweave/ArweaveClient.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAEvD,OAAO,EAAE,MAAM,EAAU,MAAM,aAAa,CAAC;AAC7C,OAAO,OAAO,MAAM,SAAS,CAAC;AAE9B,OAAO,EAAE,SAAS,EAAwE,MAAM,aAAa,CAAC;AAE9G,
|
|
1
|
+
{"version":3,"file":"ArweaveClient.d.ts","sourceRoot":"","sources":["../../../../../src/caching/Arweave/ArweaveClient.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAEvD,OAAO,EAAE,MAAM,EAAU,MAAM,aAAa,CAAC;AAC7C,OAAO,OAAO,MAAM,SAAS,CAAC;AAE9B,OAAO,EAAE,SAAS,EAAwE,MAAM,aAAa,CAAC;AAE9G,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,eAAO,MAAM,wBAAwB,EAAE,oBAAoB,EAAqD,CAAC;AAOjH,qBAAa,aAAa;IAItB,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,MAAM;IAEd,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAPpC,OAAO,CAAC,QAAQ,CAAY;gBAGlB,UAAU,EAAE,YAAY,EACxB,MAAM,EAAE,OAAO,CAAC,MAAM,EAC9B,QAAQ,GAAE,oBAAoB,EAA6B,EAC1C,OAAO,SAAI,EACX,iBAAiB,SAAI;IAsBxC;;;OAGG;YACW,aAAa;IAY3B;;;OAGG;YACW,iBAAiB;YAiBjB,aAAa;IAqB3B;;;;;;;OAOG;IACG,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IA0CrG;;;;;;OAMG;IACG,GAAG,CAAC,CAAC,EAAE,aAAa,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;IAoB5E;;;;;;;;;;;OAWG;IACG,UAAU,CAAC,CAAC,EAChB,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,EACpB,kBAAkB,SAAkC,GACnD,OAAO,CAAC;QAAE,IAAI,EAAE,CAAC,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAyDvC;;;;OAIG;IACG,WAAW,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC;IAoBhF;;;;OAIG;IACH,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC;IAI7B;;;OAGG;IACG,UAAU,IAAI,OAAO,CAAC,SAAS,CAAC;CAkBvC"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@across-protocol/sdk",
|
|
3
3
|
"author": "UMA Team",
|
|
4
|
-
"version": "4.3.143-alpha.
|
|
4
|
+
"version": "4.3.143-alpha.1",
|
|
5
5
|
"license": "AGPL-3.0",
|
|
6
6
|
"homepage": "https://docs.across.to/reference/sdk",
|
|
7
7
|
"repository": {
|
|
@@ -81,7 +81,7 @@
|
|
|
81
81
|
},
|
|
82
82
|
"dependencies": {
|
|
83
83
|
"@across-protocol/constants": "^3.1.109",
|
|
84
|
-
"@across-protocol/contracts": "5.0.
|
|
84
|
+
"@across-protocol/contracts": "5.0.6",
|
|
85
85
|
"@coral-xyz/anchor": "^0.30.1",
|
|
86
86
|
"@eth-optimism/sdk": "^3.3.1",
|
|
87
87
|
"@ethersproject/bignumber": "^5.7.0",
|
|
@@ -6,38 +6,105 @@ import winston from "winston";
|
|
|
6
6
|
import { ARWEAVE_TAG_APP_NAME, ARWEAVE_TAG_APP_VERSION, DEFAULT_ARWEAVE_STORAGE_ADDRESS } from "../../constants";
|
|
7
7
|
import { BigNumber, delay, fetchWithTimeout, isDefined, jsonReplacerWithBigNumbers, toBN } from "../../utils";
|
|
8
8
|
|
|
9
|
+
export interface ArweaveGatewayConfig {
|
|
10
|
+
host: string;
|
|
11
|
+
protocol?: string;
|
|
12
|
+
port?: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const DEFAULT_ARWEAVE_GATEWAYS: ArweaveGatewayConfig[] = [{ host: "arweave.net" }, { host: "ar-io.net" }];
|
|
16
|
+
|
|
17
|
+
interface Gateway {
|
|
18
|
+
client: Arweave;
|
|
19
|
+
url: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
9
22
|
export class ArweaveClient {
|
|
10
|
-
private
|
|
11
|
-
private gatewayUrl: string;
|
|
23
|
+
private gateways: Gateway[];
|
|
12
24
|
|
|
13
25
|
public constructor(
|
|
14
26
|
private arweaveJWT: JWKInterface,
|
|
15
27
|
private logger: winston.Logger,
|
|
16
|
-
|
|
17
|
-
public protocol = "https",
|
|
18
|
-
port = 443,
|
|
28
|
+
gateways: ArweaveGatewayConfig[] = DEFAULT_ARWEAVE_GATEWAYS,
|
|
19
29
|
private readonly retries = 2,
|
|
20
30
|
private readonly retryDelaySeconds = 1
|
|
21
31
|
) {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
port,
|
|
26
|
-
protocol,
|
|
27
|
-
timeout: 20000,
|
|
28
|
-
logging: false,
|
|
29
|
-
});
|
|
30
|
-
this.logger.debug({
|
|
31
|
-
at: "ArweaveClient:constructor",
|
|
32
|
-
message: "Arweave client initialized",
|
|
33
|
-
gateway: this.gatewayUrl,
|
|
34
|
-
});
|
|
32
|
+
if (gateways.length === 0) {
|
|
33
|
+
throw new Error("At least one gateway must be provided");
|
|
34
|
+
}
|
|
35
35
|
if (this.retries < 0) {
|
|
36
36
|
throw new Error(`retries cannot be < 0 and must be an integer. Currently set to ${this.retries}`);
|
|
37
37
|
}
|
|
38
38
|
if (this.retryDelaySeconds < 0) {
|
|
39
39
|
throw new Error(`delay cannot be < 0. Currently set to ${this.retryDelaySeconds}`);
|
|
40
40
|
}
|
|
41
|
+
this.gateways = gateways.map(({ host, protocol = "https", port = 443 }) => ({
|
|
42
|
+
client: new Arweave({ host, port, protocol, timeout: 20000, logging: false }),
|
|
43
|
+
url: `${protocol}://${host}:${port}`,
|
|
44
|
+
}));
|
|
45
|
+
this.logger.debug({
|
|
46
|
+
at: "ArweaveClient:constructor",
|
|
47
|
+
message: "Arweave client initialized",
|
|
48
|
+
gateways: this.gateways.map((g) => g.url),
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Races a request across all gateways, returning the first successful response.
|
|
54
|
+
* If all gateways fail, throws an error with details from each gateway.
|
|
55
|
+
*/
|
|
56
|
+
private async _raceGateways<T>(label: string, fn: (gw: Gateway) => Promise<T>): Promise<T> {
|
|
57
|
+
try {
|
|
58
|
+
return await Promise.any(this.gateways.map((gw) => this._retryRequest(() => fn(gw), 0)));
|
|
59
|
+
} catch (e) {
|
|
60
|
+
if (e instanceof AggregateError) {
|
|
61
|
+
const details = this.gateways.map((gw, i) => `${gw.url}: ${e.errors[i]}`).join("; ");
|
|
62
|
+
throw new Error(`All Arweave gateways failed for ${label}: ${details}`);
|
|
63
|
+
}
|
|
64
|
+
throw e;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Tries gateways sequentially, returning the first successful response.
|
|
70
|
+
* Used for write operations where we want exactly one successful submission.
|
|
71
|
+
*/
|
|
72
|
+
private async _failoverGateways<T>(label: string, fn: (gw: Gateway) => Promise<T>): Promise<T> {
|
|
73
|
+
const errors: Error[] = [];
|
|
74
|
+
for (const gw of this.gateways) {
|
|
75
|
+
try {
|
|
76
|
+
return await this._retryRequest(() => fn(gw), 0);
|
|
77
|
+
} catch (e) {
|
|
78
|
+
errors.push(e as Error);
|
|
79
|
+
this.logger.debug({
|
|
80
|
+
at: "ArweaveClient:failoverGateways",
|
|
81
|
+
message: `Gateway ${gw.url} failed for ${label}, trying next: ${e}`,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
const details = this.gateways.map((gw, i) => `${gw.url}: ${errors[i]}`).join("; ");
|
|
86
|
+
throw new Error(`All Arweave gateways failed for ${label}: ${details}`);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
private async _retryRequest<T>(request: () => Promise<T>, retryCount: number): Promise<T> {
|
|
90
|
+
try {
|
|
91
|
+
return await request();
|
|
92
|
+
} catch (e) {
|
|
93
|
+
if (retryCount < this.retries) {
|
|
94
|
+
// Implement a slightly aggressive exponential backoff to account for fierce parallelism.
|
|
95
|
+
const baseDelay = this.retryDelaySeconds * Math.pow(2, retryCount);
|
|
96
|
+
const delayS = baseDelay + baseDelay * Math.random();
|
|
97
|
+
this.logger.debug({
|
|
98
|
+
at: "ArweaveClient:retryRequest",
|
|
99
|
+
message: `Arweave request failed, retrying after waiting ${delayS} seconds: ${e}`,
|
|
100
|
+
retryCount,
|
|
101
|
+
});
|
|
102
|
+
await delay(delayS);
|
|
103
|
+
return this._retryRequest(request, retryCount + 1);
|
|
104
|
+
} else {
|
|
105
|
+
throw e;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
41
108
|
}
|
|
42
109
|
|
|
43
110
|
/**
|
|
@@ -47,46 +114,47 @@ export class ArweaveClient {
|
|
|
47
114
|
* @param value The value to store
|
|
48
115
|
* @param topicTag An optional topic tag to add to the transaction
|
|
49
116
|
* @returns The transaction ID of the stored value
|
|
50
|
-
* @
|
|
51
117
|
*/
|
|
52
118
|
async set(value: Record<string, unknown>, topicTag?: string | undefined): Promise<string | undefined> {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
119
|
+
return await this._failoverGateways("set", async ({ client }) => {
|
|
120
|
+
const transaction = await client.createTransaction(
|
|
121
|
+
{ data: JSON.stringify(value, jsonReplacerWithBigNumbers) },
|
|
122
|
+
this.arweaveJWT
|
|
123
|
+
);
|
|
57
124
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
125
|
+
// Add tags to the transaction
|
|
126
|
+
transaction.addTag("Content-Type", "application/json");
|
|
127
|
+
transaction.addTag("App-Name", ARWEAVE_TAG_APP_NAME);
|
|
128
|
+
transaction.addTag("App-Version", ARWEAVE_TAG_APP_VERSION.toString());
|
|
129
|
+
if (isDefined(topicTag)) {
|
|
130
|
+
transaction.addTag("Topic", topicTag);
|
|
131
|
+
}
|
|
65
132
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
133
|
+
// Sign the transaction
|
|
134
|
+
await client.transactions.sign(transaction, this.arweaveJWT);
|
|
135
|
+
// Send the transaction
|
|
136
|
+
const result = await client.transactions.post(transaction);
|
|
137
|
+
|
|
138
|
+
// Ensure that the result is successful
|
|
139
|
+
if (result.status !== 200) {
|
|
140
|
+
const message = result?.data?.error?.msg ?? "Unknown error";
|
|
141
|
+
this.logger.error({
|
|
142
|
+
at: "ArweaveClient:set",
|
|
143
|
+
message,
|
|
144
|
+
result,
|
|
145
|
+
txn: transaction.id,
|
|
146
|
+
address: await this.getAddress(),
|
|
147
|
+
balance: (await this.getBalance()).toString(),
|
|
148
|
+
});
|
|
149
|
+
throw new Error(message);
|
|
150
|
+
}
|
|
70
151
|
|
|
71
|
-
// Ensure that the result is successful
|
|
72
|
-
if (result.status !== 200) {
|
|
73
|
-
const message = result?.data?.error?.msg ?? "Unknown error";
|
|
74
|
-
this.logger.error({
|
|
75
|
-
at: "ArweaveClient:set",
|
|
76
|
-
message,
|
|
77
|
-
result,
|
|
78
|
-
txn: transaction.id,
|
|
79
|
-
address: await this.getAddress(),
|
|
80
|
-
balance: (await this.getBalance()).toString(),
|
|
81
|
-
});
|
|
82
|
-
throw new Error(message);
|
|
83
|
-
} else {
|
|
84
152
|
this.logger.debug({
|
|
85
153
|
at: "ArweaveClient:set",
|
|
86
154
|
message: `Arweave transaction posted with ${transaction.id}`,
|
|
87
155
|
});
|
|
88
|
-
|
|
89
|
-
|
|
156
|
+
return transaction.id;
|
|
157
|
+
});
|
|
90
158
|
}
|
|
91
159
|
|
|
92
160
|
/**
|
|
@@ -97,15 +165,12 @@ export class ArweaveClient {
|
|
|
97
165
|
* @returns The record if it exists, otherwise null
|
|
98
166
|
*/
|
|
99
167
|
async get<T>(transactionID: string, validator: Struct<T>): Promise<T | null> {
|
|
100
|
-
//
|
|
101
|
-
const transactionUrl = `${this.gatewayUrl}/${transactionID}`;
|
|
102
|
-
// We should query in via Axios directly to the gateway URL. The reasoning behind this is
|
|
168
|
+
// We query via fetchWithTimeout directly to the gateway URL. The reasoning behind this is
|
|
103
169
|
// that the Arweave SDK's `getData` method is too slow and does not provide a way to set a timeout.
|
|
104
170
|
// Therefore, something that could take milliseconds to complete could take tens of minutes.
|
|
105
|
-
const
|
|
106
|
-
return await fetchWithTimeout(
|
|
107
|
-
};
|
|
108
|
-
const data = await this._retryRequest(request, 0);
|
|
171
|
+
const data = await this._raceGateways("get", async ({ url }) => {
|
|
172
|
+
return await fetchWithTimeout(`${url}/${transactionID}`, {}, {}, 20_000);
|
|
173
|
+
});
|
|
109
174
|
try {
|
|
110
175
|
// We should validate the data and perform any logical coercion here.
|
|
111
176
|
return create(data, validator);
|
|
@@ -149,15 +214,15 @@ export class ArweaveClient {
|
|
|
149
214
|
) { edges { node { id } } }
|
|
150
215
|
}`;
|
|
151
216
|
|
|
152
|
-
const response = await this.
|
|
153
|
-
const response = await
|
|
217
|
+
const response = await this._raceGateways("getByTopic", async ({ client }) => {
|
|
218
|
+
const response = await client.api.post<{
|
|
154
219
|
data: { transactions: { edges: { node: { id: string } }[] } };
|
|
155
220
|
}>("/graphql", { query });
|
|
156
221
|
if (!response.ok) {
|
|
157
222
|
throw new Error(`Arweave GraphQL request failed with status ${response.status}`);
|
|
158
223
|
}
|
|
159
224
|
return response;
|
|
160
|
-
}
|
|
225
|
+
});
|
|
161
226
|
|
|
162
227
|
const entries = response?.data?.data?.transactions?.edges ?? [];
|
|
163
228
|
this.logger.debug({
|
|
@@ -198,7 +263,9 @@ export class ArweaveClient {
|
|
|
198
263
|
* @returns The metadata of the transaction if it exists, otherwise null
|
|
199
264
|
*/
|
|
200
265
|
async getMetadata(transactionID: string): Promise<Record<string, string> | null> {
|
|
201
|
-
const transaction = await this.client
|
|
266
|
+
const transaction = await this._raceGateways("getMetadata", async ({ client }) => {
|
|
267
|
+
return await client.transactions.get(transactionID);
|
|
268
|
+
});
|
|
202
269
|
if (!isDefined(transaction)) {
|
|
203
270
|
return null;
|
|
204
271
|
}
|
|
@@ -216,32 +283,12 @@ export class ArweaveClient {
|
|
|
216
283
|
}
|
|
217
284
|
|
|
218
285
|
/**
|
|
219
|
-
* Returns the address of the signer of the JWT
|
|
286
|
+
* Returns the address of the signer of the JWT. This is a local crypto
|
|
287
|
+
* operation and does not require a network call.
|
|
220
288
|
* @returns The address of the signer in this client
|
|
221
289
|
*/
|
|
222
290
|
getAddress(): Promise<string> {
|
|
223
|
-
return this.client.wallets.jwkToAddress(this.arweaveJWT);
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
private async _retryRequest<T>(request: () => Promise<T>, retryCount: number): Promise<T> {
|
|
227
|
-
try {
|
|
228
|
-
return await request();
|
|
229
|
-
} catch (e) {
|
|
230
|
-
if (retryCount < this.retries) {
|
|
231
|
-
// Implement a slightly aggressive exponential backoff to account for fierce parallelism.
|
|
232
|
-
const baseDelay = this.retryDelaySeconds * Math.pow(2, retryCount); // ms; attempt = [0, 1, 2, ...]
|
|
233
|
-
const delayS = baseDelay + baseDelay * Math.random();
|
|
234
|
-
this.logger.debug({
|
|
235
|
-
at: "ArweaveClient:retryRequest",
|
|
236
|
-
message: `Arweave request failed, retrying after waiting ${delayS} seconds: ${e}`,
|
|
237
|
-
retryCount,
|
|
238
|
-
});
|
|
239
|
-
await delay(delayS);
|
|
240
|
-
return this._retryRequest(request, retryCount + 1);
|
|
241
|
-
} else {
|
|
242
|
-
throw e;
|
|
243
|
-
}
|
|
244
|
-
}
|
|
291
|
+
return this.gateways[0].client.wallets.jwkToAddress(this.arweaveJWT);
|
|
245
292
|
}
|
|
246
293
|
|
|
247
294
|
/**
|
|
@@ -250,9 +297,9 @@ export class ArweaveClient {
|
|
|
250
297
|
*/
|
|
251
298
|
async getBalance(): Promise<BigNumber> {
|
|
252
299
|
const address = await this.getAddress();
|
|
253
|
-
|
|
254
|
-
const balanceInFloat = await
|
|
255
|
-
// @dev The reason we add in the BN.from
|
|
300
|
+
return this._raceGateways("getBalance", async ({ client }) => {
|
|
301
|
+
const balanceInFloat = await client.wallets.getBalance(address);
|
|
302
|
+
// @dev The reason we add in the BN.from here is because the client.getBalance call
|
|
256
303
|
// does not correctly throw an error if the request fails, instead it will return the error string as the
|
|
257
304
|
// balanceInFloat.
|
|
258
305
|
// Sometimes the balance is returned in scientific notation, so we need to
|
|
@@ -264,7 +311,6 @@ export class ArweaveClient {
|
|
|
264
311
|
} else {
|
|
265
312
|
return BigNumber.from(balanceInFloat);
|
|
266
313
|
}
|
|
267
|
-
};
|
|
268
|
-
return await this._retryRequest(request, 0);
|
|
314
|
+
});
|
|
269
315
|
}
|
|
270
316
|
}
|