@instadapp/interop-x 0.0.0-dev.0ee2ee3
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/.env.example +1 -0
- package/.github/workflows/publish-dev.yml +30 -0
- package/README.md +21 -0
- package/bin/interop-x +2 -0
- package/dist/config/index.js +17 -0
- package/dist/constants/addresses.js +13 -0
- package/dist/constants/index.js +17 -0
- package/dist/db/index.js +17 -0
- package/dist/db/models/execution.js +38 -0
- package/dist/db/models/index.js +17 -0
- package/dist/db/sequelize.js +22 -0
- package/dist/index.js +34 -0
- package/dist/logger/index.js +138 -0
- package/dist/net/index.js +19 -0
- package/dist/net/peer/index.js +100 -0
- package/dist/net/pool/index.js +107 -0
- package/dist/net/protocol/dial/BaseDialProtocol.js +106 -0
- package/dist/net/protocol/dial/SignatureDialProtocol.js +48 -0
- package/dist/net/protocol/index.js +92 -0
- package/dist/tasks/BaseTask.js +61 -0
- package/dist/tasks/index.js +19 -0
- package/dist/types.js +21 -0
- package/dist/utils/index.js +89 -0
- package/package.json +59 -0
- package/src/config/index.ts +24 -0
- package/src/constants/addresses.ts +10 -0
- package/src/constants/index.ts +1 -0
- package/src/db/index.ts +1 -0
- package/src/db/models/execution.ts +57 -0
- package/src/db/models/index.ts +1 -0
- package/src/db/sequelize.ts +21 -0
- package/src/index.ts +39 -0
- package/src/logger/index.ts +157 -0
- package/src/net/index.ts +3 -0
- package/src/net/peer/index.ts +113 -0
- package/src/net/pool/index.ts +128 -0
- package/src/net/protocol/dial/BaseDialProtocol.ts +104 -0
- package/src/net/protocol/dial/SignatureDialProtocol.ts +62 -0
- package/src/net/protocol/index.ts +138 -0
- package/src/tasks/BaseTask.ts +76 -0
- package/src/tasks/index.ts +18 -0
- package/src/types.ts +39 -0
- package/src/utils/index.ts +116 -0
- package/tsconfig.json +27 -0
@@ -0,0 +1,106 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __asyncValues = (this && this.__asyncValues) || function (o) {
|
3
|
+
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
4
|
+
var m = o[Symbol.asyncIterator], i;
|
5
|
+
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
|
6
|
+
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
|
7
|
+
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
|
8
|
+
};
|
9
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
10
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
11
|
+
};
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
13
|
+
exports.BaseDialProtocol = void 0;
|
14
|
+
const it_pipe_1 = __importDefault(require("it-pipe"));
|
15
|
+
const peer_id_1 = __importDefault(require("peer-id"));
|
16
|
+
const utils_1 = require("../../../utils");
|
17
|
+
const waait_1 = __importDefault(require("waait"));
|
18
|
+
class BaseDialProtocol {
|
19
|
+
constructor(libp2p, protocol) {
|
20
|
+
this.timeout = 20000;
|
21
|
+
this.libp2p = libp2p;
|
22
|
+
this.protocol = protocol;
|
23
|
+
this.libp2p.handle(this.protocol, this.handle.bind(this));
|
24
|
+
}
|
25
|
+
encode(data) {
|
26
|
+
return JSON.stringify(data);
|
27
|
+
}
|
28
|
+
encodeResponse(data) {
|
29
|
+
return JSON.stringify(data);
|
30
|
+
}
|
31
|
+
decode(data) {
|
32
|
+
return JSON.parse(data.toString());
|
33
|
+
}
|
34
|
+
decodeResponse(data) {
|
35
|
+
return JSON.parse(data.toString());
|
36
|
+
}
|
37
|
+
async response(data) {
|
38
|
+
return data;
|
39
|
+
}
|
40
|
+
async handle({ connection, stream }) {
|
41
|
+
const instance = this;
|
42
|
+
try {
|
43
|
+
await (0, it_pipe_1.default)(stream, async function (source) {
|
44
|
+
var e_1, _a;
|
45
|
+
try {
|
46
|
+
for (var source_1 = __asyncValues(source), source_1_1; source_1_1 = await source_1.next(), !source_1_1.done;) {
|
47
|
+
const message = source_1_1.value;
|
48
|
+
const response = instance.encodeResponse(await instance.response(instance.decode(message)));
|
49
|
+
await (0, it_pipe_1.default)([response], stream);
|
50
|
+
}
|
51
|
+
}
|
52
|
+
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
53
|
+
finally {
|
54
|
+
try {
|
55
|
+
if (source_1_1 && !source_1_1.done && (_a = source_1.return)) await _a.call(source_1);
|
56
|
+
}
|
57
|
+
finally { if (e_1) throw e_1.error; }
|
58
|
+
}
|
59
|
+
});
|
60
|
+
}
|
61
|
+
catch (err) {
|
62
|
+
console.error(err);
|
63
|
+
}
|
64
|
+
}
|
65
|
+
async send(data, peerId) {
|
66
|
+
return await (0, utils_1.asyncCallWithTimeout)(new Promise(async (resolve, reject) => {
|
67
|
+
try {
|
68
|
+
let connection = this.libp2p.connectionManager.get(peer_id_1.default.createFromB58String(peerId));
|
69
|
+
if (!connection) {
|
70
|
+
await (0, waait_1.default)(5000);
|
71
|
+
connection = this.libp2p.connectionManager.get(peer_id_1.default.createFromB58String(peerId));
|
72
|
+
if (!connection) {
|
73
|
+
await (0, waait_1.default)(3000);
|
74
|
+
connection = this.libp2p.connectionManager.get(peer_id_1.default.createFromB58String(peerId));
|
75
|
+
if (!connection) {
|
76
|
+
throw new Error('No connection available');
|
77
|
+
}
|
78
|
+
}
|
79
|
+
}
|
80
|
+
const { stream } = await connection.newStream([this.protocol]);
|
81
|
+
const instance = this;
|
82
|
+
(0, it_pipe_1.default)([this.encode(data)], stream, async function (source) {
|
83
|
+
var e_2, _a;
|
84
|
+
try {
|
85
|
+
for (var source_2 = __asyncValues(source), source_2_1; source_2_1 = await source_2.next(), !source_2_1.done;) {
|
86
|
+
const message = source_2_1.value;
|
87
|
+
resolve(instance.decodeResponse(message));
|
88
|
+
stream.close();
|
89
|
+
}
|
90
|
+
}
|
91
|
+
catch (e_2_1) { e_2 = { error: e_2_1 }; }
|
92
|
+
finally {
|
93
|
+
try {
|
94
|
+
if (source_2_1 && !source_2_1.done && (_a = source_2.return)) await _a.call(source_2);
|
95
|
+
}
|
96
|
+
finally { if (e_2) throw e_2.error; }
|
97
|
+
}
|
98
|
+
});
|
99
|
+
}
|
100
|
+
catch (error) {
|
101
|
+
reject(error);
|
102
|
+
}
|
103
|
+
}), this.timeout);
|
104
|
+
}
|
105
|
+
}
|
106
|
+
exports.BaseDialProtocol = BaseDialProtocol;
|
@@ -0,0 +1,48 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
|
+
};
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
+
exports.SignatureDialProtocol = void 0;
|
7
|
+
const utils_1 = require("../../../utils");
|
8
|
+
const BaseDialProtocol_1 = require("./BaseDialProtocol");
|
9
|
+
const waait_1 = __importDefault(require("waait"));
|
10
|
+
const config_1 = __importDefault(require("config"));
|
11
|
+
const constants_1 = require("../../../constants");
|
12
|
+
const db_1 = require("db");
|
13
|
+
class SignatureDialProtocol extends BaseDialProtocol_1.BaseDialProtocol {
|
14
|
+
constructor(libp2p) {
|
15
|
+
super(libp2p, '/signatures');
|
16
|
+
this.timeout = 30000;
|
17
|
+
}
|
18
|
+
async response(data) {
|
19
|
+
const signer = config_1.default.wallet;
|
20
|
+
let event;
|
21
|
+
let maxTimeout = 20000;
|
22
|
+
do {
|
23
|
+
event = await db_1.Execution.findOne({ where: { vnonce: data.vnonce.toString() } });
|
24
|
+
if (!event) {
|
25
|
+
await (0, waait_1.default)(1000);
|
26
|
+
maxTimeout -= 1000;
|
27
|
+
}
|
28
|
+
} while (!event && maxTimeout > 0);
|
29
|
+
if (!event) {
|
30
|
+
return {
|
31
|
+
signer: signer.address,
|
32
|
+
data: null,
|
33
|
+
error: 'Event not found'
|
34
|
+
};
|
35
|
+
}
|
36
|
+
const signedData = await (0, utils_1.signGnosisSafeTx)({
|
37
|
+
to: constants_1.addresses[event.chainId].multisend,
|
38
|
+
data: 'TODO',
|
39
|
+
chainId: event.chainId,
|
40
|
+
safeTxGas: data.safeTxGas,
|
41
|
+
}, { signer });
|
42
|
+
return {
|
43
|
+
signer: signer.address,
|
44
|
+
data: signedData,
|
45
|
+
};
|
46
|
+
}
|
47
|
+
}
|
48
|
+
exports.SignatureDialProtocol = SignatureDialProtocol;
|
@@ -0,0 +1,92 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
|
+
};
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
+
exports.protocol = void 0;
|
7
|
+
const stream_1 = require("stream");
|
8
|
+
const ethereumjs_util_1 = require("ethereumjs-util");
|
9
|
+
const SignatureDialProtocol_1 = require("./dial/SignatureDialProtocol");
|
10
|
+
const __1 = require("..");
|
11
|
+
const config_1 = __importDefault(require("config"));
|
12
|
+
const types_1 = require("types");
|
13
|
+
class Protocol extends stream_1.EventEmitter {
|
14
|
+
constructor() {
|
15
|
+
super(...arguments);
|
16
|
+
this.protocolMessages = [
|
17
|
+
{
|
18
|
+
name: 'PeerInfo',
|
19
|
+
code: 0x09,
|
20
|
+
encode: (info) => [
|
21
|
+
Buffer.from(info.publicAddress),
|
22
|
+
],
|
23
|
+
decode: ([publicAddress]) => ({
|
24
|
+
publicAddress: publicAddress.toString(),
|
25
|
+
}),
|
26
|
+
},
|
27
|
+
];
|
28
|
+
}
|
29
|
+
start({ libp2p, topic = null, }) {
|
30
|
+
this.libp2p = libp2p;
|
31
|
+
this.topic = topic || 'protocol';
|
32
|
+
if (this.libp2p.isStarted())
|
33
|
+
this.init();
|
34
|
+
this.on('PeerInfo', (payload) => {
|
35
|
+
config_1.default.events.emit(types_1.Event.PEER_CONNECTED, {
|
36
|
+
id: payload.peerId,
|
37
|
+
publicAddress: payload.data.publicAddress,
|
38
|
+
pooled: false,
|
39
|
+
updated: new Date(),
|
40
|
+
});
|
41
|
+
});
|
42
|
+
this.signature = new SignatureDialProtocol_1.SignatureDialProtocol(this.libp2p);
|
43
|
+
}
|
44
|
+
init() {
|
45
|
+
this.libp2p.pubsub.subscribe(this.topic);
|
46
|
+
this.libp2p.pubsub.on(this.topic, (message) => {
|
47
|
+
try {
|
48
|
+
const [codeBuf, payload] = ethereumjs_util_1.rlp.decode(message.data);
|
49
|
+
const code = (0, ethereumjs_util_1.bufferToInt)(codeBuf);
|
50
|
+
const protocolMessage = this.protocolMessages.find((m) => m.code === code);
|
51
|
+
if (!protocolMessage) {
|
52
|
+
return;
|
53
|
+
}
|
54
|
+
const decoded = protocolMessage.decode(payload);
|
55
|
+
this.emit(protocolMessage.name, {
|
56
|
+
peerId: message.from,
|
57
|
+
name: protocolMessage.name,
|
58
|
+
code: protocolMessage.code,
|
59
|
+
data: decoded
|
60
|
+
});
|
61
|
+
this.emit('all', {
|
62
|
+
peerId: message.from,
|
63
|
+
name: protocolMessage.name,
|
64
|
+
code: protocolMessage.code,
|
65
|
+
data: decoded,
|
66
|
+
});
|
67
|
+
}
|
68
|
+
catch (err) {
|
69
|
+
console.error(err);
|
70
|
+
}
|
71
|
+
});
|
72
|
+
}
|
73
|
+
sendPeerInfo(data) {
|
74
|
+
const message = this.protocolMessages.find((m) => m.name === 'PeerInfo');
|
75
|
+
const encoded = ethereumjs_util_1.rlp.encode([message.code, message.encode(data)]);
|
76
|
+
this.libp2p.pubsub.publish(this.topic, encoded);
|
77
|
+
}
|
78
|
+
async requestSignatures(data, peerIds) {
|
79
|
+
try {
|
80
|
+
peerIds = peerIds || __1.peerPool.activePeerIds;
|
81
|
+
const promises = peerIds.map((peerId) => this.signature.send(data, peerId));
|
82
|
+
return (await Promise.allSettled(promises))
|
83
|
+
.map((p) => p.status === 'fulfilled' ? p.value : null)
|
84
|
+
.filter(Boolean);
|
85
|
+
}
|
86
|
+
catch (error) {
|
87
|
+
console.log(error);
|
88
|
+
return [];
|
89
|
+
}
|
90
|
+
}
|
91
|
+
}
|
92
|
+
exports.protocol = new Protocol();
|
@@ -0,0 +1,61 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
|
+
};
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
+
exports.BaseTask = void 0;
|
7
|
+
const config_1 = __importDefault(require("config"));
|
8
|
+
const events_1 = __importDefault(require("events"));
|
9
|
+
const waait_1 = __importDefault(require("waait"));
|
10
|
+
const logger_1 = __importDefault(require("../logger"));
|
11
|
+
class BaseTask extends events_1.default {
|
12
|
+
constructor({ logger }) {
|
13
|
+
super();
|
14
|
+
this.started = false;
|
15
|
+
this.pollIntervalMs = 10 * 1000;
|
16
|
+
this.leadNodeOnly = false;
|
17
|
+
this.logger = logger !== null && logger !== void 0 ? logger : new logger_1.default('BaseTask');
|
18
|
+
}
|
19
|
+
async pollCheck() {
|
20
|
+
while (true) {
|
21
|
+
if (!this.started) {
|
22
|
+
return;
|
23
|
+
}
|
24
|
+
try {
|
25
|
+
const shouldPoll = this.prePollHandler();
|
26
|
+
if (shouldPoll) {
|
27
|
+
await this.pollHandler();
|
28
|
+
}
|
29
|
+
}
|
30
|
+
catch (err) {
|
31
|
+
this.logger.error(`poll check error: ${err.message}\ntrace: ${err.stack}`);
|
32
|
+
}
|
33
|
+
await this.postPollHandler();
|
34
|
+
}
|
35
|
+
}
|
36
|
+
prePollHandler() {
|
37
|
+
if (!this.leadNodeOnly) {
|
38
|
+
return true;
|
39
|
+
}
|
40
|
+
return config_1.default.isLeadNode();
|
41
|
+
}
|
42
|
+
async pollHandler() {
|
43
|
+
this.logger.warn('pollHandler not implemented');
|
44
|
+
}
|
45
|
+
async postPollHandler() {
|
46
|
+
await (0, waait_1.default)(this.pollIntervalMs);
|
47
|
+
}
|
48
|
+
async start() {
|
49
|
+
this.started = true;
|
50
|
+
try {
|
51
|
+
await this.pollCheck();
|
52
|
+
}
|
53
|
+
catch (err) {
|
54
|
+
this.logger.error(`base task error: ${err.message}\ntrace: ${err.stack}`);
|
55
|
+
}
|
56
|
+
}
|
57
|
+
async stop() {
|
58
|
+
this.started = false;
|
59
|
+
}
|
60
|
+
}
|
61
|
+
exports.BaseTask = BaseTask;
|
@@ -0,0 +1,19 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.Tasks = void 0;
|
4
|
+
class Tasks {
|
5
|
+
constructor() {
|
6
|
+
this.tasks = [];
|
7
|
+
}
|
8
|
+
async start() {
|
9
|
+
for (const task of this.tasks) {
|
10
|
+
try {
|
11
|
+
task.start();
|
12
|
+
}
|
13
|
+
catch (error) {
|
14
|
+
console.error(`Error starting task: ${task.constructor.name}`);
|
15
|
+
}
|
16
|
+
}
|
17
|
+
}
|
18
|
+
}
|
19
|
+
exports.Tasks = Tasks;
|
package/dist/types.js
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.EventBus = exports.Event = void 0;
|
4
|
+
const events_1 = require("events");
|
5
|
+
/**
|
6
|
+
* Types for the central event bus, emitted
|
7
|
+
* by different components of the client.
|
8
|
+
*/
|
9
|
+
var Event;
|
10
|
+
(function (Event) {
|
11
|
+
Event["PEER_CONNECTED"] = "peer:connected";
|
12
|
+
Event["PEER_DISCONNECTED"] = "peer:disconnected";
|
13
|
+
Event["PEER_ERROR"] = "peer:error";
|
14
|
+
Event["POOL_PEER_ADDED"] = "pool:peer:added";
|
15
|
+
Event["POOL_PEER_REMOVED"] = "pool:peer:removed";
|
16
|
+
Event["POOL_PEER_BANNED"] = "pool:peer:banned";
|
17
|
+
})(Event = exports.Event || (exports.Event = {}));
|
18
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
19
|
+
class EventBus extends events_1.EventEmitter {
|
20
|
+
}
|
21
|
+
exports.EventBus = EventBus;
|
@@ -0,0 +1,89 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
|
+
};
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
+
exports.asyncCallWithTimeout = exports.buildSignatureBytes = exports.getRpcProviderUrl = exports.signGnosisSafeTx = exports.short = exports.http = void 0;
|
7
|
+
/**
|
8
|
+
* @module util
|
9
|
+
*/
|
10
|
+
const axios_1 = __importDefault(require("axios"));
|
11
|
+
const axios_retry_1 = __importDefault(require("axios-retry"));
|
12
|
+
const constants_1 = require("../constants");
|
13
|
+
exports.http = axios_1.default.create();
|
14
|
+
(0, axios_retry_1.default)(exports.http, { retries: 3, retryDelay: axios_retry_1.default.exponentialDelay });
|
15
|
+
function short(buffer) {
|
16
|
+
return buffer.toString('hex').slice(0, 8) + '...';
|
17
|
+
}
|
18
|
+
exports.short = short;
|
19
|
+
const signGnosisSafeTx = async ({ to, data = null, value = '0', operation = '1', baseGas = '0', gasPrice = "0", gasToken = "0x0000000000000000000000000000000000000000", refundReceiver = "0x0000000000000000000000000000000000000000", safeTxGas = "79668", nonce = "0", chainId = 137, }, { signer }) => {
|
20
|
+
const gnosisSafe = constants_1.addresses[chainId].gnosisSafe;
|
21
|
+
const domain = {
|
22
|
+
verifyingContract: gnosisSafe,
|
23
|
+
chainId,
|
24
|
+
};
|
25
|
+
const types = {
|
26
|
+
SafeTx: [
|
27
|
+
{ type: 'address', name: 'to' },
|
28
|
+
{ type: 'uint256', name: 'value' },
|
29
|
+
{ type: 'bytes', name: 'data' },
|
30
|
+
{ type: 'uint8', name: 'operation' },
|
31
|
+
{ type: 'uint256', name: 'safeTxGas' },
|
32
|
+
{ type: 'uint256', name: 'baseGas' },
|
33
|
+
{ type: 'uint256', name: 'gasPrice' },
|
34
|
+
{ type: 'address', name: 'gasToken' },
|
35
|
+
{ type: 'address', name: 'refundReceiver' },
|
36
|
+
{ type: 'uint256', name: 'nonce' },
|
37
|
+
],
|
38
|
+
};
|
39
|
+
const message = {
|
40
|
+
baseGas,
|
41
|
+
data,
|
42
|
+
gasPrice,
|
43
|
+
gasToken,
|
44
|
+
nonce: Number(nonce),
|
45
|
+
operation,
|
46
|
+
refundReceiver,
|
47
|
+
safeAddress: gnosisSafe,
|
48
|
+
safeTxGas: String(safeTxGas),
|
49
|
+
to,
|
50
|
+
value,
|
51
|
+
};
|
52
|
+
return await signer._signTypedData(domain, types, message);
|
53
|
+
};
|
54
|
+
exports.signGnosisSafeTx = signGnosisSafeTx;
|
55
|
+
const getRpcProviderUrl = (chainId) => {
|
56
|
+
switch (chainId) {
|
57
|
+
case 1:
|
58
|
+
return 'https://rpc.instadapp.io/mainnet';
|
59
|
+
case 137:
|
60
|
+
return 'https://rpc.instadapp.io/polygon';
|
61
|
+
default:
|
62
|
+
throw new Error(`Unknown chainId: ${chainId}`);
|
63
|
+
}
|
64
|
+
};
|
65
|
+
exports.getRpcProviderUrl = getRpcProviderUrl;
|
66
|
+
const buildSignatureBytes = (signatures) => {
|
67
|
+
signatures.sort((left, right) => left.signer.toLowerCase().localeCompare(right.signer.toLowerCase()));
|
68
|
+
let signatureBytes = "0x";
|
69
|
+
for (const sig of signatures) {
|
70
|
+
signatureBytes += sig.data.slice(2);
|
71
|
+
}
|
72
|
+
return signatureBytes;
|
73
|
+
};
|
74
|
+
exports.buildSignatureBytes = buildSignatureBytes;
|
75
|
+
/**
|
76
|
+
* Call an async function with a maximum time limit (in milliseconds) for the timeout
|
77
|
+
* Resolved promise for async function call, or an error if time limit reached
|
78
|
+
*/
|
79
|
+
const asyncCallWithTimeout = async (asyncPromise, timeout) => {
|
80
|
+
let timeoutHandle;
|
81
|
+
const timeoutPromise = new Promise((_resolve, reject) => {
|
82
|
+
timeoutHandle = setTimeout(() => reject(new Error('Async call timeout limit reached')), timeout);
|
83
|
+
});
|
84
|
+
return Promise.race([asyncPromise, timeoutPromise]).then(result => {
|
85
|
+
clearTimeout(timeoutHandle);
|
86
|
+
return result;
|
87
|
+
});
|
88
|
+
};
|
89
|
+
exports.asyncCallWithTimeout = asyncCallWithTimeout;
|
package/package.json
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
{
|
2
|
+
"name": "@instadapp/interop-x",
|
3
|
+
"version": "0.0.0-dev.0ee2ee3",
|
4
|
+
"license": "MIT",
|
5
|
+
"main": "dist/index.js",
|
6
|
+
"engines": {
|
7
|
+
"node": ">=16",
|
8
|
+
"yarn": "^1.22.0"
|
9
|
+
},
|
10
|
+
"scripts": {
|
11
|
+
"start": "yarn build && node bin/interop-x",
|
12
|
+
"build": "export GIT_REF=$(git rev-parse --short HEAD) && rimraf ./dist && tsc -p tsconfig.json && replace-in-file '@GIT_SHORT_HASH@' $GIT_REF ./dist/src/**/*.js",
|
13
|
+
"dev": "NODE_ENV=development nodemon",
|
14
|
+
"prepublishOnly": "yarn build"
|
15
|
+
},
|
16
|
+
"nodemonConfig": {
|
17
|
+
"watch": [
|
18
|
+
"src"
|
19
|
+
],
|
20
|
+
"ext": "ts",
|
21
|
+
"exec": "./node_modules/.bin/ts-node --files -r tsconfig-paths/register ./src/index.ts"
|
22
|
+
},
|
23
|
+
"dependencies": {
|
24
|
+
"@achingbrain/libp2p-gossipsub": "^0.12.2",
|
25
|
+
"axios": "^0.27.1",
|
26
|
+
"axios-retry": "^3.2.4",
|
27
|
+
"bignumber.js": "^9.0.2",
|
28
|
+
"chalk": "4.1.2",
|
29
|
+
"dotenv": "^16.0.0",
|
30
|
+
"ethereumjs-util": "^7.1.4",
|
31
|
+
"ethers": "^5.6.4",
|
32
|
+
"ethers-multisend": "^2.1.1",
|
33
|
+
"libp2p": "^0.36.2",
|
34
|
+
"libp2p-bootstrap": "^0.14.0",
|
35
|
+
"libp2p-kad-dht": "^0.28.6",
|
36
|
+
"libp2p-mdns": "^0.18.0",
|
37
|
+
"libp2p-mplex": "^0.10.7",
|
38
|
+
"libp2p-noise": "^4.0.0",
|
39
|
+
"libp2p-pubsub-peer-discovery": "^4.0.0",
|
40
|
+
"libp2p-tcp": "^0.17.2",
|
41
|
+
"libp2p-websockets": "^0.16.2",
|
42
|
+
"luxon": "^2.3.2",
|
43
|
+
"sequelize": "^6.19.0",
|
44
|
+
"waait": "^1.0.5"
|
45
|
+
},
|
46
|
+
"bin": {
|
47
|
+
"interop-node": "bin/interop-x"
|
48
|
+
},
|
49
|
+
"devDependencies": {
|
50
|
+
"@types/fs-extra": "^9.0.13",
|
51
|
+
"@types/node": "^17.0.17",
|
52
|
+
"nodemon": "^2.0.15",
|
53
|
+
"replace-in-file": "^6.3.2",
|
54
|
+
"rimraf": "^3.0.2",
|
55
|
+
"ts-node": "^10.5.0",
|
56
|
+
"tsconfig-paths": "^3.12.0",
|
57
|
+
"typescript": "^4.5.5"
|
58
|
+
}
|
59
|
+
}
|
@@ -0,0 +1,24 @@
|
|
1
|
+
import { ethers, Wallet } from "ethers"
|
2
|
+
import { EventBus, EventBusType } from "types"
|
3
|
+
|
4
|
+
class Config {
|
5
|
+
public readonly events: EventBusType
|
6
|
+
public readonly maxPeers: number
|
7
|
+
public readonly leadNodeAddress: string
|
8
|
+
public readonly privateKey: string
|
9
|
+
public readonly wallet: Wallet
|
10
|
+
|
11
|
+
constructor() {
|
12
|
+
this.events = new EventBus() as EventBusType
|
13
|
+
this.maxPeers = 10
|
14
|
+
this.privateKey = process.env.PRIVATE_KEY as string;
|
15
|
+
this.wallet = new Wallet(this.privateKey);
|
16
|
+
this.leadNodeAddress = '0x910E413DBF3F6276Fe8213fF656726bDc142E08E'
|
17
|
+
}
|
18
|
+
|
19
|
+
isLeadNode() {
|
20
|
+
return ethers.utils.getAddress(this.leadNodeAddress) === ethers.utils.getAddress(this.wallet.address)
|
21
|
+
}
|
22
|
+
}
|
23
|
+
|
24
|
+
export default new Config()
|
@@ -0,0 +1,10 @@
|
|
1
|
+
export const addresses = {
|
2
|
+
1: {
|
3
|
+
gnosisSafe: '0x5635d2910e51da33d9DC0422c893CF4F28B69A25',
|
4
|
+
multisend: "0xA238CBeb142c10Ef7Ad8442C6D1f9E89e07e7761",
|
5
|
+
},
|
6
|
+
137: {
|
7
|
+
gnosisSafe: '0x5635d2910e51da33d9DC0422c893CF4F28B69A25',
|
8
|
+
multisend: "0xA238CBeb142c10Ef7Ad8442C6D1f9E89e07e7761",
|
9
|
+
},
|
10
|
+
}
|
@@ -0,0 +1 @@
|
|
1
|
+
export * from './addresses';
|
package/src/db/index.ts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
export * from "./models"
|
@@ -0,0 +1,57 @@
|
|
1
|
+
import { sequelize } from '../sequelize'
|
2
|
+
import { CreationOptional, InferAttributes, InferCreationAttributes, Model, DataTypes } from 'sequelize';
|
3
|
+
|
4
|
+
export class Execution extends Model<InferAttributes<Execution>, InferCreationAttributes<Execution>> {
|
5
|
+
declare id: CreationOptional<number>;
|
6
|
+
|
7
|
+
declare transactionHash: string;
|
8
|
+
declare from: string;
|
9
|
+
declare executions: any[];
|
10
|
+
declare chainId: number;
|
11
|
+
declare gas: string;
|
12
|
+
declare maxGasPrice: string;
|
13
|
+
declare assets: any[];
|
14
|
+
declare metadata: string;
|
15
|
+
declare vnonce: string;
|
16
|
+
declare txHash: string;
|
17
|
+
|
18
|
+
declare blockNumber: string;
|
19
|
+
declare status: CreationOptional<string>;
|
20
|
+
declare delayUntil: CreationOptional<Date>;
|
21
|
+
declare delayedCount: CreationOptional<number>;
|
22
|
+
|
23
|
+
declare error: CreationOptional<string>;
|
24
|
+
declare createdAt: CreationOptional<Date>;
|
25
|
+
declare updatedAt: CreationOptional<Date>;
|
26
|
+
}
|
27
|
+
|
28
|
+
Execution.init({
|
29
|
+
id: {
|
30
|
+
type: DataTypes.INTEGER,
|
31
|
+
autoIncrement: true,
|
32
|
+
primaryKey: true
|
33
|
+
},
|
34
|
+
transactionHash: DataTypes.STRING,
|
35
|
+
from: DataTypes.STRING,
|
36
|
+
executions: DataTypes.JSON,
|
37
|
+
chainId: DataTypes.NUMBER,
|
38
|
+
gas: DataTypes.STRING,
|
39
|
+
maxGasPrice: DataTypes.STRING,
|
40
|
+
assets: DataTypes.JSON,
|
41
|
+
metadata: DataTypes.STRING,
|
42
|
+
vnonce: DataTypes.STRING,
|
43
|
+
txHash: DataTypes.STRING,
|
44
|
+
blockNumber: DataTypes.STRING,
|
45
|
+
status: {
|
46
|
+
type: DataTypes.STRING,
|
47
|
+
defaultValue: 'pending'
|
48
|
+
},
|
49
|
+
delayUntil: DataTypes.DATE,
|
50
|
+
delayedCount: {
|
51
|
+
type: DataTypes.INTEGER,
|
52
|
+
defaultValue: 0
|
53
|
+
},
|
54
|
+
error: DataTypes.STRING,
|
55
|
+
createdAt: DataTypes.DATE,
|
56
|
+
updatedAt: DataTypes.DATE,
|
57
|
+
}, { sequelize, tableName: 'executions' });
|
@@ -0,0 +1 @@
|
|
1
|
+
export * from './execution';
|
@@ -0,0 +1,21 @@
|
|
1
|
+
//@ts-ignore
|
2
|
+
import expandHomeDir from "expand-home-dir";
|
3
|
+
|
4
|
+
import { Sequelize } from 'sequelize';
|
5
|
+
|
6
|
+
const basePath = expandHomeDir('~/.interop-x/data');
|
7
|
+
|
8
|
+
export const sequelize = new Sequelize({
|
9
|
+
dialect: 'sqlite',
|
10
|
+
storage: `${basePath}/localDB.sqlite`,
|
11
|
+
// dialectModulePath: '@journeyapps/sqlcipher',
|
12
|
+
logging: false,
|
13
|
+
});
|
14
|
+
|
15
|
+
sequelize.sync({
|
16
|
+
alter: true
|
17
|
+
}).then(() => {
|
18
|
+
// sequelize.query('PRAGMA cipher_compatibility = 3');
|
19
|
+
// sequelize.query("PRAGMA key = 'your-encryption-key'");
|
20
|
+
})
|
21
|
+
|
package/src/index.ts
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
import { assert } from "console";
|
2
|
+
import dotenv from "dotenv";
|
3
|
+
import { Tasks } from "tasks";
|
4
|
+
import Logger from "./logger";
|
5
|
+
import { startPeer } from "./net";
|
6
|
+
dotenv.config();
|
7
|
+
|
8
|
+
assert(process.env.PRIVATE_KEY, "PRIVATE_KEY is not defined");
|
9
|
+
|
10
|
+
const logger = new Logger('Process')
|
11
|
+
|
12
|
+
async function main() {
|
13
|
+
|
14
|
+
startPeer({})
|
15
|
+
|
16
|
+
const tasks = new Tasks()
|
17
|
+
|
18
|
+
tasks.start();
|
19
|
+
}
|
20
|
+
|
21
|
+
main()
|
22
|
+
.then(() => {
|
23
|
+
}).catch(err => {
|
24
|
+
console.error(err);
|
25
|
+
});
|
26
|
+
|
27
|
+
process.on('SIGINT', () => {
|
28
|
+
logger.debug('received SIGINT signal. exiting.')
|
29
|
+
process.exit(0)
|
30
|
+
})
|
31
|
+
|
32
|
+
process.on('SIGTERM', () => {
|
33
|
+
logger.debug('received SIGTERM signal. exiting.')
|
34
|
+
process.exit(0)
|
35
|
+
})
|
36
|
+
|
37
|
+
process.on('unhandledRejection', (reason: Error, p: Promise<any>) => {
|
38
|
+
logger.error('unhandled rejection: promise:', p, 'reason:', reason)
|
39
|
+
})
|