├── .dockerignore ├── .example.env ├── .gitignore ├── Dockerfile ├── README.md ├── abi └── prod │ ├── AddressBook.abi │ ├── GateKeeper.abi │ ├── Governance.abi │ ├── Minter.abi │ ├── OrbitHub.abi │ ├── Vault.abi │ ├── addressbook │ ├── Stacks.abi │ ├── Ton.abi │ └── Xrp.abi │ ├── bridge │ ├── Common.abi │ ├── Stacks.abi │ └── Xrp.abi │ ├── multisig │ ├── Common.abi │ ├── Ed25519.abi │ ├── Stacks.abi │ └── Xrp.abi │ └── zkevm │ ├── PolygonRollupManager.abi │ └── PolygonValidiumEtrog.abi ├── app.js ├── composes ├── bsc │ └── docker-compose.yml ├── celo │ └── docker-compose.yml ├── docker-compose.common.yml ├── epicleague │ └── docker-compose.yml ├── eth │ └── docker-compose.yml ├── faireth │ └── docker-compose.yml ├── heco │ └── docker-compose.yml ├── icon │ └── docker-compose.yml ├── klaytn │ └── docker-compose.yml ├── metadium │ └── docker-compose.yml ├── orbit │ └── docker-compose.yml ├── polygon │ └── docker-compose.yml ├── poweth │ └── docker-compose.yml ├── silicon │ └── docker-compose.yml ├── stacks │ └── docker-compose.yml ├── ton │ └── docker-compose.yml ├── wemix │ └── docker-compose.yml └── xrp │ └── docker-compose.yml ├── config ├── chain.json ├── governance.js ├── index.js ├── info.js └── prod │ ├── bsc.js │ ├── celo.js │ ├── chainIds.js │ ├── endpoints.js │ ├── epicleague.js │ ├── eth.js │ ├── heco.js │ ├── hub.js │ ├── icon.js │ ├── klaytn.js │ ├── l2.js │ ├── matic.js │ ├── metadium.js │ ├── silicon.js │ ├── system.js │ ├── ton.js │ ├── wemix.js │ └── xrp.js ├── lib ├── api.js ├── bridgeutils.js ├── britto.js ├── decimal.js ├── request.js ├── rpcAggregator.js ├── txsender.js ├── txutils.js └── utils.js ├── logger.js ├── package.json ├── pm2.yaml ├── routes ├── index.js └── v1 │ └── gov.js ├── src ├── evm │ ├── index.js │ ├── logger.js │ └── utils │ │ └── packer.js ├── gov │ ├── index.js │ └── logger.js ├── hub │ ├── index.js │ ├── logger.js │ └── utils │ │ └── packer.js ├── icon │ ├── index.js │ ├── logger.js │ └── utils │ │ ├── icon.api.js │ │ └── packer.js ├── monitor │ └── index.js ├── stacks │ ├── index.js │ ├── logger.js │ └── utils │ │ ├── packer.js │ │ └── stacks.bridgeutils.js ├── stacks_layer_1 │ ├── index.js │ ├── logger.js │ └── utils │ │ ├── packer.js │ │ └── stacks.bridgeutils.js ├── ton │ ├── index.js │ ├── logger.js │ └── utils │ │ ├── packer.js │ │ └── ton.api.js ├── ton_layer_1 │ ├── index.js │ ├── logger.js │ └── utils │ │ ├── packer.js │ │ └── ton.api.js └── xrp │ ├── index.js │ ├── logger.js │ └── utils │ ├── packer.js │ ├── ripple.api.js │ └── xrp.bridgeutils.js ├── wallet.js └── yarn.lock /.dockerignore: -------------------------------------------------------------------------------- 1 | # git 2 | **/.git 3 | 4 | # vscode 5 | **/.vscode 6 | 7 | # node 8 | **/node_modules 9 | 10 | # log 11 | **/logs 12 | 13 | # etc 14 | **/docs 15 | -------------------------------------------------------------------------------- /.example.env: -------------------------------------------------------------------------------- 1 | VALIDATOR_PK= 2 | 3 | # EXPANDED NODE RPC ex) infura, alchemy, etc... 4 | # Type of value must be an array. 5 | # ex) ["https://mainnet.infura.io/v3/[PROJECT_ID]", "https://eth-mainnet.g.alchemy.com/v2/[PROJECT_ID]"] 6 | AVAX=[] 7 | BSC=[] 8 | CELO=[] 9 | ETH=[] 10 | FANTOM=[] 11 | HARMONY=[] 12 | HECO=[] 13 | KLAYTN=[] 14 | MATIC=[] 15 | XDAI=[] 16 | 17 | #KAS CREDENTIAL 18 | KAS_ACCESS_KEY_ID= 19 | KAS_SECRET_ACCESS_KEY= 20 | 21 | #TON 22 | TON_API_KEY= -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # IDE 2 | ## webstorm? 3 | .idea/ 4 | ## vscode 5 | .vscode/ 6 | ## MacOS 7 | *.DS_Store 8 | 9 | # node dependency 10 | ## installed modules 11 | node_modules/ 12 | 13 | ## nvm 14 | .nvmrc 15 | 16 | # log 17 | logs/ 18 | log/ 19 | 20 | # dev config 21 | **/dev 22 | 23 | # docker-compose env_file 24 | **/.env 25 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:20 as builder 2 | 3 | WORKDIR /workspace 4 | 5 | #Build 6 | COPY package.json package.json 7 | COPY yarn.lock yarn.lock 8 | RUN yarn install --immutable --immutable-cache --check-cache 9 | 10 | COPY src src 11 | 12 | FROM node:20-alpine 13 | 14 | RUN npm install -g pm2 15 | 16 | COPY --from=builder workspace/node_modules node_modules 17 | RUN apk --no-cache add curl 18 | 19 | ARG ENV_FILE 20 | COPY $ENV_FILE .env 21 | COPY abi abi 22 | COPY config config 23 | COPY lib lib 24 | COPY routes routes 25 | COPY src src 26 | COPY app.js app.js 27 | COPY logger.js logger.js 28 | COPY wallet.js wallet.js 29 | COPY pm2.yaml pm2.yaml 30 | 31 | ENTRYPOINT ["pm2-runtime", "pm2.yaml"] 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ORBIT BRIDGE 2 | 3 | ## Table of Contents 4 | 5 | * [Overview](#overview) 6 | * [Requirements](#requirements) 7 | * [Installation](#installation) 8 | * [Run](#run) 9 | * [Parser APIs](#parser-apis) 10 | * [Syncer APIs](#syncer-apis) 11 | 12 |
13 | 14 | ## Overview 15 | 16 | Orbit Bridge is a service that allows people to transfer tokens from a chain to other various chains and this project allows anyone to act as a bridge in the token transfer process. 17 | 18 | **project modules** 19 | 20 | Parser : Gathers block info and filters Orbit Bridge's transactions out of it from various chains. 21 | 22 | Syncer : Saves the filtered info and provides data for the Operator to send transactions to various chains. 23 | 24 | Operator : Executes transactions to various chains. 25 | 26 | Validator : Checks if the transfer requests sent from various chains are valid. 27 | 28 |
29 | 30 | 31 | ## Requirements 32 | 33 | * Docker, [docker-compose](https://docs.docker.com/compose/install/) 34 | * Orbit chain contracts (multisig message wallets) 35 | * Vault contract or wallet of the origin chain 36 | * Minter contracts (destination chain) 37 | * Governance registered in Orbit chain 38 | * Origin / Destination / Orbit node endpoints (running your own node might be needed in addition) 39 | 40 | 41 |
42 | 43 | ## DETAILED GUIDE HERE 44 | 45 | * [FOR VALIDATOR](https://orbit-1.gitbook.io/orbit-bridge/validator-guide) 46 | 47 | ## Installation 48 | 49 | * Place your governance info in *[ VAULT_DIR ]/settings.js* 50 | 51 | ## Run 52 | 53 | * for ether vault validator 54 | ```bash 55 | cp .example.env ~/bridge-dockerize/composes/eth/.env 56 | sudo docker-compose -f ~/bridge-dockerize/eth/docker-compose.yml up --build -d 57 | ``` 58 | 59 | ## Validator APIs 60 | 61 | GET|POST / 62 | > Returns the brief status of instance. 63 | 64 | GET|POST /v1/gov/confirm/:address/:transactionId 65 | > Returns the transaction hash that has been sent by validator. 66 | 67 |
68 | -------------------------------------------------------------------------------- /abi/prod/GateKeeper.abi: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "constant": false, 4 | "inputs": [ 5 | { 6 | "name": "", 7 | "type": "string" 8 | }, 9 | { 10 | "name": "", 11 | "type": "string" 12 | }, 13 | { 14 | "name": "", 15 | "type": "bytes" 16 | }, 17 | { 18 | "name": "", 19 | "type": "bytes" 20 | }, 21 | { 22 | "name": "", 23 | "type": "bytes" 24 | }, 25 | { 26 | "name": "", 27 | "type": "bytes32[]" 28 | }, 29 | { 30 | "name": "", 31 | "type": "uint256[]" 32 | }, 33 | { 34 | "name": "", 35 | "type": "bytes32[]" 36 | } 37 | ], 38 | "name": "applyLimitation", 39 | "outputs": [], 40 | "payable": false, 41 | "stateMutability": "nonpayable", 42 | "type": "function" 43 | }, 44 | { 45 | "constant": true, 46 | "inputs": [ 47 | { 48 | "name": "", 49 | "type": "string" 50 | }, 51 | { 52 | "name": "", 53 | "type": "string" 54 | }, 55 | { 56 | "name": "", 57 | "type": "bytes" 58 | }, 59 | { 60 | "name": "", 61 | "type": "bytes32[]" 62 | }, 63 | { 64 | "name": "", 65 | "type": "uint256[]" 66 | } 67 | ], 68 | "name": "isApplied", 69 | "outputs": [ 70 | { 71 | "name": "", 72 | "type": "bool" 73 | } 74 | ], 75 | "payable": false, 76 | "stateMutability": "view", 77 | "type": "function" 78 | } 79 | ] 80 | -------------------------------------------------------------------------------- /abi/prod/Minter.abi: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "anonymous": false, 4 | "inputs": [ 5 | { 6 | "indexed": false, 7 | "internalType": "bool", 8 | "name": "success", 9 | "type": "bool" 10 | }, 11 | { 12 | "indexed": false, 13 | "internalType": "bytes", 14 | "name": "fromAddr", 15 | "type": "bytes" 16 | }, 17 | { 18 | "indexed": false, 19 | "internalType": "address", 20 | "name": "tokenAddress", 21 | "type": "address" 22 | }, 23 | { 24 | "indexed": false, 25 | "internalType": "bytes", 26 | "name": "data", 27 | "type": "bytes" 28 | } 29 | ], 30 | "name": "BridgeReceiverResult", 31 | "type": "event" 32 | }, 33 | { 34 | "anonymous": false, 35 | "inputs": [ 36 | { 37 | "indexed": false, 38 | "internalType": "string", 39 | "name": "fromChain", 40 | "type": "string" 41 | }, 42 | { 43 | "indexed": false, 44 | "internalType": "bytes", 45 | "name": "fromAddr", 46 | "type": "bytes" 47 | }, 48 | { 49 | "indexed": false, 50 | "internalType": "bytes", 51 | "name": "toAddr", 52 | "type": "bytes" 53 | }, 54 | { 55 | "indexed": false, 56 | "internalType": "address", 57 | "name": "tokenAddress", 58 | "type": "address" 59 | }, 60 | { 61 | "indexed": false, 62 | "internalType": "bytes32[]", 63 | "name": "bytes32s", 64 | "type": "bytes32[]" 65 | }, 66 | { 67 | "indexed": false, 68 | "internalType": "uint256[]", 69 | "name": "uints", 70 | "type": "uint256[]" 71 | }, 72 | { 73 | "indexed": false, 74 | "internalType": "bytes", 75 | "name": "data", 76 | "type": "bytes" 77 | } 78 | ], 79 | "name": "Swap", 80 | "type": "event" 81 | }, 82 | { 83 | "anonymous": false, 84 | "inputs": [ 85 | { 86 | "indexed": false, 87 | "internalType": "string", 88 | "name": "fromChain", 89 | "type": "string" 90 | }, 91 | { 92 | "indexed": false, 93 | "internalType": "bytes", 94 | "name": "fromAddr", 95 | "type": "bytes" 96 | }, 97 | { 98 | "indexed": false, 99 | "internalType": "bytes", 100 | "name": "toAddr", 101 | "type": "bytes" 102 | }, 103 | { 104 | "indexed": false, 105 | "internalType": "address", 106 | "name": "tokenAddress", 107 | "type": "address" 108 | }, 109 | { 110 | "indexed": false, 111 | "internalType": "bytes32[]", 112 | "name": "bytes32s", 113 | "type": "bytes32[]" 114 | }, 115 | { 116 | "indexed": false, 117 | "internalType": "uint256[]", 118 | "name": "uints", 119 | "type": "uint256[]" 120 | }, 121 | { 122 | "indexed": false, 123 | "internalType": "bytes", 124 | "name": "data", 125 | "type": "bytes" 126 | } 127 | ], 128 | "name": "SwapNFT", 129 | "type": "event" 130 | }, 131 | { 132 | "anonymous": false, 133 | "inputs": [ 134 | { 135 | "indexed": false, 136 | "internalType": "string", 137 | "name": "toChain", 138 | "type": "string" 139 | }, 140 | { 141 | "indexed": false, 142 | "internalType": "address", 143 | "name": "fromAddr", 144 | "type": "address" 145 | }, 146 | { 147 | "indexed": false, 148 | "internalType": "bytes", 149 | "name": "toAddr", 150 | "type": "bytes" 151 | }, 152 | { 153 | "indexed": false, 154 | "internalType": "bytes", 155 | "name": "token", 156 | "type": "bytes" 157 | }, 158 | { 159 | "indexed": false, 160 | "internalType": "address", 161 | "name": "tokenAddress", 162 | "type": "address" 163 | }, 164 | { 165 | "indexed": false, 166 | "internalType": "uint8", 167 | "name": "decimal", 168 | "type": "uint8" 169 | }, 170 | { 171 | "indexed": false, 172 | "internalType": "uint256", 173 | "name": "amount", 174 | "type": "uint256" 175 | }, 176 | { 177 | "indexed": false, 178 | "internalType": "uint256", 179 | "name": "depositId", 180 | "type": "uint256" 181 | }, 182 | { 183 | "indexed": false, 184 | "internalType": "bytes", 185 | "name": "data", 186 | "type": "bytes" 187 | } 188 | ], 189 | "name": "SwapRequest", 190 | "type": "event" 191 | }, 192 | { 193 | "anonymous": false, 194 | "inputs": [ 195 | { 196 | "indexed": false, 197 | "internalType": "string", 198 | "name": "toChain", 199 | "type": "string" 200 | }, 201 | { 202 | "indexed": false, 203 | "internalType": "address", 204 | "name": "fromAddr", 205 | "type": "address" 206 | }, 207 | { 208 | "indexed": false, 209 | "internalType": "bytes", 210 | "name": "toAddr", 211 | "type": "bytes" 212 | }, 213 | { 214 | "indexed": false, 215 | "internalType": "bytes", 216 | "name": "token", 217 | "type": "bytes" 218 | }, 219 | { 220 | "indexed": false, 221 | "internalType": "address", 222 | "name": "tokenAddress", 223 | "type": "address" 224 | }, 225 | { 226 | "indexed": false, 227 | "internalType": "uint256", 228 | "name": "tokenId", 229 | "type": "uint256" 230 | }, 231 | { 232 | "indexed": false, 233 | "internalType": "uint256", 234 | "name": "amount", 235 | "type": "uint256" 236 | }, 237 | { 238 | "indexed": false, 239 | "internalType": "uint256", 240 | "name": "depositId", 241 | "type": "uint256" 242 | }, 243 | { 244 | "indexed": false, 245 | "internalType": "bytes", 246 | "name": "data", 247 | "type": "bytes" 248 | } 249 | ], 250 | "name": "SwapRequestNFT", 251 | "type": "event" 252 | }, 253 | { 254 | "inputs": [], 255 | "name": "getVersion", 256 | "outputs": [ 257 | { 258 | "internalType": "string", 259 | "name": "", 260 | "type": "string" 261 | } 262 | ], 263 | "stateMutability": "pure", 264 | "type": "function" 265 | } 266 | ] 267 | -------------------------------------------------------------------------------- /abi/prod/Vault.abi: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "anonymous": false, 4 | "inputs": [ 5 | { 6 | "indexed": false, 7 | "internalType": "bool", 8 | "name": "success", 9 | "type": "bool" 10 | }, 11 | { 12 | "indexed": false, 13 | "internalType": "bytes", 14 | "name": "fromAddress", 15 | "type": "bytes" 16 | }, 17 | { 18 | "indexed": false, 19 | "internalType": "address", 20 | "name": "tokenAddress", 21 | "type": "address" 22 | }, 23 | { 24 | "indexed": false, 25 | "internalType": "bytes", 26 | "name": "data", 27 | "type": "bytes" 28 | } 29 | ], 30 | "name": "BridgeReceiverResult", 31 | "type": "event" 32 | }, 33 | { 34 | "anonymous": false, 35 | "inputs": [ 36 | { 37 | "indexed": false, 38 | "internalType": "string", 39 | "name": "toChain", 40 | "type": "string" 41 | }, 42 | { 43 | "indexed": false, 44 | "internalType": "address", 45 | "name": "fromAddr", 46 | "type": "address" 47 | }, 48 | { 49 | "indexed": false, 50 | "internalType": "bytes", 51 | "name": "toAddr", 52 | "type": "bytes" 53 | }, 54 | { 55 | "indexed": false, 56 | "internalType": "address", 57 | "name": "token", 58 | "type": "address" 59 | }, 60 | { 61 | "indexed": false, 62 | "internalType": "uint8", 63 | "name": "decimal", 64 | "type": "uint8" 65 | }, 66 | { 67 | "indexed": false, 68 | "internalType": "uint256", 69 | "name": "amount", 70 | "type": "uint256" 71 | }, 72 | { 73 | "indexed": false, 74 | "internalType": "uint256", 75 | "name": "depositId", 76 | "type": "uint256" 77 | }, 78 | { 79 | "indexed": false, 80 | "internalType": "bytes", 81 | "name": "data", 82 | "type": "bytes" 83 | } 84 | ], 85 | "name": "Deposit", 86 | "type": "event" 87 | }, 88 | { 89 | "anonymous": false, 90 | "inputs": [ 91 | { 92 | "indexed": false, 93 | "internalType": "string", 94 | "name": "toChain", 95 | "type": "string" 96 | }, 97 | { 98 | "indexed": false, 99 | "internalType": "address", 100 | "name": "fromAddr", 101 | "type": "address" 102 | }, 103 | { 104 | "indexed": false, 105 | "internalType": "bytes", 106 | "name": "toAddr", 107 | "type": "bytes" 108 | }, 109 | { 110 | "indexed": false, 111 | "internalType": "address", 112 | "name": "token", 113 | "type": "address" 114 | }, 115 | { 116 | "indexed": false, 117 | "internalType": "uint256", 118 | "name": "tokenId", 119 | "type": "uint256" 120 | }, 121 | { 122 | "indexed": false, 123 | "internalType": "uint256", 124 | "name": "amount", 125 | "type": "uint256" 126 | }, 127 | { 128 | "indexed": false, 129 | "internalType": "uint256", 130 | "name": "depositId", 131 | "type": "uint256" 132 | }, 133 | { 134 | "indexed": false, 135 | "internalType": "bytes", 136 | "name": "data", 137 | "type": "bytes" 138 | } 139 | ], 140 | "name": "DepositNFT", 141 | "type": "event" 142 | }, 143 | { 144 | "anonymous": false, 145 | "inputs": [ 146 | { 147 | "indexed": false, 148 | "internalType": "string", 149 | "name": "fromChain", 150 | "type": "string" 151 | }, 152 | { 153 | "indexed": false, 154 | "internalType": "bytes", 155 | "name": "fromAddr", 156 | "type": "bytes" 157 | }, 158 | { 159 | "indexed": false, 160 | "internalType": "bytes", 161 | "name": "toAddr", 162 | "type": "bytes" 163 | }, 164 | { 165 | "indexed": false, 166 | "internalType": "bytes", 167 | "name": "token", 168 | "type": "bytes" 169 | }, 170 | { 171 | "indexed": false, 172 | "internalType": "bytes32[]", 173 | "name": "bytes32s", 174 | "type": "bytes32[]" 175 | }, 176 | { 177 | "indexed": false, 178 | "internalType": "uint256[]", 179 | "name": "uints", 180 | "type": "uint256[]" 181 | }, 182 | { 183 | "indexed": false, 184 | "internalType": "bytes", 185 | "name": "data", 186 | "type": "bytes" 187 | } 188 | ], 189 | "name": "Withdraw", 190 | "type": "event" 191 | }, 192 | { 193 | "anonymous": false, 194 | "inputs": [ 195 | { 196 | "indexed": false, 197 | "internalType": "string", 198 | "name": "fromChain", 199 | "type": "string" 200 | }, 201 | { 202 | "indexed": false, 203 | "internalType": "bytes", 204 | "name": "fromAddr", 205 | "type": "bytes" 206 | }, 207 | { 208 | "indexed": false, 209 | "internalType": "bytes", 210 | "name": "toAddr", 211 | "type": "bytes" 212 | }, 213 | { 214 | "indexed": false, 215 | "internalType": "bytes", 216 | "name": "token", 217 | "type": "bytes" 218 | }, 219 | { 220 | "indexed": false, 221 | "internalType": "bytes32[]", 222 | "name": "bytes32s", 223 | "type": "bytes32[]" 224 | }, 225 | { 226 | "indexed": false, 227 | "internalType": "uint256[]", 228 | "name": "uints", 229 | "type": "uint256[]" 230 | }, 231 | { 232 | "indexed": false, 233 | "internalType": "bytes", 234 | "name": "data", 235 | "type": "bytes" 236 | } 237 | ], 238 | "name": "WithdrawNFT", 239 | "type": "event" 240 | }, 241 | { 242 | "inputs": [], 243 | "name": "getVersion", 244 | "outputs": [ 245 | { 246 | "internalType": "string", 247 | "name": "", 248 | "type": "string" 249 | } 250 | ], 251 | "stateMutability": "pure", 252 | "type": "function" 253 | } 254 | ] 255 | -------------------------------------------------------------------------------- /abi/prod/addressbook/Stacks.abi: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "constant": true, 4 | "inputs": [], 5 | "name": "validBlock", 6 | "outputs": [ 7 | { 8 | "name": "", 9 | "type": "uint256" 10 | } 11 | ], 12 | "payable": false, 13 | "stateMutability": "view", 14 | "type": "function" 15 | }, 16 | { 17 | "constant": true, 18 | "inputs": [], 19 | "name": "count", 20 | "outputs": [ 21 | { 22 | "name": "", 23 | "type": "uint256" 24 | } 25 | ], 26 | "payable": false, 27 | "stateMutability": "view", 28 | "type": "function" 29 | }, 30 | { 31 | "constant": true, 32 | "inputs": [], 33 | "name": "getValidInfo", 34 | "outputs": [ 35 | { 36 | "name": "_receiver", 37 | "type": "address" 38 | }, 39 | { 40 | "name": "_validBlock", 41 | "type": "uint256" 42 | } 43 | ], 44 | "payable": false, 45 | "stateMutability": "view", 46 | "type": "function" 47 | }, 48 | { 49 | "constant": true, 50 | "inputs": [], 51 | "name": "getVersion", 52 | "outputs": [ 53 | { 54 | "name": "", 55 | "type": "string" 56 | } 57 | ], 58 | "payable": false, 59 | "stateMutability": "view", 60 | "type": "function" 61 | }, 62 | { 63 | "constant": true, 64 | "inputs": [ 65 | { 66 | "name": "", 67 | "type": "bytes32" 68 | }, 69 | { 70 | "name": "", 71 | "type": "bytes32" 72 | }, 73 | { 74 | "name": "", 75 | "type": "bytes32" 76 | } 77 | ], 78 | "name": "tags", 79 | "outputs": [ 80 | { 81 | "name": "", 82 | "type": "uint256" 83 | } 84 | ], 85 | "payable": false, 86 | "stateMutability": "view", 87 | "type": "function" 88 | }, 89 | { 90 | "constant": false, 91 | "inputs": [ 92 | { 93 | "name": "_receiver", 94 | "type": "address" 95 | }, 96 | { 97 | "name": "_validBlock", 98 | "type": "uint256" 99 | } 100 | ], 101 | "name": "setInvalidParam", 102 | "outputs": [], 103 | "payable": false, 104 | "stateMutability": "nonpayable", 105 | "type": "function" 106 | }, 107 | { 108 | "constant": true, 109 | "inputs": [], 110 | "name": "hub", 111 | "outputs": [ 112 | { 113 | "name": "", 114 | "type": "address" 115 | } 116 | ], 117 | "payable": false, 118 | "stateMutability": "view", 119 | "type": "function" 120 | }, 121 | { 122 | "constant": true, 123 | "inputs": [ 124 | { 125 | "name": "", 126 | "type": "uint256" 127 | } 128 | ], 129 | "name": "addrs", 130 | "outputs": [ 131 | { 132 | "name": "", 133 | "type": "bytes" 134 | } 135 | ], 136 | "payable": false, 137 | "stateMutability": "view", 138 | "type": "function" 139 | }, 140 | { 141 | "constant": false, 142 | "inputs": [ 143 | { 144 | "name": "_id", 145 | "type": "bytes32" 146 | } 147 | ], 148 | "name": "setId", 149 | "outputs": [], 150 | "payable": false, 151 | "stateMutability": "nonpayable", 152 | "type": "function" 153 | }, 154 | { 155 | "constant": true, 156 | "inputs": [ 157 | { 158 | "name": "", 159 | "type": "uint256" 160 | } 161 | ], 162 | "name": "chains", 163 | "outputs": [ 164 | { 165 | "name": "", 166 | "type": "string" 167 | } 168 | ], 169 | "payable": false, 170 | "stateMutability": "view", 171 | "type": "function" 172 | }, 173 | { 174 | "constant": true, 175 | "inputs": [], 176 | "name": "implementation", 177 | "outputs": [ 178 | { 179 | "name": "", 180 | "type": "address" 181 | } 182 | ], 183 | "payable": false, 184 | "stateMutability": "view", 185 | "type": "function" 186 | }, 187 | { 188 | "constant": false, 189 | "inputs": [ 190 | { 191 | "name": "_nextOwner", 192 | "type": "address" 193 | } 194 | ], 195 | "name": "changeNextOwner", 196 | "outputs": [], 197 | "payable": false, 198 | "stateMutability": "nonpayable", 199 | "type": "function" 200 | }, 201 | { 202 | "constant": false, 203 | "inputs": [], 204 | "name": "changeOwner", 205 | "outputs": [], 206 | "payable": false, 207 | "stateMutability": "nonpayable", 208 | "type": "function" 209 | }, 210 | { 211 | "constant": true, 212 | "inputs": [ 213 | { 214 | "name": "ctx", 215 | "type": "bytes" 216 | } 217 | ], 218 | "name": "generate", 219 | "outputs": [ 220 | { 221 | "name": "", 222 | "type": "bytes32" 223 | } 224 | ], 225 | "payable": false, 226 | "stateMutability": "view", 227 | "type": "function" 228 | }, 229 | { 230 | "constant": false, 231 | "inputs": [ 232 | { 233 | "name": "toChain", 234 | "type": "string" 235 | }, 236 | { 237 | "name": "toAddr", 238 | "type": "bytes" 239 | }, 240 | { 241 | "name": "data", 242 | "type": "bytes" 243 | } 244 | ], 245 | "name": "relay", 246 | "outputs": [], 247 | "payable": false, 248 | "stateMutability": "nonpayable", 249 | "type": "function" 250 | }, 251 | { 252 | "constant": true, 253 | "inputs": [], 254 | "name": "nextOwner", 255 | "outputs": [ 256 | { 257 | "name": "", 258 | "type": "address" 259 | } 260 | ], 261 | "payable": false, 262 | "stateMutability": "view", 263 | "type": "function" 264 | }, 265 | { 266 | "constant": false, 267 | "inputs": [ 268 | { 269 | "name": "toChain", 270 | "type": "string" 271 | }, 272 | { 273 | "name": "toAddr", 274 | "type": "bytes" 275 | }, 276 | { 277 | "name": "data", 278 | "type": "bytes" 279 | }, 280 | { 281 | "name": "validator", 282 | "type": "address" 283 | }, 284 | { 285 | "name": "v", 286 | "type": "uint8" 287 | }, 288 | { 289 | "name": "r", 290 | "type": "bytes32" 291 | }, 292 | { 293 | "name": "s", 294 | "type": "bytes32" 295 | } 296 | ], 297 | "name": "set", 298 | "outputs": [], 299 | "payable": false, 300 | "stateMutability": "nonpayable", 301 | "type": "function" 302 | }, 303 | { 304 | "constant": false, 305 | "inputs": [ 306 | { 307 | "name": "_hub", 308 | "type": "address" 309 | } 310 | ], 311 | "name": "setHubContract", 312 | "outputs": [], 313 | "payable": false, 314 | "stateMutability": "nonpayable", 315 | "type": "function" 316 | }, 317 | { 318 | "constant": true, 319 | "inputs": [], 320 | "name": "owner", 321 | "outputs": [ 322 | { 323 | "name": "", 324 | "type": "address" 325 | } 326 | ], 327 | "payable": false, 328 | "stateMutability": "view", 329 | "type": "function" 330 | }, 331 | { 332 | "constant": true, 333 | "inputs": [ 334 | { 335 | "name": "tag", 336 | "type": "uint256" 337 | } 338 | ], 339 | "name": "get", 340 | "outputs": [ 341 | { 342 | "name": "toChain", 343 | "type": "string" 344 | }, 345 | { 346 | "name": "toAddr", 347 | "type": "bytes" 348 | }, 349 | { 350 | "name": "data", 351 | "type": "bytes" 352 | } 353 | ], 354 | "payable": false, 355 | "stateMutability": "view", 356 | "type": "function" 357 | }, 358 | { 359 | "constant": true, 360 | "inputs": [], 361 | "name": "id", 362 | "outputs": [ 363 | { 364 | "name": "", 365 | "type": "bytes32" 366 | } 367 | ], 368 | "payable": false, 369 | "stateMutability": "view", 370 | "type": "function" 371 | }, 372 | { 373 | "constant": true, 374 | "inputs": [ 375 | { 376 | "name": "toChain", 377 | "type": "string" 378 | }, 379 | { 380 | "name": "toAddr", 381 | "type": "bytes" 382 | }, 383 | { 384 | "name": "data", 385 | "type": "bytes" 386 | } 387 | ], 388 | "name": "get", 389 | "outputs": [ 390 | { 391 | "name": "tag", 392 | "type": "uint256" 393 | } 394 | ], 395 | "payable": false, 396 | "stateMutability": "view", 397 | "type": "function" 398 | }, 399 | { 400 | "constant": false, 401 | "inputs": [ 402 | { 403 | "name": "_newImp", 404 | "type": "address" 405 | } 406 | ], 407 | "name": "_setImplementation", 408 | "outputs": [], 409 | "payable": false, 410 | "stateMutability": "nonpayable", 411 | "type": "function" 412 | }, 413 | { 414 | "constant": true, 415 | "inputs": [ 416 | { 417 | "name": "", 418 | "type": "uint256" 419 | } 420 | ], 421 | "name": "datas", 422 | "outputs": [ 423 | { 424 | "name": "", 425 | "type": "bytes" 426 | } 427 | ], 428 | "payable": false, 429 | "stateMutability": "view", 430 | "type": "function" 431 | }, 432 | { 433 | "constant": false, 434 | "inputs": [ 435 | { 436 | "name": "_newOwner", 437 | "type": "address" 438 | } 439 | ], 440 | "name": "transferOwnership", 441 | "outputs": [], 442 | "payable": false, 443 | "stateMutability": "nonpayable", 444 | "type": "function" 445 | }, 446 | { 447 | "constant": true, 448 | "inputs": [], 449 | "name": "receiver", 450 | "outputs": [ 451 | { 452 | "name": "", 453 | "type": "address" 454 | } 455 | ], 456 | "payable": false, 457 | "stateMutability": "view", 458 | "type": "function" 459 | }, 460 | { 461 | "inputs": [], 462 | "payable": false, 463 | "stateMutability": "nonpayable", 464 | "type": "constructor" 465 | }, 466 | { 467 | "payable": true, 468 | "stateMutability": "payable", 469 | "type": "fallback" 470 | }, 471 | { 472 | "anonymous": false, 473 | "inputs": [ 474 | { 475 | "indexed": false, 476 | "name": "toChain", 477 | "type": "string" 478 | }, 479 | { 480 | "indexed": false, 481 | "name": "toAddr", 482 | "type": "bytes" 483 | }, 484 | { 485 | "indexed": false, 486 | "name": "data", 487 | "type": "bytes" 488 | }, 489 | { 490 | "indexed": false, 491 | "name": "hash", 492 | "type": "bytes32" 493 | } 494 | ], 495 | "name": "Relay", 496 | "type": "event" 497 | }, 498 | { 499 | "anonymous": false, 500 | "inputs": [ 501 | { 502 | "indexed": false, 503 | "name": "toChain", 504 | "type": "string" 505 | }, 506 | { 507 | "indexed": false, 508 | "name": "toAddr", 509 | "type": "bytes" 510 | }, 511 | { 512 | "indexed": false, 513 | "name": "data", 514 | "type": "bytes" 515 | }, 516 | { 517 | "indexed": false, 518 | "name": "tag", 519 | "type": "uint256" 520 | }, 521 | { 522 | "indexed": false, 523 | "name": "hash", 524 | "type": "bytes32" 525 | } 526 | ], 527 | "name": "Set", 528 | "type": "event" 529 | } 530 | ] -------------------------------------------------------------------------------- /abi/prod/addressbook/Xrp.abi: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "constant": true, 4 | "inputs": [], 5 | "name": "count", 6 | "outputs": [ 7 | { 8 | "name": "", 9 | "type": "uint256" 10 | } 11 | ], 12 | "payable": false, 13 | "stateMutability": "view", 14 | "type": "function" 15 | }, 16 | { 17 | "constant": true, 18 | "inputs": [], 19 | "name": "getVersion", 20 | "outputs": [ 21 | { 22 | "name": "", 23 | "type": "string" 24 | } 25 | ], 26 | "payable": false, 27 | "stateMutability": "view", 28 | "type": "function" 29 | }, 30 | { 31 | "constant": true, 32 | "inputs": [ 33 | { 34 | "name": "", 35 | "type": "bytes32" 36 | }, 37 | { 38 | "name": "", 39 | "type": "bytes32" 40 | }, 41 | { 42 | "name": "", 43 | "type": "bytes32" 44 | } 45 | ], 46 | "name": "tags", 47 | "outputs": [ 48 | { 49 | "name": "", 50 | "type": "uint256" 51 | } 52 | ], 53 | "payable": false, 54 | "stateMutability": "view", 55 | "type": "function" 56 | }, 57 | { 58 | "constant": true, 59 | "inputs": [], 60 | "name": "hub", 61 | "outputs": [ 62 | { 63 | "name": "", 64 | "type": "address" 65 | } 66 | ], 67 | "payable": false, 68 | "stateMutability": "view", 69 | "type": "function" 70 | }, 71 | { 72 | "constant": true, 73 | "inputs": [ 74 | { 75 | "name": "", 76 | "type": "uint256" 77 | } 78 | ], 79 | "name": "addrs", 80 | "outputs": [ 81 | { 82 | "name": "", 83 | "type": "bytes" 84 | } 85 | ], 86 | "payable": false, 87 | "stateMutability": "view", 88 | "type": "function" 89 | }, 90 | { 91 | "constant": false, 92 | "inputs": [ 93 | { 94 | "name": "_id", 95 | "type": "bytes32" 96 | } 97 | ], 98 | "name": "setId", 99 | "outputs": [], 100 | "payable": false, 101 | "stateMutability": "nonpayable", 102 | "type": "function" 103 | }, 104 | { 105 | "constant": true, 106 | "inputs": [ 107 | { 108 | "name": "", 109 | "type": "uint256" 110 | } 111 | ], 112 | "name": "chains", 113 | "outputs": [ 114 | { 115 | "name": "", 116 | "type": "string" 117 | } 118 | ], 119 | "payable": false, 120 | "stateMutability": "view", 121 | "type": "function" 122 | }, 123 | { 124 | "constant": true, 125 | "inputs": [], 126 | "name": "implementation", 127 | "outputs": [ 128 | { 129 | "name": "", 130 | "type": "address" 131 | } 132 | ], 133 | "payable": false, 134 | "stateMutability": "view", 135 | "type": "function" 136 | }, 137 | { 138 | "constant": true, 139 | "inputs": [ 140 | { 141 | "name": "ctx", 142 | "type": "bytes" 143 | } 144 | ], 145 | "name": "generate", 146 | "outputs": [ 147 | { 148 | "name": "", 149 | "type": "bytes32" 150 | } 151 | ], 152 | "payable": false, 153 | "stateMutability": "view", 154 | "type": "function" 155 | }, 156 | { 157 | "constant": false, 158 | "inputs": [ 159 | { 160 | "name": "toChain", 161 | "type": "string" 162 | }, 163 | { 164 | "name": "toAddr", 165 | "type": "bytes" 166 | }, 167 | { 168 | "name": "data", 169 | "type": "bytes" 170 | } 171 | ], 172 | "name": "relay", 173 | "outputs": [], 174 | "payable": false, 175 | "stateMutability": "nonpayable", 176 | "type": "function" 177 | }, 178 | { 179 | "constant": false, 180 | "inputs": [ 181 | { 182 | "name": "toChain", 183 | "type": "string" 184 | }, 185 | { 186 | "name": "toAddr", 187 | "type": "bytes" 188 | }, 189 | { 190 | "name": "data", 191 | "type": "bytes" 192 | }, 193 | { 194 | "name": "validator", 195 | "type": "address" 196 | }, 197 | { 198 | "name": "v", 199 | "type": "uint8" 200 | }, 201 | { 202 | "name": "r", 203 | "type": "bytes32" 204 | }, 205 | { 206 | "name": "s", 207 | "type": "bytes32" 208 | } 209 | ], 210 | "name": "set", 211 | "outputs": [], 212 | "payable": false, 213 | "stateMutability": "nonpayable", 214 | "type": "function" 215 | }, 216 | { 217 | "constant": false, 218 | "inputs": [ 219 | { 220 | "name": "_hub", 221 | "type": "address" 222 | } 223 | ], 224 | "name": "setHubContract", 225 | "outputs": [], 226 | "payable": false, 227 | "stateMutability": "nonpayable", 228 | "type": "function" 229 | }, 230 | { 231 | "constant": true, 232 | "inputs": [], 233 | "name": "owner", 234 | "outputs": [ 235 | { 236 | "name": "", 237 | "type": "address" 238 | } 239 | ], 240 | "payable": false, 241 | "stateMutability": "view", 242 | "type": "function" 243 | }, 244 | { 245 | "constant": true, 246 | "inputs": [ 247 | { 248 | "name": "tag", 249 | "type": "uint256" 250 | } 251 | ], 252 | "name": "get", 253 | "outputs": [ 254 | { 255 | "name": "toChain", 256 | "type": "string" 257 | }, 258 | { 259 | "name": "toAddr", 260 | "type": "bytes" 261 | }, 262 | { 263 | "name": "data", 264 | "type": "bytes" 265 | } 266 | ], 267 | "payable": false, 268 | "stateMutability": "view", 269 | "type": "function" 270 | }, 271 | { 272 | "constant": true, 273 | "inputs": [], 274 | "name": "id", 275 | "outputs": [ 276 | { 277 | "name": "", 278 | "type": "bytes32" 279 | } 280 | ], 281 | "payable": false, 282 | "stateMutability": "view", 283 | "type": "function" 284 | }, 285 | { 286 | "constant": true, 287 | "inputs": [ 288 | { 289 | "name": "toChain", 290 | "type": "string" 291 | }, 292 | { 293 | "name": "toAddr", 294 | "type": "bytes" 295 | }, 296 | { 297 | "name": "data", 298 | "type": "bytes" 299 | } 300 | ], 301 | "name": "get", 302 | "outputs": [ 303 | { 304 | "name": "tag", 305 | "type": "uint256" 306 | } 307 | ], 308 | "payable": false, 309 | "stateMutability": "view", 310 | "type": "function" 311 | }, 312 | { 313 | "constant": false, 314 | "inputs": [ 315 | { 316 | "name": "_newImp", 317 | "type": "address" 318 | } 319 | ], 320 | "name": "_setImplementation", 321 | "outputs": [], 322 | "payable": false, 323 | "stateMutability": "nonpayable", 324 | "type": "function" 325 | }, 326 | { 327 | "constant": true, 328 | "inputs": [ 329 | { 330 | "name": "", 331 | "type": "uint256" 332 | } 333 | ], 334 | "name": "datas", 335 | "outputs": [ 336 | { 337 | "name": "", 338 | "type": "bytes" 339 | } 340 | ], 341 | "payable": false, 342 | "stateMutability": "view", 343 | "type": "function" 344 | }, 345 | { 346 | "constant": false, 347 | "inputs": [ 348 | { 349 | "name": "_owner", 350 | "type": "address" 351 | } 352 | ], 353 | "name": "transferOwnership", 354 | "outputs": [], 355 | "payable": false, 356 | "stateMutability": "nonpayable", 357 | "type": "function" 358 | }, 359 | { 360 | "inputs": [], 361 | "payable": false, 362 | "stateMutability": "nonpayable", 363 | "type": "constructor" 364 | }, 365 | { 366 | "payable": true, 367 | "stateMutability": "payable", 368 | "type": "fallback" 369 | }, 370 | { 371 | "anonymous": false, 372 | "inputs": [ 373 | { 374 | "indexed": false, 375 | "name": "toChain", 376 | "type": "string" 377 | }, 378 | { 379 | "indexed": false, 380 | "name": "toAddr", 381 | "type": "bytes" 382 | }, 383 | { 384 | "indexed": false, 385 | "name": "data", 386 | "type": "bytes" 387 | }, 388 | { 389 | "indexed": false, 390 | "name": "hash", 391 | "type": "bytes32" 392 | } 393 | ], 394 | "name": "Relay", 395 | "type": "event" 396 | }, 397 | { 398 | "anonymous": false, 399 | "inputs": [ 400 | { 401 | "indexed": false, 402 | "name": "toChain", 403 | "type": "string" 404 | }, 405 | { 406 | "indexed": false, 407 | "name": "toAddr", 408 | "type": "bytes" 409 | }, 410 | { 411 | "indexed": false, 412 | "name": "data", 413 | "type": "bytes" 414 | }, 415 | { 416 | "indexed": false, 417 | "name": "tag", 418 | "type": "uint256" 419 | }, 420 | { 421 | "indexed": false, 422 | "name": "hash", 423 | "type": "bytes32" 424 | } 425 | ], 426 | "name": "Set", 427 | "type": "event" 428 | } 429 | ] -------------------------------------------------------------------------------- /abi/prod/bridge/Common.abi: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "constant": true, 4 | "inputs": [], 5 | "name": "getVersion", 6 | "outputs": [ 7 | { 8 | "name": "", 9 | "type": "string" 10 | } 11 | ], 12 | "payable": false, 13 | "stateMutability": "pure", 14 | "type": "function" 15 | }, 16 | { 17 | "constant": true, 18 | "inputs": [], 19 | "name": "relaySwap", 20 | "outputs": [], 21 | "payable": false, 22 | "stateMutability": "view", 23 | "type": "function" 24 | }, 25 | { 26 | "constant": false, 27 | "inputs": [ 28 | { 29 | "name": "govId", 30 | "type": "bytes32" 31 | } 32 | ], 33 | "name": "removeBridgeInfo", 34 | "outputs": [], 35 | "payable": false, 36 | "stateMutability": "nonpayable", 37 | "type": "function" 38 | }, 39 | { 40 | "constant": true, 41 | "inputs": [ 42 | { 43 | "name": "govId", 44 | "type": "bytes32" 45 | } 46 | ], 47 | "name": "getGovInfo", 48 | "outputs": [ 49 | { 50 | "name": "uints", 51 | "type": "uint256[]" 52 | }, 53 | { 54 | "name": "bytes32s", 55 | "type": "bytes32[]" 56 | }, 57 | { 58 | "name": "comment", 59 | "type": "bytes" 60 | } 61 | ], 62 | "payable": false, 63 | "stateMutability": "view", 64 | "type": "function" 65 | }, 66 | { 67 | "constant": false, 68 | "inputs": [ 69 | { 70 | "name": "sigs", 71 | "type": "bytes32[]" 72 | } 73 | ], 74 | "name": "validateSwap", 75 | "outputs": [ 76 | { 77 | "name": "major", 78 | "type": "bool" 79 | }, 80 | { 81 | "name": "vaList", 82 | "type": "address[]" 83 | } 84 | ], 85 | "payable": false, 86 | "stateMutability": "nonpayable", 87 | "type": "function" 88 | }, 89 | { 90 | "constant": true, 91 | "inputs": [], 92 | "name": "implementation", 93 | "outputs": [ 94 | { 95 | "name": "", 96 | "type": "address" 97 | } 98 | ], 99 | "payable": false, 100 | "stateMutability": "view", 101 | "type": "function" 102 | }, 103 | { 104 | "constant": true, 105 | "inputs": [ 106 | { 107 | "name": "", 108 | "type": "bytes32" 109 | }, 110 | { 111 | "name": "", 112 | "type": "uint256" 113 | } 114 | ], 115 | "name": "swapData", 116 | "outputs": [ 117 | { 118 | "name": "fromChain", 119 | "type": "string" 120 | }, 121 | { 122 | "name": "toChain", 123 | "type": "string" 124 | }, 125 | { 126 | "name": "fromAddr", 127 | "type": "bytes" 128 | }, 129 | { 130 | "name": "toAddr", 131 | "type": "bytes" 132 | }, 133 | { 134 | "name": "token", 135 | "type": "bytes" 136 | } 137 | ], 138 | "payable": false, 139 | "stateMutability": "view", 140 | "type": "function" 141 | }, 142 | { 143 | "constant": true, 144 | "inputs": [ 145 | { 146 | "name": "", 147 | "type": "bytes32" 148 | } 149 | ], 150 | "name": "isConfirmed", 151 | "outputs": [ 152 | { 153 | "name": "", 154 | "type": "bool" 155 | } 156 | ], 157 | "payable": false, 158 | "stateMutability": "view", 159 | "type": "function" 160 | }, 161 | { 162 | "constant": true, 163 | "inputs": [], 164 | "name": "bytes32sLength", 165 | "outputs": [ 166 | { 167 | "name": "", 168 | "type": "uint256" 169 | } 170 | ], 171 | "payable": false, 172 | "stateMutability": "view", 173 | "type": "function" 174 | }, 175 | { 176 | "constant": false, 177 | "inputs": [ 178 | { 179 | "name": "_hubContract", 180 | "type": "address" 181 | } 182 | ], 183 | "name": "setHubContract", 184 | "outputs": [], 185 | "payable": false, 186 | "stateMutability": "nonpayable", 187 | "type": "function" 188 | }, 189 | { 190 | "constant": false, 191 | "inputs": [ 192 | { 193 | "name": "govId", 194 | "type": "bytes32" 195 | }, 196 | { 197 | "name": "uints", 198 | "type": "uint256[]" 199 | }, 200 | { 201 | "name": "bytes32s", 202 | "type": "bytes32[]" 203 | }, 204 | { 205 | "name": "comment", 206 | "type": "bytes" 207 | } 208 | ], 209 | "name": "addBridgeInfo", 210 | "outputs": [], 211 | "payable": false, 212 | "stateMutability": "nonpayable", 213 | "type": "function" 214 | }, 215 | { 216 | "constant": true, 217 | "inputs": [], 218 | "name": "hubContract", 219 | "outputs": [ 220 | { 221 | "name": "", 222 | "type": "address" 223 | } 224 | ], 225 | "payable": false, 226 | "stateMutability": "view", 227 | "type": "function" 228 | }, 229 | { 230 | "constant": true, 231 | "inputs": [ 232 | { 233 | "name": "", 234 | "type": "bytes32" 235 | } 236 | ], 237 | "name": "swapCount", 238 | "outputs": [ 239 | { 240 | "name": "", 241 | "type": "uint256" 242 | } 243 | ], 244 | "payable": false, 245 | "stateMutability": "view", 246 | "type": "function" 247 | }, 248 | { 249 | "constant": true, 250 | "inputs": [], 251 | "name": "relaySwapNFT", 252 | "outputs": [], 253 | "payable": false, 254 | "stateMutability": "view", 255 | "type": "function" 256 | }, 257 | { 258 | "constant": true, 259 | "inputs": [], 260 | "name": "uintsLength", 261 | "outputs": [ 262 | { 263 | "name": "", 264 | "type": "uint256" 265 | } 266 | ], 267 | "payable": false, 268 | "stateMutability": "view", 269 | "type": "function" 270 | }, 271 | { 272 | "constant": true, 273 | "inputs": [ 274 | { 275 | "name": "", 276 | "type": "bytes32" 277 | } 278 | ], 279 | "name": "isValidGovId", 280 | "outputs": [ 281 | { 282 | "name": "", 283 | "type": "bool" 284 | } 285 | ], 286 | "payable": false, 287 | "stateMutability": "view", 288 | "type": "function" 289 | }, 290 | { 291 | "constant": true, 292 | "inputs": [ 293 | { 294 | "name": "", 295 | "type": "bytes32" 296 | }, 297 | { 298 | "name": "", 299 | "type": "uint256" 300 | } 301 | ], 302 | "name": "executionData", 303 | "outputs": [ 304 | { 305 | "name": "", 306 | "type": "bytes" 307 | } 308 | ], 309 | "payable": false, 310 | "stateMutability": "view", 311 | "type": "function" 312 | }, 313 | { 314 | "constant": false, 315 | "inputs": [ 316 | { 317 | "name": "_newImp", 318 | "type": "address" 319 | } 320 | ], 321 | "name": "_setImplementation", 322 | "outputs": [], 323 | "payable": false, 324 | "stateMutability": "nonpayable", 325 | "type": "function" 326 | }, 327 | { 328 | "constant": true, 329 | "inputs": [ 330 | { 331 | "name": "", 332 | "type": "bytes32" 333 | } 334 | ], 335 | "name": "govInfo", 336 | "outputs": [ 337 | { 338 | "name": "comment", 339 | "type": "bytes" 340 | } 341 | ], 342 | "payable": false, 343 | "stateMutability": "view", 344 | "type": "function" 345 | }, 346 | { 347 | "constant": true, 348 | "inputs": [], 349 | "name": "chain", 350 | "outputs": [ 351 | { 352 | "name": "", 353 | "type": "string" 354 | } 355 | ], 356 | "payable": false, 357 | "stateMutability": "view", 358 | "type": "function" 359 | }, 360 | { 361 | "constant": true, 362 | "inputs": [ 363 | { 364 | "name": "govId", 365 | "type": "bytes32" 366 | }, 367 | { 368 | "name": "dataIndex", 369 | "type": "uint256" 370 | } 371 | ], 372 | "name": "getSwapDataArray", 373 | "outputs": [ 374 | { 375 | "name": "bytes32s", 376 | "type": "bytes32[]" 377 | }, 378 | { 379 | "name": "uints", 380 | "type": "uint256[]" 381 | }, 382 | { 383 | "name": "vaList", 384 | "type": "address[]" 385 | } 386 | ], 387 | "payable": false, 388 | "stateMutability": "view", 389 | "type": "function" 390 | }, 391 | { 392 | "constant": false, 393 | "inputs": [ 394 | { 395 | "name": "sigs", 396 | "type": "bytes32[]" 397 | } 398 | ], 399 | "name": "validateSwapNFT", 400 | "outputs": [ 401 | { 402 | "name": "major", 403 | "type": "bool" 404 | }, 405 | { 406 | "name": "vaList", 407 | "type": "address[]" 408 | } 409 | ], 410 | "payable": false, 411 | "stateMutability": "nonpayable", 412 | "type": "function" 413 | }, 414 | { 415 | "inputs": [], 416 | "payable": false, 417 | "stateMutability": "nonpayable", 418 | "type": "constructor" 419 | }, 420 | { 421 | "payable": false, 422 | "stateMutability": "nonpayable", 423 | "type": "fallback" 424 | } 425 | ] 426 | -------------------------------------------------------------------------------- /abi/prod/zkevm/PolygonValidiumEtrog.abi: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "anonymous": false, 4 | "inputs": [ 5 | { 6 | "indexed": true, 7 | "internalType": "uint64", 8 | "name": "numBatch", 9 | "type": "uint64" 10 | }, 11 | { 12 | "indexed": false, 13 | "internalType": "bytes32", 14 | "name": "l1InfoRoot", 15 | "type": "bytes32" 16 | } 17 | ], 18 | "name": "SequenceBatches", 19 | "type": "event" 20 | }, 21 | { 22 | "inputs": [ 23 | { 24 | "components": [ 25 | { 26 | "internalType": "bytes32", 27 | "name": "transactionsHash", 28 | "type": "bytes32" 29 | }, 30 | { 31 | "internalType": "bytes32", 32 | "name": "forcedGlobalExitRoot", 33 | "type": "bytes32" 34 | }, 35 | { 36 | "internalType": "uint64", 37 | "name": "forcedTimestamp", 38 | "type": "uint64" 39 | }, 40 | { 41 | "internalType": "bytes32", 42 | "name": "forcedBlockHashL1", 43 | "type": "bytes32" 44 | } 45 | ], 46 | "internalType": "struct PolygonValidiumEtrog.ValidiumBatchData[]", 47 | "name": "batches", 48 | "type": "tuple[]" 49 | }, 50 | { 51 | "internalType": "uint32", 52 | "name": "l1InfoTreeLeafCount", 53 | "type": "uint32" 54 | }, 55 | { 56 | "internalType": "uint64", 57 | "name": "maxSequenceTimestamp", 58 | "type": "uint64" 59 | }, 60 | { 61 | "internalType": "bytes32", 62 | "name": "expectedFinalAccInputHash", 63 | "type": "bytes32" 64 | }, 65 | { 66 | "internalType": "address", 67 | "name": "l2Coinbase", 68 | "type": "address" 69 | }, 70 | { 71 | "internalType": "bytes", 72 | "name": "dataAvailabilityMessage", 73 | "type": "bytes" 74 | } 75 | ], 76 | "name": "sequenceBatchesValidium", 77 | "outputs": [], 78 | "stateMutability": "nonpayable", 79 | "type": "function" 80 | } 81 | ] -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | require("dotenv").config(); 3 | 4 | global.ROOT = __dirname; 5 | global.logger = require('./logger'); 6 | global.VERSION = process.env.VERSION; 7 | 8 | console.log(`[DEPLOYED VERSION] ${process.env.VERSION}`); 9 | 10 | const config = require(ROOT + '/config'); 11 | const walletUtils = require('./wallet'); 12 | 13 | const Monitor = require('./src/monitor'); 14 | global.monitor = new Monitor(); 15 | 16 | const settings = config.settings; 17 | 18 | 19 | let PK = process.env.VALIDATOR_PK; 20 | if(PK) { 21 | PK = Buffer.from(PK.replace("0x",""), 'hex'); 22 | } else { 23 | throw `VALIDATOR_PK is undefined in .env`; 24 | } 25 | 26 | let v3 = walletUtils.getWalletFromPK(PK); 27 | if (!v3) 28 | throw 'Invalid wallet information.'; 29 | 30 | let account = { 31 | address: v3.address, 32 | pk: v3.pk, 33 | publicKey: v3.publicKey, 34 | name: "validatorDocker" 35 | }; 36 | global.monitor.validatorAddress = account.address; 37 | global.monitor.publicKey = account.publicKey; 38 | global.monitor.chain = config.governance.chain; 39 | 40 | logger.info(`Start Orbit Chain Validator ! : ${account.address}`); 41 | 42 | global.instances = {}; 43 | 44 | let chainList = settings.chain_list; 45 | if(!chainList || chainList.length === 0) { 46 | console.log('No available chain.'); 47 | process.exit(1); 48 | } 49 | 50 | chainList.forEach(key => { 51 | key = key.replace(/-v[1-9]$/, '').toLowerCase(); 52 | let chain = config.chain[key] || { src: "src/evm" }; 53 | 54 | console.log(`[VALIDATOR_CHAIN] key: ${key}, chain: ${JSON.stringify(chain)}`); 55 | 56 | let instance = require(ROOT + '/' + chain.src); 57 | instance = new instance(key, account); 58 | 59 | instances[key] = instance; 60 | }); 61 | 62 | const gov = require(`${ROOT}/src/gov`); 63 | instances["gov"] = new gov(); 64 | 65 | const express = require('express'); 66 | const app = express(); 67 | const PORT = process.env.PORT || 8984; 68 | 69 | const indexRouter = require("./routes/index"); 70 | app.use('/', indexRouter); 71 | app.use("/v1/gov", require("./routes/v1/gov").setGovInstance(instances["gov"])); 72 | 73 | app.listen(PORT, () => { 74 | logger.info('Listening on port ' + PORT); 75 | }); 76 | -------------------------------------------------------------------------------- /composes/bsc/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | validator: 4 | extends: 5 | file: ../docker-compose.common.yml 6 | service: app 7 | ports: 8 | - 18985:8984 9 | networks: 10 | - br-bscvalidator 11 | build: 12 | args: 13 | ENV_FILE: composes/bsc/.env 14 | environment: 15 | PROFILE: prod 16 | CHAIN: bsc 17 | 18 | networks: 19 | br-bscvalidator: 20 | driver: bridge 21 | ipam: 22 | driver: default 23 | config: 24 | - subnet: 172.24.131.0/24 -------------------------------------------------------------------------------- /composes/celo/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | validator: 4 | extends: 5 | file: ../docker-compose.common.yml 6 | service: app 7 | ports: 8 | - 17060:8984 9 | networks: 10 | - br-celovalidator 11 | build: 12 | args: 13 | ENV_FILE: composes/celo/.env 14 | environment: 15 | PROFILE: prod 16 | CHAIN: celo 17 | 18 | networks: 19 | br-celovalidator: 20 | driver: bridge 21 | ipam: 22 | driver: default 23 | config: 24 | - subnet: 172.24.135.0/24 -------------------------------------------------------------------------------- /composes/docker-compose.common.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | app: 4 | build: 5 | context: ../ 6 | dockerfile: ./Dockerfile 7 | environment: 8 | VERSION: v2.2.9 9 | -------------------------------------------------------------------------------- /composes/epicleague/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | validator: 4 | extends: 5 | file: ../docker-compose.common.yml 6 | service: app 7 | ports: 8 | - 18983:8984 9 | networks: 10 | - br-epicleague 11 | build: 12 | args: 13 | ENV_FILE: composes/epicleague/.env 14 | environment: 15 | PROFILE: prod 16 | CHAIN: epicleague 17 | networks: 18 | br-epicleague: 19 | driver: bridge 20 | ipam: 21 | driver: default 22 | config: 23 | - subnet: 172.24.143.0/24 24 | -------------------------------------------------------------------------------- /composes/eth/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | validator: 4 | extends: 5 | file: ../docker-compose.common.yml 6 | service: app 7 | ports: 8 | - 18987:8984 9 | networks: 10 | - br-ethvalidator 11 | build: 12 | args: 13 | ENV_FILE: composes/eth/.env 14 | environment: 15 | PROFILE: prod 16 | CHAIN: eth 17 | networks: 18 | br-ethvalidator: 19 | driver: bridge 20 | ipam: 21 | driver: default 22 | config: 23 | - subnet: 172.24.127.0/24 24 | -------------------------------------------------------------------------------- /composes/faireth/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | validator: 4 | extends: 5 | file: ../docker-compose.common.yml 6 | service: app 7 | ports: 8 | - 18989:8984 9 | networks: 10 | - br-ethvalidator 11 | build: 12 | args: 13 | ENV_FILE: composes/faireth/.env 14 | environment: 15 | PROFILE: prod 16 | CHAIN: faireth 17 | networks: 18 | br-ethvalidator: 19 | driver: bridge 20 | ipam: 21 | driver: default 22 | config: 23 | - subnet: 172.24.132.0/24 24 | -------------------------------------------------------------------------------- /composes/heco/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | validator: 4 | extends: 5 | file: ../docker-compose.common.yml 6 | service: app 7 | ports: 8 | - 17110:8984 9 | networks: 10 | - br-hecovalidator 11 | build: 12 | args: 13 | ENV_FILE: composes/heco/.env 14 | environment: 15 | PROFILE: prod 16 | CHAIN: heco 17 | 18 | networks: 19 | br-hecovalidator: 20 | driver: bridge 21 | ipam: 22 | driver: default 23 | config: 24 | - subnet: 172.24.139.0/24 -------------------------------------------------------------------------------- /composes/icon/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | validator: 4 | extends: 5 | file: ../docker-compose.common.yml 6 | service: app 7 | ports: 8 | - 18991:8984 9 | networks: 10 | - br-iconvalidator 11 | build: 12 | args: 13 | ENV_FILE: composes/icon/.env 14 | environment: 15 | PROFILE: prod 16 | CHAIN: icon 17 | 18 | networks: 19 | br-iconvalidator: 20 | driver: bridge 21 | ipam: 22 | driver: default 23 | config: 24 | - subnet: 172.24.133.0/24 25 | -------------------------------------------------------------------------------- /composes/klaytn/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | validator: 4 | extends: 5 | file: ../docker-compose.common.yml 6 | service: app 7 | ports: 8 | - 17130:8984 9 | networks: 10 | - br-klaytnvalidator 11 | build: 12 | args: 13 | ENV_FILE: composes/klaytn/.env 14 | environment: 15 | PROFILE: prod 16 | CHAIN: klaytn 17 | 18 | networks: 19 | br-klaytnvalidator: 20 | driver: bridge 21 | ipam: 22 | driver: default 23 | config: 24 | - subnet: 172.24.141.0/24 -------------------------------------------------------------------------------- /composes/metadium/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | validator: 4 | extends: 5 | file: ../docker-compose.common.yml 6 | service: app 7 | ports: 8 | - 17197:8984 9 | networks: 10 | - br-metadiumvalidator 11 | build: 12 | args: 13 | ENV_FILE: composes/metadium/.env 14 | environment: 15 | PROFILE: prod 16 | CHAIN: metadium 17 | 18 | networks: 19 | br-metadiumvalidator: 20 | driver: bridge 21 | ipam: 22 | driver: default 23 | config: 24 | - subnet: 172.24.153.0/24 25 | -------------------------------------------------------------------------------- /composes/orbit/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | validator: 4 | extends: 5 | file: ../docker-compose.common.yml 6 | service: app 7 | ports: 8 | - 17090:8984 9 | networks: 10 | - br-orbitvalidator 11 | build: 12 | args: 13 | ENV_FILE: composes/orbit/.env 14 | environment: 15 | PROFILE: prod 16 | CHAIN: orbit 17 | 18 | networks: 19 | br-orbitvalidator: 20 | driver: bridge 21 | ipam: 22 | driver: default 23 | config: 24 | - subnet: 172.24.155.0/24 -------------------------------------------------------------------------------- /composes/polygon/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | validator: 4 | extends: 5 | file: ../docker-compose.common.yml 6 | service: app 7 | ports: 8 | - 17152:8984 9 | networks: 10 | - br-polygonvalidator 11 | build: 12 | args: 13 | ENV_FILE: composes/polygon/.env 14 | environment: 15 | PROFILE: prod 16 | CHAIN: matic 17 | 18 | networks: 19 | br-polygonvalidator: 20 | driver: bridge 21 | ipam: 22 | driver: default 23 | config: 24 | - subnet: 172.24.143.0/24 -------------------------------------------------------------------------------- /composes/poweth/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | validator: 4 | extends: 5 | file: ../docker-compose.common.yml 6 | service: app 7 | ports: 8 | - 18990:8984 9 | networks: 10 | - br-ethvalidator 11 | build: 12 | args: 13 | ENV_FILE: composes/poweth/.env 14 | environment: 15 | PROFILE: prod 16 | CHAIN: poweth 17 | networks: 18 | br-ethvalidator: 19 | driver: bridge 20 | ipam: 21 | driver: default 22 | config: 23 | - subnet: 172.24.130.0/24 24 | -------------------------------------------------------------------------------- /composes/silicon/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | validator: 4 | extends: 5 | file: ../docker-compose.common.yml 6 | service: app 7 | ports: 8 | - 18992:8984 9 | networks: 10 | - br-siliconvalidator 11 | build: 12 | args: 13 | ENV_FILE: composes/silicon/.env 14 | environment: 15 | PROFILE: prod 16 | CHAIN: silicon 17 | networks: 18 | br-siliconvalidator: 19 | driver: bridge 20 | ipam: 21 | driver: default 22 | config: 23 | - subnet: 172.24.127.0/24 24 | -------------------------------------------------------------------------------- /composes/stacks/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | validator: 4 | extends: 5 | file: ../docker-compose.common.yml 6 | service: app 7 | ports: 8 | - 17143:8984 9 | networks: 10 | - br-stacksvalidator 11 | build: 12 | args: 13 | ENV_FILE: composes/stacks/.env 14 | environment: 15 | PROFILE: prod 16 | CHAIN: stacks 17 | 18 | networks: 19 | br-stacksvalidator: 20 | driver: bridge 21 | ipam: 22 | driver: default 23 | config: 24 | - subnet: 172.24.142.0/24 -------------------------------------------------------------------------------- /composes/ton/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | validator: 4 | extends: 5 | file: ../docker-compose.common.yml 6 | service: app 7 | ports: 8 | - 17173:8984 9 | networks: 10 | - br-tonvalidator 11 | build: 12 | args: 13 | ENV_FILE: composes/ton/.env 14 | environment: 15 | PROFILE: prod 16 | CHAIN: ton 17 | 18 | networks: 19 | br-tonvalidator: 20 | driver: bridge 21 | ipam: 22 | driver: default 23 | config: 24 | - subnet: 172.24.150.0/24 -------------------------------------------------------------------------------- /composes/wemix/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | validator: 4 | extends: 5 | file: ../docker-compose.common.yml 6 | service: app 7 | ports: 8 | - 17195:8984 9 | networks: 10 | - br-wemixvalidator 11 | build: 12 | args: 13 | ENV_FILE: composes/wemix/.env 14 | environment: 15 | PROFILE: prod 16 | CHAIN: wemix 17 | 18 | networks: 19 | br-wemixvalidator: 20 | driver: bridge 21 | ipam: 22 | driver: default 23 | config: 24 | - subnet: 172.24.152.0/24 25 | -------------------------------------------------------------------------------- /composes/xrp/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | validator: 4 | extends: 5 | file: ../docker-compose.common.yml 6 | service: app 7 | ports: 8 | - 17000:8984 9 | networks: 10 | - br-xrpvalidator 11 | build: 12 | args: 13 | ENV_FILE: composes/xrp/.env 14 | environment: 15 | PROFILE: prod 16 | CHAIN: xrp 17 | 18 | networks: 19 | br-xrpvalidator: 20 | driver: bridge 21 | ipam: 22 | driver: default 23 | config: 24 | - subnet: 172.24.129.0/24 25 | -------------------------------------------------------------------------------- /config/chain.json: -------------------------------------------------------------------------------- 1 | { 2 | "xrp": { 3 | "src": "src/xrp" 4 | }, 5 | "icon": { 6 | "src": "src/icon" 7 | }, 8 | "stacks_layer_1": { 9 | "src": "src/stacks_layer_1" 10 | }, 11 | "stacks": { 12 | "src": "src/stacks" 13 | }, 14 | "ton_layer_1": { 15 | "src": "src/ton_layer_1" 16 | }, 17 | "ton": { 18 | "src": "src/ton" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /config/governance.js: -------------------------------------------------------------------------------- 1 | const settings = require(`./${process.env.PROFILE}/${process.env.CHAIN}`); 2 | 3 | module.exports = { 4 | chain: settings.bridge_address.governance.chain, 5 | address: settings.bridge_address.governance.address, 6 | bytes: settings.bridge_address.governance.bytes, 7 | id: settings.bridge_address.governance.id, 8 | }; 9 | -------------------------------------------------------------------------------- /config/index.js: -------------------------------------------------------------------------------- 1 | exports.settings = require(`./${process.env.PROFILE}/${process.env.CHAIN}`); 2 | exports.chainIds = require(`./${process.env.PROFILE}/chainIds.js`); 3 | exports.endpoints = require(`./${process.env.PROFILE}/endpoints.js`).endpoints; 4 | exports.system = require(`./${process.env.PROFILE}/system.js`); 5 | exports.chain = require(`./chain.json`); 6 | exports.governance = require(`./governance.js`); 7 | exports.info = require(`./info.js`); 8 | exports.orbitHub = require(`./${process.env.PROFILE}/hub.js`); 9 | exports.l2 = require(`./${process.env.PROFILE}/l2.js`) 10 | -------------------------------------------------------------------------------- /config/info.js: -------------------------------------------------------------------------------- 1 | const settings = require(`./${process.env.PROFILE}/${process.env.CHAIN}`); 2 | const { endpoints } = require(`./${process.env.PROFILE}/endpoints.js`); 3 | 4 | let obj = {}; 5 | for(let chain of settings.chain_list){ 6 | chain = chain.toLowerCase(); 7 | 8 | let key = ""; 9 | if(chain.includes("-v2")) { 10 | chain = chain.split("-")[0]; 11 | key = chain; 12 | } 13 | else if(chain.includes("_layer")) key = chain.split("_")[0]; 14 | else key = chain; 15 | 16 | let ENDPOINT = endpoints[key]; 17 | let CONTRACT_ADDRESS = settings.bridge_address[key] || {}; 18 | 19 | let CHAIN_ID = ENDPOINT.chain_id; 20 | let GAS_PRICE = ENDPOINT.gas_price; 21 | 22 | obj[chain] = { ENDPOINT, CONTRACT_ADDRESS, CHAIN_ID, GAS_PRICE }; 23 | 24 | if(key === "eth") obj[chain].ETH_TERMINAL_TOTAL_DIFFICULTY = ENDPOINT.terminal_total_difficulty || "58750000000000000000000"; 25 | } 26 | obj.ADDRESS_BOOK = settings.silicon 27 | module.exports = Object.assign({}, obj); 28 | -------------------------------------------------------------------------------- /config/prod/bsc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // operating chain list 3 | chain_list: [ 4 | 'klaytn', 5 | 'bsc', 6 | 'eth', 7 | 'matic', 8 | 'avax', 9 | 'ton', 10 | 'wemix', 11 | 'metadium', 12 | 'silicon', 13 | ], 14 | 15 | // Bridge Addresses 16 | bridge_address: { 17 | bsc: { 18 | vault: "0x89c527764f03BCb7dC469707B23b79C1D7Beb780", 19 | multisig: "0xf2C5a817cc8FFaAB4122f2cE27AB8486DFeAb09F", 20 | admin: "0x8D5DcEab358979101dC96A62e08296269F6BD1bd", 21 | }, 22 | klaytn: { 23 | minter: "0xB0a83941058b109Bd0543fa26d22eFb8a2D0f431", 24 | multisig: "0x937936FF183102Dfb1609D5dbFbC50201f92c744", 25 | }, 26 | matic: { 27 | minter: "0x89c527764f03BCb7dC469707B23b79C1D7Beb780", 28 | multisig: "0xf2C5a817cc8FFaAB4122f2cE27AB8486DFeAb09F", 29 | admin: "0x8D5DcEab358979101dC96A62e08296269F6BD1bd", 30 | }, 31 | avax: { 32 | minter: "0xC91D164267De757fe7f5569868dc2a1Ca363c136", 33 | multisig: "0xD5afF4221b353Ab0A3dd6ad7C1FB97e582DC0C9c", 34 | admin: "0xe1bbfc002714bede0f9ee84e5d1cb4cf3a3a9e75" 35 | }, 36 | eth: { 37 | minter: "0x166E514c465EF0DB69246e14C6bA866F91B1e061", 38 | multisig: "0x3DE5098FBdb858567542A949B1CE22C61eae14FB", 39 | admin: "0xE3b4270592E217d1122ddCAeBa22Ac415D718A39", 40 | }, 41 | ton: { 42 | minter: "EQDABRjlDIBMx_BTNp-TvVjQZXjqfxq2y50jmhyZSJ58bB0R", 43 | multisig: "EQAs_E5Ta00Oo5gBoAevL4npbZLLOFZuvptpUeSdRnFK6mFG", 44 | }, 45 | wemix: { 46 | minter: "0xfe4a11ec60A52A5593649510f249FEbE14Ad4e70", 47 | multisig: "0x3F4D41077dA83d6A57d8d0Cd692cd49C997bCE4F", 48 | admin: "0xcCED7af08E3E37e5C822412E0CaEE1Fb99cCB4d1" 49 | }, 50 | metadium: { 51 | minter: "0x9DC1cb0a52fC34659D18B0F31e26582a8Db609b5", 52 | multisig: "0xDf4f362E6C3Baa3Fc8Fb0179498e6c80c35Cf547", 53 | admin: "0xa37581EDC6135585287675Ee6E517897E3c42D38" 54 | }, 55 | silicon: { 56 | minter: "0xE82b8C388E0bcF7C01D05B2cE678f6d012c9B7D9", 57 | multisig: "0xFf46d621318Dcaf14f09cc7A50a68230f3562e11", 58 | admin: "0x406134c9B11dcc132d4cB810D283FbE6E31874De", 59 | }, 60 | governance: { 61 | chain: "BSC", 62 | address: "0x89c527764f03BCb7dC469707B23b79C1D7Beb780", 63 | bytes: "0x89c527764f03BCb7dC469707B23b79C1D7Beb780", 64 | id: "0xa83e44c751c7b6296864c8145d325c9a9397f30adfc5a92c840fb7cb688775b3", 65 | }, 66 | } 67 | } -------------------------------------------------------------------------------- /config/prod/celo.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // operating chain list 3 | chain_list: [ 4 | 'celo', 5 | 'klaytn', 6 | ], 7 | 8 | // Bridge Addresses 9 | bridge_address: { 10 | klaytn: { 11 | minter: "0x979cD0826C2bf62703Ef62221a4feA1f23da3777", 12 | multisig: "0xE665028E06Cab79928D8e607E0de99FfD7Eb76A7", 13 | }, 14 | celo: { 15 | vault: "0x979cD0826C2bf62703Ef62221a4feA1f23da3777", 16 | multisig: "0xE665028E06Cab79928D8e607E0de99FfD7Eb76A7", 17 | admin: "0x6a1cf2e4b8DF2C2707e34cad35D8AF4535510F53", 18 | }, 19 | governance: { 20 | chain: "CELO", 21 | address: "0x979cD0826C2bf62703Ef62221a4feA1f23da3777", 22 | bytes: "0x979cD0826C2bf62703Ef62221a4feA1f23da3777", 23 | id: "0x6c09d7b79b91a3d49c3648a1bbc811f1b99f16045218e72a597a7692580ccab1", 24 | }, 25 | } 26 | } -------------------------------------------------------------------------------- /config/prod/chainIds.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | AVAX: "0x774ad9b69090d3c3929d274caaa0fa109b2b15f39a24adb860787d10b3eba8c9", 3 | BSC: "0x252e9f7af69e5f718475e854c8a4ec34eb5262a68da244c610f2b501269572b6", 4 | ETH: "0xd71495681cc4f63a417797e97853f60220cdc1ba31deb555f2318ab770b3ca68", 5 | KLAYTN: "0x8e890c70aac933231508c13b4c58f6d67fad7e9f97cce65be0d4c82af40f0b84", 6 | MATIC: "0x3639710ae7ba531864771e9ceaea76d7a055ee9b377e2caabf886759d99b385b", 7 | METADIUM: "0xcede49e6cd419f5b9cbd2bb538ab0094cde0294b9c81ba79f2fe60ee3b81196e", 8 | SILICON: "0x738959fe9c00c831e32f667ad0ad87fb56305c649e3056e146eb76e4e63f27a3", 9 | WEMIX: "0x5560fdf32b99e139147611cfafb3bbf93294e3ac776977c78617aea67bcc93b3", 10 | TON_LAYER_1: "0x7fbf8c6a40d71b9a23ab3fe0cf9020cca506716634e0178a4fc087899130a6b0", 11 | TON: "0x57643076c3a92f82c3fea3dd79d4cfdfa8b938157ec73abcf2abfffb3de56f5a", 12 | } -------------------------------------------------------------------------------- /config/prod/endpoints.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // Node Endpoints 3 | endpoints : { 4 | avax: { 5 | rpc: ["https://avalanche-c-chain-rpc.publicnode.com", "https://ava-mainnet.public.blastapi.io/ext/bc/C/rpc", "http://prd-avax-mainnet.node.ozys.work:8545/ext/bc/C/rpc"], 6 | chain_id: '0xa86a', 7 | confirm: 10 8 | }, 9 | bsc: { 10 | rpc : ["https://bsc-dataseed.binance.org", "https://bsc-dataseed1.binance.org", "http://prd-bsc-mainnet-rpc.node.ozys.work:8545"], 11 | confirm: 10 12 | }, 13 | celo: { 14 | rpc: ["https://forno.celo.org", "https://rpc.ankr.com/celo", "http://prd-celo-mainnet-rpc.node.ozys.work:8545"], 15 | chain_id: '0xa4ec', 16 | confirm: 10 17 | }, 18 | eth: { 19 | rpc: ["http://prd-eth-mainnet-erpc.node.ozys.work:8545", "https://ethereum-rpc.publicnode.com", "https://eth.drpc.org"], 20 | beacon: "http://prd-eth-mainnet-brpc.node.ozys.work:8545", 21 | chain_id: '0x1', 22 | terminal_total_difficulty: "58750000000000000000000", 23 | confirm: 10 24 | }, 25 | faireth: { 26 | rpc: "https://rpc.etherfair.org", 27 | socket: "wss://rpc.etherfair.org", 28 | chain_id: "0x7D44C", 29 | confirm: 10 30 | }, 31 | fantom: { 32 | rpc: ["https://rpc.ftm.tools", "https://rpc.fantom.network", "https://rpc.ankr.com/fantom", "http://prd-fantom-mainnet-rpc.node.ozys.work:8545"], 33 | chain_id: '0xfa', 34 | confirm: 10 35 | }, 36 | heco: { 37 | rpc : ["https://http-mainnet-node.huobichain.com", "http://prd-heco-mainnet-rpc.node.ozys.work:8545", "https://http-mainnet.hecochain.com"], 38 | chain_id: '0x80', 39 | confirm: 10 40 | }, 41 | icon: { 42 | api: 'https://ctz.solidwallet.io/api/v3', 43 | rpc: 'https://ctz.solidwallet.io/api/v3', 44 | debug: 'https://ctz.solidwallet.io/api/debug/v3', 45 | version: 3, 46 | nid: 1, 47 | confirm: 10 48 | }, 49 | klaytn: { 50 | is_kas: false, 51 | kas: { 52 | // KAS Default 53 | rpc: "https://node-api.klaytnapi.com/v1/klaytn", 54 | chain_id: 8217 55 | }, 56 | rpc: ["https://public-en.node.kaia.io", "https://kaia.blockpi.network/v1/rpc/public", "https://klaytn.drpc.org"], 57 | confirm: 10 58 | }, 59 | silicon: { 60 | rpc: ["https://rpc.silicon.network", "https://silicon-rpc-seed3.node.ozys.work", "https://silicon-mainnet.nodeinfra.com"], 61 | chain_id: 2355, 62 | confirm: 10 63 | }, 64 | matic: { 65 | rpc : ["https://polygon-rpc.com", "https://polygon-bor-rpc.publicnode.com", "http://prd-matic-bor-mainnet-rpc.node.ozys.work:8545", "https://1rpc.io/matic"], 66 | chain_id: '0x89', 67 | confirm: 10 68 | }, 69 | metadium: { 70 | rpc: ["https://api.metadium.com/prod"], 71 | socket: "ws://prd-meta-mainnet-ws.node.ozys.work:8545 ", 72 | confirm: 10 73 | }, 74 | oec: { 75 | rpc: ["https://exchainrpc.okex.org", "http://prd-oktc-mainnet-rpc.node.ozys.work:8545"], 76 | chain_id: 66, 77 | confirm: 10 78 | }, 79 | poweth: { 80 | rpc: "https://mainnet.ethereumpow.org", 81 | socket: "wss://mainnet.ethereumpow.org", 82 | chain_id: "0x2711", 83 | confirm: 10 84 | }, 85 | stacks: { 86 | url: "https://stacks-node-api.mainnet.stacks.co", 87 | network: "mainnet", 88 | confirm: 10 89 | }, 90 | ton: { 91 | rpc: "https://toncenter.com/api/v2/jsonRPC", 92 | confirm: 10 93 | }, 94 | wemix: { 95 | rpc: "https://api.wemix.com", 96 | socket: "wss://ws.wemix.com", 97 | chain_id: 1111, 98 | confirm: 10 99 | }, 100 | xdai: { 101 | rpc: ["https://rpc.gnosischain.com", "https://rpc.ankr.com/gnosis", "https://gnosis-mainnet.public.blastapi.io"], 102 | confirm: 10 103 | }, 104 | xrp: { 105 | rpc: "https://s1.ripple.com:51234", 106 | socket: "wss://s1.ripple.com:443", 107 | confirm: 10 108 | }, 109 | }, 110 | VALIDATOR_MONITOR: { 111 | ozys: { 112 | monitor: "https://va.bridge.orbitchain.io/governance/report", 113 | orbit: "https://api.bridge.orbitchain.io", 114 | validator: "https://va.bridge.orbitchain.io", 115 | bible: "https://bridge.orbitchain.io/open", 116 | interval: 60 * 1000, 117 | }, 118 | }, 119 | } 120 | -------------------------------------------------------------------------------- /config/prod/epicleague.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | chain_list: [ 3 | "eth", 4 | "bsc", 5 | "matic", 6 | ], 7 | 8 | // Bridge Addresses 9 | bridge_address: { 10 | eth: { 11 | vault: "0x09Ac709B11E1B7d08E8bcab0472674a9d77B13eb", 12 | multisig: "0x09Ac709B11E1B7d08E8bcab0472674a9d77B13eb" 13 | }, 14 | bsc: { 15 | minter: "0x09Ac709B11E1B7d08E8bcab0472674a9d77B13eb", 16 | multisig: "0xbbf04C01AAA813c61525551e4d8014A2001500E3", 17 | admin: "0xef6D4C123078409f49037a85D3ADbcc5411DeA33" 18 | }, 19 | matic: { 20 | minter: "0x09Ac709B11E1B7d08E8bcab0472674a9d77B13eb", 21 | multisig: "0xbbf04C01AAA813c61525551e4d8014A2001500E3", 22 | admin: "0xef6D4C123078409f49037a85D3ADbcc5411DeA33" 23 | }, 24 | governance: { 25 | chain: "ETH", 26 | address: "0x09Ac709B11E1B7d08E8bcab0472674a9d77B13eb", 27 | bytes: "0x09Ac709B11E1B7d08E8bcab0472674a9d77B13eb", 28 | id: "0xd4ff2b907575ecee91528be826b644668b6017edb704f1a4fe8abb63123b75ff" 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /config/prod/eth.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // operating chain list 3 | chain_list: [ 4 | 'eth', 5 | 'klaytn', 6 | 'icon', 7 | 'avax', 8 | 'bsc', 9 | 'matic', 10 | 'ton', 11 | 'wemix' 12 | ], 13 | 14 | // Bridge Addresses 15 | bridge_address: { 16 | eth: { 17 | vault: "0x1bf68a9d1eaee7826b3593c20a0ca93293cb489a", 18 | }, 19 | avax: { 20 | minter: "0x6BD8E3beEC87176BA9c705c9507Aa5e6F0E6706f", 21 | multisig: "0xFA9c34485c3a706725130E8e0217431AC000E31e", 22 | admin: "0xe62Fa6C59AD14B46d4e7791FA817030732953b79", 23 | }, 24 | bsc: { 25 | minter: "0x6BD8E3beEC87176BA9c705c9507Aa5e6F0E6706f", 26 | multisig: "0xFA9c34485c3a706725130E8e0217431AC000E31e", 27 | admin: "0xe62Fa6C59AD14B46d4e7791FA817030732953b79", 28 | }, 29 | icon: { 30 | minter: "cx0eb215b6303142e37c0c9123abd1377feb423f0e", 31 | multisig: "cxa032c913d5d9b7577e2b19f39d91985e5c260577", 32 | }, 33 | klaytn: { 34 | minter: "0x60070F5D2e1C1001400A04F152E7ABD43410F7B9", 35 | multisig: "0x74bB62c446c592a5A8424d4f9437242df1e26BF0", 36 | }, 37 | matic: { 38 | minter: "0x6BD8E3beEC87176BA9c705c9507Aa5e6F0E6706f", 39 | multisig: "0xFA9c34485c3a706725130E8e0217431AC000E31e", 40 | admin: "0xe62Fa6C59AD14B46d4e7791FA817030732953b79", 41 | }, 42 | ton: { 43 | minter: "EQAihs8RdUgLANjNypV5LgaUHfdoUsMVL5o06K2F-qFSki00", 44 | multisig: "EQBbAqI1eVJ8PbZpKXA5njk6hq8Q6ZUxwXLZf-ntG1wf90Tm", 45 | }, 46 | wemix: { 47 | minter: "0x6BD8E3beEC87176BA9c705c9507Aa5e6F0E6706f", 48 | multisig: "0xCeBB82777bfe09c65AA47E8dD09a2f3972467901", 49 | admin: "0xe62Fa6C59AD14B46d4e7791FA817030732953b79", 50 | }, 51 | governance: { 52 | chain: "ETH", 53 | address: "0x1bf68a9d1eaee7826b3593c20a0ca93293cb489a", 54 | bytes: "0x1bf68a9d1eaee7826b3593c20a0ca93293cb489a", 55 | id: "0x50f408f4b0fb17bf4f5143de4bd95802410d00422f008e9deef06fb101a0f060", 56 | }, 57 | } 58 | } -------------------------------------------------------------------------------- /config/prod/heco.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | chain_list: [ 3 | 'avax', 4 | 'bsc', 5 | 'celo', 6 | 'heco', 7 | 'fantom', 8 | 'klaytn', 9 | 'matic', 10 | 'oec', 11 | 'xdai', 12 | ], 13 | 14 | // Bridge Addresses 15 | bridge_address: { 16 | avax: { 17 | minter: "0x38C92A7C2B358e2F2b91723e5c4Fc7aa8b4d279F", 18 | multisig: "0x8B8B037CC309bf46E23226BF38BE433ABC284Cf6", 19 | admin: "0x2bA5049df54aEde8d26786DFBE0cf0fDF7eDBBAd", 20 | }, 21 | bsc: { 22 | minter: "0x38C92A7C2B358e2F2b91723e5c4Fc7aa8b4d279F", 23 | multisig: "0x8B8B037CC309bf46E23226BF38BE433ABC284Cf6", 24 | admin: "0x2bA5049df54aEde8d26786DFBE0cf0fDF7eDBBAd", 25 | }, 26 | celo: { 27 | minter: "0x38C92A7C2B358e2F2b91723e5c4Fc7aa8b4d279F", 28 | multisig: "0x8B8B037CC309bf46E23226BF38BE433ABC284Cf6", 29 | admin: "0x2bA5049df54aEde8d26786DFBE0cf0fDF7eDBBAd", 30 | }, 31 | fantom: { 32 | minter: "0x38C92A7C2B358e2F2b91723e5c4Fc7aa8b4d279F", 33 | multisig: "0x8B8B037CC309bf46E23226BF38BE433ABC284Cf6", 34 | admin: "0x2bA5049df54aEde8d26786DFBE0cf0fDF7eDBBAd", 35 | }, 36 | heco: { 37 | vault: "0x38C92A7C2B358e2F2b91723e5c4Fc7aa8b4d279F", 38 | multisig: "0x8B8B037CC309bf46E23226BF38BE433ABC284Cf6", 39 | admin: "0x2bA5049df54aEde8d26786DFBE0cf0fDF7eDBBAd", 40 | }, 41 | klaytn: { 42 | minter: "0x38C92A7C2B358e2F2b91723e5c4Fc7aa8b4d279F", 43 | multisig: "0x8B8B037CC309bf46E23226BF38BE433ABC284Cf6", 44 | }, 45 | matic: { 46 | minter: "0x38C92A7C2B358e2F2b91723e5c4Fc7aa8b4d279F", 47 | multisig: "0x8B8B037CC309bf46E23226BF38BE433ABC284Cf6", 48 | admin: "0x2bA5049df54aEde8d26786DFBE0cf0fDF7eDBBAd", 49 | }, 50 | oec: { 51 | minter: "0x38C92A7C2B358e2F2b91723e5c4Fc7aa8b4d279F", 52 | multisig: "0x8B8B037CC309bf46E23226BF38BE433ABC284Cf6", 53 | admin: "0x2bA5049df54aEde8d26786DFBE0cf0fDF7eDBBAd", 54 | }, 55 | xdai: { 56 | minter: "0x38C92A7C2B358e2F2b91723e5c4Fc7aa8b4d279F", 57 | multisig: "0x8B8B037CC309bf46E23226BF38BE433ABC284Cf6", 58 | admin: "0x2bA5049df54aEde8d26786DFBE0cf0fDF7eDBBAd", 59 | }, 60 | governance: { 61 | chain: "HECO", 62 | address: "0x38C92A7C2B358e2F2b91723e5c4Fc7aa8b4d279F", 63 | bytes: "0x38C92A7C2B358e2F2b91723e5c4Fc7aa8b4d279F", 64 | id: "0x1958c3d245eed5312fa97ca358876d36b45c0905dd322b73efd66c8f836fb67f", 65 | }, 66 | } 67 | } -------------------------------------------------------------------------------- /config/prod/hub.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | address: "0xb5680a55d627c52de992e3ea52a86f19da475399" 3 | } -------------------------------------------------------------------------------- /config/prod/icon.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // operating chain list 3 | chain_list: [ 4 | "icon", 5 | "klaytn", 6 | ], 7 | 8 | // Bridge Addresses 9 | bridge_address: { 10 | klaytn: { 11 | minter: "0xcD953813896F766f1Eb9B613610E1752eD6F8395", 12 | multisig: "0xF6E3F95a1AC1C9A86Fa5C3c61DbD3D3BC6B566B5", 13 | }, 14 | icon: { 15 | vault: "cxa82aa03dae9ca03e3537a8a1e2f045bcae86fd3f", 16 | multisig: "cxd41e399c809a3671191c916d619e4d0fef04feea", 17 | }, 18 | governance: { 19 | chain: "ICON", 20 | address: "cxa82aa03dae9ca03e3537a8a1e2f045bcae86fd3f", 21 | bytes: "0x01a82aa03dae9ca03e3537a8a1e2f045bcae86fd3f", 22 | id: "0x6432be95e9ad50213ac792ac86951833cb24e47523feb923a677c711b05539e7", 23 | }, 24 | } 25 | } -------------------------------------------------------------------------------- /config/prod/klaytn.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | chain_list: [ 3 | 'avax', 4 | 'bsc', 5 | 'klaytn', 6 | 'matic', 7 | 'eth', 8 | 'ton', 9 | 'wemix', 10 | 'silicon', 11 | ], 12 | 13 | // Bridge Addresses 14 | bridge_address: { 15 | avax: { 16 | minter: "0x9abc3f6c11dbd83234d6e6b2c373dfc1893f648d", 17 | multisig: "0xcAA1B50341ad8Eb69A7bb1985bf39224044B1d48", 18 | admin: "0x3060E2fbDB75663b50bf9e629693DC39A4418736", 19 | }, 20 | bsc: { 21 | minter: "0x9abc3f6c11dbd83234d6e6b2c373dfc1893f648d", 22 | multisig: "0xcAA1B50341ad8Eb69A7bb1985bf39224044B1d48", 23 | admin: "0x3060E2fbDB75663b50bf9e629693DC39A4418736", 24 | }, 25 | eth: { 26 | minter: "0x012c6d79b189e1aBD1EFaC759b275c5D49Abd164", 27 | multisig: "0x9Abc3F6c11dBd83234D6E6b2c373Dfc1893F648D", 28 | admin: "0x3060E2fbDB75663b50bf9e629693DC39A4418736", 29 | }, 30 | klaytn: { 31 | vault: "0x9abc3f6c11dbd83234d6e6b2c373dfc1893f648d", 32 | multisig: "0x9abc3f6c11dbd83234d6e6b2c373dfc1893f648d", 33 | }, 34 | matic: { 35 | minter: "0x9abc3f6c11dbd83234d6e6b2c373dfc1893f648d", 36 | multisig: "0xcAA1B50341ad8Eb69A7bb1985bf39224044B1d48", 37 | admin: "0x3060E2fbDB75663b50bf9e629693DC39A4418736", 38 | }, 39 | wemix: { 40 | minter: "0xCd3698A1392A1Dd66a4934b69CCf800964817CA1", 41 | multisig: "0x58A42330c0984babD5DEc2C943eAA345B7f41e44", 42 | admin: "0x8966c07b38dcb277f1e5264368Cafb289DBCab4f", 43 | }, 44 | ton: { 45 | minter: "EQAlMRLTYOoG6kM0d3dLHqgK30ol3qIYwMNtEelktzXP_pD5", 46 | multisig: "EQAblz6Xr6b-7eLAWeagIK2Dn-g81YiNpu0okHfc9EwY9_72", 47 | }, 48 | silicon: { 49 | minter: "0x53ab0acE2f5245297917687F2a0380cf82055C57", 50 | multisig: "0x0e892b6119864592e86117d17Ef49db2f7C92258", 51 | admin: "0xE0273bDF3A45BbbB2506fDBBae96871D49d5FD19", 52 | }, 53 | governance: { 54 | chain: "KLAYTN", 55 | address: "0x9abc3f6c11dbd83234d6e6b2c373dfc1893f648d", 56 | bytes: "0x9abc3f6c11dbd83234d6e6b2c373dfc1893f648d", 57 | id: "0xf8e356a0087a537f3e1a481c46ed4bdc4438723ebe666d8a3e7e6f4021d740a4", 58 | }, 59 | } 60 | } -------------------------------------------------------------------------------- /config/prod/l2.js: -------------------------------------------------------------------------------- 1 | // l1 chain & contract infomation 2 | module.exports = { 3 | silicon : { 4 | l1_chain: "eth", 5 | PolygonValidiumEtrog: "0x419dcd0f72ebafd3524b65a97ac96699c7fbebdb", // sequence 6 | PolygonRollupManager: "0x5132A183E9F3CB7C848b0AAC5Ae0c4f0491B7aB2" // verify 7 | } 8 | } -------------------------------------------------------------------------------- /config/prod/matic.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | chain_list: [ 3 | 'avax', 4 | 'bsc', 5 | 'klaytn', 6 | 'matic', 7 | 'eth', 8 | "ton", 9 | "silicon", 10 | ], 11 | 12 | // Bridge Addresses 13 | bridge_address: { 14 | avax: { 15 | minter: "0x506DC4c6408813948470a06ef6e4a1DaF228dbd5", 16 | multisig: "0x98d729f9bD84AAC94639700e71B7916018A708B1", 17 | admin: "0x3b31c980598f9237d9C14bB44118773b92174720", 18 | }, 19 | bsc: { 20 | minter: "0x506DC4c6408813948470a06ef6e4a1DaF228dbd5", 21 | multisig: "0x98d729f9bD84AAC94639700e71B7916018A708B1", 22 | admin: "0x3b31c980598f9237d9C14bB44118773b92174720", 23 | }, 24 | eth: { 25 | minter: "0x506DC4c6408813948470a06ef6e4a1DaF228dbd5", 26 | multisig: "0x98d729f9bD84AAC94639700e71B7916018A708B1", 27 | admin: "0x3b31c980598f9237d9C14bB44118773b92174720", 28 | }, 29 | klaytn: { 30 | minter: "0x506DC4c6408813948470a06ef6e4a1DaF228dbd5", 31 | multisig: "0x98d729f9bD84AAC94639700e71B7916018A708B1", 32 | }, 33 | matic: { 34 | vault: "0x506DC4c6408813948470a06ef6e4a1DaF228dbd5", 35 | multisig: "0x98d729f9bD84AAC94639700e71B7916018A708B1", 36 | admin: "0x3b31c980598f9237d9C14bB44118773b92174720", 37 | }, 38 | ton: { 39 | minter: "EQAZPJjpx_VCoaAJW78qYtbUK59IsheysCRgzaSUcp7k_Jqd", 40 | multisig: "EQBbdymUiXgv2FK4yGwHmXC2mvnpwxUT7U9tj-nonXXnrv0L", 41 | }, 42 | silicon: { 43 | minter: "0xd4058d1f1071c03CBC19cb149885ecAda79B99b8", 44 | multisig: "0x41c687a333a9586dBdA5C1B5e8F224bF77800E87", 45 | admin: "0x72f757F0DA2ec2c3ab6a61e177e95b70ECf65E21", 46 | }, 47 | governance: { 48 | chain: "MATIC", 49 | address: "0x506DC4c6408813948470a06ef6e4a1DaF228dbd5", 50 | bytes: "0x506DC4c6408813948470a06ef6e4a1DaF228dbd5", 51 | id: "0xaf9c9bf1d10f96432ef783c6ff34815d5e22e5083554a9940cf5dcbbdce7cfe7", 52 | }, 53 | } 54 | } -------------------------------------------------------------------------------- /config/prod/metadium.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | chain_list: [ 3 | "avax", 4 | "bsc", 5 | "eth", 6 | "klaytn", 7 | "matic", 8 | "metadium", 9 | "ton", 10 | "wemix" 11 | ], 12 | bridge_address: { 13 | avax: { 14 | minter: "0xf4D9c96896d8dE644E229e37FdC9Cb02bee65e51", 15 | multisig: "0x218c6E663e43542d90E4Bf6247b1E9e719ce0FAF", 16 | admin: "0xA41eC45f1828bD1b3e91Ca31Bf005AfeA540D6f2" 17 | }, 18 | bsc: { 19 | minter: "0x3F0ADd7b24080352E4EC7DD8b9F6B8e7BbB36717", 20 | multisig: "0x005be6cAF238609E23949EF75fC1a0a13Ea02928", 21 | admin: "0x0A1ce5a7867BA59Ce9807C0774acf8b376f52E4F" 22 | }, 23 | eth: { 24 | minter: "0x06d1484298773B74235cD400926a7b1e65fdea55", 25 | multisig: "0x77258E1e42D26817Cc840a5906C212B3B8CB636a", 26 | admin: "0x77C24eB33FE159606397a5309d6C4D841e160600" 27 | }, 28 | klaytn: { 29 | minter: "0x02e0E14F84F6A07CC82E8076D09c09070B087AFf", 30 | multisig: "0xA41eC45f1828bD1b3e91Ca31Bf005AfeA540D6f2" 31 | }, 32 | matic: { 33 | minter: "0xCBCe11BCFde0377b79A83a8c358743A46fb2EaF4", 34 | multisig: "0x1976b603d73eD45154473d04f44bd9f7f26ee512", 35 | admin: "0x12F421Ffac3B16c7FF73bC82f694550Fa4D711C6" 36 | }, 37 | metadium: { 38 | vault: "0x292A00F3b99e3CB9b324EdbaA92258C3C61b55ab", 39 | multisig: "0x218c6E663e43542d90E4Bf6247b1E9e719ce0FAF", 40 | admin: "0x70cf20911fb49974532dc4EC8b56f96DA34511F4" 41 | }, 42 | ton: { 43 | minter: "EQChjxYqk_fq_fz3QiUdu27fHEiu0ZbGuN2TF0f0vVFDZLqB", 44 | multisig: "EQBuMD8iUYs8WrGky-DmHenxi5urcXgQ7kMO2w1v-OMuZKlb", 45 | }, 46 | wemix: { 47 | minter: "0xa70a4c074B93136405100FC6004cc27bDE16f602", 48 | multisig: "0x8e2cFeb906b293b329d3017eB55faff0EA0C6FF4", 49 | admin: "0x4eD917b4c9abda373d6CfcDE7Cc62c9b8beca494" 50 | }, 51 | governance: { 52 | chain: "METADIUM", 53 | address: "0x292A00F3b99e3CB9b324EdbaA92258C3C61b55ab", 54 | bytes: "0x292A00F3b99e3CB9b324EdbaA92258C3C61b55ab", 55 | id: "0xb835fb9684ac2ae102c51d53fd4e14a2b08e7fd163d7a6b1d59ad70cfd6c0c36" 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /config/prod/silicon.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // operating chain list 3 | chain_list: [ 4 | 'silicon', 5 | 'klaytn', 6 | 'icon', 7 | 'avax', 8 | 'bsc', 9 | 'matic', 10 | 'ton', 11 | 'wemix' 12 | ], 13 | 14 | // Bridge Addresses 15 | bridge_address: { 16 | silicon: { 17 | vault: "0x5aAAcf28ECDd691b4a657684135d8848d38236Bb", 18 | multisig: "0x67fAD8dd49abcc129DC25DE15bA1D3994F748AE5", 19 | admin: "0x3A054a90be288B75AEfa540f9Fff9B63d048dE5b" 20 | }, 21 | avax: { 22 | minter: "0x6BD8E3beEC87176BA9c705c9507Aa5e6F0E6706f", 23 | multisig: "0xFA9c34485c3a706725130E8e0217431AC000E31e", 24 | admin: "0xe62Fa6C59AD14B46d4e7791FA817030732953b79", 25 | }, 26 | bsc: { 27 | minter: "0x6BD8E3beEC87176BA9c705c9507Aa5e6F0E6706f", 28 | multisig: "0xFA9c34485c3a706725130E8e0217431AC000E31e", 29 | admin: "0xe62Fa6C59AD14B46d4e7791FA817030732953b79", 30 | }, 31 | icon: { 32 | minter: "cx0eb215b6303142e37c0c9123abd1377feb423f0e", 33 | multisig: "cxa032c913d5d9b7577e2b19f39d91985e5c260577", 34 | }, 35 | klaytn: { 36 | minter: "0x60070F5D2e1C1001400A04F152E7ABD43410F7B9", 37 | multisig: "0x74bB62c446c592a5A8424d4f9437242df1e26BF0", 38 | }, 39 | matic: { 40 | minter: "0x6BD8E3beEC87176BA9c705c9507Aa5e6F0E6706f", 41 | multisig: "0xFA9c34485c3a706725130E8e0217431AC000E31e", 42 | admin: "0xe62Fa6C59AD14B46d4e7791FA817030732953b79", 43 | }, 44 | ton: { 45 | minter: "EQCVcKobt9eK6KgKdpkVp_xK23My7U0DHJUrko_WuH5dm_qu", 46 | multisig: "EQDeOV9RZZA4dwS39S0YWQbmsEEfjxIT7F0BhylWTqL9jLiD", 47 | }, 48 | wemix: { 49 | minter: "0x6BD8E3beEC87176BA9c705c9507Aa5e6F0E6706f", 50 | multisig: "0xCeBB82777bfe09c65AA47E8dD09a2f3972467901", 51 | admin: "0xe62Fa6C59AD14B46d4e7791FA817030732953b79", 52 | }, 53 | governance: { 54 | chain: "SILICON", 55 | address: "0x5aAAcf28ECDd691b4a657684135d8848d38236Bb", 56 | bytes: "0x5aAAcf28ECDd691b4a657684135d8848d38236Bb", 57 | id: "0xaf3aa751581952cd44ce699915c6a0dd1b5df9b832505b2629420e87d1ddf981", 58 | }, 59 | } 60 | } -------------------------------------------------------------------------------- /config/prod/system.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | ethGasPriceApi: 'https://ethgasstation.info/json/ethgasAPI.json', 3 | maticGasPriceApi: 'https://gasstation-mainnet.matic.network/', 4 | ethConfirmCount: 24, 5 | klaytnConfirmCount: 10, 6 | iconConfirmCount: 4, 7 | bscConfirmCount: 15, 8 | hecoConfirmCount: 20, 9 | maticConfirmCount: 300, 10 | celoConfirmCount: 4, 11 | tonConfirmCount: 12, 12 | logLevel: 'debug' 13 | }; 14 | -------------------------------------------------------------------------------- /config/prod/ton.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | chain_list: [ 3 | "avax", 4 | "bsc", 5 | "eth", 6 | "klaytn", 7 | "matic", 8 | "eth", 9 | "ton_layer_1", 10 | "silicon", 11 | ], 12 | silicon: { 13 | addressbook: "0xd0B3ac7326FDf78DEc838451E031cf69933F6faF", 14 | multisig: "0x2baF90197b3C034282Dd6cdC29a9902B7f8789A4", 15 | }, 16 | // Bridge Addresses 17 | bridge_address: { 18 | ton: { 19 | vault: "EQDXbWI3jClPS510by25zTA8SUKMa4XSD2K7DbZb0jincPGw", 20 | multisig: "EQB8mNTgoG5QxqhOdVFi6X0MOjkmGNd33ct-RGBT9ZT5oDAX", 21 | }, 22 | avax: { 23 | minter: "0x58A42330c0984babD5DEc2C943eAA345B7f41e44", 24 | multisig: "0x4dd5c30ae4a140d3B9180c778bD2e74c8e64E38A", 25 | admin: "0x8966c07b38dcb277f1e5264368Cafb289DBCab4f", 26 | }, 27 | bsc: { 28 | minter: "0x58A42330c0984babD5DEc2C943eAA345B7f41e44", 29 | multisig: "0x4dd5c30ae4a140d3B9180c778bD2e74c8e64E38A", 30 | admin: "0x8966c07b38dcb277f1e5264368Cafb289DBCab4f", 31 | }, 32 | eth: { 33 | minter: "0x5Cc6a1Dc39E523eFd6C42534a478942Cadd24f8C", 34 | multisig: "0x4dd5c30ae4a140d3B9180c778bD2e74c8e64E38A", 35 | admin: "0x8966c07b38dcb277f1e5264368Cafb289DBCab4f", 36 | }, 37 | klaytn: { 38 | minter: "0x58A42330c0984babD5DEc2C943eAA345B7f41e44", 39 | multisig: "0x4dd5c30ae4a140d3B9180c778bD2e74c8e64E38A", 40 | }, 41 | matic: { 42 | minter: "0x58A42330c0984babD5DEc2C943eAA345B7f41e44", 43 | multisig: "0x4dd5c30ae4a140d3B9180c778bD2e74c8e64E38A", 44 | admin: "0x8966c07b38dcb277f1e5264368Cafb289DBCab4f", 45 | }, 46 | silicon: { 47 | minter: "0x4358fFeDCAE2e0BC7F21F2aF882bB1d723e30069", 48 | multisig: "0x2baF90197b3C034282Dd6cdC29a9902B7f8789A4", 49 | admin: "0x0461393F1cC22dE0E25939920Dceb798a94bb405", 50 | }, 51 | governance: { 52 | chain: "TON_LAYER_1", 53 | address: "EQDXbWI3jClPS510by25zTA8SUKMa4XSD2K7DbZb0jincPGw", 54 | bytes: "0xd76d62378c294f4b9d746f2db9cd303c49428c6b85d20f62bb0db65bd238a770", 55 | id: "0x0925ffa9907f762541218b8a1b7a76ada0effdc7354d5dfbaace28d6f7ffae6d", 56 | }, 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /config/prod/wemix.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // operating chain list 3 | chain_list: [ 4 | "eth", 5 | "klaytn", 6 | "avax", 7 | "bsc", 8 | "matic", 9 | "metadium", 10 | "ton", 11 | "wemix", 12 | "silicon", 13 | ], 14 | 15 | // Bridge Addresses 16 | bridge_address: { 17 | avax: { 18 | minter: "0x81aB59F77cdb158d4A9DcF66d5e04E6e277a0a43", 19 | multisig: "0x56D9c7A23CBaf1442fBDaAA3B97502f089cfecbF", 20 | admin: "0x86c462C9F64347FC1b1aA43eE5dcBCEFc0Ca5514" 21 | }, 22 | bsc: { 23 | minter: "0xeA74a390Df39080c417DA23023cAa84f6Bb28568", 24 | multisig: "0x41A307A2EEC05d7E8BbA452c1D061398bE29e4f6", 25 | admin: "0x81aB59F77cdb158d4A9DcF66d5e04E6e277a0a43" 26 | }, 27 | eth: { 28 | minter: "0x34c51c0cD541CAddcb71dB298Ec9fAf6D0256808", 29 | multisig: "0x381A07875D7C346E024cF4a9C46616154dFd1ea5", 30 | admin: "0x8e2cFeb906b293b329d3017eB55faff0EA0C6FF4" 31 | }, 32 | klaytn: { 33 | minter: "0x3be51C9F0584Cc24eA330665010d69a21edee240", 34 | multisig: "0x4A6A0c1b6452a3a4adB5F095A65BE59Eb1edd3dD" 35 | }, 36 | matic: { 37 | minter: "0xb5f76BDd8383A079a31381DcD5205Bf221B6476e", 38 | multisig: "0x3f5beBAf2A10326e5aB91777a0E23E2b68E4A17c", 39 | admin: "0x4A6A0c1b6452a3a4adB5F095A65BE59Eb1edd3dD" 40 | }, 41 | metadium: { 42 | minter: "0xeA74a390Df39080c417DA23023cAa84f6Bb28568", 43 | multisig: "0x41A307A2EEC05d7E8BbA452c1D061398bE29e4f6", 44 | admin: "0x81aB59F77cdb158d4A9DcF66d5e04E6e277a0a43" 45 | }, 46 | ton: { 47 | minter: "EQA4XgASzx1VSi6T0r8tv1XdHwfUEplQhjg1q09RUd8gcPhd", 48 | multisig: "EQAj33y_sRp4Ypuz8zdSGfrhYdTgW1uLhjVHuUNBNxnOA1RW", 49 | }, 50 | wemix: { 51 | vault: "0x445F863df0090f423A6D7005581e30d5841e4D6d", 52 | multisig: "0x775b772Bd879931433C95047aF46113E97083614", 53 | admin: "0x9CE4E2B920DdEe58158704A47650a13123907749" 54 | }, 55 | silicon: { 56 | minter: "0xc8ab468c4F94E954acC2D60a328DEd74bF315CB6", 57 | multisig: "0xe938Ff16C04C06E04AEF710F7682b437D9d47065", 58 | admin: "0x18d8037c2F2af01B5eA232175E051910C0d01812" 59 | }, 60 | governance: { 61 | chain: "WEMIX", 62 | address: "0x445F863df0090f423A6D7005581e30d5841e4D6d", 63 | bytes: "0x445F863df0090f423A6D7005581e30d5841e4D6d", 64 | id: "0x186eb827d7996bd507fef5bd466a5348258c6a0b0dcaeed907df7699579f363c" 65 | } 66 | } 67 | } -------------------------------------------------------------------------------- /config/prod/xrp.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // operating chain list 3 | chain_list: [ 4 | 'klaytn', 5 | 'xrp', 6 | 'avax', 7 | 'bsc', 8 | 'matic', 9 | "wemix", 10 | 'silicon', 11 | ], 12 | silicon: { 13 | xrpBridge: "0x83bca9503D7888F2eFcDF18cCa2E79f8Ba75d17c", 14 | addressbook: "0x37CE54AFB91F3645b3e7455Cb4C5028507D6aBeB", 15 | multisig: "0xCe303B5740C70fFe4477E0d21E3B35770587F3B1", 16 | }, 17 | // Bridge Addresses 18 | bridge_address: { 19 | avax: { 20 | minter: "0xE38ca00A6FD34B793012Bb9c1471Adc4E98386cF", 21 | multisig: "0xfa50391705D2FA7ac47Dd211B78378825bc763e6", 22 | admin: "0x009071058740276327A393B084eC447b8F0Fc6Ae", 23 | }, 24 | klaytn: { 25 | minter: "0x917655B6C27A3D831b4193CE18ECe6bfcC806BF8", 26 | multisig: "0x22Bef83bABcC1169855D748D13523CA10aD87dF7", 27 | }, 28 | bsc: { 29 | minter: "0xE38ca00A6FD34B793012Bb9c1471Adc4E98386cF", 30 | multisig: "0xfa50391705D2FA7ac47Dd211B78378825bc763e6", 31 | admin: "0x009071058740276327A393B084eC447b8F0Fc6Ae", 32 | }, 33 | matic: { 34 | minter: "0xE38ca00A6FD34B793012Bb9c1471Adc4E98386cF", 35 | multisig: "0xfa50391705D2FA7ac47Dd211B78378825bc763e6", 36 | admin: "0x009071058740276327A393B084eC447b8F0Fc6Ae", 37 | }, 38 | wemix: { 39 | minter: "0x3fc270534bBEEF400777B587D03fc66D8Ddd716E", 40 | multisig: "0x60D85ED151CBdE337019263A54AD2fb6b495547C", 41 | admin: "0xC9bD6dE100b923C275e74dC75F895B50c7488eD3", 42 | }, 43 | silicon: { 44 | minter: "0x065BaE5639EB5718E0F76B27967f582e4b7d63a8", 45 | multisig: "0xCe303B5740C70fFe4477E0d21E3B35770587F3B1", 46 | admin: "0x478172a50906CaC395F8567a8dC001c7EeCB2A0A", 47 | }, 48 | governance: { 49 | chain: "XRP", 50 | address: "rJTEBWu7u1NcJAiMQ9iEa1dbsuPyhTiW23", 51 | bytes: "0x00bf70ca91c426e78c28f0fa724e679d50ac59f9378a71efbd", 52 | id: "0x4f1d4170def98e5be4eb9a487615c2e39939c184839448e44096bafc42f5ee65", 53 | }, 54 | } 55 | } -------------------------------------------------------------------------------- /lib/api.js: -------------------------------------------------------------------------------- 1 | const request = require('request'); 2 | const req = require("request-promise"); 3 | const config = require(ROOT + '/config'); 4 | const { VALIDATOR_MONITOR } = require(`${ROOT}/config/${process.env.PROFILE}/endpoints.js`); 5 | 6 | module.exports = { 7 | ethGasPrice: { 8 | request() { 9 | return new Promise((resolve, reject) => { 10 | let options = { 11 | method: 'GET', 12 | url: config.system.ethGasPriceApi 13 | }; 14 | 15 | sendGetGasPrice(options, resolve, reject); 16 | }) 17 | } 18 | }, 19 | maticGasPrice: { 20 | request() { 21 | return new Promise((resolve, reject) => { 22 | let options = { 23 | method: 'GET', 24 | url: config.system.maticGasPriceApi 25 | }; 26 | 27 | sendGetGasPrice(options, resolve, reject); 28 | }) 29 | } 30 | }, 31 | bible: { 32 | get(path, params = {}) { 33 | if (!VALIDATOR_MONITOR || !VALIDATOR_MONITOR.ozys || !VALIDATOR_MONITOR.ozys.bible) { 34 | return new Promise((_, reject) => { 35 | reject(new Error(`Bible Endpoint missing.`)); 36 | }); 37 | } 38 | let bible = VALIDATOR_MONITOR.ozys.bible; 39 | if (bible.endsWith('/')) { 40 | bible = bible.substring(0, bible.length-1); 41 | } 42 | if (path.startsWith('/')) { 43 | path = path.substring(1); 44 | } 45 | return req.get(`${bible}/${path}`, { 46 | qs: params, 47 | headers: { 48 | 'User-Agent': 'Request-Promise', 49 | }, 50 | json: true, 51 | }); 52 | }, 53 | }, 54 | validator: { 55 | post(path, params = {}) { 56 | if (!VALIDATOR_MONITOR || !VALIDATOR_MONITOR.ozys || !VALIDATOR_MONITOR.ozys.validator) { 57 | return new Promise((_, reject) => { 58 | reject(new Error(`Validator Endpoint missing.`)); 59 | }); 60 | } 61 | let validator = VALIDATOR_MONITOR.ozys.validator; 62 | if (validator.endsWith('/')) { 63 | validator = validator.substring(0, validator.length-1); 64 | } 65 | if (path.startsWith('/')) { 66 | path = path.substring(1); 67 | } 68 | return req.post({ 69 | headers: {'User-Agent': 'Request-Promise'}, 70 | url: `${validator}/${path}`, 71 | body: params, 72 | json: true 73 | }) 74 | } 75 | }, 76 | orbit: { 77 | get(path, params = {}) { 78 | if (!VALIDATOR_MONITOR || !VALIDATOR_MONITOR.ozys || !VALIDATOR_MONITOR.ozys.orbit) { 79 | return new Promise((_, reject) => { 80 | reject(new Error(`Orbit Endpoint missing.`)); 81 | }); 82 | } 83 | let orbit = VALIDATOR_MONITOR.ozys.orbit; 84 | if (orbit.endsWith('/')) { 85 | orbit = orbit.substring(0, orbit.length-1); 86 | } 87 | if (path.startsWith('/')) { 88 | path = path.substring(1); 89 | } 90 | return req.get(`${orbit}/${path}`, { 91 | qs: params, 92 | headers: { 93 | 'User-Agent': 'Request-Promise', 94 | }, 95 | json: true, 96 | }); 97 | }, 98 | } 99 | }; 100 | 101 | function sendGetGasPrice(options, resolve, reject) { 102 | options.timeout = 1000 * 30; 103 | 104 | request(options, async (error, response, body) => { 105 | if (error) { 106 | logger.error('API call error: Request error. / req: ' + JSON.stringify(options) + ' / err: ' + JSON.stringify(error)); 107 | return reject(error); 108 | } 109 | 110 | let json; 111 | try { 112 | if (typeof body === 'string' || body instanceof String) 113 | json = JSON.parse(body); 114 | else 115 | json = body; 116 | } catch (e) { 117 | logger.error('API call error: JSON Parse error. / req: ' + JSON.stringify(options) + ' / err: ' + e.message); 118 | return reject(e); 119 | } 120 | 121 | if (!json) { 122 | logger.error('API returns malformed json. / req: ' + JSON.stringify(options)); 123 | return reject({message: 'API returns malformed json.'}); 124 | } else if (!json.fast) { 125 | logger.error('API call error: API returns fail. / req: ' + JSON.stringify(options) + ' / err: ' + JSON.stringify(json)); 126 | return reject({message: 'API returns fail. ' + JSON.stringify(json)}); 127 | } 128 | 129 | resolve(json); 130 | }); 131 | } 132 | -------------------------------------------------------------------------------- /lib/bridgeutils.js: -------------------------------------------------------------------------------- 1 | const bech32 = require('bech32'); 2 | const rippleAddr = require('ripple-address-codec'); 3 | const config = require(ROOT + '/config'); 4 | const settings = config.settings; 5 | const Endpoints = config.endpoints.endpoints; 6 | const { AddressVersion, addressFromVersionHash, addressToString } = require("@stacks/transactions"); 7 | const request = require("request-promise"); 8 | 9 | class BridgeUtils { 10 | str2hex(input){ 11 | if (typeof(input) !== 'string'){ 12 | return ""; 13 | } 14 | 15 | if (input.length < 2 || input.slice(0,2) !== '0x'){ 16 | return '0x' + Buffer.from(input).toString('hex'); 17 | } 18 | 19 | return input; 20 | } 21 | 22 | hex2str(input){ 23 | input = input || '' 24 | return Buffer.from(input.replace('0x', ''), 'hex').toString('utf8'); 25 | } 26 | 27 | isValidData(toChain, data) { 28 | if (!toChain) 29 | return false; 30 | 31 | if (!data) 32 | return false; 33 | 34 | if (toChain === "XRP"){ 35 | return data === "0x" || parseInt(data) <= 4294967295; 36 | } 37 | 38 | return true; 39 | } 40 | 41 | isValidAddress(toChain, address) { 42 | if (!address) 43 | return false; 44 | 45 | if (!toChain) 46 | return false; 47 | toChain = toChain.toUpperCase() 48 | 49 | const EVM_CHAINS = [ 50 | "ETH", 51 | "KLAYTN", 52 | "BSC", 53 | "HECO", 54 | "MATIC", 55 | "CELO", 56 | "AVAX", 57 | "FANTOM", 58 | "OEC", 59 | "XDAI", 60 | "WEMIX", 61 | "METADIUM", 62 | "SILICON" 63 | ] 64 | 65 | if (EVM_CHAINS.includes(toChain)) { 66 | return address.slice(0,2) === '0x' && address.length == 42; 67 | } 68 | 69 | if(toChain === "ICON"){ 70 | let govInfo = config.governance; 71 | if(govInfo.chain === "ICON" && address.toLowerCase() === govInfo.bytes.toLowerCase()){ 72 | return false; 73 | } 74 | 75 | return (address.slice(0,4) === '0x00' || address.slice(0,4) === '0x01') && address.length == 44; 76 | } 77 | 78 | if(toChain === "XRP"){ 79 | let govInfo = config.governance; 80 | 81 | try{ 82 | let buf = Buffer.from(address.replace('0x', ''), 'hex'); 83 | address = rippleAddr.codec.codec.encode(buf); 84 | }catch(e) { 85 | return false; 86 | } 87 | 88 | return rippleAddr.isValidClassicAddress(address) && govInfo.chain === "XRP" && address.toLowerCase() !== govInfo.address.toLowerCase(); 89 | } 90 | 91 | if (toChain.includes("STACKS")) { 92 | if(address.length != 42) { 93 | return false; 94 | } 95 | 96 | let addr; 97 | try { 98 | if(Endpoints.stacks.network === "testnet"){ 99 | addr = addressToString(addressFromVersionHash(AddressVersion.TestnetSingleSig, address.replace("0x", ""))); 100 | return addr.slice(0,2) === "ST"; 101 | } 102 | else{ 103 | addr = addressToString(addressFromVersionHash(AddressVersion.MainnetSingleSig, address.replace("0x", ""))); 104 | return addr.slice(0,2) === "SP"; 105 | } 106 | } catch(e) { 107 | return false; 108 | } 109 | } 110 | 111 | if(toChain.includes("TON")){ 112 | return address.slice(0,2) === "0x" && address.length == 66; 113 | } 114 | 115 | return false; 116 | } 117 | 118 | padLeft(data, length) { 119 | return '0x' + data.replace('0x','').padStart(length,'0'); 120 | } 121 | 122 | async checkTransaction(nodeConfig, data, functionSig) { 123 | const txhash = data.bytes32s[1]; 124 | const CHAIN = nodeConfig.peggingType.toUpperCase(); 125 | const CONFIRM_CNT = config.endpoints[CHAIN.split("_")[0].toLowerCase()].confirm || 10; 126 | 127 | const block = await nodeConfig.web3.eth.getBlock("latest").catch(e => { 128 | logger.info(`[${CHAIN}] getBlock fail: ${e.message}`); 129 | }); 130 | if (!block) { 131 | return; 132 | } 133 | const tx = await nodeConfig.web3.eth.getTransactionReceipt(txhash).catch(e => { 134 | logger.info(`[${CHAIN}] getTransaction fail: ${txhash}, ${e.message}`); 135 | }); 136 | if (!tx) { 137 | return; 138 | } 139 | 140 | // CHECK RELAY BLOCK CONFIRM 141 | if (block.number < tx.blockNumber + CONFIRM_CNT) { 142 | logger.info(`[${CHAIN}] TX: ${txhash}, ${block.number}, ${tx.blockNumber}. prematured.`); 143 | return; 144 | } 145 | 146 | // CHECK ADDRESS 147 | for (const log of tx.logs) { 148 | if (nodeConfig.address.toLowerCase() === log.address.toLowerCase()) { 149 | let receipt = nodeConfig.contract._decodeEventABI.bind({ 150 | name: "ALLEVENTS", 151 | jsonInterface: nodeConfig.contract._jsonInterface 152 | })(log); 153 | if(receipt.event !== functionSig) continue; 154 | if(receipt.transactionHash.toLowerCase() != txhash || 155 | receipt.returnValues.amount.toLowerCase() !== data.uints[0] || 156 | receipt.returnValues.decimal.toLowerCase() !== (data.uints[1]).toString() || 157 | receipt.returnValues.token.toLowerCase() !== data.token 158 | ) continue; 159 | return true; 160 | } 161 | } 162 | logger.info(`[${CHAIN}] TX: ${txhash}, ${nodeConfig.address}. governance not matched.`); 163 | } 164 | 165 | async getBeaconBlock() { 166 | const info = config.info.eth; 167 | if(!info) return; 168 | 169 | const beacon = info.ENDPOINT.beacon || "https://beacon.chain-node.orbitchain.io:7643"; 170 | let res; 171 | try { 172 | res = await request.get(`${beacon}/eth/v2/beacon/blocks/finalized`); 173 | res = JSON.parse(res); 174 | } catch (e) {console.log(e);} 175 | 176 | return res; 177 | } 178 | } 179 | 180 | module.exports = BridgeUtils; 181 | -------------------------------------------------------------------------------- /lib/decimal.js: -------------------------------------------------------------------------------- 1 | // Object.assign polyfill 2 | const BigNumber = require("bignumber.js"); 3 | const PREC = 32; 4 | 5 | if (typeof Object.assign != 'function') { 6 | (function () { 7 | Object.assign = function (target) { 8 | 'use strict'; 9 | if (target === undefined || target === null) { 10 | throw new TypeError('Cannot convert undefined or null to object'); 11 | } 12 | 13 | var output = Object(target); 14 | for (var index = 1; index < arguments.length; index++) { 15 | var source = arguments[index]; 16 | if (source !== undefined && source !== null) { 17 | for (var nextKey in source) { 18 | if (source.hasOwnProperty(nextKey)) { 19 | output[nextKey] = source[nextKey]; 20 | } 21 | } 22 | } 23 | } 24 | return output; 25 | }; 26 | })(); 27 | } 28 | 29 | // String.repeat polyfill 30 | if (!String.prototype.repeat) { 31 | String.prototype.repeat = function(count) { 32 | 'use strict'; 33 | if (this == null) { 34 | throw new TypeError('can\'t convert ' + this + ' to object'); 35 | } 36 | var str = '' + this; 37 | count = +count; 38 | if (count != count) { 39 | count = 0; 40 | } 41 | if (count < 0) { 42 | throw new RangeError('repeat count must be non-negative'); 43 | } 44 | if (count == Infinity) { 45 | throw new RangeError('repeat count must be less than infinity'); 46 | } 47 | count = Math.floor(count); 48 | if (str.length == 0 || count == 0) { 49 | return ''; 50 | } 51 | // Ensuring count is a 31-bit integer allows us to heavily optimize the 52 | // main part. But anyway, most current (August 2014) browsers can't handle 53 | // strings 1 << 28 chars or longer, so: 54 | if (str.length * count >= 1 << 28) { 55 | throw new RangeError('repeat count must not overflow maximum string size'); 56 | } 57 | var rpt = ''; 58 | for (var i = 0; i < count; i++) { 59 | rpt += str; 60 | } 61 | return rpt; 62 | } 63 | } 64 | 65 | String.prototype.dclean = function(){ // 불필요한 0 제거 66 | var v = this.toString(); 67 | var dot = v.indexOf('.'); if(dot === -1) dot = v.length; 68 | var num = v.substr(0, dot), dec = v.substr(dot + 1); 69 | 70 | num = num.replace(/^0+/, ''); 71 | if(num.length === 0) num = '0'; 72 | 73 | dec = dec.replace(/0+$/, ''); 74 | if(dec.length > 0) num += '.' + dec; 75 | 76 | return num; 77 | } 78 | 79 | String.prototype.dprec = function(d){ // 강제로 소수점 이하 d자리 출력 80 | var v = this.toString().dclean(); 81 | var dot = v.indexOf('.'); if(dot === -1) dot = v.length; 82 | var num = v.substr(0, dot), dec = v.substr(dot + 1); 83 | 84 | if(dec.length > d) dec = dec.substr(0, d); 85 | else dec += '0'.repeat(d - dec.length); 86 | 87 | if(d > 0) num += '.' + dec; 88 | 89 | return num; 90 | } 91 | 92 | String.prototype.dmove = function(d){ // 10^d 곱함 93 | var v = this.toString().dclean(); 94 | var dot = v.indexOf('.'); if(dot === -1) dot = v.length; 95 | var num = v.substr(0, dot), dec = v.substr(dot + 1); 96 | 97 | d -= dec.length; num += dec; 98 | var l = num.length; 99 | 100 | if(d > 0) num += '0'.repeat(d); 101 | else if(d < 0){ 102 | d = -d; 103 | if(d < l) num = num.substr(0, l - d) + '.' + num.substr(l - d); 104 | else num = '0.' + '0'.repeat(d - l) + num; 105 | } 106 | return num.dclean(); 107 | } 108 | 109 | function dton(v, w){ 110 | v = v.dclean(); 111 | var vt = v.indexOf('.'); if(vt === -1) vt = v.length; 112 | var vd = v.substr(vt + 1).length; 113 | 114 | w = w.dclean(); 115 | var wt = w.indexOf('.'); if(wt === -1) wt = w.length; 116 | var wd = w.substr(wt + 1).length; 117 | 118 | var d = (vd > wd ? vd : wd); 119 | 120 | return { d : d, v : v.dmove(d), w : w.dmove(d) }; 121 | } 122 | 123 | String.prototype.dcomp = function(w){ 124 | var o = dton(this.toString(), w); 125 | var d = o.d, v = o.v; w = o.w; 126 | 127 | var vl = v.length, wl = w.length; 128 | 129 | return (vl > wl ? 1 : vl < wl ? -1 : v > w ? 1 : v < w ? -1 : 0); 130 | } 131 | 132 | String.prototype.dadd = function(w){ 133 | var o = dton(this.toString(), w); 134 | var d = o.d, v = o.v; w = o.w; 135 | 136 | var vl = v.length, wl = w.length, l = (vl > wl ? vl : wl); 137 | 138 | v = v.split('').reverse().join(''); 139 | w = w.split('').reverse().join(''); 140 | 141 | var res = [], x = 0; 142 | 143 | for(var i = 0; i < l; i++){ 144 | var vi = (i < vl ? v.charCodeAt(i) - 48 : 0); 145 | var wi = (i < wl ? w.charCodeAt(i) - 48 : 0); 146 | 147 | var r = vi + wi + x; 148 | if(r > 9){ x = 1; r -= 10; } else x = 0; 149 | 150 | res.push(r); 151 | } 152 | 153 | if(x > 0) res.push(x); 154 | 155 | return res.reverse().join('').dmove(-d); 156 | } 157 | 158 | String.prototype.dsub = function(v, prec = PREC) { 159 | const ba = new BigNumber(this); 160 | const bb = new BigNumber(String(v)); 161 | return ba.minus(bb).toFixed(prec).dclean(); 162 | } 163 | 164 | String.prototype.dmul = function(w){ 165 | var o = dton(this.toString(), w); 166 | var d = o.d, v = o.v; w = o.w; 167 | 168 | var vl = v.length, wl = w.length, l = vl + wl - 1; 169 | 170 | v = v.split('').reverse().join(''); 171 | w = w.split('').reverse().join(''); 172 | 173 | var res = []; for(var i = 0; i < l; i++) res.push(0); 174 | 175 | for(var i = 0; i < vl; i++){ 176 | for(var j = 0; j < wl; j++){ 177 | var vi = v.charCodeAt(i) - 48; 178 | var wi = w.charCodeAt(j) - 48; 179 | 180 | res[i + j] += vi * wi; 181 | } 182 | } 183 | 184 | for(var i = 0; i < l; i++){ 185 | if(res[i] < 10) continue; 186 | 187 | var x = Math.floor(res[i] / 10); 188 | 189 | if(i + 1 == l) res.push(x); else res[i + 1] += x; 190 | res[i] -= x * 10; 191 | } 192 | 193 | return res.reverse().join('').dmove(-2 * d); 194 | } 195 | 196 | String.prototype.ddiv = function(w, prec){ 197 | prec = prec ? prec : 40 198 | 199 | if(w.dcomp('0') === 0){ 200 | throw 'Error: Divide by zero'; 201 | } 202 | 203 | var o = dton(this.toString(), w); 204 | var v = o.v; w = o.w; 205 | 206 | var res = '', d = 0; 207 | 208 | while(v.dcomp(w) >= 0){ w += '0'; d++; } 209 | 210 | for(var i = 1; i <= d; i++){ 211 | w = w.slice(0, -1); 212 | 213 | var c = 0; 214 | while(v.dcomp(w) >= 0){ v = v.dsub(w); c++; } 215 | 216 | res += c; 217 | } 218 | 219 | res += '.'; 220 | 221 | for(var i = 1; i <= prec; i++){ 222 | v += '0'; 223 | 224 | var c = 0; 225 | while(v.dcomp(w) >= 0){ v = v.dsub(w); c++; } 226 | 227 | res += c; 228 | } 229 | 230 | return res.dclean(); 231 | } -------------------------------------------------------------------------------- /lib/request.js: -------------------------------------------------------------------------------- 1 | var querystring = require('querystring'); 2 | var libRequest = require('request'); 3 | 4 | class Request { 5 | constructor(host) { 6 | if (!host.startsWith("http://") && !host.startsWith("https://")) 7 | host = "http://" + host; 8 | this.host = host; 9 | } 10 | 11 | _generalErrorHandler(next, error, response, body) { 12 | if (!error && response.statusCode == 200) { 13 | if (body.error) { 14 | next(body.error); 15 | return true; 16 | } 17 | return false; 18 | } else { 19 | next(error); 20 | return true; 21 | } 22 | } 23 | 24 | rpc(method, params, id, callback) { 25 | var headers = { 26 | 'content-type': 'application/json' 27 | }; 28 | 29 | id = (id || '1').toString(); 30 | var options = { 31 | url: this.host, 32 | method: 'POST', 33 | headers: headers, 34 | json: { 35 | "jsonrpc": "2.0", 36 | "id": id, 37 | "method": method, 38 | "params": params 39 | } 40 | }; 41 | 42 | if (callback) { 43 | libRequest(options, function (error, response, body) { 44 | if (this._generalErrorHandler(callback, error, response, body)) { 45 | return 46 | } 47 | callback(null, body.result); 48 | }); 49 | } else { 50 | return new Promise((resolve, reject) => { 51 | libRequest(options, function (error, response, body) { 52 | if (this._generalErrorHandler(reject, error, response, body)) { 53 | return 54 | } 55 | resolve(body.result); 56 | }); 57 | }); 58 | } 59 | 60 | } 61 | 62 | httpPost(path, json, callback) { 63 | var headers = { 64 | 'content-type': 'application/json', 65 | 'User-Agent': 'ova-request/1.0' 66 | }; 67 | var options = { 68 | url: this.host + path, 69 | method: 'POST', 70 | headers: headers, 71 | json: json 72 | }; 73 | 74 | if (callback) { 75 | libRequest(options, (error, response, body) => { 76 | if (this._generalErrorHandler(callback, error, response, body)) { 77 | return 78 | } 79 | callback(null, body); 80 | }); 81 | } else { 82 | return new Promise((resolve, reject) => { 83 | libRequest(options, (error, response, body) => { 84 | if (this._generalErrorHandler(reject, error, response, body)) { 85 | console.log(path, json) 86 | return 87 | } 88 | resolve(body); 89 | }); 90 | }); 91 | } 92 | } 93 | 94 | httpGet(path, callback) { 95 | var headers = { 96 | 'User-Agent': 'ova-request/1.0' 97 | }; 98 | var options = { 99 | url: this.host + path, 100 | headers: headers 101 | }; 102 | if (callback) { 103 | libRequest.get(options, (error, response, body) => { 104 | if (this._generalErrorHandler(callback, error, response, body)) { 105 | return 106 | } 107 | callback(null, body); 108 | }); 109 | } else { 110 | return new Promise((resolve, reject) => { 111 | libRequest.get(options, (error, response, body) => { 112 | if (this._generalErrorHandler(reject, error, response, body)) { 113 | console.log(path, error) 114 | return 115 | } 116 | resolve(body); 117 | }); 118 | }); 119 | } 120 | } 121 | 122 | monitor(title, message, key, error) { 123 | 124 | var form = { 125 | title: title, 126 | message: message, 127 | key: key, 128 | error: error 129 | }; 130 | 131 | 132 | var formData = querystring.stringify(form); 133 | var contentLength = formData.length; 134 | 135 | libRequest({ 136 | headers: { 137 | 'Content-Length': contentLength, 138 | 'Content-Type': 'application/x-www-form-urlencoded' 139 | }, 140 | uri: this.host + 'api/direct', 141 | body: formData, 142 | method: 'POST' 143 | }, function (err, res, body) { 144 | if (err || !res || res.statusCode != 200 || !body) { 145 | logger.error('Monitor direct Error'); 146 | logger.error(err); 147 | return; 148 | } 149 | try { 150 | var result = JSON.parse(body); 151 | if (result.result != "success") { 152 | logger.error('Monitor body Error'); 153 | logger.error(body); 154 | } 155 | } catch (e) { 156 | logger.error('Monitor body Error'); 157 | logger.error(body); 158 | return; 159 | } 160 | 161 | 162 | }); 163 | } 164 | } 165 | module.exports = Request; -------------------------------------------------------------------------------- /lib/rpcAggregator.js: -------------------------------------------------------------------------------- 1 | const Britto = require("./britto"); 2 | 3 | Britto.setAdd0x(); 4 | Britto.setRemove0x(); 5 | 6 | class RPCAggregator { 7 | chainId; 8 | chainName; 9 | pool = []; 10 | 11 | constructor(_chainName, _chainId) { 12 | this.chainName = _chainName; 13 | this.chainId = _chainId; 14 | } 15 | 16 | addRpc(url, { 17 | name = "mainnet", 18 | address, 19 | abi, 20 | multisig, 21 | onconnect, 22 | } = {}) { 23 | if(this.isExist(url)) return; 24 | 25 | const node = Britto.getNodeConfigBase(name); 26 | node.rpc = url; 27 | node.address = address; 28 | node.abi = abi; 29 | global.monitor.setNodeConnectStatus(`${this.chainName}_${this.pool.length}`, node.rpc, "connecting"); 30 | if (onconnect) { 31 | node.onconnect = onconnect; 32 | } 33 | new Britto(node, `${this.chainName}_${this.pool.length}`).connectWeb3(); 34 | if (multisig) { 35 | node.multisig.wallet = multisig.address; 36 | node.multisig.abi = multisig.abi; 37 | node.multisig.contract = new node.web3.eth.Contract(node.multisig.abi, node.multisig.wallet); 38 | } 39 | this.pool.push(node); 40 | } 41 | 42 | async addRpcWithBritto(node) { 43 | if(this.isExist(node.rpc)) return; 44 | this.pool.push(node); 45 | let block = await node.web3.eth.getBlock("latest").catch(e => {console.log(e)}); 46 | return !block ? false : true; 47 | } 48 | 49 | length() { 50 | return this.pool.length; 51 | } 52 | 53 | async select() { 54 | let bn = 0; 55 | let electedIndex; 56 | 57 | for(let i=0; i { 64 | logger.error(`[RPC_AGGREGATOR] getBlockNumber:${e}`); 65 | }); 66 | if(!curBlockNumber || parseInt(curBlockNumber) < bn) { 67 | continue; 68 | } 69 | 70 | bn = parseInt(curBlockNumber); 71 | electedIndex = i; 72 | } 73 | const elected = this.pool[electedIndex]; 74 | if (elected) { 75 | global.monitor.setNodeElectionStatus(elected.peggingType, elected.rpc, bn); 76 | } 77 | 78 | return elected; 79 | } 80 | 81 | async getNodes() { 82 | let arr = [...this.pool]; 83 | for (let i = arr.length - 1; i > 0; i--) { 84 | let j = Math.floor(Math.random() * (i + 1)); 85 | [arr[i], arr[j]] = [arr[j], arr[i]]; 86 | } 87 | return arr; 88 | } 89 | 90 | async majorityCheckForDatasInRpcs(func) { 91 | const nodes = await this.getNodes(); 92 | const requireCnt = parseInt(nodes.length/2) + 1; 93 | let resMap = {}; 94 | for (const node of nodes) { 95 | let res = await func(node); 96 | if (!res) { 97 | continue; 98 | } 99 | res = JSON.stringify(res); 100 | if (!resMap[res]) { 101 | resMap[res] = 1; 102 | } else { 103 | resMap[res] += 1; 104 | } 105 | if (resMap[res] >= requireCnt) { 106 | return JSON.parse(res); 107 | } 108 | } 109 | } 110 | 111 | isExist(rpc) { 112 | const nodes = this.pool; 113 | return nodes.find(node => { return node.rpc.toLowerCase() === rpc.toLowerCase() }); 114 | } 115 | } 116 | 117 | module.exports = RPCAggregator; 118 | -------------------------------------------------------------------------------- /lib/txsender.js: -------------------------------------------------------------------------------- 1 | let Tx = require('ethereumjs-tx'); 2 | let txutils = require('./txutils'); 3 | 4 | class Txsender { 5 | static sendTransaction(nodeConfig, txData, sender, callback) { 6 | let web3 = nodeConfig.web3; 7 | 8 | if (!Buffer.isBuffer(sender.pk)) 9 | sender.pk = Buffer.from(sender.pk, 'hex'); 10 | 11 | let _this = this; 12 | return new Promise((resolve, reject) => { 13 | if(!txData || !txData.method || !txData.args || !txData.options) 14 | return logger.error('Invalid transaction data.'); 15 | if(!sender || !sender.address || !sender.pk) 16 | return logger.error('Invalid transaction sender'); 17 | 18 | let rawTx = txutils.functionTx(nodeConfig.abi, txData.method, txData.args, txData.options); 19 | 20 | let timeout = (isNaN(parseInt(sender.timeout)))? 5000 : sender.timeout; 21 | 22 | setTimeout(async () => { 23 | let nonce = await _this.getWeb3Nonce(nodeConfig.web3, sender.address).catch(e => { 24 | logger.error('sendTransaction getNonce error'); 25 | logger.error(e); 26 | }); 27 | 28 | if(!nonce) 29 | return; 30 | 31 | let tx = new Tx(rawTx); 32 | tx['nonce'] = sender.nonce || nonce; 33 | // for EIP 155 compute 34 | tx._chainId = txData.options.chainId || 0; 35 | try { 36 | tx.sign(sender.pk); 37 | } catch (e) { 38 | logger.error(`Cannot Sign transaction by PK(${sender.pk}))`); 39 | return; 40 | } 41 | 42 | let serializedTx = tx.serialize(); 43 | 44 | logger.info('----------------[' + (nodeConfig.peggingType || '---') + ']----------------'); 45 | logger.info(`Send ${(txData.method || 'Unknown')}(${txData.block || ''}) Transaction`); 46 | if (txData.info) logger.info(`Info : ${txData.info}`) 47 | logger.info(`GasPrice : ${Number(txData.options.gasPrice)}`); 48 | 49 | web3.eth.sendSignedTransaction('0x' + serializedTx.toString('hex')) 50 | .once('transactionHash', thash => { 51 | if (callback) 52 | callback(thash); 53 | 54 | resolve(thash); 55 | logger.info('Transaction sent : ' + thash); 56 | logger.info('Transaction nonce: ' + (Number(sender.nonce || nonce))); 57 | logger.info('-------------------------------------'); 58 | }) 59 | .once('error', e => { 60 | logger.error(`Fail to send ${txData.method} transaction(${Number(sender.nonce || nonce)}): ${e.message}`); 61 | resolve(e.message); 62 | }); 63 | }, timeout) 64 | }); 65 | } 66 | 67 | 68 | static getWeb3Nonce(web3, address, option, callback) { 69 | return new Promise((resolve, reject) => { 70 | web3.eth.getTransactionCount(address, option || 'pending') 71 | .then(nonce => { 72 | nonce = web3.utils.toHex(nonce); 73 | 74 | callback && callback(nonce); 75 | 76 | resolve(nonce); 77 | }) 78 | .catch((e) => { 79 | console.error('getWeb3Nonce error'); 80 | console.log(e); 81 | reject(e); 82 | }); 83 | }) 84 | } 85 | } 86 | 87 | module.exports = Txsender; 88 | -------------------------------------------------------------------------------- /lib/txutils.js: -------------------------------------------------------------------------------- 1 | var Transaction = require('ethereumjs-tx'); 2 | //var coder = require('web3/lib/solidity/coder'); 3 | // When updating to web3 1.0.0, replace by 4 | var coder = require('web3-eth-abi'); 5 | var rlp = require('rlp'); 6 | var CryptoJS = require('crypto-js'); 7 | 8 | function add0x (input) { 9 | if (typeof(input) !== 'string') { 10 | return input; 11 | } 12 | if (input.length < 2 || input.slice(0,2) !== '0x') { 13 | return '0x' + input; 14 | } 15 | 16 | return input; 17 | } 18 | 19 | function strip0x (input) { 20 | if (typeof(input) !== 'string') { 21 | return input; 22 | } 23 | else if (input.length >= 2 && input.slice(0,2) === '0x') { 24 | return input.slice(2); 25 | } 26 | else { 27 | return input; 28 | } 29 | } 30 | 31 | function _encodeFunctionTxData (functionName, types, args) { 32 | 33 | var fullName = functionName + '(' + types.join() + ')'; 34 | // var signature = CryptoJS.SHA3(fullName, { outputLength: 256 }).toString(CryptoJS.enc.Hex).slice(0, 8); 35 | // var dataHex = '0x' + signature + coder.encodeParams(types, args); 36 | // When updating to web3 1.0.0, replace by 37 | var dataHex = coder.encodeFunctionSignature(fullName) + coder.encodeParameters(types, args).replace('0x','') 38 | 39 | return dataHex; 40 | } 41 | 42 | function _getTypesFromAbi (abi, functionName) { 43 | 44 | function matchesFunctionName(json) { 45 | return (json.name === functionName && json.type === 'function'); 46 | } 47 | 48 | function getTypes(json) { 49 | return json.type; 50 | } 51 | 52 | var funcJson = abi.filter(matchesFunctionName)[0]; 53 | 54 | return (funcJson.inputs).map(getTypes); 55 | } 56 | 57 | function functionTx (abi, functionName, args, txObject) { 58 | // txObject contains gasPrice, gasLimit, nonce, to, value 59 | 60 | var types = _getTypesFromAbi(abi, functionName); 61 | var txData = _encodeFunctionTxData(functionName, types, args); 62 | 63 | var txObjectCopy = {}; 64 | txObjectCopy.to = add0x(txObject.to); 65 | txObjectCopy.gasPrice = add0x(txObject.gasPrice); 66 | txObjectCopy.gasLimit = add0x(txObject.gasLimit); 67 | txObjectCopy.nonce = add0x(txObject.nonce); 68 | txObjectCopy.data = add0x(txData); 69 | txObjectCopy.value = add0x(txObject.value); 70 | 71 | return '0x' + (new Transaction(txObjectCopy)).serialize().toString('hex'); 72 | } 73 | 74 | function createdContractAddress (fromAddress, nonce) { 75 | var rlpEncodedHex = rlp.encode([new Buffer(strip0x(fromAddress), 'hex'), nonce]).toString('hex'); 76 | var rlpEncodedWordArray = CryptoJS.enc.Hex.parse(rlpEncodedHex); 77 | var hash = CryptoJS.SHA3(rlpEncodedWordArray, {outputLength: 256}).toString(CryptoJS.enc.Hex); 78 | 79 | return '0x' + hash.slice(24); 80 | } 81 | 82 | function createContractTx (fromAddress, txObject) { 83 | // txObject contains gasPrice, gasLimit, value, data, nonce 84 | 85 | var txObjectCopy = {}; 86 | txObjectCopy.to = add0x(txObject.to); 87 | txObjectCopy.gasPrice = add0x(txObject.gasPrice); 88 | txObjectCopy.gasLimit = add0x(txObject.gasLimit); 89 | txObjectCopy.nonce = add0x(txObject.nonce); 90 | txObjectCopy.data = add0x(txObject.data); 91 | txObjectCopy.value = add0x(txObject.value); 92 | 93 | var contractAddress = createdContractAddress(fromAddress, txObject.nonce); 94 | var tx = new Transaction(txObjectCopy); 95 | 96 | return {tx: '0x' + tx.serialize().toString('hex'), addr: contractAddress}; 97 | } 98 | 99 | function valueTx (txObject) { 100 | // txObject contains gasPrice, gasLimit, value, nonce 101 | 102 | var txObjectCopy = {}; 103 | txObjectCopy.to = add0x(txObject.to); 104 | txObjectCopy.gasPrice = add0x(txObject.gasPrice); 105 | txObjectCopy.gasLimit = add0x(txObject.gasLimit); 106 | txObjectCopy.nonce = add0x(txObject.nonce); 107 | txObjectCopy.value = add0x(txObject.value); 108 | 109 | var tx = new Transaction(txObjectCopy); 110 | 111 | return '0x' + tx.serialize().toString('hex'); 112 | } 113 | 114 | module.exports = { 115 | _encodeFunctionTxData: _encodeFunctionTxData, 116 | _getTypesFromAbi: _getTypesFromAbi, 117 | functionTx: functionTx, 118 | createdContractAddress: createdContractAddress, 119 | createContractTx: createContractTx, 120 | valueTx: valueTx 121 | }; 122 | -------------------------------------------------------------------------------- /lib/utils.js: -------------------------------------------------------------------------------- 1 | function getEndpoint (chain) { 2 | return require(ROOT + `/config/endpoints`).endpoints[chain.toLowerCase()] 3 | } 4 | 5 | function contractAddress (layer2Chain) { 6 | let { bridge_address } = require(ROOT + `/config/${process.env.CHAIN.toLowerCase()}`) 7 | return bridge_address[layer2Chain] 8 | } 9 | 10 | function multisigAddress(migChain) { 11 | let { bridge_address } = require(ROOT + `/config/${process.env.CHAIN.toLowerCase()}`) 12 | return bridge_address[migChain].multisig 13 | } 14 | 15 | function ed25519MultisigAddress() { 16 | let { bridge_address } = require(ROOT + `/config/${process.env.CHAIN.toLowerCase()}`) 17 | return bridge_address.multisig.ton; 18 | } 19 | 20 | function isEvmAddress(address) { 21 | return address.slice(0,2) === "0x" && address.length === 42; 22 | } 23 | 24 | module.exports = { 25 | getEndpoint, 26 | contractAddress, 27 | multisigAddress, 28 | ed25519MultisigAddress, 29 | isEvmAddress 30 | } -------------------------------------------------------------------------------- /logger.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | require(ROOT + '/lib/decimal'); 4 | const winston = require('winston'); 5 | const moment = require('moment'); 6 | const config = require(ROOT + '/config'); 7 | 8 | const tsFormat = function () { 9 | return moment().format('YYYY-MM-DD HH:mm:ss'); 10 | } 11 | 12 | ////////////////////////////////////////////////////////////////////////////////////////// 13 | const myFormat = winston.format.printf(info => { 14 | return tsFormat() + ' ' + info.message; 15 | }); 16 | 17 | // Normal Logger: Winston 18 | let logger = winston.createLogger({ 19 | level: config.system.logLevel || 'info', 20 | format: winston.format.combine( 21 | myFormat 22 | ), 23 | transports: [ 24 | new(winston.transports.Console)({ 25 | colorize: true, 26 | handleExceptions: true, 27 | }) 28 | ] 29 | }); 30 | 31 | //Promise unhandled rejection logger. 32 | //process.off('unhandledRejection', () => {}); 33 | process.on('unhandledRejection', (reason, p) => { 34 | console.error('Unhandled rejection Promise: ', p, ' reason: ', reason) 35 | }); 36 | 37 | module.exports = logger; 38 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "orbit-bridge-validators", 3 | "version": "2.0.1", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "@stacks/transactions": "^3.3.0", 14 | "abi-decoder": "^2.3.0", 15 | "bignumber.js": "^9.1.2", 16 | "bn.js": "^5.1.3", 17 | "bs58": "^4.0.1", 18 | "crypto-js": "^3.1.9-1", 19 | "dotenv": "^16.0.3", 20 | "elliptic": "^6.4.1", 21 | "ethereumjs-abi": "^0.6.8", 22 | "ethereumjs-tx": "^1.3.7", 23 | "ethereumjs-util": "^5.2.0", 24 | "ethereumjs-wallet": "^0.6.3", 25 | "ethers": "^5.0.7", 26 | "express": "^4.17.1", 27 | "icon-sdk-js": "^1.1.3", 28 | "lodash": "^4.17.20", 29 | "moment": "^2.28.0", 30 | "readline-sync": "^1.4.10", 31 | "request-promise": "^4.2.6", 32 | "ripple-address-codec": "4.2.3", 33 | "ripple-lib": "1.10.0", 34 | "secp256k1": "^4.0.2", 35 | "ton": "^12.0.0", 36 | "tonweb": "^0.0.52", 37 | "varuint-bitcoin": "^1.1.0", 38 | "web3": "^1.0.0-beta.37", 39 | "winston": "^3.1.0", 40 | "winston-daily-rotate-file": "^2.0.0-rc.1" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /pm2.yaml: -------------------------------------------------------------------------------- 1 | apps: 2 | - script : app.js 3 | name : 'validator' 4 | cwd : . 5 | instances : 1 6 | watch : false 7 | exec_mode : fork 8 | env : 9 | NODE_ENV : production 10 | PORT : 8984 -------------------------------------------------------------------------------- /routes/index.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const router = express.Router(); 3 | 4 | router.get('/', function (req, res, next) { 5 | if(!global.monitor) { 6 | res.json("monitoring not enabled."); 7 | return; 8 | } 9 | 10 | res.json(global.monitor.json()); 11 | }); 12 | 13 | module.exports = router; -------------------------------------------------------------------------------- /routes/v1/gov.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const router = express.Router(); 3 | let govInstance; 4 | 5 | // http://host/v1/gov/ 6 | router.get("/", function (req, res, next) { 7 | res.send("gov"); 8 | }); 9 | 10 | router.get("/getAddress/:chain", async function (req, res, next) { 11 | const chain = req.body && req.body.chain || req.params && req.params.chain; 12 | return res.json(await govInstance.getAddress(chain)); 13 | }) 14 | 15 | router.get("/getTransaction/:chain/:transactionId", async function (req, res, next) { 16 | const chain = req.body && req.body.chain || req.params && req.params.chain; 17 | const tid = req.body && req.body.transactionId || req.params && req.params.transactionId; 18 | return res.json(await govInstance.getTransaction(chain, tid)); 19 | }) 20 | 21 | router.get("/confirm/:chain/:transactionId/:gasPrice/:chainId", async function (req, res, next) { 22 | const chain = req.body && req.body.chain || req.params && req.params.chain; 23 | const tid = req.body && req.body.transactionId || req.params && req.params.transactionId; 24 | const gasPrice = req.body && req.body.gasPrice || req.params && req.params.gasPrice; 25 | const chainId = req.body && req.body.chainId || req.params && req.params.chainId; 26 | return res.json(await govInstance.confirmTransaction(chain, tid, gasPrice, chainId)); 27 | }) 28 | 29 | router.get("/confirmRange/:chain/:start/:end/:gasPrice/:chainId", async function (req, res, next) { 30 | const chain = req.body && req.body.chain || req.params && req.params.chain; 31 | const start = req.body && req.body.start || req.params && req.params.start; 32 | const end = req.body && req.body.end || req.params && req.params.end; 33 | const gasPrice = req.body && req.body.gasPrice || req.params && req.params.gasPrice; 34 | const chainId = req.body && req.body.chainId || req.params && req.params.chainId; 35 | return res.send(await govInstance.confirmTransactionByRange(chain, start, end, gasPrice, chainId)); 36 | }) 37 | 38 | router.get("/validate/:sigHash", async function (req, res, next) { 39 | const sigHash = req.body && req.body.sigHash || req.params && req.params.sigHash; 40 | return res.json(await govInstance.validateSigHash(sigHash)); 41 | }); 42 | 43 | // deprecated 44 | /* 45 | router.get("/validateEd25519/:sigHash", async function (req, res, next) { 46 | const sigHash = req.body && req.body.sigHash || req.params && req.params.sigHash; 47 | return res.json(await govInstance.validateEd25519SigHash(sigHash)); 48 | }); 49 | */ 50 | 51 | function setGovInstance(instance) { 52 | govInstance = instance; 53 | return router; 54 | } 55 | 56 | module.exports = { 57 | setGovInstance, 58 | } 59 | -------------------------------------------------------------------------------- /src/evm/logger.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const winston = require('winston'); 4 | const moment = require('moment'); 5 | const config = require(ROOT + '/config'); 6 | 7 | const tsFormat = function () { 8 | return moment().format('YYYY-MM-DD HH:mm:ss'); 9 | } 10 | 11 | ////////////////////////////////////////////////////////////////////////////////////////// 12 | const myFormat = winston.format.printf(info => { 13 | return `[${info.chain || "EVM"}] ` + tsFormat() + ' ' + info.message; 14 | }); 15 | 16 | // Normal Logger: Winston 17 | let logger = winston.createLogger({ 18 | level: config.system.logLevel || 'info', 19 | format: winston.format.combine( 20 | myFormat 21 | ), 22 | transports: [ 23 | new(winston.transports.Console)({ 24 | colorize: true, 25 | handleExceptions: true, 26 | }) 27 | ] 28 | }); 29 | 30 | module.exports = logger; 31 | -------------------------------------------------------------------------------- /src/evm/utils/packer.js: -------------------------------------------------------------------------------- 1 | exports.packRelayedData = function(data) { 2 | let result = []; 3 | 4 | result.push({t: 'string', v: data.fromChain}); 5 | result.push({t: 'bytes32[]', v: data.bytes32s}); 6 | result.push({t: 'uint[]', v: data.uints}); 7 | 8 | return result; 9 | } 10 | 11 | exports.packChainId = function (data) { 12 | let result = []; 13 | 14 | result.push({t: 'address', v: data.hubContract}); 15 | result.push({t: 'string', v:data.chain}); 16 | 17 | return result; 18 | } 19 | 20 | exports.packSwapData = function(data) { 21 | let result = []; 22 | 23 | result.push({t: 'address', v: data.hubContract}); 24 | result.push({t: 'string', v: data.fromChain}); 25 | result.push({t: 'string', v: data.toChain}); 26 | result.push({t: 'bytes', v: toHexBuffer(data.fromAddr)}); 27 | result.push({t: 'bytes', v: toHexBuffer(data.toAddr)}); 28 | result.push({t: 'bytes', v: toHexBuffer(data.token)}); 29 | result.push({t: 'bytes32[]', v: data.bytes32s}); 30 | result.push({t: 'uint[]', v: data.uints}); 31 | result.push({t: 'bytes', v: toHexBuffer(data.data)}); 32 | 33 | return result; 34 | }; 35 | 36 | exports.packLimitationData = function(data) { 37 | let result = []; 38 | 39 | result.push({t: 'string', v: "GateKeeper"}); 40 | result.push({t: 'string', v: data.fromChain}); 41 | result.push({t: 'string', v: data.toChain}); 42 | result.push({t: 'bytes', v: toHexBuffer(data.token)}); 43 | result.push({t: 'bytes32[]', v: data.bytes32s}); 44 | result.push({t: 'uint[]', v: data.uints}); 45 | 46 | return result; 47 | } 48 | 49 | function toHexBuffer(str) { 50 | return Buffer.from(str.replace('0x', ""), 'hex'); 51 | } 52 | -------------------------------------------------------------------------------- /src/gov/index.js: -------------------------------------------------------------------------------- 1 | global.logger.gov = require('./logger'); 2 | 3 | const config = require(ROOT + '/config'); 4 | const Britto = require(ROOT + '/lib/britto'); 5 | const abiDecoder = require('abi-decoder'); 6 | 7 | const errmBeforeInitialize = { 8 | "errm": "Before Initialized", 9 | "data": "Error: Before Initialized" 10 | }; 11 | 12 | const errmInvalidChain = (chain) => { 13 | return { 14 | "errm": "Invalid Chain", 15 | "data": `NotFoundError: Invalid Chain Name ${chain}` 16 | } 17 | }; 18 | 19 | const invalidChainList = ["gov", "xrp", "stacks", "stacks_layer_1"]; 20 | 21 | class Governance { 22 | constructor(){ 23 | if(this.initialized) 24 | throw "Already Initialized"; 25 | 26 | const ABI = Britto.getJSONInterface({filename: "Governance"}); 27 | abiDecoder.addABI(ABI); 28 | 29 | this.initialized = true; 30 | } 31 | 32 | getAddress(chain) { 33 | if(!this.initialized) return errmBeforeInitialize; 34 | 35 | return monitor.address[chain.toUpperCase()]; 36 | } 37 | 38 | async getTransaction(chain, transactionId) { 39 | if(!this.initialized) return errmBeforeInitialize; 40 | 41 | logger.gov.info(`GetTransaction: ${chain}, ${transactionId}`); 42 | 43 | chain = chain.toLowerCase(); 44 | if(invalidChainList.includes(chain) || !instances[chain]) return errmInvalidChain(chain); 45 | 46 | const instance = instances[chain]; 47 | const res = await instance.getTransaction(transactionId, abiDecoder); 48 | return res; 49 | } 50 | 51 | async confirmTransaction(chain, transactionId, gasPrice, chainId) { 52 | if(!this.initialized) return errmBeforeInitialize; 53 | 54 | chain = chain.toLowerCase(); 55 | if(invalidChainList.includes(chain) || !instances[chain]) return errmInvalidChain(chain); 56 | 57 | logger.gov.info(`ConfirmTransaction: ${chain}, ${transactionId}, ${gasPrice}, ${chainId}`); 58 | 59 | const instance = instances[chain]; 60 | const res = await instance.confirmTransaction(transactionId, gasPrice, chainId); 61 | return res; 62 | } 63 | 64 | async confirmTransactionByRange(chain, start, end, gasPrice, chainId) { 65 | if(!this.initialized) return errmBeforeInitialize; 66 | 67 | logger.gov.info(`ConfirmTransactionRange: ${chain}, ${start}, ${end}, ${gasPrice}, ${chainId}`); 68 | 69 | chain = chain.toLowerCase(); 70 | if(invalidChainList.includes(chain) || !instances[chain]) return errmInvalidChain(chain); 71 | 72 | const instance = instances[chain]; 73 | 74 | let res = []; 75 | for(let i = parseInt(start); i <= parseInt(end); i++){ 76 | let txHash = await instance.confirmTransaction(i, gasPrice, chainId); 77 | res.push({ 78 | transactionId: i, 79 | res: txHash 80 | }) 81 | } 82 | 83 | return JSON.stringify(res, null, ' '); 84 | } 85 | 86 | async validateSigHash(sigHash) { 87 | if(!this.initialized) return errmBeforeInitialize; 88 | 89 | logger.gov.info(`ValidateSigHash: ${sigHash}`) 90 | 91 | if(sigHash.length !== 66) return "Invalid Input Hash"; 92 | let signature = Britto.signMessage(sigHash, process.env.VALIDATOR_PK); 93 | 94 | return { 95 | validator: monitor.validatorAddress, 96 | sigHash, 97 | v: signature.v, 98 | r: signature.r, 99 | s: signature.s, 100 | }; 101 | } 102 | 103 | // deprecated 104 | /* 105 | async validateEd25519SigHash(sigHash) { 106 | if(!this.initialized) return errmBeforeInitialize; 107 | if(!instances["orbit"]) return errmInvalidChain; 108 | 109 | logger.gov.info(`validateEd25519SigHash: ${sigHash}`) 110 | 111 | const instance = instances["orbit"]; 112 | const res = await instance.validateEd25519SigHash(multisig, sigHash); 113 | return res; 114 | } 115 | */ 116 | } 117 | 118 | module.exports = Governance; 119 | -------------------------------------------------------------------------------- /src/gov/logger.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const winston = require('winston'); 4 | const moment = require('moment'); 5 | const config = require(ROOT + '/config'); 6 | 7 | const tsFormat = function () { 8 | return moment().format('YYYY-MM-DD HH:mm:ss'); 9 | } 10 | 11 | ////////////////////////////////////////////////////////////////////////////////////////// 12 | const myFormat = winston.format.printf(info => { 13 | return '[GOV] ' + tsFormat() + ' ' + info.message; 14 | }); 15 | 16 | // Normal Logger: Winston 17 | let logger = winston.createLogger({ 18 | level: config.system.logLevel || 'info', 19 | format: winston.format.combine( 20 | myFormat 21 | ), 22 | transports: [ 23 | new(winston.transports.Console)({ 24 | colorize: true, 25 | handleExceptions: true, 26 | }) 27 | ] 28 | }); 29 | 30 | module.exports = logger; -------------------------------------------------------------------------------- /src/hub/index.js: -------------------------------------------------------------------------------- 1 | global.logger.hub = require('./logger'); 2 | 3 | const config = require(ROOT + '/config'); 4 | const Britto = require(ROOT + '/lib/britto'); 5 | 6 | const packer = require("./utils/packer"); 7 | 8 | class OrbitHub { 9 | constructor(chainList) { 10 | if(!chainList || chainList.length === 0){ 11 | throw Error("Invalid chainList"); 12 | } 13 | this.chainList = chainList; 14 | 15 | const chainName = this.chainName = "HUB"; 16 | this.lastBlockNum = null; 17 | 18 | const govInfo = this.govInfo = config.governance; 19 | if(!govInfo || !govInfo.chain || !govInfo.address || !govInfo.bytes || !govInfo.id) { 20 | throw Error('Empty Governance Info'); 21 | } 22 | 23 | const info = config.info.orbit; 24 | 25 | const orbitHub = this.orbitHub = Britto.getNodeConfigBase('orbitHub'); 26 | orbitHub.ws = info.ENDPOINT.socket; 27 | orbitHub.rpc = info.ENDPOINT.rpc; 28 | orbitHub.address = info.CONTRACT_ADDRESS.OrbitHubContract; 29 | orbitHub.abi = Britto.getJSONInterface({filename: 'OrbitHub'}); 30 | orbitHub.gateKeeperABI = Britto.getJSONInterface({filename: 'GateKeeper'}); 31 | 32 | this.eventList = [ 33 | { 34 | name: 'SwapRelay', 35 | callback: this.receiveSwapRelay.bind(this), 36 | }, 37 | { 38 | name: 'SwapNFTRelay', 39 | callback: this.receiveSwapNFTRelay.bind(this), 40 | } 41 | ]; 42 | 43 | orbitHub.onconnect = () => { 44 | this.setChainIds(chainList); 45 | this.startSubscription(orbitHub, this.eventList); 46 | }; 47 | 48 | orbitHub.ondisconnect = () => { 49 | logger.hub.info(`On disconnected: clear ${orbitHub.ws} subscription !`); 50 | orbitHub.web3.eth.clearSubscriptions(); 51 | }; 52 | 53 | global.monitor.setNodeConnectStatus(chainName, orbitHub.ws, "connecting"); 54 | new Britto(orbitHub, chainName).connectWeb3(); 55 | 56 | this.hashMap = new Map(); 57 | this.flushHashMap(); 58 | 59 | this.chainIds = {}; 60 | this.subscribers = []; 61 | } 62 | 63 | registerSubscriber(node, eventList) { 64 | this.subscribers.push({node, eventList}); 65 | } 66 | 67 | startSubscription(node, eventList) { 68 | this.subscribeNewBlock(node.web3, blockNumber => { 69 | global.monitor.setBlockNumber(this.chainName, blockNumber); 70 | this.getPastLogs(blockNumber, node, eventList); 71 | }); 72 | } 73 | 74 | subscribeNewBlock(web3, callback) { 75 | web3.eth.subscribe('newBlockHeaders', (err, res) => { 76 | if (err) 77 | return logger.hub.error('subscribeNewBlock subscribe error: ' + err.message); 78 | 79 | if (!res.number) { 80 | return; 81 | } 82 | 83 | if (!this.lastBlockNum) { 84 | this.lastBlockNum = res.number - 1; 85 | } 86 | 87 | global.monitor.setBlockTime(); 88 | 89 | let start = this.lastBlockNum + 1; 90 | let end = res.number; 91 | this.lastBlockNum = end; 92 | 93 | for (let i = start; i <= end; i++) { 94 | if (callback) callback(i); 95 | 96 | } 97 | }) 98 | } 99 | 100 | getPastLogs(blockNumber, nodeConfig, eventList) { 101 | let options = { 102 | fromBlock: blockNumber, 103 | toBlock: blockNumber 104 | }; 105 | 106 | return new Promise((resolve, reject) => { 107 | try { 108 | if(!nodeConfig || !nodeConfig.contract || !eventList) reject(); 109 | 110 | nodeConfig.web3.eth.getPastLogs(options, (err, logs) => { 111 | if (err) return reject(err); 112 | if (logs.length === 0) resolve(); 113 | 114 | for(let subscriber of this.subscribers){ 115 | if(!subscriber.node || !subscriber.node.contract || !subscriber.eventList) continue; 116 | 117 | this.parseLogs(subscriber.node.contract, [...logs], subscriber.eventList); 118 | } 119 | 120 | resolve(this.parseLogs(nodeConfig.contract, [...logs], eventList)); 121 | }).catch(e => { 122 | reject(e) 123 | }); 124 | } catch (e) { 125 | reject(e) 126 | } 127 | }); 128 | } 129 | 130 | parseLogs(contract, logs, eventList) { 131 | let receipts = []; 132 | for(let log of logs){ 133 | if(log.address.toLowerCase() !== contract._address.toLowerCase()) continue; 134 | 135 | let receipt = contract._decodeEventABI.bind({ 136 | name: "ALLEVENTS", 137 | jsonInterface: contract._jsonInterface 138 | })(log); 139 | receipts.push(receipt); 140 | } 141 | 142 | for(let receipt of receipts){ 143 | let target = eventList.find(e => e.name === receipt.event); 144 | if(!target) continue; 145 | 146 | target.callback(receipt); 147 | } 148 | 149 | return receipts; 150 | } 151 | 152 | receiveSwapRelay(event) { 153 | if(event.returnValues.bytes32s[0].toLowerCase() !== this.govInfo.id.toLowerCase()) return; 154 | if(event.address.toLowerCase() !== this.orbitHub.address.toLowerCase()) return; 155 | 156 | let returnValues = { 157 | block: event.blockNumber, 158 | fromChain: event.returnValues.fromChain, 159 | bytes32s: event.returnValues.bytes32s, 160 | uints: event.returnValues.uints 161 | }; 162 | 163 | const hash = Britto.sha256sol(packer.packRelayedData({ 164 | fromChain: returnValues.fromChain, 165 | bytes32s: returnValues.bytes32s, 166 | uints: event.returnValues.uints.slice(2) 167 | })).toString('hex').add0x(); 168 | 169 | let obj = this.hashMap.get(hash); 170 | if(!obj){ 171 | this.hashMap.set(hash, { timestamp: parseInt(Date.now() / 1000), count: 1 }); 172 | } 173 | else{ 174 | obj.count = obj.count + 1; 175 | 176 | if(obj.count > 2){ // applyLimitation + validateSwap 177 | logger.hub.info(`Already relayed. ${hash} : ${obj.count}`); 178 | return; 179 | } 180 | } 181 | 182 | const fromInstance = instances[returnValues.fromChain.toLowerCase()]; 183 | if(!fromInstance) { 184 | logger.hub.error(`${returnValues.fromChain} instance is not exist`); 185 | return; 186 | } 187 | fromInstance.validateRelayedData(returnValues); 188 | } 189 | 190 | receiveSwapNFTRelay(event) { 191 | if(event.returnValues.bytes32s[0].toLowerCase() !== this.govInfo.id.toLowerCase()) return; 192 | if(event.address.toLowerCase() !== this.orbitHub.address.toLowerCase()) return; 193 | 194 | let returnValues = { 195 | block: event.blockNumber, 196 | fromChain: event.returnValues.fromChain, 197 | bytes32s: event.returnValues.bytes32s, 198 | uints: event.returnValues.uints 199 | }; 200 | 201 | const hash = Britto.sha256sol(packer.packRelayedData({ 202 | fromChain: returnValues.fromChain, 203 | bytes32s: returnValues.bytes32s, 204 | uints: event.returnValues.uints.slice(2) 205 | })).toString('hex').add0x(); 206 | 207 | if(this.hashMap.has(hash)){ 208 | logger.hub.info(`Already relayed. ${hash}`); 209 | return; 210 | } 211 | this.hashMap.set(hash, { timestamp: parseInt(Date.now() / 1000) }); 212 | 213 | const fromInstance = instances[returnValues.fromChain.toLowerCase()]; 214 | if(!fromInstance) { 215 | logger.hub.error(`${returnValues.fromChain} instance is not exist`); 216 | return; 217 | } 218 | fromInstance.validateRelayedNFTData(returnValues); 219 | } 220 | 221 | flushHashMap() { 222 | setTimeout(this.flushHashMap.bind(this), 1000 * 20); 223 | 224 | const now = parseInt(Date.now() / 1000); 225 | for (let [hash, obj] of this.hashMap.entries()) { 226 | if (obj.timestamp + 30 < now) { 227 | this.hashMap.delete(hash); 228 | } 229 | } 230 | } 231 | 232 | getOrbitHub() { 233 | return this.orbitHub; 234 | } 235 | 236 | getChainIds() { 237 | return this.chainIds; 238 | } 239 | 240 | setChainIds() { 241 | const orbitHub = this.orbitHub; 242 | const chainList = this.chainList; 243 | 244 | for(let chain of chainList){ 245 | chain = chain.replace(/-v[1-9]$/, '').toUpperCase(); 246 | const chainId = Britto.sha256sol(packer.packChainId({ 247 | hubContract: orbitHub.address, 248 | chain: chain 249 | })).toString('hex').add0x(); 250 | 251 | this.chainIds[chain] = chainId; 252 | } 253 | } 254 | } 255 | 256 | module.exports = OrbitHub; 257 | -------------------------------------------------------------------------------- /src/hub/logger.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const winston = require('winston'); 4 | const moment = require('moment'); 5 | const config = require(ROOT + '/config'); 6 | 7 | const tsFormat = function () { 8 | return moment().format('YYYY-MM-DD HH:mm:ss'); 9 | } 10 | 11 | ////////////////////////////////////////////////////////////////////////////////////////// 12 | const myFormat = winston.format.printf(info => { 13 | return '[HUB] ' + tsFormat() + ' ' + info.message; 14 | }); 15 | 16 | // Normal Logger: Winston 17 | let logger = winston.createLogger({ 18 | level: config.system.logLevel || 'info', 19 | format: winston.format.combine( 20 | myFormat 21 | ), 22 | transports: [ 23 | new(winston.transports.Console)({ 24 | colorize: true, 25 | handleExceptions: true, 26 | }) 27 | ] 28 | }); 29 | 30 | module.exports = logger; 31 | -------------------------------------------------------------------------------- /src/hub/utils/packer.js: -------------------------------------------------------------------------------- 1 | exports.packRelayedData = function(data) { 2 | let result = []; 3 | 4 | result.push({t: 'string', v: data.fromChain}); 5 | result.push({t: 'bytes32[]', v: data.bytes32s}); 6 | result.push({t: 'uint[]', v: data.uints}); 7 | 8 | return result; 9 | } 10 | 11 | exports.packChainId = function (data) { 12 | let result = []; 13 | 14 | result.push({t: 'address', v: data.hubContract}); 15 | result.push({t: 'string', v:data.chain}); 16 | 17 | return result; 18 | } 19 | -------------------------------------------------------------------------------- /src/icon/logger.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const winston = require('winston'); 4 | const moment = require('moment'); 5 | const config = require(ROOT + '/config'); 6 | 7 | const tsFormat = function () { 8 | return moment().format('YYYY-MM-DD HH:mm:ss'); 9 | } 10 | 11 | ////////////////////////////////////////////////////////////////////////////////////////// 12 | const myFormat = winston.format.printf(info => { 13 | return '[ICON] ' + tsFormat() + ' ' + info.message; 14 | }); 15 | 16 | // Normal Logger: Winston 17 | let logger = winston.createLogger({ 18 | level: config.system.logLevel || 'info', 19 | format: winston.format.combine( 20 | myFormat 21 | ), 22 | transports: [ 23 | new(winston.transports.Console)({ 24 | colorize: true, 25 | handleExceptions: true, 26 | }) 27 | ] 28 | }); 29 | 30 | module.exports = logger; 31 | -------------------------------------------------------------------------------- /src/icon/utils/icon.api.js: -------------------------------------------------------------------------------- 1 | const request = require('request-promise'); 2 | const IconService = require('icon-sdk-js').default; 3 | const { IconAmount, IconConverter, IconBuilder, IconWallet, SignedTransaction } = IconService; 4 | const config = require(ROOT + '/config'); 5 | 6 | const info = config.info.icon; 7 | const httpProvider = new IconService.HttpProvider(info.ENDPOINT.api); 8 | const icon = new IconService(httpProvider); 9 | const chainName = 'ICON'; 10 | 11 | let contractAddress; 12 | let migAddress; 13 | if(config.governance.chain === "ICON"){ 14 | contractAddress = config.governance.address; 15 | migAddress = config.governance.address; 16 | } 17 | else{ 18 | contractAddress = info.CONTRACT_ADDRESS.minter; 19 | migAddress = info.CONTRACT_ADDRESS.multisig; 20 | } 21 | 22 | const contract = (new IconService.IconBuilder.CallBuilder()).to(contractAddress); 23 | const mig = (new IconService.IconBuilder.CallBuilder()).to(migAddress); 24 | 25 | module.exports.api = icon; 26 | module.exports.contract = contract; 27 | module.exports.contract.address = contractAddress; 28 | module.exports.mig = mig; 29 | module.exports.mig.address = migAddress; 30 | module.exports.converter = IconConverter; 31 | 32 | module.exports.toHex = (_data) => { 33 | return "0x" + IconConverter.toBigNumber(_data).toString(16); 34 | } 35 | 36 | module.exports.getWalletByPK = async (_pk) => { 37 | return IconWallet.loadPrivateKey(_pk); 38 | } 39 | 40 | module.exports.getAddressByPK = async (_pk) => { 41 | return IconWallet.loadPrivateKey(_pk).getAddress(); 42 | } 43 | 44 | module.exports.getLastBlock = async () => { 45 | let block = await icon.getLastBlock().execute().catch(e => { 46 | logger.icon.error("getLastBlock error: " + e.message); 47 | global.monitor.setNodeConnectStatus(chainName, info.ENDPOINT.api, 'disconnected'); 48 | }); 49 | 50 | if(!block) 51 | return; 52 | 53 | global.monitor.setNodeConnectStatus(chainName, info.ENDPOINT.api, 'connected'); 54 | 55 | return block; 56 | } 57 | 58 | module.exports.getBalance = async (addr) => { 59 | let balance = await icon.getBalance(addr).execute().catch(e => { 60 | logger.icon.error("getBalance error: " + e.message); 61 | global.monitor.setNodeConnectStatus(chainName, info.ENDPOINT.api, 'disconnected'); 62 | }) 63 | 64 | if(!balance) 65 | return; 66 | 67 | global.monitor.setNodeConnectStatus(chainName, info.ENDPOINT.api, 'connected'); 68 | 69 | return balance.toNumber(); 70 | } 71 | 72 | module.exports.getTokenBalance = async (contractAddr, method, params) => { 73 | let token = (new IconService.IconBuilder.CallBuilder()).to(contractAddr); 74 | let transaction; 75 | try { 76 | transaction = await token.method(method).params(params).build(); 77 | } 78 | catch (e) { 79 | logger.icon.error("callTransaction build error: " + e.message); 80 | global.monitor.setNodeConnectStatus(chainName, info.ENDPOINT.api, 'disconnected'); 81 | } 82 | 83 | if(!transaction) 84 | return; 85 | 86 | let res = await icon.call(transaction).execute().catch(e => { 87 | logger.icon.error("call error: " + e.message); 88 | global.monitor.setNodeConnectStatus(chainName, info.ENDPOINT.api, 'disconnected'); 89 | }); 90 | 91 | if(!res) 92 | return; 93 | 94 | global.monitor.setNodeConnectStatus(chainName, info.ENDPOINT.api, 'connected'); 95 | 96 | return parseInt(res); 97 | } 98 | 99 | module.exports.getTransactionResult = async (txHash) => { 100 | let receipt = await icon.getTransactionResult(txHash).execute().catch(e => { 101 | logger.icon.error("getTransactionResult error: " + e.message); 102 | global.monitor.setNodeConnectStatus(chainName, info.ENDPOINT.api, 'disconnected'); 103 | }); 104 | 105 | if(!receipt) 106 | return; 107 | 108 | global.monitor.setNodeConnectStatus(chainName, info.ENDPOINT.api, 'connected'); 109 | 110 | return receipt 111 | } 112 | 113 | module.exports.getStepPrice = async () => { 114 | const governance = (new IconService.IconBuilder.CallBuilder()).to("cx0000000000000000000000000000000000000001"); 115 | 116 | let transaction; 117 | try { 118 | transaction = await governance.method("getStepPrice").params({}).build(); 119 | } 120 | catch (e) { 121 | logger.icon.error("callTransaction build error: " + e.message); 122 | global.monitor.setNodeConnectStatus(chainName, info.ENDPOINT.api, 'disconnected'); 123 | } 124 | 125 | if(!transaction) 126 | return; 127 | 128 | let res = await icon.call(transaction).execute().catch(e => { 129 | logger.icon.error("call error: " + e.message); 130 | global.monitor.setNodeConnectStatus(chainName, info.ENDPOINT.api, 'disconnected'); 131 | }); 132 | 133 | if(!res) 134 | return; 135 | 136 | global.monitor.setNodeConnectStatus(chainName, info.ENDPOINT.api, 'connected'); 137 | 138 | return res; 139 | } 140 | 141 | module.exports.getCallBuilder = async (address) => { 142 | return (new IconService.IconBuilder.CallBuilder()).to(address); 143 | } 144 | 145 | module.exports.call = async (contract, method, params) => { 146 | let transaction; 147 | try { 148 | transaction = await contract.method(method).params(params).build(); 149 | } 150 | catch (e) { 151 | logger.icon.error("callTransaction build error: " + e.message); 152 | global.monitor.setNodeConnectStatus(chainName, info.ENDPOINT.api, 'disconnected'); 153 | } 154 | 155 | if(!transaction) 156 | return; 157 | 158 | let res = await icon.call(transaction).execute().catch(e => { 159 | logger.icon.error("call error: " + e.message); 160 | global.monitor.setNodeConnectStatus(chainName, info.ENDPOINT.api, 'disconnected'); 161 | }); 162 | 163 | if(!res) 164 | return; 165 | 166 | global.monitor.setNodeConnectStatus(chainName, info.ENDPOINT.api, 'connected'); 167 | 168 | return res; 169 | } 170 | 171 | module.exports.makeTransferTransaction = async (_from, _to, _value) => { 172 | const { IcxTransactionBuilder } = IconBuilder; 173 | 174 | const from = _from; 175 | const to = _to; 176 | const value = IconAmount.of(_value, IconAmount.Unit.ICX).toLoop(); 177 | 178 | const version = IconConverter.toBigNumber(info.ENDPOINT.version); 179 | const nid = IconConverter.toBigNumber(info.ENDPOINT.nid); 180 | const timestamp = (new Date()).getTime() * 1000; 181 | 182 | const builder = new IcxTransactionBuilder(); 183 | const transaction = builder 184 | .from(from) 185 | .to(to) 186 | .value(value) 187 | .nid(nid) 188 | .version(version) 189 | .timestamp(timestamp) 190 | .build() 191 | 192 | return transaction; 193 | } 194 | 195 | module.exports.makeContractTransaction = async (_from, _to, _value, _method, _params) => { 196 | const { CallTransactionBuilder } = IconBuilder; 197 | 198 | const from = _from; 199 | const to = _to; 200 | const method = _method; 201 | const params = _params; 202 | const value = IconAmount.of(_value, IconAmount.Unit.ICX).toLoop(); 203 | 204 | const version = IconConverter.toBigNumber(info.ENDPOINT.version); 205 | const nid = IconConverter.toBigNumber(info.ENDPOINT.nid); 206 | const timestamp = (new Date()).getTime() * 1000; 207 | 208 | const builder = new CallTransactionBuilder(); 209 | const transaction = builder 210 | .from(from) 211 | .to(to) 212 | .value(value) 213 | .nid(nid) 214 | .version(version) 215 | .timestamp(timestamp) 216 | .method(method) 217 | .params(params) 218 | .build() 219 | 220 | return transaction; 221 | } 222 | 223 | module.exports.sendTransaction = async (_wallet, _transaction, _stepLimit) => { 224 | _transaction.stepLimit = parseInt(_stepLimit); 225 | 226 | let signedTransaction = new SignedTransaction(_transaction, _wallet); 227 | let txHash = await icon.sendTransaction(signedTransaction).execute(); 228 | 229 | return txHash; 230 | } 231 | 232 | module.exports.estimateStepLimit = async (_transaction) => { 233 | let transaction = makeRPCTransaction(_transaction); 234 | return request.post({ 235 | headers: {'Content-Type': 'application/json'}, 236 | url: info.ENDPOINT.debug, 237 | body: { 238 | "jsonrpc": "2.0", 239 | "id": 1234, 240 | "method": "debug_estimateStep", 241 | "params": transaction 242 | }, 243 | json: true 244 | }) 245 | .then(body => { 246 | return body.result; 247 | }); 248 | } 249 | 250 | function makeRPCTransaction(_transaction) { 251 | _transaction.version = "0x" + _transaction.version.toString(16); 252 | _transaction.nid = "0x" + _transaction.nid.toString(16); 253 | _transaction.value = "0x" + _transaction.value.toString(16); 254 | _transaction.timestamp = "0x" + (parseInt(_transaction.timestamp)).toString(16); 255 | return json_view(_transaction); 256 | } 257 | 258 | function json_view(j){ 259 | return JSON.parse(JSON.stringify(j)); 260 | } 261 | -------------------------------------------------------------------------------- /src/icon/utils/packer.js: -------------------------------------------------------------------------------- 1 | exports.packSwapData = function(data) { 2 | let result = []; 3 | 4 | result.push({t: 'address', v: data.hubContract}); 5 | result.push({t: 'string', v: data.fromChain}); 6 | result.push({t: 'string', v: data.toChain}); 7 | result.push({t: 'bytes', v: toHexBuffer(data.fromAddr)}); 8 | result.push({t: 'bytes', v: toHexBuffer(data.toAddr)}); 9 | result.push({t: 'bytes', v: toHexBuffer(data.token)}); 10 | result.push({t: 'bytes32[]', v: data.bytes32s}); 11 | result.push({t: 'uint[]', v: data.uints}); 12 | result.push({t: 'bytes', v: toHexBuffer(data.data)}); 13 | 14 | return result; 15 | }; 16 | 17 | exports.packLimitationData = function(data) { 18 | let result = []; 19 | 20 | result.push({t: 'string', v: "GateKeeper"}); 21 | result.push({t: 'string', v: data.fromChain}); 22 | result.push({t: 'string', v: data.toChain}); 23 | result.push({t: 'bytes', v: toHexBuffer(data.token)}); 24 | result.push({t: 'bytes32[]', v: data.bytes32s}); 25 | result.push({t: 'uint[]', v: data.uints}); 26 | 27 | return result; 28 | } 29 | 30 | function toHexBuffer(str) { 31 | return Buffer.from(str.replace('0x', ""), 'hex'); 32 | } 33 | -------------------------------------------------------------------------------- /src/monitor/index.js: -------------------------------------------------------------------------------- 1 | const { VALIDATOR_MONITOR } = require(`${ROOT}/config/${process.env.PROFILE}/endpoints.js`); 2 | const request = require('request'); 3 | 4 | function ozysReport(url, body) { 5 | return new Promise((resolve, reject) => { 6 | const options = { 7 | method: 'POST', 8 | json: true, 9 | body, 10 | } 11 | request(url, options, (err, res) => { 12 | if (err) { 13 | return reject(err); 14 | } 15 | resolve(res.body); 16 | }) 17 | }); 18 | } 19 | 20 | class Monitor { 21 | constructor () { 22 | this.validatorAddress; 23 | this.publicKey; 24 | this.chain; 25 | this.address = {}; 26 | this.nodeConnect = {}; 27 | this.blockNumber = {}; 28 | this.ibc = {}; 29 | 30 | this.lastBlockTime = parseInt(Date.now() / 1000); 31 | this.connectionHandler(); 32 | 33 | if(!VALIDATOR_MONITOR){ 34 | console.log("Validator Monitor set is empty!"); 35 | return; 36 | } 37 | 38 | for (const [key, value] of Object.entries(VALIDATOR_MONITOR) ) { 39 | setInterval(() => { 40 | this.reportMonitorStatus(key, value); 41 | }, 600 * 1000); 42 | } 43 | } 44 | 45 | connectionHandler() { 46 | setTimeout(this.connectionHandler.bind(this), 1000 * 60); 47 | 48 | const now = parseInt(Date.now() / 1000); 49 | if(this.lastBlockTime + 60 * 10 < now) process.exit(1); 50 | } 51 | 52 | static getChainFullName(chain) { 53 | chain = chain.toUpperCase(); 54 | 55 | if(chain.substr(0, 2) === 'GOV' && chain !== 'GOV_OCHAIN') 56 | return null; 57 | 58 | let fullNames = { 59 | ETH: 'ethereum', 60 | ETH_V1: 'ethereum-v1', 61 | ETH_V2: 'ethereum-v2', 62 | ETH_MAINNET: 'ethereum_mainnet', 63 | KLAYTN: 'klaytn', 64 | KLAYTN_V1: 'klaytn-v1', 65 | KLAYTN_V2: 'klaytn-v2', 66 | KLAYTN_MAINNET: 'klaytn_mainnet', 67 | ICON: 'icon', 68 | ICON_V1: 'icon-v1', 69 | ICON_V2: 'icon-v2', 70 | ICON_MAINNET: 'icon_mainnet', 71 | XRP: 'xrp', 72 | BSC: 'bsc', 73 | HECO: 'heco', 74 | MATIC: 'matic', 75 | CELO: 'celo', 76 | STACKS_LAYER_1: 'stacks_layer_1', 77 | TON_LAYER_1: 'ton_layer_1' 78 | }; 79 | 80 | return fullNames[chain] || (chain && chain.toLowerCase()) || ""; 81 | } 82 | 83 | reportMonitorStatus(method, data) { 84 | try { 85 | switch (method) { 86 | case "ozys": 87 | ozysReport(data.monitor, this.json()); 88 | break; 89 | default: 90 | console.log(`unknown monitor method offered: ${method}`); 91 | break; 92 | } 93 | } catch (e) {} 94 | } 95 | 96 | setNodeConnectStatus (chain, address, connectionStatus) { 97 | if (!chain || !address) { 98 | return; 99 | } 100 | 101 | chain = Monitor.getChainFullName(chain); 102 | if (!chain) { 103 | return; 104 | } 105 | 106 | this.nodeConnect[chain] = this.nodeConnect[chain] || {}; 107 | this.nodeConnect[chain].status = connectionStatus; 108 | } 109 | 110 | setNodeElectionStatus (chain, address, electedBlock) { 111 | if (!chain || !address) { 112 | return; 113 | } 114 | 115 | chain = Monitor.getChainFullName(chain); 116 | if (!chain) { 117 | return; 118 | } 119 | 120 | this.nodeConnect[chain] = this.nodeConnect[chain] || {}; 121 | this.nodeConnect[chain].electedBlock = electedBlock; 122 | } 123 | 124 | setBlockNumber (chain, block) { 125 | if (!chain || !block) 126 | return; 127 | 128 | chain = Monitor.getChainFullName(chain); 129 | if(!chain) 130 | return; 131 | 132 | if (!this.blockNumber[chain]) 133 | this.blockNumber[chain] = {} 134 | 135 | this.blockNumber[chain] = block 136 | } 137 | 138 | setBlockTime() { 139 | this.lastBlockTime = parseInt(Date.now() / 1000); 140 | } 141 | 142 | setProgress(chain, func, block) { 143 | if (!chain || !func || !block) 144 | return; 145 | 146 | chain = Monitor.getChainFullName(chain); 147 | if(!chain) 148 | return; 149 | 150 | if (!this.ibc[chain]) 151 | this.ibc[chain] = {} 152 | 153 | this.ibc[chain][func] = block 154 | } 155 | 156 | json () { 157 | return { 158 | version: VERSION, 159 | validatorAddress: this.validatorAddress, 160 | publicKey: this.publicKey, 161 | chain: this.chain, 162 | address: this.address, 163 | nodeConnection: this.nodeConnect, 164 | lastBlockTime: this.lastBlockTime, 165 | } 166 | } 167 | } 168 | 169 | module.exports = Monitor; 170 | -------------------------------------------------------------------------------- /src/stacks/logger.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const winston = require('winston'); 4 | const moment = require('moment'); 5 | const config = require(ROOT + '/config'); 6 | 7 | const tsFormat = function () { 8 | return moment().format('YYYY-MM-DD HH:mm:ss'); 9 | } 10 | 11 | ////////////////////////////////////////////////////////////////////////////////////////// 12 | const myFormat = winston.format.printf(info => { 13 | return '[STACKS] ' + tsFormat() + ' ' + info.message; 14 | }); 15 | 16 | // Normal Logger: Winston 17 | let logger = winston.createLogger({ 18 | level: config.system.logLevel || 'info', 19 | format: winston.format.combine( 20 | myFormat 21 | ), 22 | transports: [ 23 | new(winston.transports.Console)({ 24 | colorize: true, 25 | handleExceptions: true, 26 | }) 27 | ] 28 | }); 29 | 30 | module.exports = logger; 31 | -------------------------------------------------------------------------------- /src/stacks/utils/packer.js: -------------------------------------------------------------------------------- 1 | exports.packSwapData = function(data) { 2 | let result = []; 3 | 4 | result.push({t: 'address', v: data.hubContract}); 5 | result.push({t: 'string', v: data.fromChain}); 6 | result.push({t: 'string', v: data.toChain}); 7 | result.push({t: 'bytes', v: toHexBuffer(data.fromAddr)}); 8 | result.push({t: 'bytes', v: toHexBuffer(data.token)}); 9 | result.push({t: 'bytes32', v: data.bytes32s[0]}); 10 | result.push({t: 'bytes32', v: data.bytes32s[1]}); 11 | result.push({t: 'uint', v: data.uints[1]}); 12 | result.push({t: 'uint', v: data.uints[2]}); 13 | result.push({t: 'uint', v: data.uints[3]}); 14 | 15 | return result; 16 | }; 17 | 18 | exports.packDataHash = function(data) { 19 | let result = []; 20 | 21 | result.push({t: 'address', v: data.hubContract}); 22 | result.push({t: 'string', v: data.fromChain}); 23 | result.push({t: 'string', v: data.toChain}); 24 | result.push({t: 'bytes', v: toHexBuffer(data.fromAddr)}); 25 | result.push({t: 'bytes', v: toHexBuffer(data.token)}); 26 | result.push({t: 'bytes32', v: data.bytes32s[0]}); 27 | result.push({t: 'bytes32', v: data.bytes32s[1]}); 28 | result.push({t: 'uint', v: data.uints[1]}); 29 | result.push({t: 'uint', v: data.uints[2]}); 30 | 31 | return result; 32 | } 33 | 34 | exports.packLimitationData = function(data) { 35 | let result = []; 36 | 37 | result.push({t: 'string', v: "GateKeeper"}); 38 | result.push({t: 'string', v: data.fromChain}); 39 | result.push({t: 'string', v: data.toChain}); 40 | result.push({t: 'bytes', v: toHexBuffer(data.token)}); 41 | result.push({t: 'bytes32[]', v: data.bytes32s}); 42 | result.push({t: 'uint[]', v: data.uints}); 43 | 44 | return result; 45 | } 46 | 47 | function toHexBuffer(str) { 48 | return Buffer.from(str.replace('0x', ""), 'hex'); 49 | } 50 | -------------------------------------------------------------------------------- /src/stacks/utils/stacks.bridgeutils.js: -------------------------------------------------------------------------------- 1 | const request = require("request-promise"); 2 | const config = require(ROOT + '/config'); 3 | const Endpoints = config.endpoints; 4 | const BridgeUtils = require(ROOT + '/lib/bridgeutils'); 5 | 6 | const { 7 | AddressVersion, 8 | AnchorMode, 9 | BufferReader, 10 | deserializeMemoString, 11 | TransactionVersion, 12 | addressFromVersionHash, 13 | addressToString, 14 | broadcastTransaction, 15 | callReadOnlyFunction, 16 | deserializeCV, 17 | makeUnsignedSTXTokenTransfer, 18 | nextVerification, 19 | TransactionSigner, 20 | makeSigHashPreSign, 21 | } = require("@stacks/transactions"); 22 | 23 | const { 24 | StacksTestnet, 25 | StacksMainnet, 26 | } = require("@stacks/network"); 27 | 28 | const baseReqObj = { 29 | headers: {'Content-Type': 'application/json', 'User-Agent': 'OrbitBridge-Request'}, 30 | json: true, 31 | }; 32 | 33 | class StacksBridgeUtils extends BridgeUtils { 34 | constructor() { 35 | super(); 36 | 37 | let addressVersion = AddressVersion.MainnetMultiSig; 38 | let singleAddressVersion = AddressVersion.MainnetSingleSig; 39 | let transactionVersion = TransactionVersion.Mainnet; 40 | let network = new StacksMainnet(); 41 | if (Endpoints.stacks.network === "testnet") { 42 | addressVersion = AddressVersion.TestnetMultiSig; 43 | singleAddressVersion = AddressVersion.TestnetSingleSig; 44 | transactionVersion = TransactionVersion.Testnet; 45 | network = new StacksTestnet(); 46 | } 47 | 48 | this.AddressVersion = addressVersion; 49 | this.SingleAddressVersion = singleAddressVersion; 50 | this.TransactionVersion = transactionVersion; 51 | this.Network = network; 52 | 53 | let endpoints = Endpoints.stacks; 54 | global.monitor.setNodeConnectStatus("stacks", `${endpoints.url}/${endpoints.network ? endpoints.network : "mainnet"}`, "connected"); 55 | } 56 | 57 | hexToCV(hex) { 58 | if (hex.startsWith('0x')) 59 | hex = hex.substring(2); 60 | return deserializeCV(new BufferReader(Buffer.from(hex, 'hex'))) 61 | } 62 | 63 | async getLatestBlock() { 64 | const response = await request.get({ 65 | url: `${Endpoints.stacks.url}/extended/v1/block?limit=1`, 66 | ...baseReqObj, 67 | }).catch(e => { 68 | logger.stacks.error(`getTransaction error. tx:${thash}, err:${e.message}`); 69 | }); 70 | if (!response) { 71 | return; 72 | } 73 | 74 | return response.results[0]; 75 | } 76 | 77 | async getTransaction(thash) { 78 | const tx = await request.get({ 79 | url: `${Endpoints.stacks.url}/extended/v1/tx/${thash}`, 80 | ...baseReqObj, 81 | }).catch(e => { 82 | logger.stacks.error(`getTransaction error. tx:${thash}, err:${e.message}`); 83 | }); 84 | if (!tx) { 85 | return; 86 | } 87 | if (tx.token_transfer && tx.token_transfer.memo) { 88 | let memo = tx.token_transfer.memo.replace("0x", ""); 89 | memo = deserializeMemoString(new BufferReader(Buffer.from(memo, "hex"))); 90 | memo.content = memo.content.replace(/\u0000/g, ""); 91 | tx.token_transfer.memo = memo; 92 | } 93 | return tx; 94 | }; 95 | 96 | async getBalance(address) { 97 | const stx = await request.get({ 98 | url: `${Endpoints.stacks.url}/extended/v1/address/${address}/stx`, 99 | ...baseReqObj, 100 | }).catch(e => { 101 | logger.stacks.error(`getBalance error. addr:${address}, err:${e.message}`); 102 | }); 103 | if(!stx) 104 | return; 105 | 106 | return stx.balance; 107 | }; 108 | 109 | async getNonce(address) { 110 | const account = await request.get({ 111 | url: `${Endpoints.stacks.url}/extended/v1/address/${address}/nonces`, 112 | ...baseReqObj, 113 | }).catch(e => { 114 | logger.stacks.error(`getNonce error. addr:${address}, err:${e.message}`); 115 | }); 116 | if(!account) 117 | return; 118 | 119 | return account.possible_next_nonce; 120 | } 121 | 122 | async makeUnsignedSTXTokenTransfer(nonce, publicKeys, quorumCount, toAddr, memo, amount) { 123 | publicKeys = publicKeys.map(key => { return key.replace("0x",""); }); 124 | const transaction = await makeUnsignedSTXTokenTransfer({ 125 | recipient : toAddr, 126 | nonce: nonce, 127 | amount: amount, 128 | memo: memo, 129 | numSignatures: parseInt(quorumCount), // number of signature required 130 | publicKeys: publicKeys, // public key string array with >= numSignatures elements 131 | network: this.Network, 132 | anchorMode: AnchorMode.Any, 133 | }).catch(e => { 134 | logger.stacks.error(`makeTransaction error. nonce: ${nonce}, err:${e.message}`); 135 | }); 136 | if(!transaction) 137 | return; 138 | 139 | return transaction; 140 | } 141 | 142 | async readContract(contractAddress, contractName, functionName, functionArgs, sender) { 143 | const ret = await callReadOnlyFunction({ 144 | contractAddress, 145 | contractName, 146 | functionName, 147 | functionArgs, 148 | network: this.Network, 149 | senderAddress: sender, 150 | }); 151 | if (!ret) { 152 | return; 153 | } 154 | 155 | return ret; 156 | } 157 | 158 | async estimateFee(serializedTx) { 159 | const stx = await request.post({ 160 | url: `${Endpoints.stacks.url}/extended/v1/fee_rate`, 161 | ...baseReqObj, 162 | params: {transaction : serializedTx} 163 | }).catch(e => { 164 | logger.stacks.error(`estimateFee error. tx:${serializedTx}, err:${e.message}`); 165 | }); 166 | if(!stx) 167 | return; 168 | 169 | return stx.fee_rate; 170 | } 171 | 172 | getMultiAddressFromHex(hexAddr) { 173 | return addressToString(addressFromVersionHash(this.AddressVersion, hexAddr.replace("0x", ""))); 174 | } 175 | 176 | getSingleAddressFromHex(hexAddr) { 177 | return addressToString(addressFromVersionHash(this.SingleAddressVersion, hexAddr.replace("0x", ""))); 178 | } 179 | 180 | async broadcastTransaction(transaction) { 181 | const res = await broadcastTransaction(transaction.serialize(), Endpoints.stacks.url).catch(e => { 182 | logger.stacks.error(`broadcastTransaction fail. err: ${e.message}`); 183 | }); 184 | if(!res) 185 | return; 186 | 187 | return res.txid; 188 | } 189 | 190 | getMemo(data) { 191 | if (!data) { 192 | return ""; 193 | } 194 | return Buffer.from(data.replace("0x",""), 'hex').toString('utf-8'); 195 | } 196 | 197 | getCurrentSigHash(lastSigHash, lastSignature, fee, nonce){ 198 | let res; 199 | try{ 200 | res = nextVerification( 201 | lastSigHash.replace("0x",""), 202 | 4, // Standard 203 | fee, 204 | nonce, 205 | 1, // Uncompressed 206 | {data: lastSignature.replace("0x","")} // {00,01}{r}{s} 207 | ) 208 | } catch(e) { 209 | logger.stacks.error(`getCrrentSigHash fail. err: ${e.message}`); 210 | return; 211 | }; 212 | if(!res) 213 | return; 214 | 215 | return res.nextSigHash; 216 | } 217 | 218 | async getInitialSigHash(transaction){ 219 | transaction.auth.spendingCondition.fields = []; 220 | const signer = new TransactionSigner(transaction); 221 | if(!signer || !signer.sigHash) 222 | return; 223 | 224 | return signer.sigHash; 225 | } 226 | 227 | async getSigHashPreSign(curSigHash, authType, fee, nonce){ 228 | let res; 229 | try{ 230 | res = makeSigHashPreSign(curSigHash, authType, fee, nonce); 231 | } catch(e) { 232 | logger.stacks.error(`makeSigHashPreSign fail. err: ${e.message}`); 233 | return; 234 | } 235 | if(!res) 236 | return; 237 | 238 | return res; 239 | } 240 | } 241 | 242 | module.exports = StacksBridgeUtils; 243 | -------------------------------------------------------------------------------- /src/stacks_layer_1/logger.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const winston = require('winston'); 4 | const moment = require('moment'); 5 | const config = require(ROOT + '/config'); 6 | 7 | const tsFormat = function () { 8 | return moment().format('YYYY-MM-DD HH:mm:ss'); 9 | } 10 | 11 | ////////////////////////////////////////////////////////////////////////////////////////// 12 | const myFormat = winston.format.printf(info => { 13 | return '[STACKS_LAYER_1] ' + tsFormat() + ' ' + info.message; 14 | }); 15 | 16 | // Normal Logger: Winston 17 | let logger = winston.createLogger({ 18 | level: config.system.logLevel || 'info', 19 | format: winston.format.combine( 20 | myFormat 21 | ), 22 | transports: [ 23 | new(winston.transports.Console)({ 24 | colorize: true, 25 | handleExceptions: true, 26 | }) 27 | ] 28 | }); 29 | 30 | module.exports = logger; 31 | -------------------------------------------------------------------------------- /src/stacks_layer_1/utils/packer.js: -------------------------------------------------------------------------------- 1 | exports.packSwapData = function(data) { 2 | let result = []; 3 | 4 | result.push({t: 'address', v: data.hubContract}); 5 | result.push({t: 'string', v: data.fromChain}); 6 | result.push({t: 'string', v: data.toChain}); 7 | result.push({t: 'bytes', v: toHexBuffer(data.fromAddr)}); 8 | result.push({t: 'bytes', v: toHexBuffer(data.toAddr)}); 9 | result.push({t: 'bytes', v: toHexBuffer(data.token)}); 10 | result.push({t: 'bytes32[]', v: data.bytes32s}); 11 | result.push({t: 'uint[]', v: data.uints}); 12 | result.push({t: 'bytes', v: toHexBuffer(data.data)}); 13 | 14 | return result; 15 | }; 16 | 17 | exports.packSuggestHash = function(data) { 18 | let result = []; 19 | 20 | result.push({t: 'address', v: data.contract}); 21 | result.push({t: 'bytes32', v: data.govId}); 22 | result.push({t: 'uint', v: data.suggestIndex.toString()}); 23 | result.push({t: 'uint', v: data.swapIndex.toString()}); 24 | result.push({t: 'uint', v: data.fee.toString()}); 25 | result.push({t: 'uint', v: data.seq.toString()}); 26 | 27 | return result; 28 | }; 29 | 30 | exports.packSigningHash = function(data) { 31 | let result = []; 32 | 33 | result.push({t: 'address', v: data.contract}); 34 | result.push({t: 'bytes32', v: data.govId}); 35 | result.push({t: 'uint', v: data.selectionIndex}); 36 | result.push({t: 'address[]', v: data.vaList}); 37 | 38 | return result; 39 | }; 40 | 41 | exports.packStacksTagHash = function(data) { 42 | let result = []; 43 | 44 | result.push({t: 'string', v: data.toChain}); 45 | result.push({t: 'bytes', v: toHexBuffer(data.toAddress)}); 46 | result.push({t: 'bytes', v: toHexBuffer(data.transfortData)}); 47 | 48 | return result; 49 | } 50 | 51 | exports.packLimitationData = function(data) { 52 | let result = []; 53 | 54 | result.push({t: 'string', v: "GateKeeper"}); 55 | result.push({t: 'string', v: data.fromChain}); 56 | result.push({t: 'string', v: data.toChain}); 57 | result.push({t: 'bytes', v: toHexBuffer(data.token)}); 58 | result.push({t: 'bytes32[]', v: data.bytes32s}); 59 | result.push({t: 'uint[]', v: data.uints}); 60 | 61 | return result; 62 | } 63 | 64 | function toHexBuffer(str) { 65 | return Buffer.from(str.replace('0x', ""), 'hex'); 66 | } 67 | -------------------------------------------------------------------------------- /src/stacks_layer_1/utils/stacks.bridgeutils.js: -------------------------------------------------------------------------------- 1 | const request = require("request-promise"); 2 | const config = require(ROOT + '/config'); 3 | const Endpoints = config.endpoints; 4 | const BridgeUtils = require(ROOT + '/lib/bridgeutils'); 5 | 6 | const { 7 | AddressVersion, 8 | AnchorMode, 9 | BufferReader, 10 | deserializeMemoString, 11 | TransactionVersion, 12 | addressFromVersionHash, 13 | addressToString, 14 | broadcastTransaction, 15 | makeUnsignedSTXTokenTransfer, 16 | nextVerification, 17 | TransactionSigner, 18 | makeSigHashPreSign, 19 | } = require("@stacks/transactions"); 20 | 21 | const { 22 | StacksTestnet, 23 | StacksMainnet, 24 | } = require("@stacks/network"); 25 | 26 | const baseReqObj = { 27 | headers: {'Content-Type': 'application/json', 'User-Agent': 'OrbitBridge-Request'}, 28 | json: true, 29 | }; 30 | 31 | class StacksBridgeUtils extends BridgeUtils { 32 | constructor() { 33 | super(); 34 | 35 | let addressVersion = AddressVersion.MainnetMultiSig; 36 | let singleAddressVersion = AddressVersion.MainnetSingleSig; 37 | let transactionVersion = TransactionVersion.Mainnet; 38 | let network = new StacksMainnet(); 39 | if (Endpoints.stacks.network === "testnet") { 40 | addressVersion = AddressVersion.TestnetMultiSig; 41 | singleAddressVersion = AddressVersion.TestnetSingleSig; 42 | transactionVersion = TransactionVersion.Testnet; 43 | network = new StacksTestnet(); 44 | } 45 | 46 | this.AddressVersion = addressVersion; 47 | this.SingleAddressVersion = singleAddressVersion; 48 | this.TransactionVersion = transactionVersion; 49 | this.Network = network; 50 | 51 | let endpoints = Endpoints.stacks; 52 | global.monitor.setNodeConnectStatus("stacks", `${endpoints.url}/${endpoints.network ? endpoints.network : "mainnet"}`, "connected"); 53 | } 54 | 55 | async getTransaction(thash) { 56 | const tx = await request.get({ 57 | url: `${Endpoints.stacks.url}/extended/v1/tx/${thash}`, 58 | ...baseReqObj, 59 | }).catch(e => { 60 | logger.stacks_layer_1.error(`getTransaction error. tx:${thash}, err:${e.message}`); 61 | }); 62 | if (!tx) { 63 | return; 64 | } 65 | if (tx.token_transfer && tx.token_transfer.memo) { 66 | let memo = tx.token_transfer.memo.replace("0x", ""); 67 | memo = deserializeMemoString(new BufferReader(Buffer.from(memo, "hex"))); 68 | memo.content = memo.content.replace(/\u0000/g, ""); 69 | tx.token_transfer.memo = memo; 70 | } 71 | return tx; 72 | }; 73 | 74 | async getBalance(address) { 75 | const stx = await request.get({ 76 | url: `${Endpoints.stacks.url}/extended/v1/address/${address}/stx`, 77 | ...baseReqObj, 78 | }).catch(e => { 79 | logger.stacks_layer_1.error(`getBalance error. addr:${address}, err:${e.message}`); 80 | }); 81 | if(!stx) 82 | return; 83 | 84 | return stx.balance; 85 | }; 86 | 87 | async getNonce(address) { 88 | const account = await request.get({ 89 | url: `${Endpoints.stacks.url}/extended/v1/address/${address}/nonces`, 90 | ...baseReqObj, 91 | }).catch(e => { 92 | logger.stacks_layer_1.error(`getNonce error. addr:${address}, err:${e.message}`); 93 | }); 94 | if(!account) 95 | return; 96 | 97 | return account.possible_next_nonce; 98 | } 99 | 100 | async getCurrentBlock() { 101 | const block = await request.get({ 102 | url: `${Endpoints.stacks.url}/extended/v1/block`, 103 | ...baseReqObj, 104 | }).catch(e => { 105 | logger.stacks_layer_1.error(`getCurrentBlock error.`); 106 | }); 107 | if(!block) 108 | return; 109 | 110 | return block.results[0].height; 111 | } 112 | 113 | async makeUnsignedSTXTokenTransfer(nonce, publicKeys, quorumCount, toAddr, memo, amount) { 114 | publicKeys = publicKeys.map(key => { return key.replace("0x",""); }); 115 | const transaction = await makeUnsignedSTXTokenTransfer({ 116 | recipient : toAddr, 117 | nonce: nonce, 118 | amount: amount, 119 | memo: memo, 120 | numSignatures: parseInt(quorumCount), // number of signature required 121 | publicKeys: publicKeys, // public key string array with >= numSignatures elements 122 | network: this.Network, 123 | anchorMode: AnchorMode.Any, 124 | }).catch(e => { 125 | logger.stacks_layer_1.error(`makeTransaction error. nonce: ${nonce}, err:${e.message}`); 126 | }); 127 | if(!transaction) 128 | return; 129 | 130 | return transaction; 131 | } 132 | 133 | async estimateFee(serializedTx) { 134 | const stx = await request.post({ 135 | url: `${Endpoints.stacks.url}/extended/v1/fee_rate`, 136 | ...baseReqObj, 137 | params: {transaction : serializedTx} 138 | }).catch(e => { 139 | logger.stacks_layer_1.error(`estimateFee error. tx:${serializedTx}, err:${e.message}`); 140 | }); 141 | if(!stx) 142 | return; 143 | 144 | return stx.fee_rate; 145 | } 146 | 147 | getMultiAddressFromHex(hexAddr) { 148 | return addressToString(addressFromVersionHash(this.AddressVersion, hexAddr.replace("0x", ""))); 149 | } 150 | 151 | getSingleAddressFromHex(hexAddr) { 152 | return addressToString(addressFromVersionHash(this.SingleAddressVersion, hexAddr.replace("0x", ""))); 153 | } 154 | 155 | async broadcastTransaction(transaction) { 156 | const res = await broadcastTransaction(transaction.serialize(), Endpoints.stacks.url).catch(e => { 157 | logger.stacks_layer_1.error(`broadcastTransaction fail. err: ${e.message}`); 158 | }); 159 | if(!res) 160 | return; 161 | 162 | return res.txid; 163 | } 164 | 165 | getMemo(data) { 166 | if (!data) { 167 | return ""; 168 | } 169 | return Buffer.from(data.replace("0x",""), 'hex').toString('utf-8'); 170 | } 171 | 172 | getCurrentSigHash(lastSigHash, lastSignature, fee, nonce){ 173 | let res; 174 | try{ 175 | res = nextVerification( 176 | lastSigHash.replace("0x",""), 177 | 4, // Standard 178 | fee, 179 | nonce, 180 | 1, // Uncompressed 181 | {data: lastSignature.replace("0x","")} // {00,01}{r}{s} 182 | ) 183 | } catch(e) { 184 | logger.stacks_layer_1.error(`getCrrentSigHash fail. err: ${e.message}`); 185 | return; 186 | }; 187 | if(!res) 188 | return; 189 | 190 | return res.nextSigHash; 191 | } 192 | 193 | async getInitialSigHash(transaction){ 194 | transaction.auth.spendingCondition.fields = []; 195 | const signer = new TransactionSigner(transaction); 196 | if(!signer || !signer.sigHash) 197 | return; 198 | 199 | return signer.sigHash; 200 | } 201 | 202 | async getSigHashPreSign(curSigHash, authType, fee, nonce){ 203 | let res; 204 | try{ 205 | res = makeSigHashPreSign(curSigHash, authType, fee, nonce); 206 | } catch(e) { 207 | logger.stacks_layer_1.error(`makeSigHashPreSign fail. err: ${e.message}`); 208 | return; 209 | } 210 | if(!res) 211 | return; 212 | 213 | return res; 214 | } 215 | } 216 | 217 | module.exports = StacksBridgeUtils; 218 | -------------------------------------------------------------------------------- /src/ton/logger.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const winston = require('winston'); 4 | const moment = require('moment'); 5 | const config = require(ROOT + '/config'); 6 | 7 | const tsFormat = function () { 8 | return moment().format('YYYY-MM-DD HH:mm:ss'); 9 | } 10 | 11 | ////////////////////////////////////////////////////////////////////////////////////////// 12 | const myFormat = winston.format.printf(info => { 13 | return '[TON] ' + tsFormat() + ' ' + info.message; 14 | }); 15 | 16 | // Normal Logger: Winston 17 | let logger = winston.createLogger({ 18 | level: config.system.logLevel || 'info', 19 | format: winston.format.combine( 20 | myFormat 21 | ), 22 | transports: [ 23 | new(winston.transports.Console)({ 24 | colorize: true, 25 | handleExceptions: true, 26 | }) 27 | ] 28 | }); 29 | 30 | module.exports = logger; 31 | -------------------------------------------------------------------------------- /src/ton/utils/packer.js: -------------------------------------------------------------------------------- 1 | exports.packSwapDataA = function(data) { 2 | let result = []; 3 | 4 | result.push({t: 'address', v: data.hubContract}); 5 | result.push({t: 'bytes32', v: data.fromChainId}); 6 | result.push({t: 'bytes32', v: data.toChainId}); 7 | result.push({t: 'bytes', v: toHexBuffer(data.fromAddr)}); 8 | 9 | return result; 10 | } 11 | 12 | exports.packSwapDataB = function(data) { 13 | let result = []; 14 | 15 | result.push({t: 'bytes', v: toHexBuffer(data.toAddr)}); 16 | result.push({t: 'bytes', v: toHexBuffer(data.token)}); 17 | result.push({t: 'bytes32[]', v: data.bytes32s}); 18 | 19 | return result; 20 | } 21 | 22 | exports.packSwapDataC = function(data) { 23 | let result = []; 24 | 25 | result.push({t: 'uint[]', v: data.uints}); 26 | 27 | return result; 28 | } 29 | 30 | exports.packSigHash = function(data) { 31 | let result = []; 32 | 33 | result.push({t: 'bytes32', v: data.hashA}); 34 | result.push({t: 'bytes32', v: data.hashB}); 35 | result.push({t: 'bytes32', v: data.hashC}); 36 | 37 | return result; 38 | } 39 | 40 | exports.packLimitationData = function(data) { 41 | let result = []; 42 | 43 | result.push({t: 'string', v: "GateKeeper"}); 44 | result.push({t: 'string', v: data.fromChain}); 45 | result.push({t: 'string', v: data.toChain}); 46 | result.push({t: 'bytes', v: toHexBuffer(data.token)}); 47 | result.push({t: 'bytes32[]', v: data.bytes32s}); 48 | result.push({t: 'uint[]', v: data.uints}); 49 | 50 | return result; 51 | } 52 | 53 | function toHexBuffer(str) { 54 | return Buffer.from(str.replace('0x', ""), 'hex'); 55 | } 56 | -------------------------------------------------------------------------------- /src/ton_layer_1/logger.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const winston = require('winston'); 4 | const moment = require('moment'); 5 | const config = require(ROOT + '/config'); 6 | 7 | const tsFormat = function () { 8 | return moment().format('YYYY-MM-DD HH:mm:ss'); 9 | } 10 | 11 | ////////////////////////////////////////////////////////////////////////////////////////// 12 | const myFormat = winston.format.printf(info => { 13 | return '[TON_LAYER_1] ' + tsFormat() + ' ' + info.message; 14 | }); 15 | 16 | // Normal Logger: Winston 17 | let logger = winston.createLogger({ 18 | level: config.system.logLevel || 'info', 19 | format: winston.format.combine( 20 | myFormat 21 | ), 22 | transports: [ 23 | new(winston.transports.Console)({ 24 | colorize: true, 25 | handleExceptions: true, 26 | }) 27 | ] 28 | }); 29 | 30 | module.exports = logger; 31 | -------------------------------------------------------------------------------- /src/ton_layer_1/utils/packer.js: -------------------------------------------------------------------------------- 1 | exports.packSwapDataA = function(data) { 2 | let result = []; 3 | 4 | result.push({t: 'address', v: data.hubContract}); 5 | result.push({t: 'bytes32', v: data.fromChainId}); 6 | result.push({t: 'bytes32', v: data.toChainId}); 7 | result.push({t: 'bytes', v: toHexBuffer(data.fromAddr)}); 8 | 9 | return result; 10 | } 11 | 12 | exports.packSwapDataB = function(data) { 13 | let result = []; 14 | 15 | result.push({t: 'bytes', v: toHexBuffer(data.toAddr)}); 16 | result.push({t: 'bytes', v: toHexBuffer(data.token)}); 17 | result.push({t: 'bytes32[]', v: data.bytes32s}); 18 | 19 | return result; 20 | } 21 | 22 | exports.packSwapDataC = function(data) { 23 | let result = []; 24 | 25 | result.push({t: 'uint[]', v: data.uints}); 26 | 27 | return result; 28 | } 29 | 30 | exports.packSwapDataD = function(data) { 31 | let result = []; 32 | 33 | result.push({t: 'bytes', v: toHexBuffer(data.data)}); 34 | 35 | return result; 36 | } 37 | 38 | exports.packSigHash = function(data) { 39 | let result = []; 40 | 41 | result.push({t: 'bytes32', v:data.hash1}); 42 | result.push({t: 'bytes32', v:data.hash2}); 43 | 44 | return result; 45 | } 46 | 47 | exports.packLimitationData = function(data) { 48 | let result = []; 49 | 50 | result.push({t: 'string', v: "GateKeeper"}); 51 | result.push({t: 'string', v: data.fromChain}); 52 | result.push({t: 'string', v: data.toChain}); 53 | result.push({t: 'bytes', v: toHexBuffer(data.token)}); 54 | result.push({t: 'bytes32[]', v: data.bytes32s}); 55 | result.push({t: 'uint[]', v: data.uints}); 56 | 57 | return result; 58 | } 59 | 60 | exports.packTagHash = function(data) { 61 | let result = []; 62 | 63 | result.push({t: 'string', v: 'TON'}); 64 | result.push({t: 'string', v: 'AddressBook'}); 65 | result.push({t: 'uint256', v: data.version}); 66 | result.push({t: 'string', v: data.toChain}); 67 | result.push({t: 'bytes', v: toHexBuffer(data.toAddress)}); 68 | result.push({t: 'bytes', v: toHexBuffer(data.transfortData)}); 69 | 70 | return result; 71 | } 72 | 73 | function toHexBuffer(str) { 74 | return Buffer.from(str.replace('0x', ""), 'hex'); 75 | } 76 | -------------------------------------------------------------------------------- /src/xrp/logger.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const winston = require('winston'); 4 | const moment = require('moment'); 5 | const config = require(ROOT + '/config'); 6 | 7 | const tsFormat = function () { 8 | return moment().format('YYYY-MM-DD HH:mm:ss'); 9 | } 10 | 11 | ////////////////////////////////////////////////////////////////////////////////////////// 12 | const myFormat = winston.format.printf(info => { 13 | return '[XRP] ' + tsFormat() + ' ' + info.message; 14 | }); 15 | 16 | // Normal Logger: Winston 17 | let logger = winston.createLogger({ 18 | level: config.system.logLevel || 'info', 19 | format: winston.format.combine( 20 | myFormat 21 | ), 22 | transports: [ 23 | new(winston.transports.Console)({ 24 | colorize: true, 25 | handleExceptions: true, 26 | }) 27 | ] 28 | }); 29 | 30 | module.exports = logger; -------------------------------------------------------------------------------- /src/xrp/utils/packer.js: -------------------------------------------------------------------------------- 1 | exports.packSwapData = function(data) { 2 | let result = []; 3 | 4 | result.push({t: 'address', v: data.hubContract}); 5 | result.push({t: 'string', v: data.fromChain}); 6 | result.push({t: 'string', v: data.toChain}); 7 | result.push({t: 'bytes', v: toHexBuffer(data.fromAddr)}); 8 | result.push({t: 'bytes', v: toHexBuffer(data.toAddr)}); 9 | result.push({t: 'bytes', v: toHexBuffer(data.token)}); 10 | result.push({t: 'bytes32[]', v: data.bytes32s}); 11 | result.push({t: 'uint[]', v: data.uints}); 12 | result.push({t: 'bytes', v: toHexBuffer(data.data)}); 13 | 14 | return result; 15 | }; 16 | 17 | exports.packSuggestHash = function(data) { 18 | let result = []; 19 | 20 | result.push({t: 'address', v: data.contract}); 21 | result.push({t: 'bytes32', v: data.govId}); 22 | result.push({t: 'uint', v: data.suggestIndex.toString()}); 23 | result.push({t: 'uint', v: data.swapIndex.toString()}); 24 | result.push({t: 'address[]', v: data.validators}); 25 | result.push({t: 'bytes32[]', v: data.signatureHashs}); 26 | result.push({t: 'uint', v: data.fee.toString()}); 27 | result.push({t: 'uint', v: data.seq.toString()}); 28 | 29 | return result; 30 | }; 31 | 32 | exports.packSigningHash = function(data) { 33 | let result = []; 34 | 35 | result.push({t: 'address', v: data.contract}); 36 | result.push({t: 'bytes32', v: data.govId}); 37 | result.push({t: 'uint', v: data.selectionIndex}); 38 | result.push({t: 'bytes32[]', v: data.signatureHashs}); 39 | 40 | return result; 41 | }; 42 | 43 | exports.packXrpTagHash = function(data) { 44 | let result = []; 45 | 46 | result.push({t: 'string', v: 'XRP'}); 47 | result.push({t: 'string', v: 'AddressBook'}); 48 | result.push({t: 'uint256', v: data.version}); 49 | result.push({t: 'string', v: data.toChain}); 50 | result.push({t: 'bytes', v: toHexBuffer(data.toAddress)}); 51 | result.push({t: 'bytes', v: toHexBuffer(data.transfortData)}); 52 | 53 | return result; 54 | } 55 | 56 | exports.packLimitationData = function(data) { 57 | let result = []; 58 | 59 | result.push({t: 'string', v: "GateKeeper"}); 60 | result.push({t: 'string', v: data.fromChain}); 61 | result.push({t: 'string', v: data.toChain}); 62 | result.push({t: 'bytes', v: toHexBuffer(data.token)}); 63 | result.push({t: 'bytes32[]', v: data.bytes32s}); 64 | result.push({t: 'uint[]', v: data.uints}); 65 | 66 | return result; 67 | } 68 | 69 | function toHexBuffer(str) { 70 | return Buffer.from(str.replace('0x', ""), 'hex'); 71 | } 72 | -------------------------------------------------------------------------------- /src/xrp/utils/ripple.api.js: -------------------------------------------------------------------------------- 1 | const RippleAPI = require('ripple-lib').RippleAPI; 2 | const config = require(ROOT + '/config'); 3 | const info = config.info.xrp; 4 | const api = new RippleAPI({ server: info.ENDPOINT.socket, connectionTimeout: 60000 }); 5 | 6 | module.exports = api; 7 | module.exports.getSequence = async address => { 8 | let accountInfo = await api.getAccountInfo(address).catch(e => { 9 | logger.xrp.error('getSequence error: ' + e.message); 10 | }); 11 | 12 | if(!accountInfo) 13 | return; 14 | 15 | return accountInfo.sequence; 16 | }; 17 | 18 | module.exports.getVaultInfos = async address => { 19 | const obj = await api.getAccountObjects(address).catch(e => { 20 | logger.xrp.error('getSequence error: ' + e.message); 21 | }); 22 | if (!obj || obj.account_objects.length !== 1) { 23 | return; 24 | } 25 | return obj.account_objects[0]; 26 | } 27 | 28 | module.exports.getBalance = async address => { 29 | let accountInfo = await api.getAccountInfo(address).catch(e => { 30 | logger.xrp.error('getSequence error: ' + e.message); 31 | }); 32 | 33 | if(!accountInfo) 34 | return; 35 | 36 | return accountInfo.xrpBalance * 10 ** 6; 37 | }; 38 | -------------------------------------------------------------------------------- /src/xrp/utils/xrp.bridgeutils.js: -------------------------------------------------------------------------------- 1 | const BridgeUtils = require(ROOT + '/lib/bridgeutils'); 2 | const crypto = require('crypto'); 3 | const addressCodec = require('ripple-address-codec'); 4 | const bs58 = require('bs58'); 5 | const varuint = require('varuint-bitcoin'); 6 | const ethUtil = require('ethereumjs-util'); 7 | const codec = require('ripple-binary-codec'); 8 | const keypairs = require('ripple-keypairs'); 9 | const ripple = require('./ripple.api'); 10 | const EC = require('elliptic').ec; 11 | const secp256k1 = new EC('secp256k1'); 12 | 13 | let context = null; 14 | 15 | class XrpBridge extends BridgeUtils { 16 | constructor(network) { 17 | super(); 18 | context = this; 19 | } 20 | 21 | getLength(str) { 22 | if (!str) { 23 | throw new TypeError('The parameter is empty.'); 24 | } 25 | 26 | let len = 0; 27 | if (Buffer.isBuffer(str)) { 28 | str = str.toString('hex'); 29 | } 30 | 31 | switch (typeof str) { 32 | case 'string': 33 | len = parseInt(str.length / 2); 34 | break; 35 | case 'number': 36 | len = parseInt(str); 37 | break; 38 | default: 39 | throw new TypeError('The parameter must be a string or a number'); 40 | } 41 | return len; 42 | } 43 | 44 | getLengthHex(str) { 45 | let len = this.getLength(str); 46 | 47 | return varuint.encode(len).toString('hex'); 48 | } 49 | 50 | toDER(x) { 51 | let buf = x; 52 | if (!Buffer.isBuffer(buf)) 53 | buf = Buffer.from(x.replace('0x', ''), 'hex'); 54 | 55 | const ZERO = Buffer.alloc(1, 0); 56 | let i = 0; 57 | while (buf[i] === 0) ++i; 58 | if (i === buf.length) return ZERO; 59 | buf = buf.slice(i); 60 | if (buf[0] & 0x80) return Buffer.concat([ZERO, buf], 1 + buf.length); 61 | return buf; 62 | } 63 | 64 | async generatePaymentTx(from, to, tag, drops, memos, quorum) { 65 | if (!from) 66 | throw 'Source address is invalid.'; 67 | if (!to) 68 | throw 'Destination address is invalid.'; 69 | if (!drops) 70 | throw 'amount(drops) is invalid.'; 71 | 72 | let payment = { 73 | source: { 74 | address: from, 75 | maxAmount: { 76 | value: drops.toString(), 77 | currency: 'drops' 78 | } 79 | }, 80 | destination: { 81 | address: to, 82 | amount: { 83 | value: drops.toString(), 84 | currency: 'drops' 85 | } 86 | } 87 | } 88 | 89 | if (tag) 90 | payment.destination.tag = parseInt(tag); 91 | 92 | if (memos) 93 | payment.memos = memos; 94 | 95 | let tx = await ripple.preparePayment(from, payment); 96 | 97 | if (tx) { 98 | let json = JSON.parse(tx.txJSON); 99 | if (json) { 100 | json.Fee = parseFloat(json.Fee); 101 | 102 | quorum = parseInt(quorum); 103 | if (!Number.isNaN(quorum) && quorum > 0) { 104 | json.SigningPubKey = ''; 105 | json.Fee = parseFloat(json.Fee) * (1 + quorum); 106 | } 107 | 108 | json.Fee = (json.Fee).toString(); 109 | delete json.LastLedgerSequence; 110 | } 111 | 112 | tx.txJSON = json; 113 | } 114 | 115 | return tx; 116 | } 117 | 118 | getAddress(pubKey) { 119 | return keypairs.deriveAddress(pubKey); 120 | } 121 | 122 | getKeyPair(pk) { 123 | let keyPair = {privateKey: pk}; 124 | pk = null; 125 | 126 | keyPair.publicKey = Buffer.from(secp256k1.keyFromPrivate(keyPair.privateKey).getPublic().encodeCompressed()).toString('hex'); 127 | keyPair.address = this.getAddress(keyPair.publicKey); 128 | 129 | return keyPair; 130 | } 131 | 132 | recoverPubKey(hash, v, r, s) { 133 | v = Number(v); 134 | 135 | if (Number.isNaN(v)) 136 | v = 0; 137 | else if (v >= 27) 138 | v -= 27; 139 | 140 | hash = Buffer.from(hash.replace('0x', ''), 'hex'); 141 | if (typeof r === 'string') { 142 | r = Buffer.from(r.replace('0x', ''), 'hex'); 143 | } 144 | if (typeof s === 'string') { 145 | s = Buffer.from(s.replace('0x', ''), 'hex'); 146 | } 147 | 148 | let xy = secp256k1.recoverPubKey(hash, {r, s}, v); 149 | return xy.encodeCompressed('hex'); 150 | } 151 | 152 | getRawMultisigTx(txJson, signerAddress) { 153 | return this.encodeTxMultisig(txJson, signerAddress, true); 154 | } 155 | 156 | getSignatureHash(rawOrTxObject, signerAddress) { 157 | let rawTx = rawOrTxObject; 158 | if (typeof rawTx !== 'string' && typeof rawTx === 'object') { 159 | if (!rawTx.TransactionType) 160 | throw 'Invalid transaction object.'; 161 | 162 | rawTx = this.getRawMultisigTx(rawTx, signerAddress) 163 | } 164 | 165 | let signingData = Buffer.from(rawTx, 'hex').toJSON().data; 166 | let hash = crypto.createHash('sha512').update(Buffer.from(signingData)).digest('hex'); 167 | 168 | return hash.slice(0, 64); 169 | } 170 | 171 | getTxnSignature(r, s) { 172 | let sig = `02${this.getLengthHex(r)}${r}02${this.getLengthHex(s)}${s}`; 173 | sig = `30${this.getLengthHex(sig)}${sig}`; 174 | 175 | return sig; 176 | } 177 | 178 | ecsign(hash, pk) { 179 | if (!Buffer.isBuffer(hash)) 180 | hash = Buffer.from(hash.replace('0x', ''), 'hex'); 181 | if (!Buffer.isBuffer(pk)) 182 | pk = Buffer.from(pk.replace('0x', ''), 'hex'); 183 | 184 | let vrs = ethUtil.ecsign(hash, pk); 185 | pk = null; 186 | 187 | return { 188 | v: vrs.s, 189 | r: '0x' + vrs.r.toString('hex'), 190 | s: '0x' + vrs.s.toString('hex') 191 | } 192 | } 193 | 194 | getSerializedTx(txJson, signatureObject) { 195 | let tx = txJson; 196 | tx.SigningPubKey = ''; 197 | 198 | let signer = { 199 | Account: signatureObject.account, 200 | SigningPubKey: signatureObject.publicKey.toUpperCase(), 201 | TxnSignature: signatureObject.txnSignature.toUpperCase() 202 | }; 203 | 204 | tx.Signers = [{Signer: signer}]; 205 | 206 | let serialized = codec.encode(tx); 207 | return serialized; 208 | } 209 | 210 | getAddressToHex(address, isBtcDigit) { 211 | let bytes = isBtcDigit ? bs58.decode(address) : addressCodec.codec.codec.decode(address); 212 | return '0x' + Buffer.from(bytes).toString('hex'); 213 | } 214 | 215 | getAddressFromHex(hex, isBtcDigit) { 216 | let buf = Buffer.from(hex.replace('0x', ''), 'hex'); 217 | return isBtcDigit ? bs58.encode(buf) : addressCodec.codec.codec.encode(buf); 218 | } 219 | 220 | encodeTxMultisig(txJson, signAs) { 221 | if (!signAs) 222 | throw 'signAs is not defined.'; 223 | 224 | if (typeof txJson === 'string') 225 | txJson = JSON.parse(txJson); 226 | 227 | let hex = codec.encodeForMultisigning(txJson, signAs); 228 | 229 | return hex; 230 | } 231 | 232 | getReleaseMemo(govId, swapIndex) { 233 | let memos = []; 234 | 235 | memos.push({ 236 | Memo: { 237 | MemoData: this.string2hex(swapIndex.toString()).toUpperCase(), 238 | MemoType: this.string2hex('swapIndex').toUpperCase() 239 | } 240 | }); 241 | 242 | memos.push({ 243 | Memo: { 244 | MemoData: this.string2hex(govId).toUpperCase(), 245 | MemoType: this.string2hex('govId').toUpperCase() 246 | } 247 | }); 248 | 249 | return memos 250 | } 251 | 252 | string2hex(str) { 253 | var hex = ''; 254 | for (var i = 0; i < str.length; i++) { 255 | hex += str.charCodeAt(i).toString(16); 256 | } 257 | 258 | return hex; 259 | } 260 | } 261 | 262 | module.exports = XrpBridge; 263 | -------------------------------------------------------------------------------- /wallet.js: -------------------------------------------------------------------------------- 1 | let walletApi = require('ethereumjs-wallet'); 2 | let ethUtil = require('ethereumjs-util'); 3 | let hdKey = require('ethereumjs-wallet/hdkey'); 4 | let fs = require('fs'); 5 | let Web3 = require('web3'); 6 | const web3 = new Web3(); 7 | const path = require('path'); 8 | const readline = require('readline-sync'); 9 | 10 | class WalletUtil { 11 | static getKeystoreJSON(keyPath) { 12 | keyPath = keyPath || path.resolve() + '/keystore.json'; 13 | 14 | let file = null; 15 | 16 | try { 17 | file = fs.readFileSync(keyPath, 'utf8'); 18 | } catch (e) { 19 | throw e; 20 | } 21 | 22 | let json = {}; 23 | try { 24 | json = JSON.parse(file); 25 | } catch (e) { 26 | throw e; 27 | } 28 | 29 | if (!json) 30 | throw 'No JSON type keystore.'; 31 | 32 | if (json.Crypto) 33 | json.crypto = json.Crypto; 34 | 35 | return json; 36 | } 37 | 38 | static getWallet(keystore, password) { 39 | let wallet = walletApi.fromV3(keystore, password); 40 | return { 41 | address: wallet.getAddressString(), 42 | addressBuffer: wallet.getAddress(), 43 | pk: wallet.getPrivateKey().toString('hex'), 44 | pkBuffer: wallet.getPrivateKey() 45 | } 46 | } 47 | 48 | static getWalletFromPK(pk) { 49 | let wallet = walletApi.fromPrivateKey(pk); 50 | return { 51 | address: wallet.getAddressString(), 52 | addressBuffer: wallet.getAddress(), 53 | pk: wallet.getPrivateKey().toString('hex'), 54 | pkBuffer: wallet.getPrivateKey(), 55 | publicKey: wallet.getPublicKeyString() 56 | } 57 | } 58 | static makeWallet(seed, password, encryptCount) { 59 | let wallet = hdKey.fromMasterSeed(seed).getWallet(); 60 | 61 | return wallet.toV3(password, { 62 | n: encryptCount || 8192 63 | }); 64 | } 65 | 66 | static migrateWallet(pk, password, encryptCount) { 67 | pk = pk.replace('0x', ''); 68 | 69 | if (pk === '') { 70 | let newaccount = web3.eth.accounts.create(web3.utils.randomHex(32)); 71 | pk = newaccount.privateKey; 72 | if (password === ''){ 73 | console.log(newaccount.address, pk); 74 | process.exit(0); 75 | } 76 | } 77 | let pkBuffer = ethUtil.toBuffer('0x' + pk.replace('0x', '')); 78 | let wallet = walletApi.fromPrivateKey(pkBuffer); 79 | 80 | return wallet.toV3(password, { 81 | n: encryptCount || 8192 82 | }); 83 | } 84 | } 85 | 86 | if (process.argv[1].indexOf('wallet') !== -1) { 87 | let argvAccount = getAccountFromParams(); 88 | if (argvAccount) { 89 | let keystore = WalletUtil.migrateWallet(argvAccount.pk, argvAccount.pw); 90 | let address = keystore.address; 91 | let filename = `keystore_${address}.json`; 92 | 93 | fs.writeFileSync('./' + filename, JSON.stringify(keystore), 'utf8'); 94 | console.log('Keystore file saved: ' + filename); 95 | } 96 | } 97 | 98 | function getAccountFromParams() { 99 | if (process.argv.length < 2) 100 | return null; 101 | 102 | let pk = process.argv[2]; 103 | let pw = process.argv[3]; 104 | 105 | if (pk.length === 66) { 106 | pk = pk.replace('0x', ''); 107 | } else if (pk === 'load') { 108 | let kpw = readline.question('Password: ', { 109 | hideEchoBack: true 110 | }); 111 | try { 112 | console.log(WalletUtil.getWallet(WalletUtil.getKeystoreJSON(pw), kpw)); 113 | process.exit(0); 114 | } catch (e) { 115 | console.log(e); 116 | } 117 | } else if (pk === '0x') { 118 | return { 119 | pk:'', 120 | pw:'' 121 | } 122 | } else if (pk === 'new') { 123 | pk = '' 124 | } else if (pk.length !== 64) { 125 | throw 'Account private key must be 32Byte Hex.' 126 | } 127 | 128 | if (!pw || pw.length == 0) { 129 | 130 | pw = readline.question('Password: ', { 131 | hideEchoBack: true 132 | }); 133 | if (pw.length == 0) { 134 | throw 'Password length muse be bigger than 1'; 135 | } 136 | } 137 | 138 | return { 139 | pk: pk, 140 | pw: pw 141 | } 142 | } 143 | 144 | module.exports = WalletUtil; 145 | --------------------------------------------------------------------------------