@reality.eth/contracts 3.2.26 → 3.2.27
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/chains/deployments/1/SAFE/RealityETH_ERC20-3.0.json +7 -0
- package/chains/deployments/11155111/ETH/Arbitrator.json +5 -0
- package/chains/deployments/11155111/ETH/RealityETH-3.2.json +3 -1
- package/chains/deployments/11155111/SAFE/RealityETH_ERC20-3.0.json +7 -0
- package/chains/deployments/30/RBTC/RealityETH-3.2.json +6 -0
- package/chains/deployments/31/tRBTC/RealityETH-3.2.json +6 -0
- package/chains/supported.json +41 -1
- package/generated/chains.json +66 -1
- package/generated/contracts.json +45 -0
- package/generated/custom-templates.json +1995 -0
- package/generated/tokens.json +44 -19
- package/generated/website-data.js +1 -1
- package/package.json +2 -2
- package/scripts/create-hash-template.js +113 -0
- package/scripts/deploy.js +19 -37
- package/scripts/fetch-templates.js +214 -0
- package/scripts/generate_chains_json.js +4 -0
- package/scripts/generate_templates_bundle.js +46 -0
- package/scripts/retry-chain1-templates.js +102 -0
- package/scripts/update_token_prices.js +2 -0
- package/tokens/ARETH.json +1 -1
- package/tokens/AVAX.json +1 -1
- package/tokens/BNB.json +1 -1
- package/tokens/BOND.json +1 -1
- package/tokens/CELO.json +1 -1
- package/tokens/CTH.json +1 -1
- package/tokens/DAOOS.json +1 -1
- package/tokens/DEXE.json +1 -1
- package/tokens/ETH.json +1 -1
- package/tokens/FOX.json +1 -1
- package/tokens/GNO.json +1 -1
- package/tokens/MONAD.json +1 -1
- package/tokens/OETH.json +1 -1
- package/tokens/POLK.json +1 -1
- package/tokens/RBTC.json +8 -0
- package/tokens/SAFE.json +9 -0
- package/tokens/SUKU.json +1 -1
- package/tokens/SWISE.json +1 -1
- package/tokens/TLOS.json +1 -1
- package/tokens/XDAI.json +1 -1
- package/tokens/ZBS.json +1 -1
- package/tokens/tRBTC.json +8 -0
package/scripts/deploy.js
CHANGED
|
@@ -18,20 +18,7 @@ const deployed_at = null;
|
|
|
18
18
|
var undef;
|
|
19
19
|
|
|
20
20
|
const defaultConfigs = {
|
|
21
|
-
//maxFeePerGas: 610000000000,
|
|
22
|
-
//maxPriorityFeePerGas: 10000000000,
|
|
23
|
-
//gasPrice: 70000000000,
|
|
24
|
-
//gasPrice: 10000000000,
|
|
25
|
-
// gasPrice: 100000000,
|
|
26
|
-
// gasPrice: 10000, // optimism 1000000,
|
|
27
|
-
/// gasPrice: 5000000000,
|
|
28
|
-
//gasLimit: 6000000, // optimism 4500000
|
|
29
21
|
gasLimit: 4500000,
|
|
30
|
-
//etherscanApiKey: 'TPA4BFDDIH8Q7YBQ4JMGN6WDDRRPAV6G34'
|
|
31
|
-
//gasLimit: 155734867 // arbitrum
|
|
32
|
-
//gasLimit: 7000000
|
|
33
|
-
//gasLimit: 800035294
|
|
34
|
-
// gasLimit: 4291955938
|
|
35
22
|
}
|
|
36
23
|
const task = process.argv[2]
|
|
37
24
|
const version = process.argv[3]
|
|
@@ -74,6 +61,7 @@ const chains = {
|
|
|
74
61
|
'backstopTestnet1': 88558801
|
|
75
62
|
}
|
|
76
63
|
const non_infura_chains = {
|
|
64
|
+
'mainnet': 'http://127.0.0.1:8545',
|
|
77
65
|
'gnosis': 'https://gnosis.oat.farm',
|
|
78
66
|
'scroll-alpha-testnet': 'https://alpha-rpc.scroll.io/l2',
|
|
79
67
|
'sokol': 'https://sokol.poa.network',
|
|
@@ -94,7 +82,7 @@ const non_infura_chains = {
|
|
|
94
82
|
'kintsugi': 'https://rpc.kintsugi.themerge.dev',
|
|
95
83
|
'monad': 'https://rpc.monad.xyz',
|
|
96
84
|
'mumbai': 'https://matic-mumbai.chainstacklabs.com',
|
|
97
|
-
'sepolia': '
|
|
85
|
+
'sepolia': 'http://127.0.0.1:8546',
|
|
98
86
|
'holesky': 'https://ethereum-holesky.publicnode.com',
|
|
99
87
|
'telosevm': 'https://mainnet.telos.net/evm',
|
|
100
88
|
'unichain': 'https://mainnet.unichain.org',
|
|
@@ -252,25 +240,17 @@ function realityETHName() {
|
|
|
252
240
|
return tmpl;
|
|
253
241
|
}
|
|
254
242
|
|
|
243
|
+
// Fetch current fee data and return EIP-1559 overrides: { maxFeePerGas, maxPriorityFeePerGas }.
|
|
244
|
+
// tip comes from eth_maxPriorityFeePerGas (actual market rate, not ethers v5's hardcoded 1.5 gwei).
|
|
245
|
+
// maxFeePerGas = baseFee * 2 + tip (gives headroom for a few blocks of fee movement).
|
|
255
246
|
async function waitForGas(provider) {
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
const
|
|
261
|
-
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
const f = await provider.getFeeData()
|
|
265
|
-
console.log('fee', f)
|
|
266
|
-
throw new Error();
|
|
267
|
-
return;
|
|
268
|
-
if (f.gasPrice.gt(ethers.BigNumber.from(defaultConfigs.maxFeePerGas))) {
|
|
269
|
-
console.log('Gas is too expensive, got', f.gasPrice.toString(), 'but you will only pay ', defaultConfigs.maxFeePerGas, ', retrying...')
|
|
270
|
-
await sleep(2000);
|
|
271
|
-
await waitForGas(provider);
|
|
272
|
-
}
|
|
273
|
-
return true;
|
|
247
|
+
const block = await provider.getBlock('latest');
|
|
248
|
+
const base = block.baseFeePerGas || ethers.BigNumber.from(0);
|
|
249
|
+
const tipHex = await provider.send('eth_maxPriorityFeePerGas', []);
|
|
250
|
+
const tip = ethers.BigNumber.from(tipHex);
|
|
251
|
+
const maxFee = base.mul(2).add(tip);
|
|
252
|
+
console.log('base fee:', base.toString(), 'tip:', tip.toString(), 'maxFee:', maxFee.toString());
|
|
253
|
+
return { maxFeePerGas: maxFee, maxPriorityFeePerGas: tip };
|
|
274
254
|
}
|
|
275
255
|
|
|
276
256
|
async function deployRealityETH() {
|
|
@@ -287,7 +267,8 @@ async function deployRealityETH() {
|
|
|
287
267
|
txt = txt + ' (from address ' + signer.address + ')';
|
|
288
268
|
console.log(txt);
|
|
289
269
|
|
|
290
|
-
await waitForGas(provider);
|
|
270
|
+
const feeOverrides = await waitForGas(provider);
|
|
271
|
+
const txConfig = { ...defaultConfigs, ...feeOverrides };
|
|
291
272
|
|
|
292
273
|
if (deployed_at) {
|
|
293
274
|
|
|
@@ -311,7 +292,7 @@ async function deployRealityETH() {
|
|
|
311
292
|
}
|
|
312
293
|
|
|
313
294
|
} else {
|
|
314
|
-
confac.deploy(
|
|
295
|
+
confac.deploy(txConfig).then(function(result) {
|
|
315
296
|
const txid = result.deployTransaction.hash;
|
|
316
297
|
const address = result.address;
|
|
317
298
|
console.log('storing address', address);
|
|
@@ -327,7 +308,7 @@ async function deployRealityETH() {
|
|
|
327
308
|
}
|
|
328
309
|
|
|
329
310
|
//console.log('result was', result);
|
|
330
|
-
store_deployed_contract(tmpl, chain_id, token_name, settings);
|
|
311
|
+
store_deployed_contract(tmpl, chain_id, token_name, settings);
|
|
331
312
|
if (isERC20()) {
|
|
332
313
|
console.log('Setting token')
|
|
333
314
|
result.setToken(token_address);
|
|
@@ -442,9 +423,10 @@ async function deployFactory() {
|
|
|
442
423
|
txt = txt + ' (from address ' + signer.address + ')';
|
|
443
424
|
console.log(txt);
|
|
444
425
|
|
|
445
|
-
await waitForGas(provider);
|
|
426
|
+
const feeOverrides = await waitForGas(provider);
|
|
427
|
+
const txConfig = { ...defaultConfigs, ...feeOverrides };
|
|
446
428
|
|
|
447
|
-
confac.deploy(lib,
|
|
429
|
+
confac.deploy(lib, txConfig).then(function(result) {
|
|
448
430
|
const txid = result.deployTransaction.hash;
|
|
449
431
|
const address = result.address;
|
|
450
432
|
console.log('storing address', address);
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Fetches all templates from every deployed RealityETH contract across all chains.
|
|
3
|
+
//
|
|
4
|
+
// The contracts().templates(id) view returns the block number where
|
|
5
|
+
// LogNewTemplate was emitted for that template ID, or 0 if it doesn't exist.
|
|
6
|
+
// We call it for IDs 0, 1, 2, ... stopping at the first 0.
|
|
7
|
+
// For each unique block number we get a single pinpoint getLogs call that
|
|
8
|
+
// retrieves all LogNewTemplate events in that block for that contract.
|
|
9
|
+
//
|
|
10
|
+
// Usage:
|
|
11
|
+
// cd packages/contracts && node scripts/fetch-templates.js
|
|
12
|
+
//
|
|
13
|
+
// Output: generated/custom-templates.json
|
|
14
|
+
//
|
|
15
|
+
// Errors (e.g. RPC nodes that don't serve old logs) are written to _errors in
|
|
16
|
+
// the output so the file can be checked in and specific failures retried later
|
|
17
|
+
// with a different RPC.
|
|
18
|
+
|
|
19
|
+
'use strict';
|
|
20
|
+
const fs = require('fs');
|
|
21
|
+
const path = require('path');
|
|
22
|
+
const ethers = require('ethers');
|
|
23
|
+
|
|
24
|
+
const CONTRACTS_JSON = path.join(__dirname, '../generated/contracts.json');
|
|
25
|
+
const SUPPORTED_JSON = path.join(__dirname, '../chains/supported.json');
|
|
26
|
+
const CHAINID_NET_JSON = path.join(__dirname, '../chains/chainid.network.json');
|
|
27
|
+
const OUTPUT_PATH = path.join(__dirname, '../generated/custom-templates.json');
|
|
28
|
+
|
|
29
|
+
const TEMPLATES_ABI = [
|
|
30
|
+
'function templates(uint256 template_id) view returns (uint256)',
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
const LOG_TEMPLATE_TOPIC = ethers.utils.id('LogNewTemplate(uint256,address,string)');
|
|
34
|
+
|
|
35
|
+
const iface = new ethers.utils.Interface([
|
|
36
|
+
'event LogNewTemplate(uint256 indexed template_id, address indexed user, string question_text)',
|
|
37
|
+
]);
|
|
38
|
+
|
|
39
|
+
function sleep(ms) { return new Promise(r => setTimeout(r, ms)); }
|
|
40
|
+
|
|
41
|
+
async function fetchForContract(prov, chainId, address, existingTemplates, errors) {
|
|
42
|
+
const rc = new ethers.Contract(address, TEMPLATES_ABI, prov);
|
|
43
|
+
const templates = Object.assign({}, existingTemplates);
|
|
44
|
+
const blocksQueried = new Set();
|
|
45
|
+
|
|
46
|
+
for (let id = 0; ; id++) {
|
|
47
|
+
let blockNum;
|
|
48
|
+
try {
|
|
49
|
+
const bn = await rc.templates(id);
|
|
50
|
+
blockNum = bn.toNumber();
|
|
51
|
+
} catch (err) {
|
|
52
|
+
const msg = err.message || String(err);
|
|
53
|
+
console.error(` ✗ templates(${id}): ${msg.slice(0, 120)}`);
|
|
54
|
+
errors.push({ chainId, contract: address, templateId: id, phase: 'templates()', error: msg });
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (blockNum === 0) {
|
|
59
|
+
console.log(` templates(${id}) = 0 — done (${id} template${id !== 1 ? 's' : ''})`);
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
console.log(` templates(${id}) = block ${blockNum}`);
|
|
64
|
+
|
|
65
|
+
if (!blocksQueried.has(blockNum)) {
|
|
66
|
+
blocksQueried.add(blockNum);
|
|
67
|
+
try {
|
|
68
|
+
const logs = await prov.getLogs({
|
|
69
|
+
address,
|
|
70
|
+
topics: [LOG_TEMPLATE_TOPIC],
|
|
71
|
+
fromBlock: blockNum,
|
|
72
|
+
toBlock: blockNum,
|
|
73
|
+
});
|
|
74
|
+
for (const log of logs) {
|
|
75
|
+
try {
|
|
76
|
+
const parsed = iface.parseLog(log);
|
|
77
|
+
const tid = parsed.args.template_id.toString();
|
|
78
|
+
const text = parsed.args.question_text;
|
|
79
|
+
templates[tid] = text;
|
|
80
|
+
console.log(` ✓ template ${tid}: ${text.slice(0, 80)}${text.length > 80 ? '…' : ''}`);
|
|
81
|
+
} catch (parseErr) {
|
|
82
|
+
console.error(` ✗ log parse failed: ${parseErr.message}`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
await sleep(150);
|
|
86
|
+
} catch (logErr) {
|
|
87
|
+
const msg = logErr.message || String(logErr);
|
|
88
|
+
console.error(` ✗ getLogs(block ${blockNum}): ${msg.slice(0, 120)}`);
|
|
89
|
+
errors.push({ chainId, contract: address, block: blockNum, phase: 'getLogs', error: msg });
|
|
90
|
+
// Don't break — continue to next template ID in case we can get the block number at least
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
await sleep(150);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return templates;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function pickRpc(chainId, supported, publicRpcs) {
|
|
101
|
+
// Highest priority: env var (same convention as the indexer's .env.local)
|
|
102
|
+
const envRpc = process.env[`PONDER_RPC_URL_${chainId}`];
|
|
103
|
+
if (envRpc) return envRpc;
|
|
104
|
+
if (supported[chainId]?.hostedRPC) return supported[chainId].hostedRPC;
|
|
105
|
+
// Fall back to first public (non-template) HTTP RPC from chainid.network.json
|
|
106
|
+
const pub = (publicRpcs[chainId] || []).find(r => !r.includes('${') && r.startsWith('http'));
|
|
107
|
+
return pub || null;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
async function main() {
|
|
111
|
+
const allContracts = JSON.parse(fs.readFileSync(CONTRACTS_JSON, 'utf8'));
|
|
112
|
+
const supported = JSON.parse(fs.readFileSync(SUPPORTED_JSON, 'utf8'));
|
|
113
|
+
const cidList = JSON.parse(fs.readFileSync(CHAINID_NET_JSON, 'utf8'));
|
|
114
|
+
const publicRpcs = Object.fromEntries(
|
|
115
|
+
cidList.filter(c => c.chainId).map(c => [String(c.chainId), c.rpc || []])
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
// Load existing output so we can skip already-complete contracts
|
|
119
|
+
let existing = { _errors: [] };
|
|
120
|
+
if (fs.existsSync(OUTPUT_PATH)) {
|
|
121
|
+
try {
|
|
122
|
+
existing = JSON.parse(fs.readFileSync(OUTPUT_PATH, 'utf8'));
|
|
123
|
+
console.log(`Loaded existing output from ${OUTPUT_PATH}`);
|
|
124
|
+
} catch { /* start fresh */ }
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const output = { _errors: [] };
|
|
128
|
+
let totalContracts = 0;
|
|
129
|
+
let skipped = 0;
|
|
130
|
+
|
|
131
|
+
for (const [chainId, tokenMap] of Object.entries(allContracts)) {
|
|
132
|
+
const rpcUrl = pickRpc(chainId, supported, publicRpcs);
|
|
133
|
+
if (!rpcUrl) {
|
|
134
|
+
console.log(`\nChain ${chainId}: no RPC available, skipping`);
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
output[chainId] = output[chainId] || {};
|
|
139
|
+
|
|
140
|
+
// Collect unique RealityETH contract addresses — skip arbitrators etc.
|
|
141
|
+
const seen = new Set();
|
|
142
|
+
const toFetch = [];
|
|
143
|
+
for (const [token, vers] of Object.entries(tokenMap)) {
|
|
144
|
+
for (const [ver, info] of Object.entries(vers)) {
|
|
145
|
+
if (!info.address) continue;
|
|
146
|
+
if (!ver.includes('RealityETH')) continue;
|
|
147
|
+
const lc = info.address.toLowerCase();
|
|
148
|
+
if (seen.has(lc)) continue;
|
|
149
|
+
seen.add(lc);
|
|
150
|
+
toFetch.push({ address: lc, ver, token });
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (!toFetch.length) continue;
|
|
155
|
+
|
|
156
|
+
const prov = new ethers.providers.JsonRpcProvider(rpcUrl, {
|
|
157
|
+
chainId: Number(chainId),
|
|
158
|
+
name: `chain-${chainId}`,
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
for (const { address, ver } of toFetch) {
|
|
162
|
+
totalContracts++;
|
|
163
|
+
const chainExisting = existing[chainId] || {};
|
|
164
|
+
const contractExisting = chainExisting[address];
|
|
165
|
+
|
|
166
|
+
// Skip if already marked complete in a previous run
|
|
167
|
+
if (contractExisting && contractExisting._complete) {
|
|
168
|
+
console.log(`\nChain ${chainId} ${ver} ${address} — already complete, skipping`);
|
|
169
|
+
output[chainId][address] = contractExisting;
|
|
170
|
+
skipped++;
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
console.log(`\nChain ${chainId} ${ver} ${address} (via ${rpcUrl.slice(0, 50)})`);
|
|
175
|
+
|
|
176
|
+
const contractErrors = [];
|
|
177
|
+
const templates = await fetchForContract(
|
|
178
|
+
prov, chainId, address,
|
|
179
|
+
contractExisting || {}, contractErrors
|
|
180
|
+
);
|
|
181
|
+
output._errors.push(...contractErrors);
|
|
182
|
+
|
|
183
|
+
// Only mark complete if no getLogs errors — incomplete contracts will be
|
|
184
|
+
// retried automatically on the next run (e.g. with a better RPC set via env).
|
|
185
|
+
const hasLogGaps = contractErrors.some(e => e.phase === 'getLogs');
|
|
186
|
+
templates._complete = !hasLogGaps;
|
|
187
|
+
output[chainId][address] = templates;
|
|
188
|
+
|
|
189
|
+
// Save after every contract so progress isn't lost on failure
|
|
190
|
+
fs.writeFileSync(OUTPUT_PATH, JSON.stringify(output, null, 2));
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Final save
|
|
195
|
+
fs.writeFileSync(OUTPUT_PATH, JSON.stringify(output, null, 2));
|
|
196
|
+
|
|
197
|
+
console.log(`\n${'='.repeat(60)}`);
|
|
198
|
+
console.log(`Done. ${totalContracts} contract(s) processed (${skipped} skipped as already complete).`);
|
|
199
|
+
console.log(`Output: ${OUTPUT_PATH}`);
|
|
200
|
+
|
|
201
|
+
if (output._errors.length > 0) {
|
|
202
|
+
console.log(`\n${output._errors.length} error(s) — check _errors in the output file:`);
|
|
203
|
+
for (const e of output._errors) {
|
|
204
|
+
console.log(` chain ${e.chainId} ${e.contract} ${e.phase}${e.block ? ` block ${e.block}` : ` id ${e.templateId}`}: ${e.error.slice(0, 80)}`);
|
|
205
|
+
}
|
|
206
|
+
} else {
|
|
207
|
+
console.log('No errors.');
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
main().catch(err => {
|
|
212
|
+
console.error('\nFatal error:', err.message || err);
|
|
213
|
+
process.exit(1);
|
|
214
|
+
});
|
|
@@ -77,6 +77,10 @@ for (var ci = 0; ci< chain_id_list.length; ci++) {
|
|
|
77
77
|
chainparams['network_name'] = our_data['network_name'];
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
+
if (our_data['display_name']) {
|
|
81
|
+
chainparams['display_name'] = our_data['display_name'];
|
|
82
|
+
}
|
|
83
|
+
|
|
80
84
|
if (our_data['deprecated']) {
|
|
81
85
|
chainparams['deprecated'] = true;
|
|
82
86
|
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Generates website-templates.js from custom-templates.json.
|
|
3
|
+
// Strips the _errors key, the _complete marker from each contract,
|
|
4
|
+
// and excludes chains that aren't worth bundling (large testnet chains, etc).
|
|
5
|
+
//
|
|
6
|
+
// Usage:
|
|
7
|
+
// cd packages/contracts && node scripts/generate_templates_bundle.js
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
const fs = require('fs');
|
|
11
|
+
const path = require('path');
|
|
12
|
+
|
|
13
|
+
const INPUT = path.join(__dirname, '../generated/custom-templates.json');
|
|
14
|
+
const OUTPUT = path.join(__dirname, '../../frontend/webroot/js/vendor/website-templates.js');
|
|
15
|
+
|
|
16
|
+
// Chains excluded from the bundle (too large, or not useful in production).
|
|
17
|
+
const EXCLUDE_CHAINS = new Set(['1301']); // Unichain Sepolia: 672 templates, testnet only
|
|
18
|
+
|
|
19
|
+
const raw = JSON.parse(fs.readFileSync(INPUT, 'utf8'));
|
|
20
|
+
|
|
21
|
+
const bundle = {};
|
|
22
|
+
for (const [chainId, contracts] of Object.entries(raw)) {
|
|
23
|
+
if (chainId === '_errors') continue;
|
|
24
|
+
if (EXCLUDE_CHAINS.has(chainId)) continue;
|
|
25
|
+
bundle[chainId] = {};
|
|
26
|
+
for (const [addr, templates] of Object.entries(contracts)) {
|
|
27
|
+
const cleaned = {};
|
|
28
|
+
for (const [k, v] of Object.entries(templates)) {
|
|
29
|
+
if (k === '_complete') continue;
|
|
30
|
+
cleaned[k] = v;
|
|
31
|
+
}
|
|
32
|
+
if (Object.keys(cleaned).length > 0) bundle[chainId][addr] = cleaned;
|
|
33
|
+
}
|
|
34
|
+
if (Object.keys(bundle[chainId]).length === 0) delete bundle[chainId];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const totalTemplates = Object.values(bundle)
|
|
38
|
+
.flatMap(c => Object.values(c))
|
|
39
|
+
.reduce((n, t) => n + Object.keys(t).length, 0);
|
|
40
|
+
|
|
41
|
+
const js = `window.RealityBundledTemplates = ${JSON.stringify(bundle)};\n`;
|
|
42
|
+
fs.writeFileSync(OUTPUT, js);
|
|
43
|
+
|
|
44
|
+
const kb = Math.round(fs.statSync(OUTPUT).size / 1024);
|
|
45
|
+
console.log(`Written ${OUTPUT}`);
|
|
46
|
+
console.log(`${Object.keys(bundle).length} chains, ${totalTemplates} templates, ${kb}KB`);
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Fresh fetch of all chain 1 (Ethereum mainnet) templates using local archive node.
|
|
3
|
+
// Wipes any existing chain 1 data and errors, re-fetches cleanly.
|
|
4
|
+
'use strict';
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
const ethers = require('ethers');
|
|
8
|
+
|
|
9
|
+
const CONTRACTS_JSON = path.join(__dirname, '../generated/contracts.json');
|
|
10
|
+
const OUTPUT_PATH = path.join(__dirname, '../generated/custom-templates.json');
|
|
11
|
+
const LOCAL_RPC = 'http://localhost:8545';
|
|
12
|
+
const CHAIN_ID = 1;
|
|
13
|
+
|
|
14
|
+
const TEMPLATES_ABI = ['function templates(uint256 template_id) view returns (uint256)'];
|
|
15
|
+
const LOG_TEMPLATE_TOPIC = ethers.utils.id('LogNewTemplate(uint256,address,string)');
|
|
16
|
+
const iface = new ethers.utils.Interface([
|
|
17
|
+
'event LogNewTemplate(uint256 indexed template_id, address indexed user, string question_text)',
|
|
18
|
+
]);
|
|
19
|
+
|
|
20
|
+
function sleep(ms) { return new Promise(r => setTimeout(r, ms)); }
|
|
21
|
+
|
|
22
|
+
async function fetchForContract(prov, address, errors) {
|
|
23
|
+
const rc = new ethers.Contract(address, TEMPLATES_ABI, prov);
|
|
24
|
+
const templates = {};
|
|
25
|
+
const blocksQueried = new Set();
|
|
26
|
+
|
|
27
|
+
for (let id = 0; ; id++) {
|
|
28
|
+
let blockNum;
|
|
29
|
+
try {
|
|
30
|
+
const bn = await rc.templates(id);
|
|
31
|
+
blockNum = bn.toNumber();
|
|
32
|
+
} catch (err) {
|
|
33
|
+
const msg = err.message || String(err);
|
|
34
|
+
console.error(` ✗ templates(${id}): ${msg.slice(0, 120)}`);
|
|
35
|
+
errors.push({ chainId: CHAIN_ID, contract: address, templateId: id, phase: 'templates()', error: msg });
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
38
|
+
if (blockNum === 0) { console.log(` templates(${id}) = 0 — done`); break; }
|
|
39
|
+
console.log(` templates(${id}) = block ${blockNum}`);
|
|
40
|
+
if (!blocksQueried.has(blockNum)) {
|
|
41
|
+
blocksQueried.add(blockNum);
|
|
42
|
+
try {
|
|
43
|
+
const logs = await prov.getLogs({ address, topics: [LOG_TEMPLATE_TOPIC], fromBlock: blockNum, toBlock: blockNum });
|
|
44
|
+
for (const log of logs) {
|
|
45
|
+
const parsed = iface.parseLog(log);
|
|
46
|
+
const tid = parsed.args.template_id.toString();
|
|
47
|
+
const text = parsed.args.question_text;
|
|
48
|
+
templates[tid] = text;
|
|
49
|
+
console.log(` ✓ template ${tid}: ${text.slice(0, 80)}${text.length > 80 ? '…' : ''}`);
|
|
50
|
+
}
|
|
51
|
+
} catch (logErr) {
|
|
52
|
+
const msg = logErr.message || String(logErr);
|
|
53
|
+
console.error(` ✗ getLogs(block ${blockNum}): ${msg.slice(0, 120)}`);
|
|
54
|
+
errors.push({ chainId: CHAIN_ID, contract: address, block: blockNum, phase: 'getLogs', error: msg });
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
await sleep(50);
|
|
58
|
+
}
|
|
59
|
+
return templates;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async function main() {
|
|
63
|
+
const allContracts = JSON.parse(fs.readFileSync(CONTRACTS_JSON, 'utf8'));
|
|
64
|
+
const output = JSON.parse(fs.readFileSync(OUTPUT_PATH, 'utf8'));
|
|
65
|
+
|
|
66
|
+
// Clean slate for chain 1
|
|
67
|
+
delete output['1'];
|
|
68
|
+
output._errors = (output._errors || []).filter(e => e.chainId !== CHAIN_ID);
|
|
69
|
+
output['1'] = {};
|
|
70
|
+
|
|
71
|
+
const prov = new ethers.providers.JsonRpcProvider(LOCAL_RPC, { chainId: CHAIN_ID, name: 'mainnet' });
|
|
72
|
+
const bn = await prov.getBlockNumber();
|
|
73
|
+
console.log(`Local node at block ${bn}\n`);
|
|
74
|
+
|
|
75
|
+
const seen = new Set();
|
|
76
|
+
const errors = [];
|
|
77
|
+
for (const [token, vers] of Object.entries(allContracts[String(CHAIN_ID)] || {})) {
|
|
78
|
+
for (const [ver, info] of Object.entries(vers)) {
|
|
79
|
+
if (!info.address || !ver.includes('RealityETH')) continue;
|
|
80
|
+
const lc = info.address.toLowerCase();
|
|
81
|
+
if (seen.has(lc)) continue;
|
|
82
|
+
seen.add(lc);
|
|
83
|
+
console.log(`\nChain 1 ${ver} ${lc}`);
|
|
84
|
+
const templates = await fetchForContract(prov, lc, errors);
|
|
85
|
+
templates._complete = true;
|
|
86
|
+
output['1'][lc] = templates;
|
|
87
|
+
output._errors.push(...errors.splice(0));
|
|
88
|
+
fs.writeFileSync(OUTPUT_PATH, JSON.stringify(output, null, 2));
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
console.log(`\n${'='.repeat(60)}`);
|
|
93
|
+
if (output._errors.filter(e => e.chainId === CHAIN_ID).length === 0) {
|
|
94
|
+
console.log('No errors for chain 1.');
|
|
95
|
+
} else {
|
|
96
|
+
const e1 = output._errors.filter(e => e.chainId === CHAIN_ID);
|
|
97
|
+
console.log(`${e1.length} error(s) for chain 1:`);
|
|
98
|
+
for (const e of e1) console.log(` ${e.phase}${e.block ? ` block ${e.block}` : ''}: ${e.error.slice(0, 80)}`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
main().catch(err => { console.error('\nFatal:', err.message || err); process.exit(1); });
|
|
@@ -26,6 +26,7 @@ const COINGECKO_IDS = {
|
|
|
26
26
|
AVAX: 'avalanche-2',
|
|
27
27
|
CELO: 'celo',
|
|
28
28
|
FOX: 'shapeshift-fox-token',
|
|
29
|
+
SAFE: 'safe',
|
|
29
30
|
SWISE: 'stakewise',
|
|
30
31
|
POLK: 'polkamarkets',
|
|
31
32
|
DEXE: 'dexe',
|
|
@@ -56,6 +57,7 @@ const FALLBACKS = {
|
|
|
56
57
|
'avalanche-2': 38,
|
|
57
58
|
celo: 0.60,
|
|
58
59
|
'shapeshift-fox-token': 0.03,
|
|
60
|
+
safe: 0.40,
|
|
59
61
|
stakewise: 0.15,
|
|
60
62
|
polkamarkets: 0.008,
|
|
61
63
|
dexe: 12,
|
package/tokens/ARETH.json
CHANGED
package/tokens/AVAX.json
CHANGED
package/tokens/BNB.json
CHANGED
package/tokens/BOND.json
CHANGED
package/tokens/CELO.json
CHANGED
package/tokens/CTH.json
CHANGED
package/tokens/DAOOS.json
CHANGED
package/tokens/DEXE.json
CHANGED
package/tokens/ETH.json
CHANGED
package/tokens/FOX.json
CHANGED
package/tokens/GNO.json
CHANGED
package/tokens/MONAD.json
CHANGED
package/tokens/OETH.json
CHANGED
package/tokens/POLK.json
CHANGED
package/tokens/RBTC.json
ADDED
package/tokens/SAFE.json
ADDED
package/tokens/SUKU.json
CHANGED
package/tokens/SWISE.json
CHANGED
package/tokens/TLOS.json
CHANGED
package/tokens/XDAI.json
CHANGED