diff --git a/client/.env.example b/client/.env.example new file mode 100644 index 0000000..d9d0281 --- /dev/null +++ b/client/.env.example @@ -0,0 +1,30 @@ +# Client Configuration + +# Values set for local development +DEBUG=1 +RPC='http://localhost:8545' +ROOT_URL='https://localhost:3100/' +SERVER_NETWORK='eth-ganache' +ASSET_MANAGER_GANACHE=0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0 + +# Mandatory Values +IPFS_GATEWAY='https://ipfs.infura.io/ipfs/{{hash}}' + + +# Default Values (can be omitted) +GAS_PRICE=1000 +EXPLORER_URL='https://explorer.harmony.one/#/tx/{{txId}}' +SERVER_URL='https://localhost:8443' +SERVER_SECRET='none' + +# TRANSAK Information + +## TRANSAK Staging +TRANSAK_STAGING_API_KEY: '12a1a123-1234-1234-a123-12345ab12a12' +TRANSAK_STAGING_DEFAULT_CURRENCY: 'USD' +TRANSAK_STAGING_ENVIRONMENT: 'STAGING' + +## TRANSAK Production +TRANSAK_PRODUCTION_API_KEY: '12a1a123-1234-1234-a123-12345ab12a12' +TRANSAK_PRODUCTION_DEFAULT_CURRENCY: 'USD' +TRANSAK_PRODUCTION_ENVIRONMENT: 'PRODUCTION' \ No newline at end of file diff --git a/client/src/config.js b/client/src/config.js index 8a4e6f0..1691b1c 100644 --- a/client/src/config.js +++ b/client/src/config.js @@ -19,14 +19,14 @@ const config = { network: process.env.SERVER_NETWORK || 'harmony', transak: { staging: { - apiKey: '50f1c430-7807-4760-a337-57583de69f73', - defaultCurrency: 'USD', - environment: 'STAGING' + apiKey: process.env.TRANSAK_STAGING_API_KEY, + defaultCurrency: process.env.TRANSAK_STAGING_DEFAULT_CURRENCY || 'USD', + environment: process.env.TRANSAK_STAGING_ENVIRONMENT || 'STAGING' }, production: { - apiKey: '28c4ba82-b701-4d05-a44c-1466fbb99265', - defaultCurrency: 'USD', - environment: 'PRODUCTION' + apiKey: process.env.TRANSAK_PRODUCTION_API_KEY, + defaultCurrency: process.env.TRANSAK_PRODUCTION_DEFAULT_CURRENCY || 'USD', + environment: process.env.TRANSAK_PRODUCTION_ENVIRONMENT || 'PRODUCTION' }, currencies: ['USD', 'NZD', 'AUD', 'EUR', 'GBP', 'CHF', 'SEK', 'PLN', 'NOK', 'MXN', 'DKK', 'CAD', 'ARS', 'BRL', 'CLP', 'CRC', 'DOP', 'IDR', 'ILS', 'JPY', 'KRW', 'MYR', 'PYG', 'PEN', 'PHP', 'SGD', 'ZAR', 'TZS', 'THB', 'TRY', 'BBD', 'BMD', 'BGN', 'HRK', 'CZK', 'FKP', 'FJD', 'GIP', 'HUF', 'ISK', 'JMD', 'KES', 'MDL', 'RON'], countries: [ diff --git a/demo/.env.example b/demo/.env.example new file mode 100644 index 0000000..5b34dbe --- /dev/null +++ b/demo/.env.example @@ -0,0 +1,4 @@ +DEBUG=1 +SERVER_URL=https://localhost:8343 +CLIENT_URL=https://localhost:3100 +ASSET_MANAGER_GANACHE=0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0 \ No newline at end of file diff --git a/server/.env.example b/server/.env.example new file mode 100644 index 0000000..9c7e12b --- /dev/null +++ b/server/.env.example @@ -0,0 +1,70 @@ +# Server Configuration + +## Configurable (set these values to change default behaviour for local testing) +#RELAYER_DEBUG=1 +#VERBOSE=1 +#SAFE_NONCE=1 + +## Mandatory +CORS=* +SECRET='none' + +# Datastore +GCP_PROJECT='sms-wallet-server' +GCP_CRED_PATH='./credentials/sms-wallet-server-credentials.json' +GCP_NAMESPACE='sms-wallet-server' + +# Twilio +TWILIO_ACCOUNT_SID=ACab1ab1ab1ab1ab1ab1ab1ab1ab1ab1ab +TWILIO_AUTH_TOKEN=1ab11ab11ab1ab1ab1ab1ab1ab1ab1ab +TWILIO_FROM=+11231231234 + +# OTP +OTP_SALT='local-salt' + +# Client +CLIENT_ROOT='https://localhost:3100/' + +## Netork Information + +# eth-ganache +GANACHE_RPC='http://localhost:8545' +GANACHE_WSS='ws://localhost:8545' +ETH_GANACHE_KEY='<>' +ETH_GANACHE_MNEMONIC='test test test test test test test test test test test junk' +#SKIP_GANACHE=0 +GANACHE_NUM_ACCOUNTS=1 +GANACHE_ASSET_MANAGER=0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0 + +# Harmony Testnet +HARMONY_TESTNET_KEY='<>' +TESTNET_RPC='https://api.s0.b.hmny.io' +TESTNET_WSS='wss://ws.s0.pga.hmny.io/' +HARMONY_TESTNET_MNEMONIC='NOT USED' +SKIP_TESTNET=1 +TESTNET_NUM_ACCOUNTS=1 +TESTNET_ASSET_MANAGER=0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0 + +# Harmony Mainnet +HARMONY_MAINNET_KEY='<>' +BEACON_MAINNET_RPC='https://api.s0.t.hmny.io/' +MAINNET_RPC='https://api.s0.t.hmny.io/' +MAINNET_WSS='wss://ws.s0.t.hmny.io/' +HARMONY_MAINNET_MNEMONIC='NOT USED' +SKIP_MAINNET=1 +MAINNET_NUM_ACCOUNTS=1 +MAINNET_ASSET_MANAGER=0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0 + + + +## Default Values (can be ommitted) +RELAYER_ID='unknown' +pollingInterval=1000 +DEFAULT_NETWORK='harmony-mainnet' +GAS_LIMIT='12345678' +GAS_PRICE='200' +CACHE='cache' +STATS_PATH='../data/stats.json' +OTP_INTERVAL=60000 + + diff --git a/server/app.js b/server/app.js index cb6bd4c..75d3d52 100644 --- a/server/app.js +++ b/server/app.js @@ -14,6 +14,7 @@ const https = require('https') const http = require('http') const env = process.env.NODE_ENV || 'development' const fs = require('fs') +const blockchain = require('./blockchain') Error.stackTraceLimit = 100 app.locals.ENV = env @@ -21,6 +22,17 @@ app.locals.ENV_DEVELOPMENT = env === 'development' app.set('trust proxy', true) +try { + blockchain.init().catch(ex => { + console.error('Blockchain initialization failed') + console.error(ex) + process.exit(2) + }) +} catch (ex) { + console.error(ex) + process.exit(1) +} + // console.log('config', config) let httpServer, httpsServer diff --git a/server/blockchain.js b/server/blockchain.js new file mode 100644 index 0000000..32d0e01 --- /dev/null +++ b/server/blockchain.js @@ -0,0 +1,45 @@ +const config = require('./config') +const { ethers } = require('ethers') +const { Logger } = require('./logger') +const AssetManager = require('../miniwallet/build/contracts/AssetManager.sol/AssetManager.json') + +const networks = [] +const providers = {} +const signers = {} +const assetManagers = {} + +const init = async () => { + Logger.log('Initializing blockchain for server') + Object.keys(config.networks).forEach(k => { + if (config.networks[k].skip) { + Logger.log(`[${k}] Skipped initialization`) + return + } + const n = config.networks[k] + if (n.key) { + try { + Logger.log(`n.url: ${n.url}`) + providers[k] = ethers.getDefaultProvider(n.url) + Logger.log(`n.key: ${n.key}`) + signers[k] = new ethers.Wallet(n.key, providers[k]) + Logger.log(`am address; ${config.networks[k].assetManagerAddress}`) + // console.log(`AssetManager.abi: ${JSON.stringify(AssetManager.abi)}`) + assetManagers[k] = new ethers.Contract(config.networks[k].assetManagerAddress, AssetManager.abi, signers[k]) + Logger.log('AssetManager deployed to:', assetManagers[k].address) + networks.push(k) + } catch (ex) { + console.error(ex) + console.trace(ex) + } + } + }) + console.log(`networks: ${networks}`) +} + +module.exports = { + init, + getNetworks: () => networks, + getProvider: (network) => providers[network], + getSigner: (network) => signers[network], + getAssetManager: (network) => assetManagers[network], +} diff --git a/server/config.js b/server/config.js index 8c2aac8..29c776e 100644 --- a/server/config.js +++ b/server/config.js @@ -25,6 +25,7 @@ const config = { skip: process.env.SKIP_TESTNET, numAccounts: process.env.TESTNET_NUM_ACCOUNTS || 1, blockTime: 2, + assetManagerAddress: process.env.TESTNET_ASSET_MANAGER, }, 'harmony-mainnet': { key: process.env.HARMONY_MAINNET_KEY || '', @@ -35,14 +36,16 @@ const config = { skip: process.env.SKIP_MAINNET, numAccounts: process.env.MAINNET_NUM_ACCOUNTS || 1, blockTime: 2, + assetManagerAddress: process.env.MAINNET_ASSET_MANAGER, }, 'eth-ganache': { - url: process.env.GANACHE_RPC || 'http://127.0.0.1:7545', + url: process.env.GANACHE_RPC || 'http://localhost:8545', wss: process.env.GANACHE_WSS, key: process.env.ETH_GANACHE_KEY, mnemonic: process.env.ETH_GANACHE_MNEMONIC, skip: process.env.SKIP_GANACHE, numAccounts: process.env.GANACHE_NUM_ACCOUNTS || 1, + assetManagerAddress: process.env.GANACHE_ASSET_MANAGER, }, }, gasLimit: parseInt(process.env.GAS_LIMIT || '12345678'), @@ -58,7 +61,7 @@ const config = { cred: !process.env.GCP_CRED_PATH ? {} : require(process.env.GCP_CRED_PATH), mock: !process.env.GCP_CRED_PATH, mockPort: 9000, - namespace: 'sms-wallet-server' + namespace: process.env.GCP_NAMESPACE || 'sms-wallet-server' }, twilio: { diff --git a/server/package.json b/server/package.json index 394c6d3..c7f2444 100644 --- a/server/package.json +++ b/server/package.json @@ -60,6 +60,7 @@ "eslint-plugin-node": "^11.1.0", "eslint-plugin-promise": "^5.1.0", "eslint-plugin-standard": "^5.0.0", + "ethers": "^5.6.9", "standard": "^17.0.0" }, "resolutions": { diff --git a/server/routes/index.js b/server/routes/index.js index 37f077a..c727993 100644 --- a/server/routes/index.js +++ b/server/routes/index.js @@ -7,6 +7,7 @@ const NodeCache = require('node-cache') const Cache = new NodeCache() const { phone } = require('phone') const Twilio = require('twilio')(config.twilio.sid, config.twilio.token) +const TwilioV = require('twilio') const utils = require('../utils') const { User } = require('../src/data/user') const { isEqual, pick } = require('lodash') @@ -14,6 +15,8 @@ const w3utils = require('../w3utils') const stringify = require('json-stable-stringify') const { Setting } = require('../src/data/setting') const { Request } = require('../src/data/request') +const blockchain = require('../blockchain') +const { ethers } = require('ethers') router.get('/health', async (req, res) => { Logger.log('[/health]', req.fingerprint) @@ -338,4 +341,21 @@ router.post('/request-complete', async (req, res) => { } }) +// Process sms requests sent to the twilio operator Number +router.post('/sms', async (req, res) => { + // check valid Twilio Request + if (!TwilioV.validateRequest(config.twilio.token, req.headers['x-twilio-signature'], ('https://' + req.get('host') + '/sms'), req.body)) { + return res.status(StatusCodes.BAD_REQUEST).json({ error: 'request not from twilio' }) + } + // Look up the from Phone Number to get the address + const { From: phoneNumber } = req.body + const u = await User.findByPhone({ phone: phoneNumber }) + if (!u) { + return res.status(StatusCodes.BAD_REQUEST).json({ error: 'phone number does not exist' }) + } + const assetManager = blockchain.getAssetManager('eth-ganache') + const balance = ethers.utils.formatEther(await assetManager.userBalances(u.address)) + return res.json({ userAddress: u.address, balance: balance }) +}) + module.exports = router diff --git a/server/yarn.lock b/server/yarn.lock index f4f83dc..c1f1cdf 100644 --- a/server/yarn.lock +++ b/server/yarn.lock @@ -3592,7 +3592,7 @@ ethers@^4.0.32: uuid "2.0.1" xmlhttprequest "1.8.0" -ethers@^5.0.13: +ethers@^5.0.13, ethers@^5.6.9: version "5.6.9" resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.6.9.tgz#4e12f8dfcb67b88ae7a78a9519b384c23c576a4d" integrity sha512-lMGC2zv9HC5EC+8r429WaWu3uWJUCgUCt8xxKCFqkrFuBDZXDYIdzDUECxzjf2BMF8IVBByY1EBoGSL3RTm8RA==