IMplemented one side bridge, eth => bnc
This commit is contained in:
parent
7defc1e814
commit
8b50b4dced
|
@ -5,3 +5,7 @@ node_modules/
|
|||
**/signature
|
||||
**/params
|
||||
src/tss/multi-party-ecdsa/
|
||||
data/
|
||||
demo/validator*/
|
||||
demo/ganache_data/
|
||||
src/deploy*/build/
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
[submodule "src/deploy/contracts/openzeppelin-solidity"]
|
||||
path = src/deploy/contracts/openzeppelin-solidity
|
||||
url = https://github.com/OpenZeppelin/openzeppelin-solidity.git
|
||||
[submodule "src/deploy-test/contracts/openzeppelin-solidity"]
|
||||
path = src/deploy-test/contracts/openzeppelin-solidity
|
||||
url = https://github.com/OpenZeppelin/openzeppelin-solidity.git
|
|
@ -0,0 +1,15 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
cd $(dirname "$0")
|
||||
|
||||
for (( I = 1; I < 4; ++I )); do
|
||||
DIRNAME="validator$I"
|
||||
rm -r "$DIRNAME/db"
|
||||
rm -r "$DIRNAME/queue"
|
||||
rm -r "$DIRNAME/keys"
|
||||
mkdir "$DIRNAME/db"
|
||||
mkdir "$DIRNAME/queue"
|
||||
mkdir "$DIRNAME/keys"
|
||||
done
|
|
@ -0,0 +1,14 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
DCU_FLAGS="--build --force-recreate"
|
||||
NAME="validator$N"
|
||||
|
||||
cd $(dirname "$0")
|
||||
|
||||
echo "Starting $NAME"
|
||||
|
||||
mkdir -p "$NAME"
|
||||
cd "$NAME"
|
||||
docker-compose -p "$NAME" -f ../../src/oracle/docker-compose.yml up ${DCU_FLAGS}
|
|
@ -0,0 +1,29 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
cd $(dirname "$0")
|
||||
|
||||
echo "Starting blockchain"
|
||||
|
||||
rm -r ./ganache_data
|
||||
|
||||
mkdir ganache_data
|
||||
|
||||
kill $(sudo lsof -t -i:7545)
|
||||
|
||||
ganache-cli --db ./ganache_data -p 7545 -m "shrug dwarf easily blade trigger lucky reopen cage lake scatter desk boat" -i 33 -q &
|
||||
|
||||
sleep 3
|
||||
|
||||
echo "Deploying erc20"
|
||||
|
||||
cd ../src/deploy-test
|
||||
|
||||
truffle deploy --network development --reset > /dev/null
|
||||
|
||||
echo "Deploying main part"
|
||||
|
||||
cd ../deploy
|
||||
|
||||
truffle deploy --network development --reset > /dev/null
|
File diff suppressed because it is too large
Load Diff
|
@ -1,9 +0,0 @@
|
|||
{
|
||||
"name": "bridge",
|
||||
"version": "0.0.1",
|
||||
"dependencies": {
|
||||
"dotenv": "8.0.0",
|
||||
"truffle-hdwallet-provider": "1.0.10",
|
||||
"web3": "1.0.0-beta.55"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
RPC_URL=https://sokol.poa.network
|
||||
RPC_URL_DEV=http://127.0.0.1:7545
|
||||
|
||||
PRIVATE_KEY=e49fe947f224ae8e126c41b1be3e52be701509c2366e835ea8c08651f91030e0
|
||||
PRIVATE_KEY_DEV=e2aeb24eaa63102d0c0821717c3b6384abdabd7af2ad4ec8e650dce300798b27
|
||||
|
||||
SHARED_DB_ADDRESS=0xED3B25004A77de5dE38850a7D148315537C15572
|
|
@ -0,0 +1,24 @@
|
|||
pragma solidity ^0.5.9;
|
||||
|
||||
contract Migrations {
|
||||
address public owner;
|
||||
|
||||
uint public last_completed_migration;
|
||||
|
||||
modifier restricted() {
|
||||
if (msg.sender == owner) _;
|
||||
}
|
||||
|
||||
constructor() public {
|
||||
owner = msg.sender;
|
||||
}
|
||||
|
||||
function setCompleted(uint completed) restricted public {
|
||||
last_completed_migration = completed;
|
||||
}
|
||||
|
||||
function upgrade(address new_address) restricted public {
|
||||
Migrations upgraded = Migrations(new_address);
|
||||
upgraded.setCompleted(last_completed_migration);
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
Subproject commit c9f328ef66251db7fac7c704dd6c5523fc53b0ab
|
|
@ -0,0 +1,5 @@
|
|||
const Migrations = artifacts.require('Migrations')
|
||||
|
||||
module.exports = deployer => {
|
||||
deployer.deploy(Migrations)
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
const TokenContract = artifacts.require('ERC20Mintable')
|
||||
|
||||
module.exports = async (deployer, network, accounts) => {
|
||||
await deployer.deploy(TokenContract)
|
||||
|
||||
const instance = await TokenContract.deployed()
|
||||
await instance.mint(accounts[0], 1000000)
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
require('dotenv').config()
|
||||
|
||||
const PrivateKeyProvider = require('truffle-hdwallet-provider')
|
||||
|
||||
const { RPC_URL, PRIVATE_KEY, RPC_URL_DEV, PRIVATE_KEY_DEV } = process.env
|
||||
|
||||
module.exports = {
|
||||
networks: {
|
||||
development: {
|
||||
provider: new PrivateKeyProvider(PRIVATE_KEY_DEV, RPC_URL_DEV),
|
||||
network_id: '33'
|
||||
},
|
||||
staging: {
|
||||
provider: new PrivateKeyProvider(PRIVATE_KEY, RPC_URL),
|
||||
network_id: '77'
|
||||
}
|
||||
},
|
||||
compilers: {
|
||||
solc: {
|
||||
version: '0.5.9',
|
||||
settings: {
|
||||
optimizer: {
|
||||
enabled: true,
|
||||
runs: 3
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,7 +2,16 @@ RPC_URL=https://sokol.poa.network
|
|||
RPC_URL_DEV=http://127.0.0.1:7545
|
||||
|
||||
PRIVATE_KEY=e49fe947f224ae8e126c41b1be3e52be701509c2366e835ea8c08651f91030e0
|
||||
PRIVATE_KEY_DEV=dc8f77f02a4aba01c3ff0aa22ff13b7c9fd47da936db8d7f0a69abd3198a8c7e
|
||||
PRIVATE_KEY_DEV=e2aeb24eaa63102d0c0821717c3b6384abdabd7af2ad4ec8e650dce300798b27
|
||||
|
||||
THRESHOLD=2
|
||||
PARTIES=6
|
||||
TOKEN_ADDRESS=0x44c158FE850821ae69DaF37AADF5c539e9d0025B
|
||||
|
||||
VALIDATOR_ADDRESS_1=0x99Eb3D86663c6Db090eFFdBC20510Ca9f836DCE3
|
||||
VALIDATOR_ADDRESS_2=0xAa006899B0EC407De930bA8A166DEfe59bBfd3DC
|
||||
VALIDATOR_ADDRESS_3=0x6352e3e6038e05b9da00C84AE851308f9774F883
|
||||
VALIDATOR_ADDRESS_4=0x4dB6b4bD0a3fdc03B027A60f1c48f05C572312aa
|
||||
VALIDATOR_ADDRESS_5=0xf7Ca4aED1795E424433498CEf43f6a3825C88731
|
||||
VALIDATOR_ADDRESS_6=0xAd6c8127143032D843A260c5D379D8d9b3D51F15
|
||||
|
||||
THRESHOLD=1
|
||||
PARTIES=3
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,20 @@
|
|||
pragma solidity ^0.5.0;
|
||||
|
||||
import './openzeppelin-solidity/contracts/token/ERC20/IERC20.sol';
|
||||
|
||||
contract Bridge {
|
||||
|
||||
IERC20 public tokenContract;
|
||||
|
||||
event ReceivedTokens(address from, string recipient, uint value);
|
||||
|
||||
constructor(address _tokenContract) public {
|
||||
tokenContract = IERC20(_tokenContract);
|
||||
}
|
||||
|
||||
function requestAffirmation(uint value, string memory recipient) public {
|
||||
tokenContract.transfer(address(this), value);
|
||||
|
||||
emit ReceivedTokens(msg.sender, recipient, value);
|
||||
}
|
||||
}
|
|
@ -1,47 +1,143 @@
|
|||
pragma solidity ^0.5.0;
|
||||
import './openzeppelin-solidity/contracts/token/ERC20/IERC20.sol';
|
||||
|
||||
contract SharedDB {
|
||||
uint32 threshold;
|
||||
uint32 parties;
|
||||
uint32 signupKeygenID;
|
||||
uint32 signupKeygenCurrent;
|
||||
uint32 signupSignID;
|
||||
uint32 signupSignCurrent;
|
||||
mapping(bytes32 => string) public db;
|
||||
|
||||
event SignupKeygen(address indexed from, uint32 uuid, uint32 number);
|
||||
event SignupSign(address indexed from, uint32 uuid, uint32 number);
|
||||
|
||||
constructor(uint32 _threshold, uint32 _parties) public {
|
||||
threshold = _threshold;
|
||||
parties = _parties;
|
||||
signupKeygenID = 1;
|
||||
signupSignID = 0x80000000;
|
||||
struct Validator {
|
||||
address addr;
|
||||
uint partyId;
|
||||
bytes32 next;
|
||||
}
|
||||
|
||||
function set(bytes32 key, string memory value) public {
|
||||
db[key] = value;
|
||||
event NewEpoch(uint indexed epoch);
|
||||
event KeygenCompleted(uint indexed epoch, uint x, uint y);
|
||||
event Signup(address indexed from, bytes32 indexed hash, uint epoch, uint partyId);
|
||||
|
||||
Validator validator;
|
||||
mapping(bytes32 => Validator) public dbValidator;
|
||||
mapping(bytes32 => bytes) public dbKeygen;
|
||||
mapping(bytes32 => uint) public confirmationsCount;
|
||||
mapping(bytes32 => bytes) public dbSign;
|
||||
mapping(bytes32 => uint) public signupsCount;
|
||||
mapping(bytes32 => bool) public confirmations;
|
||||
mapping(bytes32 => uint) public dbSignups;
|
||||
|
||||
uint public x;
|
||||
uint public y;
|
||||
|
||||
bool public ready;
|
||||
|
||||
mapping(uint => uint) public threshold;
|
||||
mapping(uint => uint) public parties;
|
||||
|
||||
uint public epoch;
|
||||
|
||||
constructor(uint32 _threshold, uint32 _parties, address[] memory validators, address _tokenContract) public {
|
||||
require(_parties > 0);
|
||||
require(_threshold < _parties);
|
||||
require(validators.length == _parties);
|
||||
|
||||
tokenContract = IERC20(_tokenContract);
|
||||
|
||||
epoch = 1;
|
||||
ready = false;
|
||||
|
||||
threshold[epoch] = _threshold;
|
||||
parties[epoch] = _parties;
|
||||
// First validator
|
||||
validator = Validator(validators[0], 1, 0);
|
||||
setValidator(validators[0], validator);
|
||||
|
||||
// Other validators
|
||||
for (uint i = 1; i < _parties; i++) {
|
||||
setValidator(validators[i], Validator(validators[i], i + 1, 0));
|
||||
// Link to prev one
|
||||
Validator storage v = getValidator(validators[i - 1]);
|
||||
v.next = keccak256(abi.encodePacked(epoch, validators[i]));
|
||||
}
|
||||
|
||||
emit NewEpoch(epoch);
|
||||
}
|
||||
|
||||
function signupKeygen() public {
|
||||
if (signupKeygenCurrent < parties) {
|
||||
signupKeygenCurrent++;
|
||||
}
|
||||
else {
|
||||
signupKeygenID++;
|
||||
signupKeygenCurrent = 1;
|
||||
}
|
||||
emit SignupKeygen(msg.sender, signupKeygenID, signupKeygenCurrent);
|
||||
IERC20 public tokenContract;
|
||||
|
||||
event ReceivedTokens(address from, string recipient, uint value);
|
||||
|
||||
function requestAffirmation(uint value, string memory recipient) public {
|
||||
tokenContract.transferFrom(msg.sender, address(this), value);
|
||||
|
||||
emit ReceivedTokens(msg.sender, recipient, value);
|
||||
}
|
||||
|
||||
function signupSign() public {
|
||||
if (signupSignCurrent < threshold + 1) {
|
||||
signupSignCurrent++;
|
||||
function confirm(uint _x, uint _y) public {
|
||||
Validator storage v = getValidator(msg.sender);
|
||||
require(v.partyId != 0);
|
||||
require(!confirmations[keccak256(abi.encodePacked(epoch, v.partyId, _x, _y))]);
|
||||
|
||||
confirmations[keccak256(abi.encodePacked(epoch, v.partyId, _x, _y))] = true;
|
||||
if (++confirmationsCount[keccak256(abi.encodePacked(epoch, _x, _y))] == parties[epoch]) {
|
||||
x = _x;
|
||||
y = _y;
|
||||
ready = true;
|
||||
emit KeygenCompleted(epoch, x, y);
|
||||
}
|
||||
else {
|
||||
signupSignID++;
|
||||
signupSignCurrent = 1;
|
||||
}
|
||||
emit SignupSign(msg.sender, signupSignID, signupSignCurrent);
|
||||
}
|
||||
|
||||
function setKeygenData(bytes32 key, bytes memory data) public {
|
||||
Validator storage v = getValidator(msg.sender);
|
||||
require(v.partyId != 0);
|
||||
require(!ready);
|
||||
|
||||
dbKeygen[keccak256(abi.encodePacked(epoch, key, v.partyId))] = data;
|
||||
}
|
||||
|
||||
function getKeygenData(uint fromPartyId, bytes32 key) view public returns (bytes memory) {
|
||||
return dbKeygen[keccak256(abi.encodePacked(epoch, key, fromPartyId))];
|
||||
}
|
||||
|
||||
function signupSign(bytes32 hash) public {
|
||||
signupSign(hash, epoch);
|
||||
}
|
||||
|
||||
function signupSign(bytes32 hash, uint _epoch) public {
|
||||
Validator storage v = getValidator(msg.sender, _epoch);
|
||||
require(v.partyId != 0);
|
||||
require(ready);
|
||||
require(signupsCount[keccak256(abi.encodePacked(_epoch, hash))] <= threshold[_epoch], "Already enough signers");
|
||||
//require(confirmationsCount[keccak256(abi.encodePacked(_epoch, x, y))] == parties[_epoch]); == ready
|
||||
|
||||
dbSignups[keccak256(abi.encodePacked(_epoch, hash, v.partyId))] = ++signupsCount[keccak256(abi.encodePacked(_epoch, hash))];
|
||||
|
||||
emit Signup(msg.sender, hash, _epoch, signupsCount[keccak256(abi.encodePacked(_epoch, hash))]);
|
||||
}
|
||||
|
||||
function setSignData(bytes32 hash, bytes32 key, bytes memory data) public {
|
||||
Validator storage v = getValidator(msg.sender);
|
||||
require(v.partyId != 0);
|
||||
require(ready);
|
||||
uint signupId = dbSignups[keccak256(abi.encodePacked(epoch, hash, v.partyId))];
|
||||
require(signupId != 0);
|
||||
|
||||
dbSign[keccak256(abi.encodePacked(epoch, hash, signupId, key))] = data;
|
||||
}
|
||||
|
||||
function getSignData(uint signupId, bytes32 hash, bytes32 key) view public returns (bytes memory) {
|
||||
//uint id = dbSignups[keccak256(abi.encodePacked(epoch, hash, fromPartyId))];
|
||||
return dbSign[keccak256(abi.encodePacked(epoch, hash, signupId, key))];
|
||||
}
|
||||
|
||||
function setValidator(address a, Validator memory v) private {
|
||||
dbValidator[keccak256(abi.encodePacked(epoch, a))] = v;
|
||||
}
|
||||
|
||||
function getValidator(address a) view private returns (Validator storage) {
|
||||
return getValidator(a, epoch);
|
||||
}
|
||||
|
||||
function getValidator(address a, uint kv) view private returns (Validator storage) {
|
||||
return dbValidator[keccak256(abi.encodePacked(kv, a))];
|
||||
}
|
||||
|
||||
function getPartyId() view public returns (uint) {
|
||||
return getValidator(msg.sender).partyId;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Subproject commit c9f328ef66251db7fac7c704dd6c5523fc53b0ab
|
|
@ -1,9 +1,25 @@
|
|||
require('dotenv').config()
|
||||
|
||||
const Migrations = artifacts.require('SharedDB')
|
||||
const SharedDB = artifacts.require('SharedDB')
|
||||
|
||||
const { THRESHOLD, PARTIES } = process.env
|
||||
const {
|
||||
THRESHOLD, PARTIES, VALIDATOR_ADDRESS_1, VALIDATOR_ADDRESS_2, VALIDATOR_ADDRESS_3, VALIDATOR_ADDRESS_4,
|
||||
VALIDATOR_ADDRESS_5, VALIDATOR_ADDRESS_6, TOKEN_ADDRESS
|
||||
} = process.env
|
||||
|
||||
module.exports = deployer => {
|
||||
deployer.deploy(Migrations, THRESHOLD, PARTIES)
|
||||
deployer.deploy(
|
||||
SharedDB,
|
||||
THRESHOLD,
|
||||
PARTIES,
|
||||
[
|
||||
VALIDATOR_ADDRESS_1,
|
||||
VALIDATOR_ADDRESS_2,
|
||||
VALIDATOR_ADDRESS_3,
|
||||
//VALIDATOR_ADDRESS_4,
|
||||
//VALIDATOR_ADDRESS_5,
|
||||
//VALIDATOR_ADDRESS_6
|
||||
],
|
||||
TOKEN_ADDRESS
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
const Web3 = require('web3')
|
||||
|
||||
const web3 = new Web3('https://sokol.poa.network')
|
||||
|
||||
async function main () {
|
||||
console.log(await web3.eth.getBalance('0x48138BEC745673Fe2CE28C62c9944Ab0Fa56b495'))
|
||||
}
|
||||
|
||||
main()
|
|
@ -1,14 +1,25 @@
|
|||
THRESHOLD=2
|
||||
PARTIES=6
|
||||
THRESHOLD=1
|
||||
PARTIES=3
|
||||
|
||||
KEY_FILE=keys.store
|
||||
|
||||
#RPC_URL=https://sokol.poa.network
|
||||
RPC_URL=http://host.docker.internal:7545
|
||||
RPC_URL_DEV=http://127.0.0.1:7545
|
||||
|
||||
SHARED_DB_ADDRESS=0x213b9cF674ef08E1E30A55f679Dfa55a16494975
|
||||
SHARED_DB_ADDRESS=0x94b40CC641Ed7db241A1f04C8896ba6f6cC36b85
|
||||
TOKEN_ADDRESS=0x44c158FE850821ae69DaF37AADF5c539e9d0025B
|
||||
|
||||
#VALIDATOR_PRIVATE_KEY=d1e7b8ff274e517e1a332f2bc0ac051e30db196ba31c68c2efcd022e8ec358f1
|
||||
VALIDATOR_PRIVATE_KEY=72c16a6812258f999190ccb11ff8bfc1e9f07438c8411f8840dbbe18137785e2
|
||||
VALIDATOR_PRIVATE_KEY=2be3f252e16541bf1bb2d4a517d2bf173e6d09f2d765d32c64dc50515aec63ea
|
||||
|
||||
#SSM_URL=http://127.0.0.1:8001
|
||||
|
||||
LOCAL=true
|
||||
|
||||
#MESSAGE=fb2487601395e1cabad725e2e006ae16dd134a536ea1e30919b86e7aa572584d
|
||||
|
||||
DEPLOY_PRIVATE_KEY=e2aeb24eaa63102d0c0821717c3b6384abdabd7af2ad4ec8e650dce300798b27
|
||||
|
||||
FOREIGN_URL=https://testnet-dex.binance.org/
|
||||
FOREIGN_CHAIN_ID=Binance-Chain-Nile
|
||||
|
|
|
@ -1,135 +0,0 @@
|
|||
version: '3.7'
|
||||
services:
|
||||
proxy1:
|
||||
image: blockchain-proxy
|
||||
build: ./proxy
|
||||
environment:
|
||||
- RPC_URL
|
||||
- SHARED_DB_ADDRESS
|
||||
- VALIDATOR_PRIVATE_KEY=e2c1349f1d13f22cd011a9cfef7007388b8df16a6e1f318517cb93dbadcd9c2e
|
||||
volumes:
|
||||
- '../deploy/build/contracts:/proxy/contracts_data'
|
||||
networks:
|
||||
- keygen-proxy-net1
|
||||
proxy2:
|
||||
image: blockchain-proxy
|
||||
build: ./proxy
|
||||
environment:
|
||||
- RPC_URL
|
||||
- SHARED_DB_ADDRESS
|
||||
- VALIDATOR_PRIVATE_KEY=7562a3ea655c2aad92a819069d334e7cf6edc9d2ae0fcc9a6498bd38842fafd4
|
||||
volumes:
|
||||
- '../deploy/build/contracts:/proxy/contracts_data'
|
||||
networks:
|
||||
- keygen-proxy-net2
|
||||
proxy3:
|
||||
image: blockchain-proxy
|
||||
build: ./proxy
|
||||
environment:
|
||||
- RPC_URL
|
||||
- SHARED_DB_ADDRESS
|
||||
- VALIDATOR_PRIVATE_KEY=955b1f58a207160459e3be344e8a9cae2c3db47a0cb8275eb771a51da84de244
|
||||
volumes:
|
||||
- '../deploy/build/contracts:/proxy/contracts_data'
|
||||
networks:
|
||||
- keygen-proxy-net3
|
||||
proxy4:
|
||||
image: blockchain-proxy
|
||||
build: ./proxy
|
||||
environment:
|
||||
- RPC_URL
|
||||
- SHARED_DB_ADDRESS
|
||||
- VALIDATOR_PRIVATE_KEY=a1c08300192fdd27aa92cd836ca98601c35184319c6873b1d1478f21cdb1c867
|
||||
volumes:
|
||||
- '../deploy/build/contracts:/proxy/contracts_data'
|
||||
networks:
|
||||
- keygen-proxy-net4
|
||||
proxy5:
|
||||
image: blockchain-proxy
|
||||
build: ./proxy
|
||||
environment:
|
||||
- RPC_URL
|
||||
- SHARED_DB_ADDRESS
|
||||
- VALIDATOR_PRIVATE_KEY=3aef900c61246653308ed0770f3bd67a1c21342cf2a7dbf0ee5bcc787b627de0
|
||||
volumes:
|
||||
- '../deploy/build/contracts:/proxy/contracts_data'
|
||||
networks:
|
||||
- keygen-proxy-net5
|
||||
proxy6:
|
||||
image: blockchain-proxy
|
||||
build: ./proxy
|
||||
environment:
|
||||
- RPC_URL
|
||||
- SHARED_DB_ADDRESS
|
||||
- VALIDATOR_PRIVATE_KEY=abe7f999209549463e7da719eddd6bb3e00fe77832f5166c1e57d067452954b6
|
||||
volumes:
|
||||
- '../deploy/build/contracts:/proxy/contracts_data'
|
||||
networks:
|
||||
- keygen-proxy-net6
|
||||
keygen1:
|
||||
image: keygen-client
|
||||
build: ./tss-keygen
|
||||
command: 'http://proxy1:8001'
|
||||
volumes:
|
||||
- './keys1.store:/tss/keys.store'
|
||||
- './params:/tss/params'
|
||||
networks:
|
||||
- keygen-proxy-net1
|
||||
keygen2:
|
||||
image: keygen-client
|
||||
build: ./tss-keygen
|
||||
command: 'http://proxy2:8001'
|
||||
volumes:
|
||||
- './keys2.store:/tss/keys.store'
|
||||
- './params:/tss/params'
|
||||
networks:
|
||||
- keygen-proxy-net2
|
||||
keygen3:
|
||||
image: keygen-client
|
||||
build: ./tss-keygen
|
||||
command: 'http://proxy3:8001'
|
||||
volumes:
|
||||
- './keys3.store:/tss/keys.store'
|
||||
- './params:/tss/params'
|
||||
networks:
|
||||
- keygen-proxy-net3
|
||||
keygen4:
|
||||
image: keygen-client
|
||||
build: ./tss-keygen
|
||||
command: 'http://proxy4:8001'
|
||||
environment:
|
||||
- SKIP_SIGN=true
|
||||
volumes:
|
||||
- './keys4.store:/tss/keys.store'
|
||||
- './params:/tss/params'
|
||||
networks:
|
||||
- keygen-proxy-net4
|
||||
keygen5:
|
||||
image: keygen-client
|
||||
build: ./tss-keygen
|
||||
command: 'http://proxy5:8001'
|
||||
environment:
|
||||
- SKIP_SIGN=true
|
||||
volumes:
|
||||
- './keys5.store:/tss/keys.store'
|
||||
- './params:/tss/params'
|
||||
networks:
|
||||
- keygen-proxy-net5
|
||||
keygen6:
|
||||
image: keygen-client
|
||||
build: ./tss-keygen
|
||||
command: 'http://proxy6:8001'
|
||||
environment:
|
||||
- SKIP_SIGN=true
|
||||
volumes:
|
||||
- './keys6.store:/tss/keys.store'
|
||||
- './params:/tss/params'
|
||||
networks:
|
||||
- keygen-proxy-net6
|
||||
networks:
|
||||
keygen-proxy-net1:
|
||||
keygen-proxy-net2:
|
||||
keygen-proxy-net3:
|
||||
keygen-proxy-net4:
|
||||
keygen-proxy-net5:
|
||||
keygen-proxy-net6:
|
|
@ -1,24 +0,0 @@
|
|||
version: '3.7'
|
||||
services:
|
||||
proxy:
|
||||
image: blockchain-proxy
|
||||
build: ./proxy
|
||||
environment:
|
||||
- RPC_URL
|
||||
- SHARED_DB_ADDRESS
|
||||
- VALIDATOR_PRIVATE_KEY
|
||||
volumes:
|
||||
- '../deploy/build/contracts:/proxy/contracts_data'
|
||||
networks:
|
||||
- keygen-proxy-net
|
||||
keygen:
|
||||
image: keygen-client
|
||||
build: ./tss-keygen
|
||||
command: 'http://proxy:8001'
|
||||
volumes:
|
||||
- './${KEY_FILE}:/tss/keys.store'
|
||||
- './params:/tss/params'
|
||||
networks:
|
||||
- keygen-proxy-net
|
||||
networks:
|
||||
keygen-proxy-net:
|
|
@ -1,7 +1,78 @@
|
|||
version: '3.7'
|
||||
services:
|
||||
sign-client:
|
||||
proxy:
|
||||
image: blockchain-proxy
|
||||
build: ./proxy
|
||||
environment:
|
||||
- RPC_URL
|
||||
- SHARED_DB_ADDRESS
|
||||
- VALIDATOR_PRIVATE_KEY
|
||||
volumes:
|
||||
- '../deploy/build/contracts:/proxy/contracts_data'
|
||||
networks:
|
||||
- sign-proxy-net
|
||||
- keygen-proxy-net
|
||||
keygen:
|
||||
image: keygen-client
|
||||
build: ./tss-keygen
|
||||
environment:
|
||||
- 'RABBITMQ_URL=amqp://rabbitmq:5672'
|
||||
- 'PROXY_URL=http://proxy:8001'
|
||||
volumes:
|
||||
- '${PWD}/keys:/keys'
|
||||
networks:
|
||||
- keygen-proxy-net
|
||||
- rabbit-keygen-net
|
||||
- redis-keygen-net
|
||||
signer:
|
||||
image: sign-client
|
||||
build:
|
||||
context: .
|
||||
dockerfile:
|
||||
build: ./tss-sign
|
||||
environment:
|
||||
- 'RABBITMQ_URL=amqp://rabbitmq:5672'
|
||||
- 'PROXY_URL=http://proxy:8001'
|
||||
- FOREIGN_CHAIN_ID
|
||||
- FOREIGN_URL
|
||||
volumes:
|
||||
- '${PWD}/keys:/keys'
|
||||
networks:
|
||||
- sign-proxy-net
|
||||
- rabbit-signer-net
|
||||
- redis-signer-net
|
||||
redis:
|
||||
image: redis:5.0.5-alpine
|
||||
volumes:
|
||||
- '${PWD}/db:/data'
|
||||
networks:
|
||||
- redis-signer-net
|
||||
- redis-keygen-net
|
||||
- redis-watcher-net
|
||||
rabbitmq:
|
||||
hostname: rabbit
|
||||
image: rabbitmq:3.7.15-alpine
|
||||
volumes:
|
||||
- '${PWD}/queue:/var/lib/rabbitmq/mnesia'
|
||||
networks:
|
||||
- rabbit-signer-net
|
||||
- rabbit-keygen-net
|
||||
- rabbit-watcher-net
|
||||
eth-watcher:
|
||||
build: ./watcher
|
||||
image: eth-watcher
|
||||
environment:
|
||||
- 'HOME_RPC_URL=${RPC_URL}'
|
||||
- 'HOME_BRIDGE_ADDRESS=${SHARED_DB_ADDRESS}'
|
||||
- 'RABBITMQ_URL=amqp://rabbitmq:5672'
|
||||
volumes:
|
||||
- '../deploy/build/contracts:/watcher/contracts_data'
|
||||
networks:
|
||||
- rabbit-watcher-net
|
||||
- redis-watcher-net
|
||||
networks:
|
||||
sign-proxy-net:
|
||||
keygen-proxy-net:
|
||||
rabbit-signer-net:
|
||||
rabbit-keygen-net:
|
||||
rabbit-watcher-net:
|
||||
redis-keygen-net:
|
||||
redis-signer-net:
|
||||
redis-watcher-net:
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
cd $(dirname "$0")
|
||||
|
||||
set -o allexport
|
||||
source ./.env
|
||||
set +o allexport
|
||||
|
||||
echo Writing params
|
||||
echo \{\"parties\":\""$PARTIES"\",\"threshold\":\""$THRESHOLD"\"\} > ./params
|
||||
|
||||
if [[ -z "$LOCAL" ]]; then
|
||||
echo Building tss source from git
|
||||
docker build -t tss ../tss > /dev/null
|
||||
else
|
||||
echo Building tss local source
|
||||
docker build -t tss -f ../tss/Dockerfile-local ../tss > /dev/null
|
||||
fi
|
||||
|
||||
echo Building tss keygen client
|
||||
docker build -t tss-keygen-client ./tss-keygen > /dev/null
|
||||
|
||||
for (( i = 1 ; i <= $PARTIES ; i++ )) do
|
||||
touch keys"$i".store
|
||||
done
|
||||
|
||||
docker-compose -f ./docker-compose-keygen-all.yml kill $(eval echo proxy{1..${PARTIES}})
|
||||
|
||||
echo Running keygen
|
||||
docker-compose -f ./docker-compose-keygen-all.yml up $@
|
|
@ -1,30 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
cd $(dirname "$0")
|
||||
|
||||
set -o allexport
|
||||
source ./.env
|
||||
set +o allexport
|
||||
|
||||
echo Writing params
|
||||
echo \{\"parties\":\""$PARTIES"\",\"threshold\":\""$THRESHOLD"\"\} > ./params
|
||||
|
||||
if [[ -z "$LOCAL" ]]; then
|
||||
echo Building tss source from git
|
||||
docker build -t tss ../tss > /dev/null
|
||||
else
|
||||
echo Building tss local source
|
||||
docker build -t tss -f ../tss/Dockerfile-local ../tss > /dev/null
|
||||
fi
|
||||
|
||||
echo Building tss keygen client
|
||||
docker build -t tss-keygen-client ./tss-keygen > /dev/null
|
||||
|
||||
touch "$KEY_FILE"
|
||||
|
||||
docker-compose -f ./docker-compose-keygen.yml kill proxy
|
||||
|
||||
echo Running keygen
|
||||
docker-compose -f ./docker-compose-keygen.yml up $@
|
|
@ -1,5 +1,8 @@
|
|||
const express = require('express')
|
||||
const Web3 = require('web3')
|
||||
const fs = require('fs')
|
||||
const BN = require('bignumber.js')
|
||||
const ethers = require('ethers')
|
||||
|
||||
const { RPC_URL, SHARED_DB_ADDRESS, VALIDATOR_PRIVATE_KEY } = process.env
|
||||
const abi = require('./contracts_data/SharedDB.json').abi
|
||||
|
@ -15,14 +18,22 @@ app.use(express.json())
|
|||
app.use(express.urlencoded({ extended: true }))
|
||||
|
||||
app.post('/get', get)
|
||||
|
||||
app.post('/set', set)
|
||||
app.post('/signupkeygen', signupKeygen)
|
||||
app.post('/signupsign', signupSign)
|
||||
|
||||
app.get('/params', params)
|
||||
app.post('/confirm', confirm)
|
||||
|
||||
async function main () {
|
||||
validatorNonce = await web3.eth.getTransactionCount(validatorAddress)
|
||||
|
||||
try {
|
||||
fs.mkdirSync('/generated_data')
|
||||
} catch (e) {
|
||||
|
||||
}
|
||||
|
||||
app.listen(8001, () => {
|
||||
console.log('Listening on port 8001')
|
||||
})
|
||||
|
@ -32,26 +43,41 @@ function Ok (data) {
|
|||
return { Ok: data }
|
||||
}
|
||||
|
||||
function hash (key) {
|
||||
return web3.utils.sha3(JSON.stringify(key))
|
||||
function Err (data) {
|
||||
return { Err: data }
|
||||
}
|
||||
|
||||
async function get (req, res) {
|
||||
console.log('Get call')
|
||||
while (true) {
|
||||
const result = await contract.methods.db(hash(req.body.key)).call()
|
||||
if (result !== '') {
|
||||
res.send(Ok({ key: req.body.key, value: result }))
|
||||
break
|
||||
}
|
||||
const uuid = req.body.key.third
|
||||
const from = parseInt(req.body.key.first)
|
||||
const to = Number(req.body.key.fourth)
|
||||
const key = web3.utils.sha3(`${req.body.key.second}_${to}`)
|
||||
|
||||
const data = await (uuid.startsWith('k')
|
||||
? contract.methods.getKeygenData(from, key).call()
|
||||
: contract.methods.getSignData(from, uuid, key).call())
|
||||
|
||||
const result = web3.utils.hexToUtf8(data)
|
||||
if (result.length)
|
||||
res.send(Ok({ key: req.body.key, value: result }))
|
||||
else {
|
||||
setTimeout(() => res.send(Err(null)), 1000)
|
||||
}
|
||||
|
||||
console.log('Get end')
|
||||
}
|
||||
|
||||
async function set (req, res) {
|
||||
console.log('Set call')
|
||||
const query = contract.methods.set(hash(req.body.key), req.body.value)
|
||||
const uuid = req.body.key.third
|
||||
const to = Number(req.body.key.fourth)
|
||||
const key = web3.utils.sha3(`${req.body.key.second}_${to}`)
|
||||
|
||||
const query = uuid.startsWith('k') ? contract.methods.setKeygenData(key, web3.utils.utf8ToHex(req.body.value))
|
||||
: contract.methods.setSignData(uuid, key, web3.utils.utf8ToHex(req.body.value))
|
||||
await sendQuery(query)
|
||||
fs.writeFileSync(`/generated_data/${req.body.key.first}_${req.body.key.second}_${req.body.key.third}_${req.body.key.fourth}.json`, req.body.value)
|
||||
|
||||
res.send(Ok(null))
|
||||
console.log('Set end')
|
||||
|
@ -59,44 +85,54 @@ async function set (req, res) {
|
|||
|
||||
async function signupKeygen (req, res) {
|
||||
console.log('SignupKeygen call')
|
||||
const query = contract.methods.signupKeygen()
|
||||
const receipt = await sendQuery(query)
|
||||
const epoch = (await contract.methods.epoch().call()).toNumber()
|
||||
const partyId = (await contract.methods.getPartyId().call({ from: validatorAddress })).toNumber()
|
||||
|
||||
while (true) {
|
||||
const events = await contract.getPastEvents('SignupKeygen', {
|
||||
filter: { from: validatorAddress },
|
||||
fromBlock: receipt.blockNumber,
|
||||
toBlock: receipt.blockNumber
|
||||
})
|
||||
const event = events[0]
|
||||
|
||||
if (event) {
|
||||
res.send(Ok({ uuid: event.returnValues.uuid.toString(), number: event.returnValues.number }))
|
||||
break
|
||||
}
|
||||
}
|
||||
res.send(Ok({ uuid: `k${epoch}`, number: partyId }))
|
||||
console.log('SignupKeygen end')
|
||||
}
|
||||
|
||||
async function signupSign (req, res) {
|
||||
console.log('SignupSign call')
|
||||
const query = contract.methods.signupSign()
|
||||
console.log(req.body.third)
|
||||
const hash = web3.utils.sha3(`0x${req.body.third}`)
|
||||
const query = contract.methods.signupSign(hash)
|
||||
const receipt = await sendQuery(query)
|
||||
|
||||
while (true) {
|
||||
const events = await contract.getPastEvents('SignupSign', {
|
||||
filter: { from: validatorAddress },
|
||||
const events = await contract.getPastEvents('Signup', {
|
||||
filter: { from: validatorAddress, hash },
|
||||
fromBlock: receipt.blockNumber,
|
||||
toBlock: receipt.blockNumber
|
||||
})
|
||||
const event = events[0]
|
||||
|
||||
if (event) {
|
||||
res.send(Ok({ uuid: event.returnValues.uuid.toString(), number: event.returnValues.number }))
|
||||
res.send(Ok({ uuid: hash, number: event.returnValues.partyId.toNumber() }))
|
||||
break
|
||||
}
|
||||
}
|
||||
console.log('SignupSign call')
|
||||
console.log('SignupSign end')
|
||||
}
|
||||
|
||||
async function confirm (req, res) {
|
||||
console.log('Confirm call')
|
||||
const { x, y } = req.body[5]
|
||||
const query = contract.methods.confirm(`0x${x}`, `0x${y}`)
|
||||
await sendQuery(query)
|
||||
//const addr = `0x${web3.utils.sha3(`0x${x}${y}`).substring(26)}`
|
||||
//console.log(addr)
|
||||
res.send()
|
||||
console.log('Confirm end')
|
||||
}
|
||||
|
||||
async function params (req, res) {
|
||||
console.log('Params call')
|
||||
const epoch = parseInt(req.query.epoch)
|
||||
const parties = (await contract.methods.parties(epoch).call()).toNumber().toString()
|
||||
const threshold = (await contract.methods.threshold(epoch).call()).toNumber().toString()
|
||||
res.send({ parties, threshold })
|
||||
console.log('Params end')
|
||||
}
|
||||
|
||||
async function sendQuery (query) {
|
||||
|
@ -108,7 +144,7 @@ async function sendQuery (query) {
|
|||
nonce: validatorNonce++,
|
||||
chainId: 33
|
||||
}
|
||||
tx.gas = await query.estimateGas(tx)
|
||||
tx.gas = Math.min(Math.ceil(await query.estimateGas(tx) * 1.5), 6721975)
|
||||
const signedTx = await web3.eth.accounts.signTransaction(tx, VALIDATOR_PRIVATE_KEY)
|
||||
|
||||
const receipt = await web3.eth.sendSignedTransaction(signedTx.rawTransaction)
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
"dependencies": {
|
||||
"web3": "1.0.0-beta.55",
|
||||
"dotenv": "8.0.0",
|
||||
"express": "4.17.1"
|
||||
"express": "4.17.1",
|
||||
"bignumber.js": "9.0.0",
|
||||
"ethers": "4.0.31"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
require('dotenv').config()
|
||||
|
||||
const Web3 = require('web3')
|
||||
|
||||
const { RPC_URL_DEV, SHARED_DB_ADDRESS, DEPLOY_PRIVATE_KEY, TOKEN_ADDRESS } = process.env
|
||||
const web3 = new Web3(RPC_URL_DEV, null, { transactionConfirmationBlocks: 1 })
|
||||
const abiBridge = require('../deploy/build/contracts/SharedDB').abi
|
||||
const abiToken = require('../deploy/build/contracts/IERC20').abi
|
||||
const bridge = new web3.eth.Contract(abiBridge, SHARED_DB_ADDRESS)
|
||||
const token = new web3.eth.Contract(abiToken, TOKEN_ADDRESS)
|
||||
|
||||
const query1 = token.methods.approve(SHARED_DB_ADDRESS, 1)
|
||||
const query2 = bridge.methods.requestAffirmation(1, 'tbnb1h3nmmqukrtjc0prmtdts0kxlgmw8rend4zfasn')
|
||||
|
||||
let nonce
|
||||
const deployAddress = web3.eth.accounts.privateKeyToAccount(`0x${DEPLOY_PRIVATE_KEY}`).address
|
||||
|
||||
async function main () {
|
||||
console.log(deployAddress)
|
||||
nonce = await web3.eth.getTransactionCount(deployAddress)
|
||||
await sendQuery(query1, TOKEN_ADDRESS)
|
||||
await sendQuery(query2, SHARED_DB_ADDRESS)
|
||||
}
|
||||
|
||||
async function sendQuery (query, to) {
|
||||
const encodedABI = query.encodeABI()
|
||||
const tx = {
|
||||
data: encodedABI,
|
||||
from: deployAddress,
|
||||
to,
|
||||
nonce: nonce++,
|
||||
chainId: 33
|
||||
}
|
||||
tx.gas = Math.min(Math.ceil(await query.estimateGas(tx) * 1.5), 6721975)
|
||||
const signedTx = await web3.eth.accounts.signTransaction(tx, DEPLOY_PRIVATE_KEY)
|
||||
|
||||
const receipt = await web3.eth.sendSignedTransaction(signedTx.rawTransaction)
|
||||
|
||||
return receipt
|
||||
}
|
||||
|
||||
main()
|
|
@ -0,0 +1,55 @@
|
|||
const Bnc = require('@binance-chain/javascript-sdk')
|
||||
const axios = require('axios')
|
||||
const Transaction = require('../oracle/tss-sign/tx')
|
||||
const crypto = require('crypto')
|
||||
const ecc = require('tiny-secp256k1')
|
||||
|
||||
const privKey = 'b92a59209e28149e5cee8e54dfceb80a08ea08e654261bdb9d264b15dee2525c'
|
||||
const asset = 'BNB'
|
||||
const amount = 2.5
|
||||
const addressTo = process.argv[2]
|
||||
const addressFrom = Bnc.crypto.getAddressFromPrivateKey(privKey)
|
||||
const message = 'A note to you'
|
||||
const api = 'https://testnet-dex.binance.org/'
|
||||
|
||||
|
||||
|
||||
const httpClient = axios.create({ baseURL: api })
|
||||
httpClient
|
||||
.get(`/api/v1/account/${addressFrom}`)
|
||||
.then((res) => {
|
||||
const { sequence } = res.data
|
||||
const tx = new Transaction('tbnb1h3nmmqukrtjc0prmtdts0kxlgmw8rend4zfasn', 674629, sequence, process.argv[2], amount, 'BNB', 'test')
|
||||
const hash = crypto.createHash('sha256').update(tx.getSignBytes()).digest('hex')
|
||||
console.log(tx.getSignBytes().toString('hex'))
|
||||
console.log(hash)
|
||||
const signature = ecc.sign(Buffer.from(hash, 'hex'), Buffer.from('b92a59209e28149e5cee8e54dfceb80a08ea08e654261bdb9d264b15dee2525c', 'hex'))
|
||||
const sig = {
|
||||
r: signature.toString('hex').substr(0, 64),
|
||||
s: signature.toString('hex').substr(64, 64)
|
||||
}
|
||||
console.log(sig)
|
||||
const publicKey = {
|
||||
x: 'b32b5ea8698156239ea7092ef8a44a4b711ea29525da34a8233bdc0dd3af7f1a',
|
||||
y: '6b5b77f2e925f93cae7fc894ff50bafcb7b6e6e96e339c96e41663ccaf0a4d68'
|
||||
}
|
||||
return tx.addSignature(publicKey, sig)
|
||||
})
|
||||
.then(signed => {
|
||||
console.log('sending')
|
||||
return httpClient.post(`/api/v1/broadcast?sync=true`, signed, {
|
||||
headers: {
|
||||
'content-type': 'text/plain'
|
||||
}
|
||||
})
|
||||
})
|
||||
.then((result) => {
|
||||
if (result.status === 200) {
|
||||
console.log('success', result.data)
|
||||
} else {
|
||||
console.error('error', result)
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('error', error)
|
||||
})
|
|
@ -1,12 +0,0 @@
|
|||
FROM ubuntu:19.10
|
||||
|
||||
WORKDIR /tss
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y libssl1.1 libssl-dev curl
|
||||
|
||||
COPY params /tss/
|
||||
|
||||
COPY --from=tss /tss/target/release/gg18_sign_client /tss/
|
||||
|
||||
ENTRYPOINT ["./gg18_sign_client"]
|
|
@ -1,13 +0,0 @@
|
|||
{
|
||||
"redis": {
|
||||
"port": 6379,
|
||||
"host": "127.0.0.1",
|
||||
"family": 4,
|
||||
"password": "auth",
|
||||
"db": 0
|
||||
},
|
||||
"eth": {
|
||||
"rpcUrl": "https://sokol.poa.network",
|
||||
"pollingInterval": 5000
|
||||
}
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
import Web3 from 'web3'
|
||||
import { eth } from 'config'
|
||||
import {get, set} from 'db'
|
||||
|
||||
const {rpcUrl, pollingInterval} = eth
|
||||
|
||||
const web3 = new Web3(rpcUrl)
|
||||
|
||||
async function main () {
|
||||
const lastProcessedBlock = await get('lastProcessedBlock')
|
||||
|
||||
try {
|
||||
const block = await web3.eth.getBlock(lastProcessedBlock + 1)
|
||||
block.transactions.forEach(transaction => {
|
||||
|
||||
})
|
||||
} catch (e) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
setInterval(main, pollingInterval)
|
|
@ -1,32 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
cd $(dirname "$0")
|
||||
|
||||
if [[ -z "$SKIP_ENV" ]]; then
|
||||
set -o allexport
|
||||
source ../.env
|
||||
set +o allexport
|
||||
fi
|
||||
|
||||
echo Writing params
|
||||
echo \{\"parties\":\""$PARTIES"\",\"threshold\":\""$THRESHOLD"\"\} > ./params
|
||||
|
||||
if [[ -z "$LOCAL" ]]; then
|
||||
echo Building tss source from git
|
||||
docker build -t tss ../../tss > /dev/null
|
||||
else
|
||||
echo Building tss local source
|
||||
docker build -t tss -f ../../tss/Dockerfile-local ../../tss > /dev/null
|
||||
fi
|
||||
|
||||
echo Building tss sign client
|
||||
docker build -t tss-sign-client . > /dev/null
|
||||
|
||||
touch signature
|
||||
|
||||
echo Signing message using ssm server at "$SSM_URL"
|
||||
docker run --rm -v "$(cd ..; pwd)/$KEY_FILE:/tss/keys.store" -v "$(pwd)/signature:/tss/signature" --network host tss-sign-client "$SSM_URL" keys.store "$1"
|
||||
|
||||
echo Signed message
|
|
@ -1,12 +1,18 @@
|
|||
FROM ubuntu:19.10
|
||||
FROM node:10.16.0-slim
|
||||
|
||||
WORKDIR /tss
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y libssl1.1 libssl-dev curl
|
||||
|
||||
COPY keygen-entrypoint.sh /tss/
|
||||
COPY package.json /tss/
|
||||
|
||||
COPY --from=tss /tss/target/release/gg18_keygen_client /tss/target/release/gg18_sign_client /tss/
|
||||
RUN npm install
|
||||
|
||||
ENTRYPOINT ["./keygen-entrypoint.sh"]
|
||||
COPY keygen-entrypoint.sh keygen.js /tss/
|
||||
|
||||
COPY --from=tss /tss/target/release/gg18_keygen_client /tss/
|
||||
|
||||
RUN mkdir /keys
|
||||
|
||||
ENTRYPOINT ["node", "keygen.js"]
|
||||
|
|
|
@ -8,20 +8,16 @@ until curl "$1" > /dev/null 2>&1; do
|
|||
sleep 1;
|
||||
done
|
||||
|
||||
#curl "$1"
|
||||
echo "Fetching current tss params"
|
||||
|
||||
curl -X GET "$1/params?epoch=$3" -o ./params > /dev/null 2>&1
|
||||
|
||||
echo "Generating key using server $1"
|
||||
|
||||
./gg18_keygen_client "$1" keys.store
|
||||
./gg18_keygen_client "$1" "$2"
|
||||
|
||||
echo "Generated keys for all parties"
|
||||
|
||||
echo "Signing message"
|
||||
echo "Sending confirmation"
|
||||
|
||||
if [[ -z "$SKIP_SIGN" ]]; then
|
||||
|
||||
./gg18_sign_client "$1" keys.store some_message
|
||||
|
||||
echo "Signed message"
|
||||
|
||||
fi
|
||||
curl -X POST -H "Content-Type: application/json" -d @"$2" "$1/confirm" > /dev/null 2>&1
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
const exec = require('child_process')
|
||||
const fs = require('fs')
|
||||
const crypto = require('crypto')
|
||||
const bech32 = require('bech32')
|
||||
const amqp = require('amqplib')
|
||||
|
||||
const { RABBITMQ_URL, PROXY_URL } = process.env
|
||||
|
||||
async function main () {
|
||||
console.log('Connecting to RabbitMQ server')
|
||||
const connection = await connectRabbit(RABBITMQ_URL)
|
||||
console.log('Connecting to epoch events queue')
|
||||
const channel = await connection.createConfirmChannel()
|
||||
const queue = await channel.assertQueue('epochQueue')
|
||||
|
||||
channel.prefetch(1)
|
||||
channel.consume(queue.queue, msg => {
|
||||
const data = JSON.parse(msg.content)
|
||||
console.log(`Consumed new epoch event, starting keygen for epoch ${data.epoch}`)
|
||||
|
||||
const keysFile = `/keys/keys${data.epoch}.store`
|
||||
|
||||
console.log('Running ./keygen-entrypoint.sh')
|
||||
const cmd = exec.execFile('./keygen-entrypoint.sh', [PROXY_URL, keysFile, data.epoch], () => {
|
||||
console.log('Finished keygen')
|
||||
const publicKey = JSON.parse(fs.readFileSync(keysFile).toString())[5]
|
||||
console.log(`Generated multisig account in binance chain: ${publicKeyToAddress(publicKey)}`)
|
||||
channel.ack(msg)
|
||||
})
|
||||
cmd.stdout.on('data', data => console.log(data.toString()))
|
||||
cmd.stderr.on('data', data => console.error(data.toString()))
|
||||
})
|
||||
}
|
||||
|
||||
main()
|
||||
|
||||
async function connectRabbit (url) {
|
||||
return amqp.connect(url).catch(() => {
|
||||
console.log('Failed to connect, reconnecting')
|
||||
return new Promise(resolve =>
|
||||
setTimeout(() => resolve(connectRabbit(url)), 1000)
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
function publicKeyToAddress({x, y}) {
|
||||
const compact = (parseInt(y[63], 16) % 2 ? '03' : '02') + x
|
||||
const sha256Hash = crypto.createHash('sha256').update(Buffer.from(compact, 'hex')).digest('hex')
|
||||
const hash = crypto.createHash('ripemd160').update(Buffer.from(sha256Hash, 'hex')).digest('hex')
|
||||
const words = bech32.toWords(Buffer.from(hash, 'hex'))
|
||||
return bech32.encode('tbnb', words)
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
cd $(dirname "$0")
|
||||
|
||||
set -o allexport
|
||||
source ../.env
|
||||
set +o allexport
|
||||
|
||||
echo Writing params
|
||||
echo \{\"parties\":\""$PARTIES"\",\"threshold\":\""$THRESHOLD"\"\} > ./params
|
||||
|
||||
if [[ -z "$LOCAL" ]]; then
|
||||
echo Building tss source from git
|
||||
docker build -t tss ../../tss > /dev/null
|
||||
else
|
||||
echo Building tss local source
|
||||
docker build -t tss -f ../../tss/Dockerfile-local ../../tss > /dev/null
|
||||
fi
|
||||
|
||||
echo Building tss keygen client
|
||||
docker build -t tss-keygen-client . > /dev/null
|
||||
|
||||
touch ../"$KEY_FILE"
|
||||
|
||||
echo Generating keys using ssm server at "$SSM_URL"
|
||||
docker run --rm -v "$(cd ..; pwd)/$KEY_FILE:/tss/keys.store" --network host tss-keygen-client "$SSM_URL"
|
||||
|
||||
echo ==========================================================
|
||||
|
||||
echo All keys generated, ready to test sign
|
||||
|
||||
if [[ -z "$SKIP_SIGN" ]]; then
|
||||
sleep 3
|
||||
|
||||
SKIP_ENV=true ../tss-client/sign.sh test_message
|
||||
|
||||
echo Signed successful
|
||||
fi
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"name": "tss-keygen",
|
||||
"version": "0.0.1",
|
||||
"dependencies": {
|
||||
"amqplib": "0.5.3",
|
||||
"bech32": "1.1.3"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
FROM node:10.16.0-slim
|
||||
|
||||
WORKDIR /tss
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y libssl1.1 libssl-dev curl python make g++ libudev-dev libusb-dev usbutils
|
||||
#apk packages: libssl1.1 eudev-dev libressl-dev curl build-base python linux-headers libusb-dev
|
||||
|
||||
COPY package.json /tss/
|
||||
|
||||
RUN npm install --no-optional
|
||||
|
||||
COPY sign-entrypoint.sh signer.js tx.js /tss/
|
||||
|
||||
COPY --from=tss /tss/target/release/gg18_sign_client /tss/
|
||||
|
||||
ENTRYPOINT ["node", "signer.js"]
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"name": "tss-sign",
|
||||
"version": "0.0.1",
|
||||
"dependencies": {
|
||||
"@binance-chain/javascript-sdk": "2.13.9",
|
||||
"amqplib": "0.5.3",
|
||||
"axios": "0.19.0"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
echo "Connecting to $1"
|
||||
|
||||
until curl "$1" > /dev/null 2>&1; do
|
||||
sleep 1;
|
||||
done
|
||||
|
||||
echo "Fetching current tss params"
|
||||
|
||||
curl -X GET "$1/params?epoch=$3" -o ./params > /dev/null 2>&1
|
||||
|
||||
echo "Signing message using server $1"
|
||||
|
||||
./gg18_sign_client "$1" "$2" "$4"
|
||||
|
||||
echo "Signed message"
|
|
@ -0,0 +1,186 @@
|
|||
const exec = require('child_process')
|
||||
const fs = require('fs')
|
||||
const amqp = require('amqplib')
|
||||
const crypto = require('crypto')
|
||||
const bech32 = require('bech32')
|
||||
|
||||
const { RABBITMQ_URL, FOREIGN_URL, PROXY_URL } = process.env
|
||||
const Transaction = require('./tx')
|
||||
const axios = require('axios')
|
||||
|
||||
const httpClient = axios.create({ baseURL: FOREIGN_URL })
|
||||
|
||||
async function main () {
|
||||
console.log('Connecting to RabbitMQ server')
|
||||
const connection = await connectRabbit(RABBITMQ_URL)
|
||||
console.log('Connecting to signature events queue')
|
||||
const channel = await connection.createConfirmChannel()
|
||||
const queue = await channel.assertQueue('signQueue')
|
||||
|
||||
channel.prefetch(1)
|
||||
channel.consume(queue.queue, async msg => {
|
||||
const data = JSON.parse(msg.content)
|
||||
|
||||
console.log('Consumed sign event')
|
||||
console.log(data)
|
||||
const { recipient, value, nonce, epoch } = data
|
||||
const keysFile = `/keys/keys${epoch}.store`
|
||||
|
||||
console.log(`Reading ${keysFile}`)
|
||||
const { address, publicKey } = await getAccountFromFile(keysFile)
|
||||
console.log(`Tx from ${address}`)
|
||||
|
||||
console.log('Getting account data')
|
||||
const account = await getAccount(address)
|
||||
|
||||
console.log(`Building corresponding transaction, nonce ${nonce}, recipient ${recipient}`)
|
||||
const tx = new Transaction(address, account.account_number, nonce, recipient, value, 'BNB')
|
||||
const hash = crypto.createHash('sha256').update(tx.getSignBytes()).digest('hex')
|
||||
|
||||
console.log(`Starting signature generation for transaction hash ${hash}`)
|
||||
const cmd = exec.execFile('./sign-entrypoint.sh', [PROXY_URL, keysFile, epoch, hash], async () => {
|
||||
console.log('Finished signature generation')
|
||||
const signature = JSON.parse(fs.readFileSync('signature'))
|
||||
console.log(signature)
|
||||
|
||||
console.log('Building signed transaction')
|
||||
const signedTx = tx.addSignature(publicKey, { r: signature[1], s: signature[3] })
|
||||
|
||||
console.log('Sending transaction')
|
||||
console.log(signedTx)
|
||||
await sendTx(signedTx)
|
||||
|
||||
channel.ack(msg)
|
||||
})
|
||||
cmd.stdout.on('data', data => console.log(data.toString()))
|
||||
cmd.stderr.on('data', data => console.error(data.toString()))
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
main()
|
||||
|
||||
async function connectRabbit (url) {
|
||||
return amqp.connect(url).catch(() => {
|
||||
console.log('Failed to connect, reconnecting')
|
||||
return new Promise(resolve =>
|
||||
setTimeout(() => resolve(connectRabbit(url)), 1000)
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
async function getAccountFromFile (file) {
|
||||
while (!fs.existsSync(file)) {
|
||||
console.log('Waiting for needed epoch key')
|
||||
await new Promise(resolve => setTimeout(resolve, 1000))
|
||||
}
|
||||
const publicKey = JSON.parse(fs.readFileSync(file))[5]
|
||||
return {
|
||||
address: publicKeyToAddress(publicKey),
|
||||
publicKey: publicKey
|
||||
}
|
||||
}
|
||||
|
||||
async function getAccount (address) {
|
||||
return httpClient
|
||||
.get(`/api/v1/account/${address}`)
|
||||
.then(res => res.data)
|
||||
}
|
||||
|
||||
async function sendTx (tx) {
|
||||
return httpClient
|
||||
.post(`/api/v1/broadcast?sync=true`, tx, {
|
||||
headers: {
|
||||
'Content-Type': 'text/plain'
|
||||
}
|
||||
})
|
||||
.then(x => console.log(x.response), x => console.log(x.response))
|
||||
}
|
||||
|
||||
function buildTx (acc, nonce, to, value) {
|
||||
const tx = new Transaction({
|
||||
account_number: acc.account_number,
|
||||
chain_id: 'Binance-Chain-Nile',
|
||||
memo: '',
|
||||
msg: {
|
||||
'inputs': [
|
||||
{
|
||||
'coins': [
|
||||
{
|
||||
'denom': 'BNB',
|
||||
'amount': value.toString()
|
||||
}
|
||||
],
|
||||
'address': acc.address
|
||||
}
|
||||
],
|
||||
'outputs': [
|
||||
{
|
||||
'address': to,
|
||||
'coins': [
|
||||
{
|
||||
'denom': 'BNB',
|
||||
'amount': value.toString()
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
type: 'MsgSend',
|
||||
sequence: nonce
|
||||
})
|
||||
return tx.getSignBytes(tx.msgs[0])
|
||||
}
|
||||
|
||||
function buildSignedTx (acc, publicKey, nonce, to, value, signature) {
|
||||
const tx = new Transaction({
|
||||
account_number: acc.account_number,
|
||||
chain_id: 'Binance-Chain-Nile',
|
||||
memo: '',
|
||||
msg: {
|
||||
'inputs': [
|
||||
{
|
||||
'coins': [
|
||||
{
|
||||
'denom': 'BNB',
|
||||
'amount': value.toString()
|
||||
}
|
||||
],
|
||||
'address': acc.address
|
||||
}
|
||||
],
|
||||
'outputs': [
|
||||
{
|
||||
'address': to,
|
||||
'coins': [
|
||||
{
|
||||
'denom': 'BNB',
|
||||
'amount': value.toString()
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
type: 'MsgSend',
|
||||
sequence: nonce
|
||||
})
|
||||
tx.signatures = [{
|
||||
pub_key: Buffer.from(publicKey, 'hex', 38),
|
||||
signature: Buffer.concat([Buffer.from(signature[1], 'hex', 32), Buffer.from(signature[3], 'hex', 32)]),
|
||||
account_number: acc.account_number,
|
||||
sequence: nonce
|
||||
}]
|
||||
return tx
|
||||
}
|
||||
|
||||
function encodePublicKey ({ x, y }) {
|
||||
return 'eb5ae98721' + (parseInt(y[63], 16) % 2 ? '03' : '02') + x
|
||||
}
|
||||
|
||||
function publicKeyToAddress ({ x, y }) {
|
||||
const compact = (parseInt(y[63], 16) % 2 ? '03' : '02') + x
|
||||
const sha256Hash = crypto.createHash('sha256').update(Buffer.from(compact, 'hex')).digest('hex')
|
||||
const hash = crypto.createHash('ripemd160').update(Buffer.from(sha256Hash, 'hex')).digest('hex')
|
||||
const words = bech32.toWords(Buffer.from(hash, 'hex'))
|
||||
return bech32.encode('tbnb', words)
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
const TransactionBnc = require('@binance-chain/javascript-sdk/lib/tx').default
|
||||
const { crypto } = require('@binance-chain/javascript-sdk')
|
||||
const BN = require('bn.js')
|
||||
|
||||
const { FOREIGN_CHAIN_ID } = process.env
|
||||
|
||||
class Transaction {
|
||||
constructor (fromAddress, accountNumber, sequence, toAddress, amount, asset, memo = 'test') {
|
||||
const accCode = crypto.decodeAddress(fromAddress)
|
||||
const toAccCode = crypto.decodeAddress(toAddress)
|
||||
|
||||
amount *= 10 ** 8
|
||||
|
||||
const coin = {
|
||||
denom: asset,
|
||||
amount: amount,
|
||||
}
|
||||
|
||||
const msg = {
|
||||
inputs: [{
|
||||
address: accCode,
|
||||
coins: [coin]
|
||||
}],
|
||||
outputs: [{
|
||||
address: toAccCode,
|
||||
coins: [coin]
|
||||
}],
|
||||
msgType: 'MsgSend'
|
||||
}
|
||||
|
||||
this.signMsg = {
|
||||
inputs: [{
|
||||
address: fromAddress,
|
||||
coins: [{
|
||||
amount: amount,
|
||||
denom: asset
|
||||
}]
|
||||
}],
|
||||
outputs: [{
|
||||
address: toAddress,
|
||||
coins: [{
|
||||
amount: amount,
|
||||
denom: asset
|
||||
}]
|
||||
}]
|
||||
}
|
||||
|
||||
const options = {
|
||||
account_number: accountNumber,
|
||||
chain_id: FOREIGN_CHAIN_ID,
|
||||
memo: memo,
|
||||
msg,
|
||||
sequence,
|
||||
type: msg.msgType,
|
||||
}
|
||||
this.tx = new TransactionBnc(options)
|
||||
}
|
||||
|
||||
getSignBytes () {
|
||||
return this.tx.getSignBytes(this.signMsg)
|
||||
}
|
||||
|
||||
addSignature (publicKey, signature) {
|
||||
const yLast = parseInt(publicKey.y[publicKey.y.length - 1], 16)
|
||||
const n = new BN('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141', 16)
|
||||
const s = new BN(signature.s, 16)
|
||||
if (s.gt(n.divn(2))) {
|
||||
console.log('Normalizing s')
|
||||
signature.s = n.sub(s).toString(16)
|
||||
}
|
||||
const publicKeyEncoded = Buffer.from('eb5ae98721' + (yLast % 2 ? '03' : '02') + padZeros(publicKey.x, 64), 'hex')
|
||||
this.tx.signatures = [{
|
||||
pub_key: publicKeyEncoded,
|
||||
signature: Buffer.from(padZeros(signature.r, 64) + padZeros(signature.s, 64), 'hex'),
|
||||
account_number: this.tx.account_number,
|
||||
sequence: this.tx.sequence,
|
||||
}]
|
||||
return this.tx.serialize()
|
||||
}
|
||||
}
|
||||
|
||||
function padZeros (s, len) {
|
||||
while (s.length < len)
|
||||
s = '0' + s
|
||||
return s
|
||||
}
|
||||
|
||||
module.exports = Transaction
|
|
@ -0,0 +1,14 @@
|
|||
FROM node:10.16.0-alpine
|
||||
|
||||
WORKDIR /watcher
|
||||
|
||||
RUN apk update && \
|
||||
apk add libssl1.1 libressl-dev curl
|
||||
|
||||
COPY package.json /watcher/
|
||||
|
||||
RUN npm install
|
||||
|
||||
COPY ethWatcher.js db.js /watcher/
|
||||
|
||||
ENTRYPOINT ["node", "ethWatcher.js"]
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"sideChain": {
|
||||
"rpcUrl": "http://host.docker.internal:7545"
|
||||
},
|
||||
"redis": {
|
||||
"port": 6379,
|
||||
"host": "127.0.0.1",
|
||||
"family": 4,
|
||||
"password": "password",
|
||||
"db": 0
|
||||
},
|
||||
"home": {
|
||||
"rpcUrl": "http://host.docker.internal:7545",
|
||||
"pollingInterval": 1000
|
||||
},
|
||||
"foreign": {
|
||||
"api": "https://testnet-dex.binance.org/",
|
||||
"pollingInterval": 1000
|
||||
}
|
||||
}
|
|
@ -1,9 +1,14 @@
|
|||
import Redis from 'ioredis'
|
||||
import { redis as redisConfig } from 'config'
|
||||
const Redis = require('ioredis')
|
||||
|
||||
console.log('Connecting to redis')
|
||||
|
||||
const redis = Redis(redisConfig)
|
||||
const redis = new Redis({
|
||||
port: 6379,
|
||||
host: 'redis',
|
||||
family: 4,
|
||||
password: 'password',
|
||||
db: 0
|
||||
})
|
||||
|
||||
redis.on('connect', () => {
|
||||
console.log('Connected to redis')
|
||||
|
@ -13,5 +18,4 @@ redis.on('error', () => {
|
|||
console.log('Redis error')
|
||||
})
|
||||
|
||||
export const get = redis.get
|
||||
export const set = redis.set
|
||||
module.exports = redis
|
|
@ -0,0 +1,126 @@
|
|||
const amqp = require('amqplib')
|
||||
const Web3 = require('web3')
|
||||
const redis = require('./db')
|
||||
const bridgeAbi = require('./contracts_data/SharedDB.json').abi
|
||||
|
||||
const { HOME_RPC_URL, HOME_BRIDGE_ADDRESS, RABBITMQ_URL } = process.env
|
||||
|
||||
const web3Home = new Web3(HOME_RPC_URL)
|
||||
const homeBridge = new web3Home.eth.Contract(bridgeAbi, HOME_BRIDGE_ADDRESS)
|
||||
|
||||
let channel
|
||||
let signQueue
|
||||
let epochQueue
|
||||
let blockNumber
|
||||
let foreignNonce = []
|
||||
let epoch
|
||||
|
||||
async function connectRabbit (url) {
|
||||
return amqp.connect(url).catch(() => {
|
||||
console.log('Failed to connect, reconnecting')
|
||||
return new Promise(resolve =>
|
||||
setTimeout(() => resolve(connectRabbit(url)), 1000)
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
async function initialize () {
|
||||
const connection = await connectRabbit(RABBITMQ_URL)
|
||||
channel = await connection.createChannel()
|
||||
signQueue = await channel.assertQueue('signQueue')
|
||||
epochQueue = await channel.assertQueue('epochQueue')
|
||||
|
||||
const events = await homeBridge.getPastEvents('KeygenCompleted', {
|
||||
fromBlock: 1
|
||||
})
|
||||
epoch = events.length ? events[events.length - 1].returnValues.epoch.toNumber() : 0
|
||||
console.log(`Current epoch ${epoch}`)
|
||||
const dbEpoch = parseInt(await redis.get('epoch')) // number, or NaN if empty
|
||||
if (epoch !== dbEpoch) {
|
||||
console.log('Current epoch is outdated, starting from new epoch and block number')
|
||||
blockNumber = events.length ? events[events.length - 1].blockNumber : 1
|
||||
await redis.multi()
|
||||
.set('epoch', epoch)
|
||||
.set('homeBlock', blockNumber - 1)
|
||||
.set(`foreignNonce${epoch}`, 0)
|
||||
.exec()
|
||||
foreignNonce[epoch] = 0
|
||||
} else {
|
||||
console.log('Restoring epoch and block number from local db')
|
||||
blockNumber = (parseInt(await redis.get('homeBlock')) + 1) || 1
|
||||
foreignNonce[epoch] = parseInt(await redis.get(`foreignNonce${epoch}`)) || 0
|
||||
}
|
||||
}
|
||||
|
||||
// By design, epoch change needs last epoch to be confirmed
|
||||
// Each transfer needs last epoch to be confirmed too
|
||||
async function main () {
|
||||
console.log(`Watching events in block #${blockNumber}`)
|
||||
if (await web3Home.eth.getBlock(blockNumber) === null) {
|
||||
await new Promise(r => setTimeout(r, 1000))
|
||||
return
|
||||
}
|
||||
|
||||
const events = await homeBridge.getPastEvents('allEvents', {
|
||||
fromBlock: blockNumber,
|
||||
toBlock: blockNumber
|
||||
})
|
||||
const epochEvents = events.filter(x => x.event === 'NewEpoch')
|
||||
const transferEvents = events.filter(x => x.event === 'ReceivedTokens')
|
||||
|
||||
epochEvents.forEach(event => {
|
||||
const newEpoch = event.returnValues.epoch.toNumber()
|
||||
const oldEpoch = newEpoch - 1
|
||||
channel.sendToQueue(epochQueue.queue, Buffer.from(JSON.stringify({
|
||||
epoch: newEpoch
|
||||
})), {
|
||||
persistent: true
|
||||
})
|
||||
console.log('Sent new epoch event')
|
||||
|
||||
if (oldEpoch > 0) {
|
||||
channel.sendToQueue(signQueue.queue, Buffer.from(JSON.stringify({
|
||||
epoch: oldEpoch,
|
||||
nonce: foreignNonce[oldEpoch],
|
||||
})), {
|
||||
persistent: true
|
||||
})
|
||||
console.log('Sent new epoch sign event')
|
||||
|
||||
foreignNonce[oldEpoch]++
|
||||
redis.incr(`foreignNonce${oldEpoch}`)
|
||||
}
|
||||
|
||||
redis.multi()
|
||||
.incr('epoch')
|
||||
.set(`foreignNonce${newEpoch}`, 0)
|
||||
.exec()
|
||||
foreignNonce[newEpoch] = 0
|
||||
epoch++
|
||||
}
|
||||
)
|
||||
|
||||
transferEvents.forEach(event => {
|
||||
channel.sendToQueue(signQueue.queue, Buffer.from(JSON.stringify({
|
||||
recipient: event.returnValues.recipient,
|
||||
value: event.returnValues.value.toNumber(),
|
||||
epoch,
|
||||
nonce: foreignNonce[epoch]
|
||||
})), {
|
||||
persistent: true
|
||||
})
|
||||
console.log('Sent new sign event')
|
||||
|
||||
redis.incr(`foreignNonce${epoch}`)
|
||||
foreignNonce[epoch]++
|
||||
}
|
||||
)
|
||||
await redis.incr('homeBlock')
|
||||
blockNumber++
|
||||
}
|
||||
|
||||
initialize().then(async () => {
|
||||
while (true) {
|
||||
await main()
|
||||
}
|
||||
})
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"name": "watcher",
|
||||
"version": "0.0.1",
|
||||
"dependencies": {
|
||||
"ioredis": "4.10.0",
|
||||
"amqplib": "0.5.3",
|
||||
"web3": "1.0.0-beta.55"
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue