Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add: topwallet and whitelist on celo #385

Merged
merged 23 commits into from
Oct 3, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
357a877
add: topwallet and whitelist on celo
sirpy Sep 21, 2022
8068ad4
add refactor multi wallet, remove mainnet wallet from celo
johnsmith-gooddollar Sep 26, 2022
7ec20eb
remove chainid hardcode from multi wallet
johnsmith-gooddollar Sep 26, 2022
b6f663f
add remove some other celo hardcode
johnsmith-gooddollar Sep 26, 2022
5a78b1c
add fix imports
johnsmith-gooddollar Sep 26, 2022
960c290
add adjust lint config, lint fixes
johnsmith-gooddollar Sep 27, 2022
f92372d
add small fix
johnsmith-gooddollar Sep 27, 2022
8b39638
Merge branch 'master' into add-celo
johnsmith-gooddollar Sep 27, 2022
3fa5514
add fix startup errors (part 1)
johnsmith-gooddollar Sep 27, 2022
36279cb
add fix startup errors (part 2)
johnsmith-gooddollar Sep 27, 2022
89a9abc
add updte protocol, removie workarounds, add aggregated ready to Mutl…
johnsmith-gooddollar Sep 28, 2022
a8ad9c5
Merge branch 'master' into add-celo
johnsmith-gooddollar Sep 28, 2022
a5f468e
add fix FV tests
johnsmith-gooddollar Sep 28, 2022
74aef4e
fix storage tests
johnsmith-gooddollar Sep 29, 2022
3398556
add dapptest-celo reference (commented temporarily)
johnsmith-gooddollar Sep 29, 2022
36c4d4a
Update .env.test
johnsmith-gooddollar Sep 29, 2022
d7a9eba
fix: exclude celowallet from running on tests
sirpy Sep 29, 2022
cb931c5
add reduce Web3Wallet constructor args, remove celo wallet auto init …
johnsmith-gooddollar Sep 29, 2022
ee7a937
Merge branch 'master' into add-celo
johnsmith-gooddollar Sep 29, 2022
bd749ad
Merge branch 'master' into add-celo
johnsmith-gooddollar Sep 29, 2022
97a5b45
Merge branch 'master' into add-celo
johnsmith-gooddollar Sep 29, 2022
7447977
fix: blockchain tests
sirpy Sep 29, 2022
a72569a
fix: adminwallet tests
sirpy Sep 29, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .env.test
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ PORT=3004
NODE_ENV=test
GUNDB_PASS=password
GUNDB_SERVERMODE=true
#MNEMONIC="myth like bonus scare over problem client lizard pioneer submit female collect"
# MNEMONIC="myth like bonus scare over problem client lizard pioneer submit female collect"
MNEMONIC="test test test test test test test test test test test junk"
NETWORK=dapptest
LOG_LEVEL=debug
Expand Down
14 changes: 14 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -1,15 +1,29 @@
{
"extends": [
"eslint:recommended",
"plugin:node/recommended",
"plugin:flowtype/recommended",
"plugin:import/recommended",
"plugin:prettier/recommended",
"prettier",
"prettier/babel",
"prettier/flowtype"
],
"parserOptions": {
"ecmaVersion": 2020
},
"plugins": ["dependencies", "flowtype", "import", "prettier", "jest"],
"settings": {},
"env": {
"jest/globals": true
},
"rules": {
"node/no-unpublished-import": "off",
"node/no-extraneous-import": "off",
"node/no-deprecated-api": "off",
"no-console": "off",
"no-process-exit": "off",
"node/no-unsupported-features/es-syntax": "off",
"prettier/prettier": "error",
"dependencies/no-cycles": "error",
"dependencies/no-unresolved": [
Expand Down
27,055 changes: 13,430 additions & 13,625 deletions package-lock.json

Large diffs are not rendered by default.

8 changes: 6 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@
"prod": "npm start -- --inspect --optimize_for_size --max_old_space_size=460 | pino-pretty -c -f -s \"msg!='request completed'\"",
"flow": "flow",
"docs": "node scripts/docs.js",
"version": "auto-changelog -p && git add CHANGELOG.md"
"version": "auto-changelog -p && git add CHANGELOG.md",
"lint": "eslint \"src/**/*.js\" --max-warnings=0",
"lint:fix": "npm run lint -- --fix"
},
"repository": {
"type": "git",
Expand All @@ -49,7 +51,7 @@
"@babel/polyfill": "^7.11.5",
"@babel/runtime": "^7.16.5",
"@gooddollar/goodcontracts": "^2.6.1",
"@gooddollar/goodprotocol": "^1.0.28",
"@gooddollar/goodprotocol": "^1.0.29-beta.3",
"@sendgrid/mail": "^6.5.5",
"@sentry/integrations": "^5.24.2",
"@sentry/node": "^5.24.2",
Expand Down Expand Up @@ -92,6 +94,7 @@
"multer": "^1.4.2",
"newrelic": "^5.13.1",
"passport": "^0.4.1",
"passport-anonymous": "^1.0.1",
"passport-jwt": "^4.0.0",
"pino": "^5.17.0",
"plivo": "^4.9.0",
Expand Down Expand Up @@ -137,6 +140,7 @@
"eslint-plugin-import": "^2.22.0",
"eslint-plugin-jest": "^23.20.0",
"eslint-plugin-jsx-a11y": "^6.3.1",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^3.1.4",
"file-loader": "^2.0.0",
"flow-bin": "^0.91.0",
Expand Down
2 changes: 0 additions & 2 deletions src/imports/facebookVerifier.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ import Config from '../server/server.config'
import logger from '../imports/logger'

class FacebookVerifier {
static factory(log = logger.child({ from: 'TorusVerifier' })) {}

constructor(Config, httpFactory, logger) {
const { facebookGraphApiUrl } = Config

Expand Down
30 changes: 15 additions & 15 deletions src/server/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import express from 'express'
import { EventEmitter } from 'events'

import middlewares from './server-middlewares'
import AdminWallet from './blockchain/AdminWallet'
import MultiWallet from './blockchain/MultiWallet'

import { withTimeout } from './utils/async'
import conf from './server.config'

Expand All @@ -11,24 +12,23 @@ import logger from '../imports/logger'
const log = logger.child({ from: 'startapp' })

EventEmitter.defaultMaxListeners = 100

// we're logging uncaught exceptions in logger monitor so just exiting process
process.on('uncaughtException', () => process.exit(-1))

const startApp = async () => {
await withTimeout(
AdminWallet.ready.then(() => {
log.info('AdminWallet ready', { addresses: AdminWallet.addresses })
}),
30000,
'wallet not initialized'
).catch(e => {
if (conf.env === 'test') {
return
}

console.log('wallet failed... quiting', e)
process.exit(-1)
})
await withTimeout(MultiWallet.ready, 30000, 'wallet not initialized')
.then(addresses => {
log.info('AdminWallet ready', { addresses })
})
.catch(e => {
if (conf.env === 'test') {
return
}

console.log('wallet failed... quiting', e)
process.exit(-1)
})

const app = express()

Expand Down
262 changes: 260 additions & 2 deletions src/server/blockchain/AdminWallet.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,260 @@
import { default as Wallet } from './AdminWalletV2'
export default Wallet
// @flow

import Crypto from 'crypto'
import Web3 from 'web3'
import { assign } from 'lodash'
import * as web3Utils from 'web3-utils'

import { Web3Wallet, getAuthHeader, web3Default, defaultGas, adminMinBalance } from './Web3Wallet'
import conf from '../server.config'
import { isNonceError, isFundsError } from '../utils/eth'
import { getManager } from '../utils/tx-manager'
import { sendSlackAlert } from '../../imports/slack'

const defaultRopstenGasPrice = web3Utils.toWei('5', 'gwei')

class AdminWallet extends Web3Wallet {
constructor(name, conf, options) {
super(name, conf, options)

this.networkIdMainnet = conf.ethereumMainnet.network_id
this.maxMainnetGasPrice = conf.maxGasPrice * 1000000000 // maxGasPrice is in gwei, convert to wei
}

addWallet(account) {
super.addWallet(account)
this.addWalletAccount(this.mainnetWeb3, account)
}

getMainnetWeb3TransportProvider(): HttpProvider | WebSocketProvider {
let provider
let web3Provider
let transport = this.conf.ethereumMainnet.web3Transport
const { log } = this

switch (transport) {
case 'WebSocket':
provider = this.conf.ethereumMainnet.websocketWeb3Provider
web3Provider = new Web3.providers.WebsocketProvider(provider)
break

default:
case 'HttpProvider': {
provider = this.conf.ethereumMainnet.httpWeb3Provider
const headers = getAuthHeader(provider)

web3Provider = new Web3.providers.HttpProvider(provider, { headers })
break
}
}

log.debug('mainnet', { web3Provider, provider })
return web3Provider
}

async init() {
const { log, conf } = this
const { ethereumMainnet, env } = conf

log.debug('Initializing wallet mainnet:', { mainnet: ethereumMainnet })

const mainnetWeb3 = new Web3(this.getMainnetWeb3TransportProvider(), null, web3Default)
const mainnetTxManager = getManager(ethereumMainnet.network_id)
const { eth } = mainnetWeb3
const mainnetAddresses = []

assign(mainnetTxManager, { getTransactionCount: eth.getTransactionCount })
assign(eth, web3Default, { transactionPollingTimeout: 600 }) // slow ropsten
assign(this, { mainnetWeb3, mainnetTxManager, mainnetAddresses })

await super.init()

if (env !== 'production') {
log.info('Initializing adminwallet mainnet addresses', { addresses: this.addresses })

await Promise.all(
this.addresses.map(async addr => {
const mainnetBalance = await mainnetWeb3.eth.getBalance(addr)

log.info(`try mainnnet address ${addr}:`, { mainnetBalance, adminMinBalance })

if (parseFloat(web3Utils.fromWei(mainnetBalance, 'gwei')) > adminMinBalance * 100) {
log.info(`admin wallet ${addr} mainnet balance ${mainnetBalance}`)
mainnetAddresses.push(addr)
}
})
)

log.info('Initialized adminwallet mainnet addresses', { mainnetAddresses })
await mainnetTxManager.createListIfNotExists(mainnetAddresses)
}

log.debug('AdminWallet mainnet Ready:', {
activeMainnetWallets: mainnetAddresses.length
})

return true
}

/**
* Helper function to handle a tx Send call
* @param tx
* @param {object} promiEvents
* @param {function} promiEvents.onTransactionHash
* @param {function} promiEvents.onReceipt
* @param {function} promiEvents.onConfirmation
* @param {function} promiEvents.onError
* @param {object} gasValues
* @param {number} gasValues.gas
* @param {number} gasValues.gasPrice
* @returns {Promise<Promise|Q.Promise<any>|Promise<*>|Promise<*>|Promise<*>|*>}
*/
async sendTransactionMainnet(
tx: any,
txCallbacks: PromiEvents = {},
{ gas, gasPrice }: GasValues = { gas: undefined, gasPrice: undefined },
forceAddress: string
) {
let currentAddress
const { log } = this

try {
const { onTransactionHash, onReceipt, onConfirmation, onError } = txCallbacks

gas =
gas ||
(await tx
.estimateGas()
.then(gas => gas + 200000) // buffer for proxy contract, reimburseGas?, and low gas unexpected failures
.catch(e => {
log.warn('Failed to estimate gas for tx mainnet', e.message, e)
return defaultGas
}))

// adminwallet contract might give wrong gas estimates, so if its more than block gas limit reduce it to default
if (gas > 8000000) {
gas = defaultGas
}

gasPrice = gasPrice || defaultRopstenGasPrice

const uuid = Crypto.randomBytes(5).toString('base64')

log.debug('getting tx lock mainnet:', { uuid, forceAddress })

const { nonce, release, fail, address } = await this.mainnetTxManager.lock(forceAddress || this.mainnetAddresses)

log.debug('got tx lock mainnet:', { uuid, address, forceAddress })

let balance = NaN

if (this.conf.env === 'development') {
balance = await this.mainnetWeb3.eth.getBalance(address)
}

currentAddress = address

log.debug(`sending tx mainnet from: ${address} | nonce: ${nonce}`, {
network: this.networkIdMainNet,
uuid,
balance,
gas,
gasPrice
})

return new Promise((res, rej) => {
tx.send({
gas,
gasPrice,
nonce,
from: address
})
.on('transactionHash', h => {
release()

log.debug('got tx hash mainnet:', { txhash: h, uuid })

if (onTransactionHash) {
onTransactionHash(h)
}
})
.on('receipt', r => {
log.debug('got tx receipt mainnet:', { uuid })

if (onReceipt) {
onReceipt(r)
}

res(r)
})
.on('confirmation', c => {
if (onConfirmation) {
onConfirmation(c)
}
})
.on('error', async exception => {
const { message } = exception

if (isFundsError(exception)) {
balance = await this.mainnetWeb3.eth.getBalance(address)

log.warn('sendTransaciton funds issue retry mainnet', {
errMessage: message,
nonce,
gas,
gasPrice,
address,
balance,
uuid
})

sendSlackAlert({ msg: 'admin account funds low mainnet', address, balance })
await this.mainnetTxManager.unlock(address)

try {
await this.sendTransaction(tx, txCallbacks, { gas, gasPrice }).then(res)
} catch (e) {
await this.mainnetTxManager.unlock(address)
rej(e)
}
} else if (isNonceError(exception)) {
let netNonce = parseInt(await this.mainnetWeb3.eth.getTransactionCount(address))

log.warn('sendTransaciton nonce failure retry mainnet', {
errMessage: message,
nonce,
gas,
gasPrice,
address,
newNonce: netNonce,
uuid
})

await this.mainnetTxManager.unlock(address, netNonce)

try {
await this.sendTransactionMainnet(tx, txCallbacks, { gas, gasPrice }, forceAddress).then(res)
} catch (e) {
await this.mainnetTxManager.unlock(address)
rej(e)
}
} else {
fail()

if (onError) {
onError(exception)
}

log.error('sendTransaction error mainnet:', message, exception, { from: address, uuid })
rej(exception)
}
})
})
} catch (e) {
await this.mainnetTxManager.unlock(currentAddress)
throw new Error(e)
}
}
}

export default new AdminWallet('AdminWallet', conf)
Loading