@ar.io/sdk 3.9.0-alpha.4 → 3.9.0-alpha.6
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/bundles/web.bundle.min.js +70 -52
- package/lib/cjs/common/contracts/ao-process.js +54 -38
- package/lib/cjs/common/io.js +12 -6
- package/lib/cjs/utils/arweave.js +87 -1
- package/lib/cjs/version.js +1 -1
- package/lib/esm/common/contracts/ao-process.js +54 -38
- package/lib/esm/common/io.js +13 -7
- package/lib/esm/utils/arweave.js +83 -0
- package/lib/esm/version.js +1 -1
- package/lib/types/common/contracts/ao-process.d.ts +1 -1
- package/lib/types/utils/arweave.d.ts +18 -1
- package/lib/types/version.d.ts +1 -1
- package/package.json +1 -1
|
@@ -68,13 +68,14 @@ class AOProcess {
|
|
|
68
68
|
processId: this.processId,
|
|
69
69
|
});
|
|
70
70
|
if (attempts >= retries) {
|
|
71
|
-
this.logger.
|
|
71
|
+
this.logger.debug(`Maximum read attempts exceeded`, {
|
|
72
72
|
error: error?.message,
|
|
73
73
|
stack: error?.stack,
|
|
74
74
|
tags,
|
|
75
75
|
processId: this.processId,
|
|
76
|
+
ao: JSON.stringify(this.ao),
|
|
76
77
|
});
|
|
77
|
-
throw new Error(`
|
|
78
|
+
throw new Error(`Failed to evaluate a dry-run on process ${this.processId}.`);
|
|
78
79
|
}
|
|
79
80
|
// exponential backoff
|
|
80
81
|
await new Promise((resolve) => setTimeout(resolve, 2 ** attempts * 1000));
|
|
@@ -92,7 +93,7 @@ class AOProcess {
|
|
|
92
93
|
throw new Error(error);
|
|
93
94
|
}
|
|
94
95
|
if (result.Messages === undefined || result.Messages.length === 0) {
|
|
95
|
-
this.logger.debug(`
|
|
96
|
+
this.logger.debug(`Empty result - process ${this.processId} does not support provided action.`, {
|
|
96
97
|
result,
|
|
97
98
|
tags,
|
|
98
99
|
processId: this.processId,
|
|
@@ -108,32 +109,50 @@ class AOProcess {
|
|
|
108
109
|
return response;
|
|
109
110
|
}
|
|
110
111
|
async send({ tags, data, signer, retries = 3, }) {
|
|
111
|
-
// main purpose of retries is to handle network errors/new process delays
|
|
112
|
-
let attempts = 0;
|
|
113
112
|
let messageId;
|
|
113
|
+
const anchor = (0, base64_js_1.getRandomText)(32); // anchor is a random text produce non-deterministic messages IDs when deterministic signers are provided (ETH)
|
|
114
|
+
try {
|
|
115
|
+
this.logger.debug(`Evaluating send interaction on contract`, {
|
|
116
|
+
tags,
|
|
117
|
+
data,
|
|
118
|
+
processId: this.processId,
|
|
119
|
+
});
|
|
120
|
+
/**
|
|
121
|
+
* DO NOT retry messaging if a message was already sent.
|
|
122
|
+
* This could result in a double entry-like condition when sending tokens for example.
|
|
123
|
+
* If the message fails to send we will throw an error and the caller can retry.
|
|
124
|
+
*/
|
|
125
|
+
messageId = await this.ao.message({
|
|
126
|
+
process: this.processId,
|
|
127
|
+
tags: [...tags, { name: 'AR-IO-SDK', value: version_js_1.version }],
|
|
128
|
+
data,
|
|
129
|
+
signer,
|
|
130
|
+
anchor,
|
|
131
|
+
});
|
|
132
|
+
this.logger.debug(`Sent message to process`, {
|
|
133
|
+
messageId,
|
|
134
|
+
processId: this.processId,
|
|
135
|
+
anchor,
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
catch (error) {
|
|
139
|
+
this.logger.debug('Error sending message to process', {
|
|
140
|
+
error: error?.message,
|
|
141
|
+
stack: error?.stack,
|
|
142
|
+
processId: this.processId,
|
|
143
|
+
tags,
|
|
144
|
+
});
|
|
145
|
+
// throw the error so it can be handled by the caller
|
|
146
|
+
throw error;
|
|
147
|
+
}
|
|
148
|
+
if (messageId === undefined) {
|
|
149
|
+
throw new Error('Failed to send message to process.');
|
|
150
|
+
}
|
|
151
|
+
// get the result of the message before returning, using retries to handle network errors/new process delays
|
|
114
152
|
let result = undefined;
|
|
115
|
-
|
|
116
|
-
const anchor = (0, base64_js_1.getRandomText)(32);
|
|
153
|
+
let attempts = 0;
|
|
117
154
|
while (attempts < retries) {
|
|
118
155
|
try {
|
|
119
|
-
this.logger.debug(`Evaluating send interaction on contract`, {
|
|
120
|
-
tags,
|
|
121
|
-
data,
|
|
122
|
-
processId: this.processId,
|
|
123
|
-
});
|
|
124
|
-
// MUST NOT retry messaging if a message was already sent. This could result in a double entry-like condition when sending tokens for example.
|
|
125
|
-
messageId ??= await this.ao.message({
|
|
126
|
-
process: this.processId,
|
|
127
|
-
tags: [...tags, { name: 'AR-IO-SDK', value: version_js_1.version }],
|
|
128
|
-
data,
|
|
129
|
-
signer,
|
|
130
|
-
anchor,
|
|
131
|
-
});
|
|
132
|
-
this.logger.debug(`Sent message to process`, {
|
|
133
|
-
messageId,
|
|
134
|
-
processId: this.processId,
|
|
135
|
-
anchor,
|
|
136
|
-
});
|
|
137
156
|
result = await this.ao.result({
|
|
138
157
|
message: messageId,
|
|
139
158
|
process: this.processId,
|
|
@@ -146,12 +165,6 @@ class AOProcess {
|
|
|
146
165
|
break;
|
|
147
166
|
}
|
|
148
167
|
catch (error) {
|
|
149
|
-
this.logger.error('Error sending message to process', {
|
|
150
|
-
error: error?.message,
|
|
151
|
-
stack: error?.stack,
|
|
152
|
-
processId: this.processId,
|
|
153
|
-
tags,
|
|
154
|
-
});
|
|
155
168
|
attempts++;
|
|
156
169
|
this.logger.debug('Retrying send interaction', {
|
|
157
170
|
attempts,
|
|
@@ -160,20 +173,26 @@ class AOProcess {
|
|
|
160
173
|
processId: this.processId,
|
|
161
174
|
});
|
|
162
175
|
if (attempts >= retries) {
|
|
163
|
-
this.logger.
|
|
176
|
+
this.logger.debug(`Message was sent to process ${this.processId} with id ${messageId} but result was not returned. Review transactions for more details.`, {
|
|
164
177
|
error: error?.message,
|
|
165
178
|
stack: error?.stack,
|
|
166
179
|
tags,
|
|
167
180
|
processId: this.processId,
|
|
181
|
+
messageId,
|
|
168
182
|
});
|
|
169
|
-
|
|
183
|
+
return { id: messageId };
|
|
170
184
|
}
|
|
171
185
|
// exponential backoff
|
|
172
186
|
await new Promise((resolve) => setTimeout(resolve, 2 ** attempts * 2000));
|
|
173
187
|
}
|
|
174
188
|
}
|
|
175
|
-
if (result === undefined
|
|
176
|
-
|
|
189
|
+
if (result === undefined) {
|
|
190
|
+
this.logger.debug(`Message was sent to process ${this.processId} with id ${messageId} but the result was not returned. Review transactions for more details.`, {
|
|
191
|
+
tags,
|
|
192
|
+
processId: this.processId,
|
|
193
|
+
messageId,
|
|
194
|
+
});
|
|
195
|
+
return { id: messageId };
|
|
177
196
|
}
|
|
178
197
|
const error = (0, index_js_1.errorMessageFromOutput)(result);
|
|
179
198
|
if (error !== undefined) {
|
|
@@ -183,9 +202,6 @@ class AOProcess {
|
|
|
183
202
|
if (result.Messages?.length === 0 || result.Messages === undefined) {
|
|
184
203
|
return { id: messageId };
|
|
185
204
|
}
|
|
186
|
-
if (result.Messages.length === 0) {
|
|
187
|
-
throw new Error(`Process ${this.processId} does not support provided action.`);
|
|
188
|
-
}
|
|
189
205
|
if (this.isMessageDataEmpty(result.Messages[0].Data)) {
|
|
190
206
|
return { id: messageId };
|
|
191
207
|
}
|
package/lib/cjs/common/io.js
CHANGED
|
@@ -84,10 +84,11 @@ class ARIOReadable {
|
|
|
84
84
|
const epochIndex = await this.computeEpochIndex(epoch);
|
|
85
85
|
const currentIndex = await this.computeCurrentEpochIndex();
|
|
86
86
|
if (epochIndex !== undefined && epochIndex < currentIndex) {
|
|
87
|
-
const epochData = await (0, arweave_js_1.
|
|
87
|
+
const epochData = await (0, arweave_js_1.getEpochDataFromGqlWithCUFallback)({
|
|
88
88
|
arweave: this.arweave,
|
|
89
89
|
epochIndex: epochIndex,
|
|
90
90
|
processId: this.process.processId,
|
|
91
|
+
ao: this.process.ao,
|
|
91
92
|
});
|
|
92
93
|
return (0, arweave_js_1.removeEligibleRewardsFromEpochData)(epochData);
|
|
93
94
|
}
|
|
@@ -211,7 +212,8 @@ class ARIOReadable {
|
|
|
211
212
|
const epochIndex = await this.computeEpochIndex(epoch);
|
|
212
213
|
const currentIndex = await this.computeCurrentEpochIndex();
|
|
213
214
|
if (epochIndex !== undefined && epochIndex < currentIndex) {
|
|
214
|
-
const epochData = await (0, arweave_js_1.
|
|
215
|
+
const epochData = await (0, arweave_js_1.getEpochDataFromGqlWithCUFallback)({
|
|
216
|
+
ao: this.process.ao,
|
|
215
217
|
arweave: this.arweave,
|
|
216
218
|
epochIndex: epochIndex,
|
|
217
219
|
processId: this.process.processId,
|
|
@@ -233,10 +235,11 @@ class ARIOReadable {
|
|
|
233
235
|
const epochIndex = await this.computeEpochIndex(epoch);
|
|
234
236
|
const currentIndex = await this.computeCurrentEpochIndex();
|
|
235
237
|
if (epochIndex !== undefined && epochIndex < currentIndex) {
|
|
236
|
-
const epochData = await (0, arweave_js_1.
|
|
238
|
+
const epochData = await (0, arweave_js_1.getEpochDataFromGqlWithCUFallback)({
|
|
237
239
|
arweave: this.arweave,
|
|
238
240
|
epochIndex: epochIndex,
|
|
239
241
|
processId: this.process.processId,
|
|
242
|
+
ao: this.process.ao,
|
|
240
243
|
});
|
|
241
244
|
return epochData?.prescribedNames;
|
|
242
245
|
}
|
|
@@ -256,10 +259,11 @@ class ARIOReadable {
|
|
|
256
259
|
const epochIndex = await this.computeEpochIndex(epoch);
|
|
257
260
|
const currentIndex = await this.computeCurrentEpochIndex();
|
|
258
261
|
if (epochIndex !== undefined && epochIndex < currentIndex) {
|
|
259
|
-
const epochData = await (0, arweave_js_1.
|
|
262
|
+
const epochData = await (0, arweave_js_1.getEpochDataFromGqlWithCUFallback)({
|
|
260
263
|
arweave: this.arweave,
|
|
261
264
|
epochIndex: epochIndex,
|
|
262
265
|
processId: this.process.processId,
|
|
266
|
+
ao: this.process.ao,
|
|
263
267
|
});
|
|
264
268
|
return epochData?.observations;
|
|
265
269
|
}
|
|
@@ -279,10 +283,11 @@ class ARIOReadable {
|
|
|
279
283
|
const epochIndex = await this.computeEpochIndex(epoch);
|
|
280
284
|
const currentIndex = await this.computeCurrentEpochIndex();
|
|
281
285
|
if (epochIndex !== undefined && epochIndex < currentIndex) {
|
|
282
|
-
const epochData = await (0, arweave_js_1.
|
|
286
|
+
const epochData = await (0, arweave_js_1.getEpochDataFromGqlWithCUFallback)({
|
|
283
287
|
arweave: this.arweave,
|
|
284
288
|
epochIndex: epochIndex,
|
|
285
289
|
processId: this.process.processId,
|
|
290
|
+
ao: this.process.ao,
|
|
286
291
|
});
|
|
287
292
|
return epochData?.distributions;
|
|
288
293
|
}
|
|
@@ -302,10 +307,11 @@ class ARIOReadable {
|
|
|
302
307
|
const epochIndex = await this.computeEpochIndex(epoch);
|
|
303
308
|
const currentIndex = await this.computeCurrentEpochIndex();
|
|
304
309
|
if (epochIndex !== undefined && epochIndex < currentIndex) {
|
|
305
|
-
const epochData = await (0, arweave_js_1.
|
|
310
|
+
const epochData = await (0, arweave_js_1.getEpochDataFromGqlWithCUFallback)({
|
|
306
311
|
arweave: this.arweave,
|
|
307
312
|
epochIndex: epochIndex,
|
|
308
313
|
processId: this.process.processId,
|
|
314
|
+
ao: this.process.ao,
|
|
309
315
|
});
|
|
310
316
|
return (0, arweave_js_1.sortAndPaginateEpochDataIntoEligibleDistributions)(epochData, params);
|
|
311
317
|
}
|
package/lib/cjs/utils/arweave.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.removeEligibleRewardsFromEpochData = exports.sortAndPaginateEpochDataIntoEligibleDistributions = exports.epochDistributionNoticeGqlQuery = exports.getEpochDataFromGql = exports.paginationParamsToTags = exports.pruneTags = exports.isBlockHeight = exports.validateArweaveId = void 0;
|
|
3
|
+
exports.removeEligibleRewardsFromEpochData = exports.sortAndPaginateEpochDataIntoEligibleDistributions = exports.epochDistributionNoticeGqlQueryFallback = exports.epochDistributionNoticeGqlQuery = exports.getEpochDataFromGqlFallback = exports.getEpochDataFromGqlWithCUFallback = exports.getEpochDataFromGql = exports.paginationParamsToTags = exports.pruneTags = exports.isBlockHeight = exports.validateArweaveId = void 0;
|
|
4
4
|
const constants_js_1 = require("../constants.js");
|
|
5
5
|
const io_js_1 = require("../types/io.js");
|
|
6
6
|
const ao_js_1 = require("./ao.js");
|
|
@@ -69,6 +69,66 @@ const getEpochDataFromGql = async ({ arweave, epochIndex, processId = constants_
|
|
|
69
69
|
return undefined;
|
|
70
70
|
};
|
|
71
71
|
exports.getEpochDataFromGql = getEpochDataFromGql;
|
|
72
|
+
const getEpochDataFromGqlWithCUFallback = async ({ arweave, ao, epochIndex, processId = constants_js_1.ARIO_MAINNET_PROCESS_ID, }) => {
|
|
73
|
+
const gqlResult = await (0, exports.getEpochDataFromGql)({
|
|
74
|
+
arweave,
|
|
75
|
+
epochIndex,
|
|
76
|
+
processId,
|
|
77
|
+
});
|
|
78
|
+
if (gqlResult) {
|
|
79
|
+
return gqlResult;
|
|
80
|
+
}
|
|
81
|
+
const gqlFallbackResult = await (0, exports.getEpochDataFromGqlFallback)({
|
|
82
|
+
ao,
|
|
83
|
+
epochIndex,
|
|
84
|
+
processId,
|
|
85
|
+
});
|
|
86
|
+
if (gqlFallbackResult) {
|
|
87
|
+
return gqlFallbackResult;
|
|
88
|
+
}
|
|
89
|
+
return undefined;
|
|
90
|
+
};
|
|
91
|
+
exports.getEpochDataFromGqlWithCUFallback = getEpochDataFromGqlWithCUFallback;
|
|
92
|
+
const getEpochDataFromGqlFallback = async ({ ao, epochIndex, processId = constants_js_1.ARIO_MAINNET_PROCESS_ID, gqlUrl = 'https://arweave-search.goldsky.com/graphql', }) => {
|
|
93
|
+
const query = (0, exports.epochDistributionNoticeGqlQueryFallback)({
|
|
94
|
+
epochIndex,
|
|
95
|
+
processId,
|
|
96
|
+
});
|
|
97
|
+
const response = await fetch(gqlUrl, {
|
|
98
|
+
method: 'POST',
|
|
99
|
+
body: query,
|
|
100
|
+
headers: {
|
|
101
|
+
'Content-Type': 'application/json',
|
|
102
|
+
},
|
|
103
|
+
});
|
|
104
|
+
const responseJson = (await response.json());
|
|
105
|
+
if (responseJson.data.transactions.edges.length === 0) {
|
|
106
|
+
return undefined;
|
|
107
|
+
}
|
|
108
|
+
for (const edge of responseJson.data.transactions.edges) {
|
|
109
|
+
const id = edge.node.id;
|
|
110
|
+
const messageResult = await ao
|
|
111
|
+
.result({
|
|
112
|
+
message: id,
|
|
113
|
+
process: processId,
|
|
114
|
+
})
|
|
115
|
+
.catch(() => undefined);
|
|
116
|
+
if (!messageResult) {
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
for (const message of messageResult.Messages) {
|
|
120
|
+
const data = JSON.parse(message.Data);
|
|
121
|
+
const tags = message.Tags;
|
|
122
|
+
// check if the message results include epoch-distribution-notice for the requested epoch index
|
|
123
|
+
if (tags.some((tag) => tag.name === 'Action' && tag.value === 'Epoch-Distribution-Notice') &&
|
|
124
|
+
tags.some((tag) => tag.name === 'Epoch-Index' && tag.value === epochIndex.toString())) {
|
|
125
|
+
return (0, ao_js_1.parseAoEpochData)(data);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return undefined;
|
|
130
|
+
};
|
|
131
|
+
exports.getEpochDataFromGqlFallback = getEpochDataFromGqlFallback;
|
|
72
132
|
/**
|
|
73
133
|
* Get the epoch with distribution data for the current epoch
|
|
74
134
|
* @param arweave - The Arweave instance
|
|
@@ -104,6 +164,32 @@ const epochDistributionNoticeGqlQuery = ({ epochIndex, processId = constants_js_
|
|
|
104
164
|
return gqlQuery;
|
|
105
165
|
};
|
|
106
166
|
exports.epochDistributionNoticeGqlQuery = epochDistributionNoticeGqlQuery;
|
|
167
|
+
// fallback query if the distribution notice does not get cranked
|
|
168
|
+
const epochDistributionNoticeGqlQueryFallback = ({ processId = constants_js_1.ARIO_MAINNET_PROCESS_ID, owners = ['OAb-n-ZugyN598kZNpfOy0ACelGVmwCQ0kYbgNGDUK8'], // ar.io team wallet ticks once a day
|
|
169
|
+
}) => {
|
|
170
|
+
return JSON.stringify({
|
|
171
|
+
query: `
|
|
172
|
+
query {
|
|
173
|
+
transactions(
|
|
174
|
+
tags: [
|
|
175
|
+
{ name: "Action", values: ["Tick"] }
|
|
176
|
+
],
|
|
177
|
+
first: 100,
|
|
178
|
+
owners: [${owners.map((a) => `"${a}"`).join(',')}],
|
|
179
|
+
recipients: ["${processId}"],
|
|
180
|
+
sort: HEIGHT_DESC
|
|
181
|
+
) {
|
|
182
|
+
edges {
|
|
183
|
+
node {
|
|
184
|
+
id
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
`,
|
|
190
|
+
});
|
|
191
|
+
};
|
|
192
|
+
exports.epochDistributionNoticeGqlQueryFallback = epochDistributionNoticeGqlQueryFallback;
|
|
107
193
|
function sortAndPaginateEpochDataIntoEligibleDistributions(epochData, params) {
|
|
108
194
|
const rewards = [];
|
|
109
195
|
const sortBy = params?.sortBy ?? 'eligibleReward';
|
package/lib/cjs/version.js
CHANGED
|
@@ -65,13 +65,14 @@ export class AOProcess {
|
|
|
65
65
|
processId: this.processId,
|
|
66
66
|
});
|
|
67
67
|
if (attempts >= retries) {
|
|
68
|
-
this.logger.
|
|
68
|
+
this.logger.debug(`Maximum read attempts exceeded`, {
|
|
69
69
|
error: error?.message,
|
|
70
70
|
stack: error?.stack,
|
|
71
71
|
tags,
|
|
72
72
|
processId: this.processId,
|
|
73
|
+
ao: JSON.stringify(this.ao),
|
|
73
74
|
});
|
|
74
|
-
throw new Error(`
|
|
75
|
+
throw new Error(`Failed to evaluate a dry-run on process ${this.processId}.`);
|
|
75
76
|
}
|
|
76
77
|
// exponential backoff
|
|
77
78
|
await new Promise((resolve) => setTimeout(resolve, 2 ** attempts * 1000));
|
|
@@ -89,7 +90,7 @@ export class AOProcess {
|
|
|
89
90
|
throw new Error(error);
|
|
90
91
|
}
|
|
91
92
|
if (result.Messages === undefined || result.Messages.length === 0) {
|
|
92
|
-
this.logger.debug(`
|
|
93
|
+
this.logger.debug(`Empty result - process ${this.processId} does not support provided action.`, {
|
|
93
94
|
result,
|
|
94
95
|
tags,
|
|
95
96
|
processId: this.processId,
|
|
@@ -105,32 +106,50 @@ export class AOProcess {
|
|
|
105
106
|
return response;
|
|
106
107
|
}
|
|
107
108
|
async send({ tags, data, signer, retries = 3, }) {
|
|
108
|
-
// main purpose of retries is to handle network errors/new process delays
|
|
109
|
-
let attempts = 0;
|
|
110
109
|
let messageId;
|
|
110
|
+
const anchor = getRandomText(32); // anchor is a random text produce non-deterministic messages IDs when deterministic signers are provided (ETH)
|
|
111
|
+
try {
|
|
112
|
+
this.logger.debug(`Evaluating send interaction on contract`, {
|
|
113
|
+
tags,
|
|
114
|
+
data,
|
|
115
|
+
processId: this.processId,
|
|
116
|
+
});
|
|
117
|
+
/**
|
|
118
|
+
* DO NOT retry messaging if a message was already sent.
|
|
119
|
+
* This could result in a double entry-like condition when sending tokens for example.
|
|
120
|
+
* If the message fails to send we will throw an error and the caller can retry.
|
|
121
|
+
*/
|
|
122
|
+
messageId = await this.ao.message({
|
|
123
|
+
process: this.processId,
|
|
124
|
+
tags: [...tags, { name: 'AR-IO-SDK', value: version }],
|
|
125
|
+
data,
|
|
126
|
+
signer,
|
|
127
|
+
anchor,
|
|
128
|
+
});
|
|
129
|
+
this.logger.debug(`Sent message to process`, {
|
|
130
|
+
messageId,
|
|
131
|
+
processId: this.processId,
|
|
132
|
+
anchor,
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
this.logger.debug('Error sending message to process', {
|
|
137
|
+
error: error?.message,
|
|
138
|
+
stack: error?.stack,
|
|
139
|
+
processId: this.processId,
|
|
140
|
+
tags,
|
|
141
|
+
});
|
|
142
|
+
// throw the error so it can be handled by the caller
|
|
143
|
+
throw error;
|
|
144
|
+
}
|
|
145
|
+
if (messageId === undefined) {
|
|
146
|
+
throw new Error('Failed to send message to process.');
|
|
147
|
+
}
|
|
148
|
+
// get the result of the message before returning, using retries to handle network errors/new process delays
|
|
111
149
|
let result = undefined;
|
|
112
|
-
|
|
113
|
-
const anchor = getRandomText(32);
|
|
150
|
+
let attempts = 0;
|
|
114
151
|
while (attempts < retries) {
|
|
115
152
|
try {
|
|
116
|
-
this.logger.debug(`Evaluating send interaction on contract`, {
|
|
117
|
-
tags,
|
|
118
|
-
data,
|
|
119
|
-
processId: this.processId,
|
|
120
|
-
});
|
|
121
|
-
// MUST NOT retry messaging if a message was already sent. This could result in a double entry-like condition when sending tokens for example.
|
|
122
|
-
messageId ??= await this.ao.message({
|
|
123
|
-
process: this.processId,
|
|
124
|
-
tags: [...tags, { name: 'AR-IO-SDK', value: version }],
|
|
125
|
-
data,
|
|
126
|
-
signer,
|
|
127
|
-
anchor,
|
|
128
|
-
});
|
|
129
|
-
this.logger.debug(`Sent message to process`, {
|
|
130
|
-
messageId,
|
|
131
|
-
processId: this.processId,
|
|
132
|
-
anchor,
|
|
133
|
-
});
|
|
134
153
|
result = await this.ao.result({
|
|
135
154
|
message: messageId,
|
|
136
155
|
process: this.processId,
|
|
@@ -143,12 +162,6 @@ export class AOProcess {
|
|
|
143
162
|
break;
|
|
144
163
|
}
|
|
145
164
|
catch (error) {
|
|
146
|
-
this.logger.error('Error sending message to process', {
|
|
147
|
-
error: error?.message,
|
|
148
|
-
stack: error?.stack,
|
|
149
|
-
processId: this.processId,
|
|
150
|
-
tags,
|
|
151
|
-
});
|
|
152
165
|
attempts++;
|
|
153
166
|
this.logger.debug('Retrying send interaction', {
|
|
154
167
|
attempts,
|
|
@@ -157,20 +170,26 @@ export class AOProcess {
|
|
|
157
170
|
processId: this.processId,
|
|
158
171
|
});
|
|
159
172
|
if (attempts >= retries) {
|
|
160
|
-
this.logger.
|
|
173
|
+
this.logger.debug(`Message was sent to process ${this.processId} with id ${messageId} but result was not returned. Review transactions for more details.`, {
|
|
161
174
|
error: error?.message,
|
|
162
175
|
stack: error?.stack,
|
|
163
176
|
tags,
|
|
164
177
|
processId: this.processId,
|
|
178
|
+
messageId,
|
|
165
179
|
});
|
|
166
|
-
|
|
180
|
+
return { id: messageId };
|
|
167
181
|
}
|
|
168
182
|
// exponential backoff
|
|
169
183
|
await new Promise((resolve) => setTimeout(resolve, 2 ** attempts * 2000));
|
|
170
184
|
}
|
|
171
185
|
}
|
|
172
|
-
if (result === undefined
|
|
173
|
-
|
|
186
|
+
if (result === undefined) {
|
|
187
|
+
this.logger.debug(`Message was sent to process ${this.processId} with id ${messageId} but the result was not returned. Review transactions for more details.`, {
|
|
188
|
+
tags,
|
|
189
|
+
processId: this.processId,
|
|
190
|
+
messageId,
|
|
191
|
+
});
|
|
192
|
+
return { id: messageId };
|
|
174
193
|
}
|
|
175
194
|
const error = errorMessageFromOutput(result);
|
|
176
195
|
if (error !== undefined) {
|
|
@@ -180,9 +199,6 @@ export class AOProcess {
|
|
|
180
199
|
if (result.Messages?.length === 0 || result.Messages === undefined) {
|
|
181
200
|
return { id: messageId };
|
|
182
201
|
}
|
|
183
|
-
if (result.Messages.length === 0) {
|
|
184
|
-
throw new Error(`Process ${this.processId} does not support provided action.`);
|
|
185
|
-
}
|
|
186
202
|
if (this.isMessageDataEmpty(result.Messages[0].Data)) {
|
|
187
203
|
return { id: messageId };
|
|
188
204
|
}
|
package/lib/esm/common/io.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ARIO_MAINNET_PROCESS_ID } from '../constants.js';
|
|
2
2
|
import { isProcessConfiguration, isProcessIdConfiguration, } from '../types/io.js';
|
|
3
3
|
import { createAoSigner } from '../utils/ao.js';
|
|
4
|
-
import {
|
|
4
|
+
import { getEpochDataFromGqlWithCUFallback, paginationParamsToTags, pruneTags, removeEligibleRewardsFromEpochData, sortAndPaginateEpochDataIntoEligibleDistributions, } from '../utils/arweave.js';
|
|
5
5
|
import { defaultArweave } from './arweave.js';
|
|
6
6
|
import { AOProcess } from './contracts/ao-process.js';
|
|
7
7
|
import { InvalidContractConfigurationError } from './error.js';
|
|
@@ -80,10 +80,11 @@ export class ARIOReadable {
|
|
|
80
80
|
const epochIndex = await this.computeEpochIndex(epoch);
|
|
81
81
|
const currentIndex = await this.computeCurrentEpochIndex();
|
|
82
82
|
if (epochIndex !== undefined && epochIndex < currentIndex) {
|
|
83
|
-
const epochData = await
|
|
83
|
+
const epochData = await getEpochDataFromGqlWithCUFallback({
|
|
84
84
|
arweave: this.arweave,
|
|
85
85
|
epochIndex: epochIndex,
|
|
86
86
|
processId: this.process.processId,
|
|
87
|
+
ao: this.process.ao,
|
|
87
88
|
});
|
|
88
89
|
return removeEligibleRewardsFromEpochData(epochData);
|
|
89
90
|
}
|
|
@@ -207,7 +208,8 @@ export class ARIOReadable {
|
|
|
207
208
|
const epochIndex = await this.computeEpochIndex(epoch);
|
|
208
209
|
const currentIndex = await this.computeCurrentEpochIndex();
|
|
209
210
|
if (epochIndex !== undefined && epochIndex < currentIndex) {
|
|
210
|
-
const epochData = await
|
|
211
|
+
const epochData = await getEpochDataFromGqlWithCUFallback({
|
|
212
|
+
ao: this.process.ao,
|
|
211
213
|
arweave: this.arweave,
|
|
212
214
|
epochIndex: epochIndex,
|
|
213
215
|
processId: this.process.processId,
|
|
@@ -229,10 +231,11 @@ export class ARIOReadable {
|
|
|
229
231
|
const epochIndex = await this.computeEpochIndex(epoch);
|
|
230
232
|
const currentIndex = await this.computeCurrentEpochIndex();
|
|
231
233
|
if (epochIndex !== undefined && epochIndex < currentIndex) {
|
|
232
|
-
const epochData = await
|
|
234
|
+
const epochData = await getEpochDataFromGqlWithCUFallback({
|
|
233
235
|
arweave: this.arweave,
|
|
234
236
|
epochIndex: epochIndex,
|
|
235
237
|
processId: this.process.processId,
|
|
238
|
+
ao: this.process.ao,
|
|
236
239
|
});
|
|
237
240
|
return epochData?.prescribedNames;
|
|
238
241
|
}
|
|
@@ -252,10 +255,11 @@ export class ARIOReadable {
|
|
|
252
255
|
const epochIndex = await this.computeEpochIndex(epoch);
|
|
253
256
|
const currentIndex = await this.computeCurrentEpochIndex();
|
|
254
257
|
if (epochIndex !== undefined && epochIndex < currentIndex) {
|
|
255
|
-
const epochData = await
|
|
258
|
+
const epochData = await getEpochDataFromGqlWithCUFallback({
|
|
256
259
|
arweave: this.arweave,
|
|
257
260
|
epochIndex: epochIndex,
|
|
258
261
|
processId: this.process.processId,
|
|
262
|
+
ao: this.process.ao,
|
|
259
263
|
});
|
|
260
264
|
return epochData?.observations;
|
|
261
265
|
}
|
|
@@ -275,10 +279,11 @@ export class ARIOReadable {
|
|
|
275
279
|
const epochIndex = await this.computeEpochIndex(epoch);
|
|
276
280
|
const currentIndex = await this.computeCurrentEpochIndex();
|
|
277
281
|
if (epochIndex !== undefined && epochIndex < currentIndex) {
|
|
278
|
-
const epochData = await
|
|
282
|
+
const epochData = await getEpochDataFromGqlWithCUFallback({
|
|
279
283
|
arweave: this.arweave,
|
|
280
284
|
epochIndex: epochIndex,
|
|
281
285
|
processId: this.process.processId,
|
|
286
|
+
ao: this.process.ao,
|
|
282
287
|
});
|
|
283
288
|
return epochData?.distributions;
|
|
284
289
|
}
|
|
@@ -298,10 +303,11 @@ export class ARIOReadable {
|
|
|
298
303
|
const epochIndex = await this.computeEpochIndex(epoch);
|
|
299
304
|
const currentIndex = await this.computeCurrentEpochIndex();
|
|
300
305
|
if (epochIndex !== undefined && epochIndex < currentIndex) {
|
|
301
|
-
const epochData = await
|
|
306
|
+
const epochData = await getEpochDataFromGqlWithCUFallback({
|
|
302
307
|
arweave: this.arweave,
|
|
303
308
|
epochIndex: epochIndex,
|
|
304
309
|
processId: this.process.processId,
|
|
310
|
+
ao: this.process.ao,
|
|
305
311
|
});
|
|
306
312
|
return sortAndPaginateEpochDataIntoEligibleDistributions(epochData, params);
|
|
307
313
|
}
|
package/lib/esm/utils/arweave.js
CHANGED
|
@@ -61,6 +61,64 @@ export const getEpochDataFromGql = async ({ arweave, epochIndex, processId = ARI
|
|
|
61
61
|
}
|
|
62
62
|
return undefined;
|
|
63
63
|
};
|
|
64
|
+
export const getEpochDataFromGqlWithCUFallback = async ({ arweave, ao, epochIndex, processId = ARIO_MAINNET_PROCESS_ID, }) => {
|
|
65
|
+
const gqlResult = await getEpochDataFromGql({
|
|
66
|
+
arweave,
|
|
67
|
+
epochIndex,
|
|
68
|
+
processId,
|
|
69
|
+
});
|
|
70
|
+
if (gqlResult) {
|
|
71
|
+
return gqlResult;
|
|
72
|
+
}
|
|
73
|
+
const gqlFallbackResult = await getEpochDataFromGqlFallback({
|
|
74
|
+
ao,
|
|
75
|
+
epochIndex,
|
|
76
|
+
processId,
|
|
77
|
+
});
|
|
78
|
+
if (gqlFallbackResult) {
|
|
79
|
+
return gqlFallbackResult;
|
|
80
|
+
}
|
|
81
|
+
return undefined;
|
|
82
|
+
};
|
|
83
|
+
export const getEpochDataFromGqlFallback = async ({ ao, epochIndex, processId = ARIO_MAINNET_PROCESS_ID, gqlUrl = 'https://arweave-search.goldsky.com/graphql', }) => {
|
|
84
|
+
const query = epochDistributionNoticeGqlQueryFallback({
|
|
85
|
+
epochIndex,
|
|
86
|
+
processId,
|
|
87
|
+
});
|
|
88
|
+
const response = await fetch(gqlUrl, {
|
|
89
|
+
method: 'POST',
|
|
90
|
+
body: query,
|
|
91
|
+
headers: {
|
|
92
|
+
'Content-Type': 'application/json',
|
|
93
|
+
},
|
|
94
|
+
});
|
|
95
|
+
const responseJson = (await response.json());
|
|
96
|
+
if (responseJson.data.transactions.edges.length === 0) {
|
|
97
|
+
return undefined;
|
|
98
|
+
}
|
|
99
|
+
for (const edge of responseJson.data.transactions.edges) {
|
|
100
|
+
const id = edge.node.id;
|
|
101
|
+
const messageResult = await ao
|
|
102
|
+
.result({
|
|
103
|
+
message: id,
|
|
104
|
+
process: processId,
|
|
105
|
+
})
|
|
106
|
+
.catch(() => undefined);
|
|
107
|
+
if (!messageResult) {
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
for (const message of messageResult.Messages) {
|
|
111
|
+
const data = JSON.parse(message.Data);
|
|
112
|
+
const tags = message.Tags;
|
|
113
|
+
// check if the message results include epoch-distribution-notice for the requested epoch index
|
|
114
|
+
if (tags.some((tag) => tag.name === 'Action' && tag.value === 'Epoch-Distribution-Notice') &&
|
|
115
|
+
tags.some((tag) => tag.name === 'Epoch-Index' && tag.value === epochIndex.toString())) {
|
|
116
|
+
return parseAoEpochData(data);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return undefined;
|
|
121
|
+
};
|
|
64
122
|
/**
|
|
65
123
|
* Get the epoch with distribution data for the current epoch
|
|
66
124
|
* @param arweave - The Arweave instance
|
|
@@ -95,6 +153,31 @@ export const epochDistributionNoticeGqlQuery = ({ epochIndex, processId = ARIO_M
|
|
|
95
153
|
});
|
|
96
154
|
return gqlQuery;
|
|
97
155
|
};
|
|
156
|
+
// fallback query if the distribution notice does not get cranked
|
|
157
|
+
export const epochDistributionNoticeGqlQueryFallback = ({ processId = ARIO_MAINNET_PROCESS_ID, owners = ['OAb-n-ZugyN598kZNpfOy0ACelGVmwCQ0kYbgNGDUK8'], // ar.io team wallet ticks once a day
|
|
158
|
+
}) => {
|
|
159
|
+
return JSON.stringify({
|
|
160
|
+
query: `
|
|
161
|
+
query {
|
|
162
|
+
transactions(
|
|
163
|
+
tags: [
|
|
164
|
+
{ name: "Action", values: ["Tick"] }
|
|
165
|
+
],
|
|
166
|
+
first: 100,
|
|
167
|
+
owners: [${owners.map((a) => `"${a}"`).join(',')}],
|
|
168
|
+
recipients: ["${processId}"],
|
|
169
|
+
sort: HEIGHT_DESC
|
|
170
|
+
) {
|
|
171
|
+
edges {
|
|
172
|
+
node {
|
|
173
|
+
id
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
`,
|
|
179
|
+
});
|
|
180
|
+
};
|
|
98
181
|
export function sortAndPaginateEpochDataIntoEligibleDistributions(epochData, params) {
|
|
99
182
|
const rewards = [];
|
|
100
183
|
const sortBy = params?.sortBy ?? 'eligibleReward';
|