@instadapp/interop-x 0.0.0-dev.dc4f10a → 0.0.0-dev.e69b5e8
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/package.json +5 -5
- package/dist/src/api/index.js +3 -3
- package/dist/src/config/index.js +1 -0
- package/dist/src/index.js +44 -5
- package/dist/src/net/peer/index.js +2 -1
- package/dist/src/net/pool/index.js +18 -2
- package/dist/src/net/protocol/dial/SignatureDialProtocol.1.js +28 -0
- package/dist/src/net/protocol/index.js +41 -1
- package/dist/src/tasks/AutoUpdateTask.js +67 -0
- package/dist/src/tasks/BaseTask.js +7 -3
- package/dist/src/tasks/InteropBridge/ProcessWithdrawEvents.js +2 -3
- package/dist/src/tasks/InteropBridge/SyncWithdrawEvents.js +0 -1
- package/dist/src/tasks/InteropXGateway/ProcessDepositEvents.js +3 -1
- package/dist/src/tasks/InteropXGateway/SyncDepositEvents.js +0 -1
- package/dist/src/tasks/Transactions/SyncTransactionStatusTask.js +53 -0
- package/dist/src/tasks/index.js +4 -0
- package/dist/src/utils/index.js +21 -6
- package/package.json +5 -5
- package/src/api/index.ts +2 -2
- package/src/config/index.ts +2 -0
- package/src/index.ts +56 -7
- package/src/net/peer/index.ts +2 -1
- package/src/net/pool/index.ts +25 -5
- package/src/net/protocol/dial/SignatureDialProtocol.1.ts +31 -0
- package/src/net/protocol/index.ts +57 -1
- package/src/tasks/AutoUpdateTask.ts +81 -0
- package/src/tasks/BaseTask.ts +8 -3
- package/src/tasks/InteropBridge/ProcessWithdrawEvents.ts +2 -12
- package/src/tasks/InteropBridge/SyncWithdrawEvents.ts +0 -2
- package/src/tasks/InteropXGateway/ProcessDepositEvents.ts +4 -2
- package/src/tasks/InteropXGateway/SyncDepositEvents.ts +0 -2
- package/src/tasks/Transactions/SyncTransactionStatusTask.ts +65 -0
- package/src/tasks/index.ts +5 -0
- package/src/utils/index.ts +23 -5
    
        package/package.json
    CHANGED
    
    | @@ -1,6 +1,6 @@ | |
| 1 1 | 
             
            {
         | 
| 2 2 | 
             
              "name": "@instadapp/interop-x",
         | 
| 3 | 
            -
              "version": "0.0.0-dev. | 
| 3 | 
            +
              "version": "0.0.0-dev.e69b5e8",
         | 
| 4 4 | 
             
              "license": "MIT",
         | 
| 5 5 | 
             
              "main": "dist/index.js",
         | 
| 6 6 | 
             
              "engines": {
         | 
| @@ -24,9 +24,10 @@ | |
| 24 24 | 
             
              },
         | 
| 25 25 | 
             
              "dependencies": {
         | 
| 26 26 | 
             
                "@achingbrain/libp2p-gossipsub": "^0.12.2",
         | 
| 27 | 
            +
                "@fastify/cors": "^7.0.0",
         | 
| 28 | 
            +
                "await-spawn": "^4.0.2",
         | 
| 27 29 | 
             
                "axios": "^0.27.1",
         | 
| 28 30 | 
             
                "axios-retry": "^3.2.4",
         | 
| 29 | 
            -
                "bignumber.js": "^9.0.2",
         | 
| 30 31 | 
             
                "chalk": "4.1.2",
         | 
| 31 32 | 
             
                "dotenv": "^16.0.0",
         | 
| 32 33 | 
             
                "ethereumjs-util": "^7.1.4",
         | 
| @@ -34,7 +35,6 @@ | |
| 34 35 | 
             
                "ethers-multisend": "^2.1.1",
         | 
| 35 36 | 
             
                "expand-home-dir": "^0.0.3",
         | 
| 36 37 | 
             
                "fastify": "^3.28.0",
         | 
| 37 | 
            -
                "fastify-cors": "^6.0.3",
         | 
| 38 38 | 
             
                "libp2p": "^0.36.2",
         | 
| 39 39 | 
             
                "libp2p-bootstrap": "^0.14.0",
         | 
| 40 40 | 
             
                "libp2p-kad-dht": "^0.28.6",
         | 
| @@ -46,6 +46,8 @@ | |
| 46 46 | 
             
                "libp2p-websockets": "^0.16.2",
         | 
| 47 47 | 
             
                "luxon": "^2.3.2",
         | 
| 48 48 | 
             
                "module-alias": "^2.2.2",
         | 
| 49 | 
            +
                "patch-package": "^6.4.7",
         | 
| 50 | 
            +
                "postinstall-postinstall": "^2.1.0",
         | 
| 49 51 | 
             
                "sequelize": "6.18.0",
         | 
| 50 52 | 
             
                "sqlite3": "^5.0.5",
         | 
| 51 53 | 
             
                "waait": "^1.0.5"
         | 
| @@ -60,8 +62,6 @@ | |
| 60 62 | 
             
                "@types/fs-extra": "^9.0.13",
         | 
| 61 63 | 
             
                "@types/node": "^17.0.17",
         | 
| 62 64 | 
             
                "nodemon": "^2.0.15",
         | 
| 63 | 
            -
                "patch-package": "^6.4.7",
         | 
| 64 | 
            -
                "postinstall-postinstall": "^2.1.0",
         | 
| 65 65 | 
             
                "replace-in-file": "^6.3.2",
         | 
| 66 66 | 
             
                "rimraf": "^3.0.2",
         | 
| 67 67 | 
             
                "ts-node": "^10.5.0",
         | 
    
        package/src/api/index.ts
    CHANGED
    
    | @@ -1,5 +1,5 @@ | |
| 1 1 | 
             
            import fastify from "fastify"
         | 
| 2 | 
            -
            import cors from 'fastify | 
| 2 | 
            +
            import cors from '@fastify/cors'
         | 
| 3 3 | 
             
            import Logger from "@/logger"
         | 
| 4 4 | 
             
            import { Transaction } from "@/db";
         | 
| 5 5 |  | 
| @@ -27,7 +27,7 @@ export const startApiServer = async () => { | |
| 27 27 |  | 
| 28 28 | 
             
                    logger.log(`RPC Server listening at http://${HOST}:${PORT}`)
         | 
| 29 29 | 
             
                } catch (err) {
         | 
| 30 | 
            -
                    logger.error(err)
         | 
| 30 | 
            +
                    logger.error(err.message)
         | 
| 31 31 | 
             
                    process.exit(1)
         | 
| 32 32 | 
             
                }
         | 
| 33 33 | 
             
            }
         | 
    
        package/src/config/index.ts
    CHANGED
    
    | @@ -8,12 +8,14 @@ class Config { | |
| 8 8 | 
             
                public readonly privateKey: string
         | 
| 9 9 | 
             
                public readonly wallet: Wallet
         | 
| 10 10 | 
             
                public readonly staging: boolean
         | 
| 11 | 
            +
                public readonly autoUpdate: boolean
         | 
| 11 12 |  | 
| 12 13 | 
             
                constructor() {
         | 
| 13 14 | 
             
                    this.events = new EventBus()  as EventBusType
         | 
| 14 15 | 
             
                    this.maxPeers = 10
         | 
| 15 16 | 
             
                    this.privateKey = process.env.PRIVATE_KEY as string;
         | 
| 16 17 | 
             
                    this.staging = !! process.env.STAGING && process.env.STAGING === 'true';
         | 
| 18 | 
            +
                    this.autoUpdate = !! process.env.AUTO_UPDATE && process.env.AUTO_UPDATE === 'true';
         | 
| 17 19 | 
             
                    this.wallet = new Wallet(this.privateKey);
         | 
| 18 20 | 
             
                    this.leadNodeAddress = '0x910E413DBF3F6276Fe8213fF656726bDc142E08E'
         | 
| 19 21 | 
             
                }
         | 
    
        package/src/index.ts
    CHANGED
    
    | @@ -16,8 +16,8 @@ moduleAlias.addAliases({ | |
| 16 16 | 
             
            })
         | 
| 17 17 |  | 
| 18 18 | 
             
            moduleAlias();
         | 
| 19 | 
            -
            import assert from "assert";
         | 
| 20 19 | 
             
            import dotenv from "dotenv";
         | 
| 20 | 
            +
            import chalk from 'chalk';
         | 
| 21 21 | 
             
            import { ethers } from "ethers";
         | 
| 22 22 | 
             
            import packageJson from '../package.json'
         | 
| 23 23 | 
             
            dotenv.config();
         | 
| @@ -25,28 +25,46 @@ dotenv.config(); | |
| 25 25 | 
             
            import Logger from "@/logger";
         | 
| 26 26 | 
             
            const logger = new Logger('Process')
         | 
| 27 27 |  | 
| 28 | 
            -
             | 
| 29 | 
            -
            if (process.argv.at(-1) === 'help') {
         | 
| 28 | 
            +
            const printUsage = () => {
         | 
| 30 29 | 
             
                console.log('Usage:')
         | 
| 31 30 | 
             
                console.log('   PRIVATE_KEY=abcd1234 interop-x')
         | 
| 32 31 | 
             
                console.log('   PRIVATE_KEY=abcd1234 STAGING=true interop-x')
         | 
| 32 | 
            +
                console.log('   PRIVATE_KEY=abcd1234 AUTO_UPDATE=true interop-x')
         | 
| 33 | 
            +
                console.log('   PRIVATE_KEY=abcd1234 API_HOST=0.0.0.0 API_PORT=8080 interop-x')
         | 
| 34 | 
            +
            }
         | 
| 35 | 
            +
             | 
| 36 | 
            +
            if (process.argv.at(-1) === 'help') {
         | 
| 37 | 
            +
                printUsage()
         | 
| 33 38 | 
             
                process.exit(0)
         | 
| 34 39 | 
             
            }
         | 
| 35 40 |  | 
| 36 | 
            -
             | 
| 41 | 
            +
            const GIT_SHORT_HASH = '@GIT_SHORT_HASH@';
         | 
| 37 42 |  | 
| 43 | 
            +
            if (process.argv.at(-1) === 'version') {
         | 
| 44 | 
            +
                console.log(`Interop X Node (v${packageJson.version} - rev.${GIT_SHORT_HASH})`)
         | 
| 45 | 
            +
                process.exit(0)
         | 
| 46 | 
            +
            }
         | 
| 47 | 
            +
             | 
| 48 | 
            +
            if(! process.env.PRIVATE_KEY) {
         | 
| 49 | 
            +
                console.error(chalk.bgRed.white.bold('Please provide a private key\n'))
         | 
| 50 | 
            +
                printUsage()
         | 
| 51 | 
            +
                process.exit(1)
         | 
| 52 | 
            +
            }
         | 
| 38 53 | 
             
            try {
         | 
| 39 54 | 
             
                new ethers.Wallet(process.env.PRIVATE_KEY!)
         | 
| 40 55 | 
             
            } catch (e) {
         | 
| 41 | 
            -
                 | 
| 56 | 
            +
                console.error(chalk.bgRed.white('Invalid private key\n'))
         | 
| 57 | 
            +
                printUsage()
         | 
| 42 58 | 
             
                process.exit(1)
         | 
| 43 59 | 
             
            }
         | 
| 44 60 |  | 
| 45 | 
            -
            logger.debug(`Starting Interop X Node (v${packageJson.version} - rev | 
| 61 | 
            +
            logger.debug(`Starting Interop X Node (v${packageJson.version} - rev.${GIT_SHORT_HASH})`)
         | 
| 46 62 |  | 
| 47 63 | 
             
            import { Tasks } from "@/tasks";
         | 
| 48 | 
            -
            import { startPeer } from "@/net";
         | 
| 64 | 
            +
            import { startPeer, protocol, peerPool } from "@/net";
         | 
| 49 65 | 
             
            import { startApiServer } from '@/api';
         | 
| 66 | 
            +
            import { Transaction } from './db';
         | 
| 67 | 
            +
            import { shortenHash } from './utils';
         | 
| 50 68 |  | 
| 51 69 | 
             
            async function main() {
         | 
| 52 70 |  | 
| @@ -57,6 +75,37 @@ async function main() { | |
| 57 75 | 
             
                tasks.start();
         | 
| 58 76 |  | 
| 59 77 | 
             
                startApiServer()
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                protocol.on('TransactionStatus', async (payload) => {
         | 
| 80 | 
            +
                    if (!peerPool.isLeadNode(payload.peerId)) {
         | 
| 81 | 
            +
                        const peer = peerPool.getPeer(payload.peerId)
         | 
| 82 | 
            +
             | 
| 83 | 
            +
                        if(! peer) {
         | 
| 84 | 
            +
                            return;
         | 
| 85 | 
            +
                        }
         | 
| 86 | 
            +
                        
         | 
| 87 | 
            +
                        logger.info(`ignored transaction status from ${payload.peerId} ${shortenHash(peer.publicAddress)} `)
         | 
| 88 | 
            +
                        return;
         | 
| 89 | 
            +
                    }
         | 
| 90 | 
            +
             | 
| 91 | 
            +
                    const transaction = await Transaction.findOne({ where: { transactionHash: payload.data.transactionHash } })
         | 
| 92 | 
            +
             | 
| 93 | 
            +
                    if (!transaction) {
         | 
| 94 | 
            +
                        return;
         | 
| 95 | 
            +
                    }
         | 
| 96 | 
            +
             | 
| 97 | 
            +
                    transaction.sourceStatus = payload.data.sourceStatus
         | 
| 98 | 
            +
                    transaction.sourceTransactionHash = payload.data.sourceTransactionHash
         | 
| 99 | 
            +
                    transaction.sourceErrors = payload.data.sourceErrors
         | 
| 100 | 
            +
             | 
| 101 | 
            +
                    transaction.targetStatus = payload.data.targetStatus
         | 
| 102 | 
            +
                    transaction.targetTransactionHash = payload.data.targetTransactionHash
         | 
| 103 | 
            +
                    transaction.targetErrors = payload.data.targetErrors
         | 
| 104 | 
            +
             | 
| 105 | 
            +
                    transaction.status = payload.data.status
         | 
| 106 | 
            +
             | 
| 107 | 
            +
                    await transaction.save()
         | 
| 108 | 
            +
                })
         | 
| 60 109 | 
             
            }
         | 
| 61 110 |  | 
| 62 111 | 
             
            main()
         | 
    
        package/src/net/peer/index.ts
    CHANGED
    
    | @@ -17,6 +17,7 @@ import KadDHT from "libp2p-kad-dht"; | |
| 17 17 | 
             
            import PubsubPeerDiscovery from "libp2p-pubsub-peer-discovery";
         | 
| 18 18 | 
             
            import { protocol } from "@/net";
         | 
| 19 19 | 
             
            import config from "@/config";
         | 
| 20 | 
            +
            import chalk from "chalk";
         | 
| 20 21 |  | 
| 21 22 | 
             
            const logger = new Logger("Peer");
         | 
| 22 23 |  | 
| @@ -80,7 +81,7 @@ export const startPeer = async ({ }: IPeerOptions) => { | |
| 80 81 | 
             
                },
         | 
| 81 82 | 
             
              });
         | 
| 82 83 |  | 
| 83 | 
            -
              logger.info("Peer ID:", node.peerId.toB58String());
         | 
| 84 | 
            +
              logger.info("Peer ID:", chalk.bold(node.peerId.toB58String()));
         | 
| 84 85 |  | 
| 85 86 | 
             
              await node.start();
         | 
| 86 87 |  | 
    
        package/src/net/pool/index.ts
    CHANGED
    
    | @@ -1,6 +1,9 @@ | |
| 1 1 | 
             
            import { Event } from "@/types";
         | 
| 2 2 | 
             
            import config from "@/config";
         | 
| 3 3 | 
             
            import Logger from "@/logger";
         | 
| 4 | 
            +
            import { getAddress } from "ethers/lib/utils";
         | 
| 5 | 
            +
            import { shortenHash } from "@/utils";
         | 
| 6 | 
            +
            import chalk from "chalk";
         | 
| 4 7 |  | 
| 5 8 |  | 
| 6 9 | 
             
            const logger = new Logger('PeerPool')
         | 
| @@ -83,10 +86,10 @@ export class PeerPool { | |
| 83 86 | 
             
                        const newPeer = !this.pool.get(peer.id);
         | 
| 84 87 | 
             
                        this.pool.set(peer.id, peer)
         | 
| 85 88 | 
             
                        peer.pooled = true
         | 
| 86 | 
            -
             | 
| 87 | 
            -
                        if(newPeer) {
         | 
| 89 | 
            +
             | 
| 90 | 
            +
                        if (newPeer) {
         | 
| 88 91 | 
             
                            config.events.emit(Event.POOL_PEER_ADDED, peer)
         | 
| 89 | 
            -
                            logger.info(`Peer ${peer.id} with address ${peer.publicAddress} added to pool`)
         | 
| 92 | 
            +
                            logger.info(`Peer ${chalk.bold(shortenHash(peer.id, 16))} with address ${chalk.bold(shortenHash(peer.publicAddress))} added to pool`)
         | 
| 90 93 | 
             
                        }
         | 
| 91 94 | 
             
                    }
         | 
| 92 95 | 
             
                }
         | 
| @@ -101,7 +104,7 @@ export class PeerPool { | |
| 101 104 | 
             
                        if (this.pool.delete(peer.id)) {
         | 
| 102 105 | 
             
                            peer.pooled = false
         | 
| 103 106 | 
             
                            config.events.emit(Event.POOL_PEER_REMOVED, peer)
         | 
| 104 | 
            -
                            logger.info(`Peer ${peer.id} with address ${peer.publicAddress} removed from pool`)
         | 
| 107 | 
            +
                            logger.info(`Peer ${chalk.bold(shortenHash(peer.id, 16))} with address ${chalk.bold(shortenHash(peer.publicAddress))} removed from pool`)
         | 
| 105 108 | 
             
                        }
         | 
| 106 109 | 
             
                    }
         | 
| 107 110 | 
             
                }
         | 
| @@ -110,7 +113,7 @@ export class PeerPool { | |
| 110 113 | 
             
                    this.cleanup()
         | 
| 111 114 |  | 
| 112 115 | 
             
                    return this.peers.filter((p) => {
         | 
| 113 | 
            -
                        if(!p.pooled) return false;
         | 
| 116 | 
            +
                        if (!p.pooled) return false;
         | 
| 114 117 |  | 
| 115 118 | 
             
                        const now = new Date()
         | 
| 116 119 |  | 
| @@ -122,6 +125,23 @@ export class PeerPool { | |
| 122 125 | 
             
                    return this.activePeers.map((p) => p.id)
         | 
| 123 126 | 
             
                }
         | 
| 124 127 |  | 
| 128 | 
            +
                getPeer(id: string){
         | 
| 129 | 
            +
                 return this.pool.get(id);   
         | 
| 130 | 
            +
                }
         | 
| 131 | 
            +
             | 
| 132 | 
            +
                isLeadNode(id: string) {
         | 
| 133 | 
            +
                    const peer = this.pool.get(id);
         | 
| 134 | 
            +
             | 
| 135 | 
            +
                    if (!peer) {
         | 
| 136 | 
            +
                        return false;
         | 
| 137 | 
            +
                    }
         | 
| 138 | 
            +
             | 
| 139 | 
            +
                    return getAddress(peer.publicAddress) === getAddress(config.leadNodeAddress)
         | 
| 140 | 
            +
                }
         | 
| 141 | 
            +
             | 
| 142 | 
            +
                getLeadPeer() {
         | 
| 143 | 
            +
                    return this.peers.find((p) => this.isLeadNode(p.id))
         | 
| 144 | 
            +
                }
         | 
| 125 145 |  | 
| 126 146 | 
             
                cleanup() {
         | 
| 127 147 | 
             
                    // let compDate = Date.now() - this.PEERS_CLEANUP_TIME_LIMIT * 60
         | 
| @@ -0,0 +1,31 @@ | |
| 1 | 
            +
            import { BaseDialProtocol } from "./BaseDialProtocol";
         | 
| 2 | 
            +
            import { Transaction } from "@/db";
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            export class TransactionStatusDialProtocol extends BaseDialProtocol<string, Pick<Transaction, 'transactionHash' | 'sourceStatus' | 'sourceTransactionHash' | 'sourceErrors' | 'targetStatus' | 'targetTransactionHash' | 'targetErrors' | 'status'> | null> {
         | 
| 5 | 
            +
                protected timeout = 30000;
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                constructor(libp2p) {
         | 
| 8 | 
            +
                    super(libp2p, '/interop-x/transaction-status')
         | 
| 9 | 
            +
                }
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                async response(transactionHash: string){
         | 
| 12 | 
            +
                    const transaction = await Transaction.findOne({ where: { transactionHash } })
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                    if(! transaction){
         | 
| 15 | 
            +
                        return null
         | 
| 16 | 
            +
                    }
         | 
| 17 | 
            +
                    return {
         | 
| 18 | 
            +
                        transactionHash: transaction.transactionHash,
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                        sourceStatus: transaction.sourceStatus,
         | 
| 21 | 
            +
                        sourceTransactionHash: transaction.sourceTransactionHash,
         | 
| 22 | 
            +
                        sourceErrors: transaction.sourceErrors,
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                        targetStatus: transaction.targetStatus,
         | 
| 25 | 
            +
                        targetTransactionHash: transaction.targetTransactionHash,
         | 
| 26 | 
            +
                        targetErrors: transaction.targetErrors,
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                        status: transaction.status,
         | 
| 29 | 
            +
                    }
         | 
| 30 | 
            +
                }
         | 
| 31 | 
            +
            }
         | 
| @@ -5,6 +5,8 @@ import { SignatureDialProtocol, ISignatureRequest, ISignatureResponse } from "./ | |
| 5 5 | 
             
            import { IPeerInfo, peerPool } from "..";
         | 
| 6 6 | 
             
            import config from "@/config";
         | 
| 7 7 | 
             
            import { Event } from "@/types";
         | 
| 8 | 
            +
            import { Transaction } from "@/db";
         | 
| 9 | 
            +
            import { TransactionStatusDialProtocol } from "./dial/SignatureDialProtocol.1";
         | 
| 8 10 |  | 
| 9 11 | 
             
            export interface ProtocolOptions {
         | 
| 10 12 | 
             
                /* Handshake timeout in ms (default: 8000) */
         | 
| @@ -33,7 +35,12 @@ interface PeerInfoEvent extends BaseMessageEvent { | |
| 33 35 | 
             
                data: Omit<IPeerInfo, 'id' | 'updated' | 'idle' | 'pooled'>
         | 
| 34 36 | 
             
            }
         | 
| 35 37 |  | 
| 38 | 
            +
            interface TransactionStatusEvent extends BaseMessageEvent {
         | 
| 39 | 
            +
                data: Pick<Transaction, 'transactionHash' | 'sourceStatus' | 'sourceTransactionHash' | 'sourceErrors' | 'targetStatus' | 'targetTransactionHash' | 'targetErrors' | 'status'>
         | 
| 40 | 
            +
            }
         | 
| 41 | 
            +
             | 
| 36 42 | 
             
            declare interface Protocol {
         | 
| 43 | 
            +
                on(event: 'TransactionStatus', listener: (payload: TransactionStatusEvent) => void): this;
         | 
| 37 44 | 
             
                on(event: 'PeerInfo', listener: (payload: PeerInfoEvent) => void): this;
         | 
| 38 45 | 
             
                on(event: string, listener: (payload: BaseMessageEvent) => void): this;
         | 
| 39 46 | 
             
            }
         | 
| @@ -44,7 +51,7 @@ class Protocol extends EventEmitter { | |
| 44 51 | 
             
                private protocolMessages: Message[] = [
         | 
| 45 52 | 
             
                    {
         | 
| 46 53 | 
             
                        name: 'PeerInfo',
         | 
| 47 | 
            -
                        code:  | 
| 54 | 
            +
                        code: 0x01,
         | 
| 48 55 | 
             
                        encode: (info: Pick<IPeerInfo, 'publicAddress'>) => [
         | 
| 49 56 | 
             
                            Buffer.from(info.publicAddress),
         | 
| 50 57 | 
             
                        ],
         | 
| @@ -52,8 +59,39 @@ class Protocol extends EventEmitter { | |
| 52 59 | 
             
                            publicAddress: publicAddress.toString(),
         | 
| 53 60 | 
             
                        }),
         | 
| 54 61 | 
             
                    },
         | 
| 62 | 
            +
                    {
         | 
| 63 | 
            +
                        name: 'TransactionStatus',
         | 
| 64 | 
            +
                        code: 0x02,
         | 
| 65 | 
            +
                        encode: (transaction: Transaction) => [
         | 
| 66 | 
            +
                            Buffer.from(transaction.transactionHash),
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                            Buffer.from(transaction.sourceStatus),
         | 
| 69 | 
            +
                            Buffer.from(transaction.sourceTransactionHash),
         | 
| 70 | 
            +
                            transaction.sourceErrors ? transaction.sourceErrors.map((e) => Buffer.from(e)) : [],
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                            Buffer.from(transaction.targetStatus),
         | 
| 73 | 
            +
                            Buffer.from(transaction.targetTransactionHash),
         | 
| 74 | 
            +
                            transaction.targetErrors ? transaction.targetErrors.map((e) => Buffer.from(e)) : [],
         | 
| 75 | 
            +
             | 
| 76 | 
            +
                            Buffer.from(transaction.status),
         | 
| 77 | 
            +
                        ],
         | 
| 78 | 
            +
                        decode: ([transactionHash, sourceStatus, sourceTransactionHash, sourceErrors, targetStatus, targetTransactionHash, targetErrors, status]: [Buffer, Buffer, Buffer, Buffer[], Buffer, Buffer, Buffer[], Buffer]) => ({
         | 
| 79 | 
            +
                            transactionHash: transactionHash.toString(),
         | 
| 80 | 
            +
             | 
| 81 | 
            +
                            sourceStatus: sourceStatus.toString(),
         | 
| 82 | 
            +
                            sourceTransactionHash: sourceTransactionHash.toString(),
         | 
| 83 | 
            +
                            sourceErrors: sourceErrors.map((e) => e.toString()),
         | 
| 84 | 
            +
             | 
| 85 | 
            +
                            targetStatus: targetStatus.toString(),
         | 
| 86 | 
            +
                            targetTransactionHash: targetTransactionHash.toString(),
         | 
| 87 | 
            +
                            targetErrors: targetErrors.map((e) => e.toString()),
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                            status: status.toString(),
         | 
| 90 | 
            +
                        }),
         | 
| 91 | 
            +
                    },
         | 
| 55 92 | 
             
                ];
         | 
| 56 93 | 
             
                private signature: SignatureDialProtocol;
         | 
| 94 | 
            +
                private transactionStatus: TransactionStatusDialProtocol;
         | 
| 57 95 |  | 
| 58 96 |  | 
| 59 97 | 
             
                start({ libp2p, topic = null, }) {
         | 
| @@ -73,6 +111,7 @@ class Protocol extends EventEmitter { | |
| 73 111 | 
             
                    })
         | 
| 74 112 |  | 
| 75 113 | 
             
                    this.signature = new SignatureDialProtocol(this.libp2p);
         | 
| 114 | 
            +
                    this.transactionStatus = new TransactionStatusDialProtocol(this.libp2p);
         | 
| 76 115 | 
             
                }
         | 
| 77 116 |  | 
| 78 117 |  | 
| @@ -121,6 +160,14 @@ class Protocol extends EventEmitter { | |
| 121 160 | 
             
                    this.libp2p.pubsub.publish(this.topic, encoded)
         | 
| 122 161 | 
             
                }
         | 
| 123 162 |  | 
| 163 | 
            +
                public sendTransaction(transaction: Transaction) {
         | 
| 164 | 
            +
                    const message = this.protocolMessages.find((m) => m.name === 'TransactionStatus')!
         | 
| 165 | 
            +
             | 
| 166 | 
            +
                    const encoded = rlp.encode([message.code, message.encode(transaction)]);
         | 
| 167 | 
            +
             | 
| 168 | 
            +
                    this.libp2p.pubsub.publish(this.topic, encoded)
         | 
| 169 | 
            +
                }
         | 
| 170 | 
            +
             | 
| 124 171 | 
             
                async requestSignatures(data: ISignatureRequest, peerIds?: string[]) {
         | 
| 125 172 | 
             
                    try {
         | 
| 126 173 | 
             
                        peerIds = peerIds || peerPool.activePeerIds;
         | 
| @@ -133,6 +180,15 @@ class Protocol extends EventEmitter { | |
| 133 180 | 
             
                        return []
         | 
| 134 181 | 
             
                    }
         | 
| 135 182 | 
             
                }
         | 
| 183 | 
            +
             | 
| 184 | 
            +
                async requestTransactionStatus(transactionHash: string, peerId: string) {
         | 
| 185 | 
            +
                    try {
         | 
| 186 | 
            +
                        return await this.transactionStatus.send(transactionHash, peerId);
         | 
| 187 | 
            +
                    } catch (error) {
         | 
| 188 | 
            +
                        console.log(error);
         | 
| 189 | 
            +
                        return null
         | 
| 190 | 
            +
                    }
         | 
| 191 | 
            +
                }
         | 
| 136 192 | 
             
            }
         | 
| 137 193 |  | 
| 138 194 | 
             
            export const protocol = new Protocol();
         | 
| @@ -0,0 +1,81 @@ | |
| 1 | 
            +
            import { BaseTask } from "./BaseTask";
         | 
| 2 | 
            +
            import Logger from '@/logger';
         | 
| 3 | 
            +
            import { http } from "@/utils";
         | 
| 4 | 
            +
            import spawn from 'await-spawn';
         | 
| 5 | 
            +
            import config from "@/config";
         | 
| 6 | 
            +
            import wait from "waait";
         | 
| 7 | 
            +
            import packageJson from "../../package.json";
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            const currentVersion = packageJson.version;
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            class AutoUpdateTask extends BaseTask {
         | 
| 12 | 
            +
                pollIntervalMs: number = 60 * 5 * 1000
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                constructor() {
         | 
| 15 | 
            +
                    super({
         | 
| 16 | 
            +
                        logger: new Logger("AutoUpdateTask"),
         | 
| 17 | 
            +
                    })
         | 
| 18 | 
            +
                }
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                prePollHandler(): boolean {
         | 
| 21 | 
            +
                    return config.autoUpdate && !config.isLeadNode();
         | 
| 22 | 
            +
                }
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                async getInstalledVersion() {
         | 
| 25 | 
            +
                    try {
         | 
| 26 | 
            +
                        const stdout = await spawn('npm', ['-g', 'ls', '--depth=0', '--json'])
         | 
| 27 | 
            +
                        return JSON.parse(stdout.toString()).dependencies[packageJson.name].version
         | 
| 28 | 
            +
                    } catch (error) {
         | 
| 29 | 
            +
                        this.logger.error(error)
         | 
| 30 | 
            +
                        
         | 
| 31 | 
            +
                        return currentVersion
         | 
| 32 | 
            +
                    }
         | 
| 33 | 
            +
                }
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                async getLatestVersion() {
         | 
| 36 | 
            +
                    try {
         | 
| 37 | 
            +
                        const stdout = await spawn('npm', ['view', packageJson.name, 'version'])
         | 
| 38 | 
            +
                        return stdout.toString().trim()
         | 
| 39 | 
            +
                    } catch (error) {
         | 
| 40 | 
            +
                        this.logger.error(error)
         | 
| 41 | 
            +
                        
         | 
| 42 | 
            +
                        return currentVersion
         | 
| 43 | 
            +
                    }
         | 
| 44 | 
            +
                }
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                async pollHandler() {
         | 
| 47 | 
            +
                    const version = await this.getLatestVersion()
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                    if (version === currentVersion) {
         | 
| 50 | 
            +
                        return;
         | 
| 51 | 
            +
                    }
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                    this.logger.warn(`New version ${version} available.`)
         | 
| 54 | 
            +
             | 
| 55 | 
            +
             | 
| 56 | 
            +
                    this.logger.info('Updating...')
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                    const spawner = spawn('npm', ['-g', 'install', '@instadapp/interop-x@latest', '-f']);
         | 
| 59 | 
            +
                    spawner.child.on('data', console.log)
         | 
| 60 | 
            +
                    await spawner
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                    await wait(5000)
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                    if (version !== await this.getInstalledVersion()) {
         | 
| 65 | 
            +
                        this.logger.warn(`failed to install ${version}, retrying in 5 minutes`)
         | 
| 66 | 
            +
                        return;
         | 
| 67 | 
            +
                    }
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                    this.logger.warn(`Installed version ${version}`)
         | 
| 70 | 
            +
                    this.logger.warn(`Restarting...`)
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                    spawn(process.argv[0], process.argv.slice(1), {
         | 
| 73 | 
            +
                        cwd: process.cwd(),
         | 
| 74 | 
            +
                        stdio: "inherit"
         | 
| 75 | 
            +
                    });
         | 
| 76 | 
            +
             | 
| 77 | 
            +
                    process.exit()
         | 
| 78 | 
            +
                }
         | 
| 79 | 
            +
            }
         | 
| 80 | 
            +
             | 
| 81 | 
            +
            export default AutoUpdateTask;
         | 
    
        package/src/tasks/BaseTask.ts
    CHANGED
    
    | @@ -19,6 +19,7 @@ export class BaseTask extends EventEmitter implements IBaseTask { | |
| 19 19 | 
             
                started: boolean = false
         | 
| 20 20 | 
             
                pollIntervalMs: number = 10 * 1000
         | 
| 21 21 | 
             
                leadNodeOnly: boolean = false
         | 
| 22 | 
            +
                exceptLeadNode: boolean = false
         | 
| 22 23 |  | 
| 23 24 | 
             
                public constructor({ logger }: { logger?: Logger }) {
         | 
| 24 25 | 
             
                    super()
         | 
| @@ -45,11 +46,15 @@ export class BaseTask extends EventEmitter implements IBaseTask { | |
| 45 46 | 
             
                }
         | 
| 46 47 |  | 
| 47 48 | 
             
                prePollHandler(): boolean {
         | 
| 48 | 
            -
                    if ( | 
| 49 | 
            -
                        return  | 
| 49 | 
            +
                    if (this.exceptLeadNode) {
         | 
| 50 | 
            +
                        return !config.isLeadNode();
         | 
| 50 51 | 
             
                    }
         | 
| 51 52 |  | 
| 52 | 
            -
                     | 
| 53 | 
            +
                    if (this.leadNodeOnly) {
         | 
| 54 | 
            +
                        return config.isLeadNode()
         | 
| 55 | 
            +
                    }
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                    return true
         | 
| 53 58 | 
             
                }
         | 
| 54 59 |  | 
| 55 60 | 
             
                async pollHandler() {
         | 
| @@ -54,9 +54,7 @@ const generateGnosisTransaction = async (transactionData: any, safeContract: Gno | |
| 54 54 | 
             
            }
         | 
| 55 55 |  | 
| 56 56 | 
             
            class ProcessWithdrawEvents extends BaseTask {
         | 
| 57 | 
            -
                contractAddress: string;
         | 
| 58 57 | 
             
                provider: ethers.providers.JsonRpcProvider;
         | 
| 59 | 
            -
                contract: InteropXGateway;
         | 
| 60 58 | 
             
                chainId: ChainId;
         | 
| 61 59 | 
             
                leadNodeOnly = true
         | 
| 62 60 |  | 
| @@ -209,31 +207,23 @@ class ProcessWithdrawEvents extends BaseTask { | |
| 209 207 | 
             
                    if (parsedLogs.find(e => e.name === 'ExecutionSuccess')) {
         | 
| 210 208 | 
             
                        console.log('ExecutionSuccess')
         | 
| 211 209 | 
             
                        transaction.targetStatus = 'success'
         | 
| 210 | 
            +
                        transaction.targetTransactionHash = txSent.hash
         | 
| 212 211 | 
             
                        transaction.status = 'success'
         | 
| 213 212 | 
             
                        await transaction.save();
         | 
| 214 213 | 
             
                    } else {
         | 
| 215 214 | 
             
                        console.log('ExecutionFailure')
         | 
| 216 215 | 
             
                        transaction.targetStatus = 'failed'
         | 
| 216 | 
            +
                        transaction.targetTransactionHash = txSent.hash
         | 
| 217 217 | 
             
                        transaction.status = 'failed'
         | 
| 218 218 | 
             
                        await transaction.save();
         | 
| 219 219 | 
             
                    }
         | 
| 220 220 | 
             
                }
         | 
| 221 221 |  | 
| 222 222 | 
             
                async start(): Promise<void> {
         | 
| 223 | 
            -
                    this.logger.info(`Starting execution watcher on interop chain`);
         | 
| 224 | 
            -
             | 
| 225 | 
            -
                    this.contractAddress = addresses[this.chainId].interopXGateway;
         | 
| 226 | 
            -
             | 
| 227 223 | 
             
                    this.provider = new ethers.providers.JsonRpcProvider(
         | 
| 228 224 | 
             
                        getRpcProviderUrl(this.chainId)
         | 
| 229 225 | 
             
                    );
         | 
| 230 226 |  | 
| 231 | 
            -
                    this.contract = getContract<InteropXGateway>(
         | 
| 232 | 
            -
                        this.contractAddress,
         | 
| 233 | 
            -
                        abi.interopXGateway,
         | 
| 234 | 
            -
                        new ethers.Wallet(config.privateKey!, this.provider)
         | 
| 235 | 
            -
                    );
         | 
| 236 | 
            -
             | 
| 237 227 | 
             
                    await super.start()
         | 
| 238 228 | 
             
                }
         | 
| 239 229 | 
             
            }
         | 
| @@ -102,8 +102,6 @@ class SyncWithdrawEvents extends BaseTask { | |
| 102 102 | 
             
                }
         | 
| 103 103 |  | 
| 104 104 | 
             
                async start(): Promise<void> {
         | 
| 105 | 
            -
                    this.logger.info(`Starting execution watcher on interop chain`);
         | 
| 106 | 
            -
             | 
| 107 105 | 
             
                    this.provider = new ethers.providers.JsonRpcProvider(
         | 
| 108 106 | 
             
                        getRpcProviderUrl(this.chainId)
         | 
| 109 107 | 
             
                    );
         | 
| @@ -209,19 +209,21 @@ class ProcessDepositEvents extends BaseTask { | |
| 209 209 | 
             
                    if (parsedLogs.find(e => e.name === 'ExecutionSuccess')) {
         | 
| 210 210 | 
             
                        console.log('ExecutionSuccess')
         | 
| 211 211 | 
             
                        transaction.targetStatus = 'success'
         | 
| 212 | 
            +
                        transaction.targetTransactionHash = txSent.hash
         | 
| 212 213 | 
             
                        transaction.status = 'success'
         | 
| 213 214 | 
             
                        await transaction.save();
         | 
| 214 215 | 
             
                    } else {
         | 
| 215 216 | 
             
                        console.log('ExecutionFailure')
         | 
| 216 217 | 
             
                        transaction.targetStatus = 'failed'
         | 
| 218 | 
            +
                        transaction.targetTransactionHash = txSent.hash
         | 
| 217 219 | 
             
                        transaction.status = 'failed'
         | 
| 218 220 | 
             
                        await transaction.save();
         | 
| 219 221 | 
             
                    }
         | 
| 222 | 
            +
             | 
| 223 | 
            +
                    protocol.sendTransaction(transaction)
         | 
| 220 224 | 
             
                }
         | 
| 221 225 |  | 
| 222 226 | 
             
                async start(): Promise<void> {
         | 
| 223 | 
            -
                    this.logger.info(`Starting execution watcher on interop chain`);
         | 
| 224 | 
            -
             | 
| 225 227 | 
             
                    this.contractAddress = addresses[this.chainId].interopXGateway;
         | 
| 226 228 |  | 
| 227 229 | 
             
                    this.provider = new ethers.providers.JsonRpcProvider(
         | 
| @@ -105,8 +105,6 @@ class SyncDepositEvents extends BaseTask { | |
| 105 105 | 
             
                }
         | 
| 106 106 |  | 
| 107 107 | 
             
                async start(): Promise<void> {
         | 
| 108 | 
            -
                    this.logger.info(`Starting execution watcher on interop chain`);
         | 
| 109 | 
            -
             | 
| 110 108 | 
             
                    this.contractAddress = addresses[this.chainId].interopXGateway;
         | 
| 111 109 |  | 
| 112 110 | 
             
                    this.provider = new ethers.providers.JsonRpcProvider(
         | 
| @@ -0,0 +1,65 @@ | |
| 1 | 
            +
            import { BaseTask } from "../BaseTask";
         | 
| 2 | 
            +
            import Logger from '@/logger';
         | 
| 3 | 
            +
            import config from "@/config";
         | 
| 4 | 
            +
            import { peerPool, protocol } from "@/net";
         | 
| 5 | 
            +
            import { Transaction } from "@/db";
         | 
| 6 | 
            +
            import { Op } from "sequelize";
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            class SyncTransactionStatusTask extends BaseTask {
         | 
| 9 | 
            +
                pollIntervalMs: number = 60 * 1000
         | 
| 10 | 
            +
                exceptLeadNode: boolean = true;
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                constructor() {
         | 
| 13 | 
            +
                    super({
         | 
| 14 | 
            +
                        logger: new Logger("SyncTransactionStatusTask"),
         | 
| 15 | 
            +
                    })
         | 
| 16 | 
            +
                }
         | 
| 17 | 
            +
                
         | 
| 18 | 
            +
                async pollHandler() {
         | 
| 19 | 
            +
                    // if transaction is pending for more than 1 hour, check lead node for status
         | 
| 20 | 
            +
                    const leadNode = peerPool.getLeadPeer();
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                    if (!leadNode) {
         | 
| 23 | 
            +
                        return;
         | 
| 24 | 
            +
                    }
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                    const transaction = await Transaction.findOne({
         | 
| 27 | 
            +
                        where: {
         | 
| 28 | 
            +
                            status: 'pending',
         | 
| 29 | 
            +
                            sourceCreatedAt: {
         | 
| 30 | 
            +
                                [Op.gte]: new Date(Date.now() - 60 * 60 * 1000),
         | 
| 31 | 
            +
                            },
         | 
| 32 | 
            +
                        }
         | 
| 33 | 
            +
                    })
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                    if (!transaction) {
         | 
| 36 | 
            +
                        return;
         | 
| 37 | 
            +
                    }
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                    this.logger.info(`Requesting transaction status for ${transaction.transactionHash}`)
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                    const transactionStatus = await protocol.requestTransactionStatus(transaction.transactionHash, leadNode.id);
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                    if (!transactionStatus) {
         | 
| 44 | 
            +
                        return;
         | 
| 45 | 
            +
                    }
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                    this.logger.info(`Received transaction status for ${transaction.transactionHash}`)
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                    transaction.sourceStatus = transactionStatus.sourceStatus
         | 
| 50 | 
            +
                    transaction.sourceTransactionHash = transactionStatus.sourceTransactionHash
         | 
| 51 | 
            +
                    transaction.sourceErrors = transactionStatus.sourceErrors
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                    transaction.targetStatus = transactionStatus.targetStatus
         | 
| 54 | 
            +
                    transaction.targetTransactionHash = transactionStatus.targetTransactionHash
         | 
| 55 | 
            +
                    transaction.targetErrors = transactionStatus.targetErrors
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                    transaction.status = transactionStatus.status
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                    await transaction.save()
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                    this.logger.info(`Updated transaction status for ${transaction.transactionHash}`)
         | 
| 62 | 
            +
                }
         | 
| 63 | 
            +
            }
         | 
| 64 | 
            +
             | 
| 65 | 
            +
            export default SyncTransactionStatusTask;
         | 
    
        package/src/tasks/index.ts
    CHANGED
    
    | @@ -4,10 +4,15 @@ import InteropXGatewaySyncDepositEvents from "./InteropXGateway/SyncDepositEvent | |
| 4 4 |  | 
| 5 5 | 
             
            import InteropBridgeSyncWithdrawEvents from "./InteropBridge/SyncWithdrawEvents";
         | 
| 6 6 | 
             
            import InteropBridgeProcessWithdrawEvents from "./InteropBridge/ProcessWithdrawEvents";
         | 
| 7 | 
            +
            import AutoUpdateTask from "./AutoUpdateTask";
         | 
| 8 | 
            +
            import SyncTransactionStatusTask from "./Transactions/SyncTransactionStatusTask";
         | 
| 7 9 |  | 
| 8 10 | 
             
            export class Tasks {
         | 
| 9 11 |  | 
| 10 12 | 
             
                tasks: BaseTask[] = [
         | 
| 13 | 
            +
                    new SyncTransactionStatusTask(),
         | 
| 14 | 
            +
                    new AutoUpdateTask(),
         | 
| 15 | 
            +
             | 
| 11 16 | 
             
                    new InteropXGatewaySyncDepositEvents({
         | 
| 12 17 | 
             
                        chainId: 43114
         | 
| 13 18 | 
             
                    }),
         |