mirror of
https://github.com/fullstack-cash/fullstack-gatsby-theme-bch-wallet.git
synced 2026-09-21 16:52:06 -07:00
Merge pull request #158 from Permissionless-Software-Foundation/dh-re-init-mslpw
feat(wallet): Re-initialize minimal-slp-wallet
This commit is contained in:
Generated
+20944
-39
File diff suppressed because it is too large
Load Diff
+2
-1
@@ -36,7 +36,8 @@
|
|||||||
"gatsby-source-filesystem": "^3.7.1",
|
"gatsby-source-filesystem": "^3.7.1",
|
||||||
"gatsby-transformer-sharp": "3.7.1",
|
"gatsby-transformer-sharp": "3.7.1",
|
||||||
"https-browserify": "^1.0.0",
|
"https-browserify": "^1.0.0",
|
||||||
"ipfs-coord": "^6.6.4",
|
"ipfs-coord": "^6.7.3",
|
||||||
|
"jsonrpc-lite": "^2.2.0",
|
||||||
"path-browserify": "^1.0.1",
|
"path-browserify": "^1.0.1",
|
||||||
"process": "^0.11.10",
|
"process": "^0.11.10",
|
||||||
"prop-types": "^15.7.2",
|
"prop-types": "^15.7.2",
|
||||||
|
|||||||
@@ -6,7 +6,9 @@ import IPFSTabs from './ipfs-tabs'
|
|||||||
import CommandRouter from '../lib/commands'
|
import CommandRouter from '../lib/commands'
|
||||||
|
|
||||||
import './ipfs.css'
|
import './ipfs.css'
|
||||||
// const BchWallet = typeof window !== 'undefined' ? window.SlpWallet : null
|
|
||||||
|
const WalletService = require('../lib/wallet-service')
|
||||||
|
const BchWallet = typeof window !== 'undefined' ? window.SlpWallet : null
|
||||||
|
|
||||||
const { Checkbox } = Inputs
|
const { Checkbox } = Inputs
|
||||||
|
|
||||||
@@ -30,6 +32,9 @@ class IPFS extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
_this = this
|
_this = this
|
||||||
|
_this.BchWallet = BchWallet
|
||||||
|
_this.WalletService = WalletService
|
||||||
|
|
||||||
this.initIPFSControl()
|
this.initIPFSControl()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,6 +183,7 @@ class IPFS extends React.Component {
|
|||||||
|
|
||||||
// Adds a line to the Status terminal
|
// Adds a line to the Status terminal
|
||||||
onStatusLog (str) {
|
onStatusLog (str) {
|
||||||
|
console.log('onStatusLog', str)
|
||||||
try {
|
try {
|
||||||
// Update the Status terminal
|
// Update the Status terminal
|
||||||
_this.setState({
|
_this.setState({
|
||||||
@@ -227,8 +233,9 @@ class IPFS extends React.Component {
|
|||||||
// Handle decrypted, private messages and send them to the right terminal.
|
// Handle decrypted, private messages and send them to the right terminal.
|
||||||
privLogChat (str, from) {
|
privLogChat (str, from) {
|
||||||
try {
|
try {
|
||||||
// console.log(`privLogChat str: ${str}`)
|
console.log(`privLogChat str: ${str}`)
|
||||||
// console.log(`privLogChat from: ${from}`)
|
// console.log(`privLogChat from: ${from}`)
|
||||||
|
_this.handleRpcDataQueue(str)
|
||||||
|
|
||||||
const { chatOutputs } = _this.state
|
const { chatOutputs } = _this.state
|
||||||
|
|
||||||
@@ -290,7 +297,8 @@ class IPFS extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onAppStatus (msg) {
|
// pollForServices callback
|
||||||
|
async onAppStatus (msg) {
|
||||||
try {
|
try {
|
||||||
let output
|
let output
|
||||||
if (!msg) {
|
if (!msg) {
|
||||||
@@ -301,12 +309,68 @@ class IPFS extends React.Component {
|
|||||||
_this.setState({
|
_this.setState({
|
||||||
appStatusOutput: output
|
appStatusOutput: output
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Updates the bchWallet instance so it works
|
||||||
|
// under the ipfs services
|
||||||
|
await _this.reInitialize()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.warn(error)
|
console.warn(error)
|
||||||
// Don't throw an error as this is a top-level handler.
|
// Don't throw an error as this is a top-level handler.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Updates the bchWallet instance so it works
|
||||||
|
// under the ipfs services
|
||||||
|
async reInitialize () {
|
||||||
|
try {
|
||||||
|
_this.onStatusLog('waiting for re-initialize...')
|
||||||
|
|
||||||
|
const currentWallet = _this.props.walletInfo
|
||||||
|
const { mnemonic } = currentWallet
|
||||||
|
|
||||||
|
const walletService = new _this.WalletService({
|
||||||
|
ipfsControl: this.ipfsControl
|
||||||
|
})
|
||||||
|
const advancedConfig = {
|
||||||
|
interface: 'json-rpc',
|
||||||
|
jsonRpcWalletService: walletService
|
||||||
|
}
|
||||||
|
|
||||||
|
_this.bchWalletLib = new _this.BchWallet(mnemonic, advancedConfig)
|
||||||
|
|
||||||
|
await _this.bchWalletLib.walletInfoPromise // Wait for wallet to be created.
|
||||||
|
|
||||||
|
// If UTXOs fail to update, try one more time.
|
||||||
|
if (!_this.bchWalletLib.utxos.utxoStore) {
|
||||||
|
await _this.bchWalletLib.getUtxos()
|
||||||
|
|
||||||
|
// Throw an error if UTXOs are still not updated.
|
||||||
|
if (!_this.bchWalletLib.utxos.utxoStore) {
|
||||||
|
throw new Error('UTXOs failed to update. Try again.')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update redux state
|
||||||
|
_this.props.setBchWallet(_this.bchWalletLib)
|
||||||
|
_this.onStatusLog('re-initialize success!')
|
||||||
|
} catch (error) {
|
||||||
|
_this.onStatusLog('Error on re-initialize')
|
||||||
|
_this.onStatusLog(error.message)
|
||||||
|
// Don't throw an error as this is a top-level handler.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill the queue with the incoming data (private messages) from the petitions
|
||||||
|
// So it will be sweeped by the lib/wallet-service/waitForRPCResponse() function
|
||||||
|
handleRpcDataQueue (data) {
|
||||||
|
try {
|
||||||
|
_this.bchWalletLib.ar.jsonRpcWalletService.rpcHandler(data)
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('Error in handleRpcDataQueue', error)
|
||||||
|
// Don't throw an error as this is a top-level handler.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sleep (ms) {
|
sleep (ms) {
|
||||||
return new Promise(resolve => setTimeout(resolve, ms))
|
return new Promise(resolve => setTimeout(resolve, ms))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,225 @@
|
|||||||
|
/*
|
||||||
|
This library interacts with the ipfs-bch-wallet-service via the JSON RPC
|
||||||
|
over IPFS.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const { v4: uid } = require('uuid')
|
||||||
|
const jsonrpc = require('jsonrpc-lite')
|
||||||
|
|
||||||
|
// Public npm libraries.
|
||||||
|
const axios = require('axios')
|
||||||
|
// const Conf = require('conf')
|
||||||
|
|
||||||
|
class WalletService {
|
||||||
|
constructor (localConfig = {}) {
|
||||||
|
// Encapsulate dependencies
|
||||||
|
this.axios = axios
|
||||||
|
// this.conf = new Conf()
|
||||||
|
// this.ipfsControl = localConfig.ipfsControl
|
||||||
|
this.uid = uid
|
||||||
|
this.jsonrpc = jsonrpc
|
||||||
|
this.ipfsControl = localConfig.ipfsControl
|
||||||
|
// A queue for holding RPC data that has arrived.
|
||||||
|
this.rpcDataQueue = []
|
||||||
|
}
|
||||||
|
|
||||||
|
// This handler is triggered when RPC data comes in over IPFS.
|
||||||
|
// Handle RPC input, and match the input to the RPC queue.
|
||||||
|
|
||||||
|
// NOTE: This function is called when a private message
|
||||||
|
// is sent to this node
|
||||||
|
|
||||||
|
rpcHandler (data) {
|
||||||
|
try {
|
||||||
|
// Convert string input into an object.
|
||||||
|
const jsonData = JSON.parse(data)
|
||||||
|
|
||||||
|
// console.log(
|
||||||
|
// 'rest-api.js/rpcHandler() data: ',
|
||||||
|
// JSON.stringify(jsonData, null, 2),
|
||||||
|
// )
|
||||||
|
console.log(`JSON RPC response for ID ${jsonData.id} received.`)
|
||||||
|
|
||||||
|
this.rpcDataQueue.push(jsonData)
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error in rest-api.js/rpcHandler(): ', err)
|
||||||
|
// Do not throw error. This is a top-level function.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
checkServiceId () {
|
||||||
|
try {
|
||||||
|
// this.conf = new Conf()
|
||||||
|
|
||||||
|
const serviceId = this.ipfsControl.selectedServiceProvider
|
||||||
|
console.log(`serviceId : ${serviceId}`)
|
||||||
|
if (!serviceId) {
|
||||||
|
throw new Error('Wallet service ID does not exist')
|
||||||
|
}
|
||||||
|
|
||||||
|
return serviceId
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error in checkServiceId()')
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get up to 20 addresses.
|
||||||
|
async getBalances (addrs) {
|
||||||
|
try {
|
||||||
|
// Input validation.
|
||||||
|
if (!addrs || !Array.isArray(addrs)) {
|
||||||
|
throw new Error(
|
||||||
|
'addrs input to getBalance() must be an array, of up to 20 addresses.'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const serviceId = this.checkServiceId()
|
||||||
|
// console.log(`serviceId: ${serviceId}`)
|
||||||
|
|
||||||
|
const rpcId = this.uid()
|
||||||
|
const rpcData = {
|
||||||
|
endpoint: 'balance',
|
||||||
|
addresses: addrs
|
||||||
|
}
|
||||||
|
// Generate a JSON RPC command.
|
||||||
|
const cmd = this.jsonrpc.request(rpcId, 'bch', rpcData)
|
||||||
|
const cmdStr = JSON.stringify(cmd)
|
||||||
|
const thisNode = this.ipfsControl.ipfsCoord.thisNode
|
||||||
|
|
||||||
|
await this.ipfsControl.ipfsCoord.useCases.peer.sendPrivateMessage(
|
||||||
|
serviceId,
|
||||||
|
cmdStr,
|
||||||
|
thisNode
|
||||||
|
)
|
||||||
|
|
||||||
|
const data = await this.waitForRPCResponse(rpcId)
|
||||||
|
|
||||||
|
return data
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error in getBalance()')
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get hydrated UTXOs for an address
|
||||||
|
async getUtxos (addr) {
|
||||||
|
try {
|
||||||
|
// Input validation
|
||||||
|
if (!addr || typeof addr !== 'string') {
|
||||||
|
throw new Error('getUtxos() input address must be a string.')
|
||||||
|
}
|
||||||
|
|
||||||
|
const serviceId = this.checkServiceId()
|
||||||
|
// console.log(`serviceId: ${serviceId}`)
|
||||||
|
|
||||||
|
const rpcId = this.uid()
|
||||||
|
const rpcData = {
|
||||||
|
endpoint: 'utxos',
|
||||||
|
address: addr
|
||||||
|
}
|
||||||
|
// Generate a JSON RPC command.
|
||||||
|
const cmd = this.jsonrpc.request(rpcId, 'bch', rpcData)
|
||||||
|
const cmdStr = JSON.stringify(cmd)
|
||||||
|
const thisNode = this.ipfsControl.ipfsCoord.thisNode
|
||||||
|
console.log('cmdStr', cmdStr)
|
||||||
|
await this.ipfsControl.ipfsCoord.useCases.peer.sendPrivateMessage(
|
||||||
|
serviceId,
|
||||||
|
cmdStr,
|
||||||
|
thisNode
|
||||||
|
)
|
||||||
|
// Wait for data to come back from the wallet service.
|
||||||
|
const data = await this.waitForRPCResponse(rpcId)
|
||||||
|
return data
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error in getUtxos()', err)
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Broadcast a transaction to the network.
|
||||||
|
async sendTx (hex) {
|
||||||
|
try {
|
||||||
|
// Input validation
|
||||||
|
if (!hex || typeof hex !== 'string') {
|
||||||
|
throw new Error('sendTx() input hex must be a string.')
|
||||||
|
}
|
||||||
|
|
||||||
|
const serviceId = this.checkServiceId()
|
||||||
|
// console.log(`serviceId: ${serviceId}`)
|
||||||
|
const rpcId = this.uid()
|
||||||
|
const rpcData = {
|
||||||
|
endpoint: 'broadcast',
|
||||||
|
hex
|
||||||
|
}
|
||||||
|
// Generate a JSON RPC command.
|
||||||
|
const cmd = this.jsonrpc.request(rpcId, 'bch', rpcData)
|
||||||
|
const cmdStr = JSON.stringify(cmd)
|
||||||
|
console.log('cmdStr', cmdStr)
|
||||||
|
|
||||||
|
const thisNode = this.ipfsControl.ipfsCoord.thisNode
|
||||||
|
|
||||||
|
await this.ipfsControl.ipfsCoord.useCases.peer.sendPrivateMessage(
|
||||||
|
serviceId,
|
||||||
|
cmdStr,
|
||||||
|
thisNode
|
||||||
|
)
|
||||||
|
const data = await this.waitForRPCResponse(rpcId)
|
||||||
|
|
||||||
|
return data
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error in sendTx()')
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a promise that resolves to data when the RPC response is recieved.
|
||||||
|
async waitForRPCResponse (rpcId) {
|
||||||
|
try {
|
||||||
|
// Initialize variables for tracking the return data.
|
||||||
|
let dataFound = false
|
||||||
|
let cnt = 0
|
||||||
|
let data = {
|
||||||
|
success: false,
|
||||||
|
message: 'request timed out',
|
||||||
|
data: ''
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop that waits for a response from the service provider.
|
||||||
|
do {
|
||||||
|
for (let i = 0; i < this.rpcDataQueue.length; i++) {
|
||||||
|
const rawData = this.rpcDataQueue[i]
|
||||||
|
// console.log(`rawData: ${JSON.stringify(rawData, null, 2)}`)
|
||||||
|
|
||||||
|
if (rawData.id === rpcId) {
|
||||||
|
dataFound = true
|
||||||
|
// console.log('data was found in the queue')
|
||||||
|
|
||||||
|
data = rawData.result.value
|
||||||
|
|
||||||
|
// Remove the data from the queue
|
||||||
|
this.rpcDataQueue.splice(i, 1)
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait between loops.
|
||||||
|
// await this.sleep(1000)
|
||||||
|
await this.ipfsControl.wallet.bchjs.Util.sleep(5000)
|
||||||
|
|
||||||
|
cnt++
|
||||||
|
|
||||||
|
// Exit if data was returned, or the window for a response expires.
|
||||||
|
} while (!dataFound && cnt < 10)
|
||||||
|
// console.log(`dataFound: ${dataFound}, cnt: ${cnt}`)
|
||||||
|
console.log('waitForRPCResponse', data)
|
||||||
|
return data
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error in waitForRPCResponse()')
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = WalletService
|
||||||
@@ -145,6 +145,8 @@ class Send extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount () {
|
componentDidMount () {
|
||||||
|
const { bchWallet } = _this.props
|
||||||
|
console.log('bchWallet', bchWallet)
|
||||||
_this.defineExplorer()
|
_this.defineExplorer()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -354,10 +356,10 @@ class Send extends React.Component {
|
|||||||
|
|
||||||
// Send the BCH.
|
// Send the BCH.
|
||||||
const result = await bchWalletLib.send(receivers)
|
const result = await bchWalletLib.send(receivers)
|
||||||
// console.log('result',result)
|
console.log('result', result)
|
||||||
|
|
||||||
_this.setState({
|
_this.setState({
|
||||||
txId: result
|
txId: result.txid || result
|
||||||
})
|
})
|
||||||
|
|
||||||
// update balance
|
// update balance
|
||||||
|
|||||||
Reference in New Issue
Block a user