Added bch-dex-lib and Nostr libraries

This commit is contained in:
Chris Troutner
2025-03-05 19:03:14 -08:00
parent 1b16f62b99
commit 77d83349c1
10 changed files with 252 additions and 4 deletions
+8
View File
@@ -8,6 +8,7 @@
"name": "bch-dex-taker-v2", "name": "bch-dex-taker-v2",
"version": "1.0.0", "version": "1.0.0",
"dependencies": { "dependencies": {
"@chris.troutner/nostr-tools": "2.10.4",
"@chris.troutner/react-jdenticon": "1.0.1", "@chris.troutner/react-jdenticon": "1.0.1",
"@fortawesome/fontawesome-svg-core": "6.7.2", "@fortawesome/fontawesome-svg-core": "6.7.2",
"@fortawesome/free-regular-svg-icons": "6.7.2", "@fortawesome/free-regular-svg-icons": "6.7.2",
@@ -16,6 +17,7 @@
"axios": "0.27.2", "axios": "0.27.2",
"bch-dex-lib": "2.0.2", "bch-dex-lib": "2.0.2",
"bch-message-lib": "2.2.1", "bch-message-lib": "2.2.1",
"bch-nostr": "1.3.4",
"bootstrap": "5.2.0", "bootstrap": "5.2.0",
"crypto-browserify": "3.12.1", "crypto-browserify": "3.12.1",
"process": "0.11.10", "process": "0.11.10",
@@ -1884,6 +1886,8 @@
}, },
"node_modules/@chris.troutner/nostr-tools": { "node_modules/@chris.troutner/nostr-tools": {
"version": "2.10.4", "version": "2.10.4",
"resolved": "http://94.130.170.209:4873/@chris.troutner%2fnostr-tools/-/nostr-tools-2.10.4.tgz",
"integrity": "sha512-e8AYJ0yQ0O3bvnuXQUIdB+P3W7f06st+TXfmbpd6U7IpJ5jWhczoLGvF0NiCgKB6YHTaTGx4hoRLF2A744PzmQ==",
"license": "Unlicense", "license": "Unlicense",
"dependencies": { "dependencies": {
"@noble/ciphers": "^0.5.1", "@noble/ciphers": "^0.5.1",
@@ -5426,6 +5430,8 @@
}, },
"node_modules/bch-dex-lib": { "node_modules/bch-dex-lib": {
"version": "2.0.2", "version": "2.0.2",
"resolved": "http://94.130.170.209:4873/bch-dex-lib/-/bch-dex-lib-2.0.2.tgz",
"integrity": "sha512-x639TqYjRucvFrWzr9PMWN5Jdj2+lJkk1m4LC9Zlfm0QNe1PLD4WqyqH1dxMUdA/L9TVpPq1V/HbAiiQZmjV6Q==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@chris.troutner/retry-queue": "1.0.10", "@chris.troutner/retry-queue": "1.0.10",
@@ -5500,6 +5506,8 @@
}, },
"node_modules/bch-nostr": { "node_modules/bch-nostr": {
"version": "1.3.4", "version": "1.3.4",
"resolved": "http://94.130.170.209:4873/bch-nostr/-/bch-nostr-1.3.4.tgz",
"integrity": "sha512-5R6PtZsP1F+oDs7+sZ5d+DeM3XNhr+3QsyHmTbFdoyNcb3w0vFN3KYNvaXpfPYBUDncXPJBNSR5GOstEDRSCgg==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@chris.troutner/nostr-tools": "2.10.4", "@chris.troutner/nostr-tools": "2.10.4",
+2
View File
@@ -2,6 +2,7 @@
"name": "bch-dex-taker-v2", "name": "bch-dex-taker-v2",
"version": "1.0.0", "version": "1.0.0",
"dependencies": { "dependencies": {
"@chris.troutner/nostr-tools": "2.10.4",
"@chris.troutner/react-jdenticon": "1.0.1", "@chris.troutner/react-jdenticon": "1.0.1",
"@fortawesome/fontawesome-svg-core": "6.7.2", "@fortawesome/fontawesome-svg-core": "6.7.2",
"@fortawesome/free-regular-svg-icons": "6.7.2", "@fortawesome/free-regular-svg-icons": "6.7.2",
@@ -10,6 +11,7 @@
"axios": "0.27.2", "axios": "0.27.2",
"bch-dex-lib": "2.0.2", "bch-dex-lib": "2.0.2",
"bch-message-lib": "2.2.1", "bch-message-lib": "2.2.1",
"bch-nostr": "1.3.4",
"bootstrap": "5.2.0", "bootstrap": "5.2.0",
"crypto-browserify": "3.12.1", "crypto-browserify": "3.12.1",
"process": "0.11.10", "process": "0.11.10",
+10
View File
@@ -71,6 +71,16 @@ function App (props) {
addToModal('Getting BCH spot price in USD', appData) addToModal('Getting BCH spot price in USD', appData)
await asyncLoad.getUSDExchangeRate(walletTemp, appData.updateBchWalletState, appData) await asyncLoad.getUSDExchangeRate(walletTemp, appData.updateBchWalletState, appData)
// Load the DEX library.
addToModal('Loading DEX Library', appData)
const dexLib = await asyncLoad.getDexLib({bchWallet: walletTemp})
appData.setDexLib(dexLib)
// Load the Nostr library.
addToModal('Loading Nostr Library', appData)
const nostrLib = await asyncLoad.getNostrLib({bchWallet: walletTemp})
appData.setNostr(nostrLib)
// Update state // Update state
appData.setShowStartModal(false) appData.setShowStartModal(false)
appData.setDenyClose(false) appData.setDenyClose(false)
@@ -0,0 +1,79 @@
/*
This component renders as a button. When clicked, it initiates the
purchase of the token. This is the Signal part of the SWaP protocol.
*/
// Global npm libraries
import React, { useState } from 'react'
import { Button, Modal, Container, Row, Col } from 'react-bootstrap'
function InfoButton (props) {
const [show, setShow] = useState(false)
const handleClose = () => {
console.log('handleClose()')
setShow(false)
// props.instance.setState({ showModal: false })
}
const handleOpen = () => {
console.log('handleOpen()')
setShow(true)
}
// Replace with dummy button until token data is loaded.
if (!props.token.tokenData) {
return (
<>
<Button variant='info'>Info</Button>
</>
)
}
return (
<>
<Button variant='info' disabled={props.disabled} onClick={handleOpen}>Info</Button>
<Modal show={show} onHide={handleClose}>
<Modal.Header closeButton>
<Modal.Title>Token Information</Modal.Title>
</Modal.Header>
<Modal.Body>
<Container>
<Row>
<Col xs={4}><b>Ticker</b>:</Col>
<Col xs={8}>{props.token.ticker}</Col>
</Row>
<Row style={{ backgroundColor: '#eee' }}>
<Col xs={4}><b>Name</b>:</Col>
<Col xs={8}>{props.token.tokenData.genesisData.name}</Col>
</Row>
<Row>
<Col xs={4}><b>Token ID</b>:</Col>
<Col xs={8} style={{ wordBreak: 'break-all' }}>
<a href={`https://explorer.tokentiger.com/?tokenid=${props.token.tokenId}`} target='_blank' rel='noreferrer'>
{props.token.tokenId}
</a>
</Col>
</Row>
<Row style={{ backgroundColor: '#eee' }}>
<Col xs={4}><b>Decimals</b>:</Col>
<Col xs={8}>{props.token.tokenData.genesisData.decimals}</Col>
</Row>
<Row>
<Col xs={4}><b>Token Type</b>:</Col>
<Col xs={8}>{props.token.tokenType}</Col>
</Row>
</Container>
</Modal.Body>
<Modal.Footer />
</Modal>
</>
)
}
export default InfoButton
@@ -205,6 +205,7 @@ function NftsForSale (props) {
} }
return url return url
} }
// This function generates a Token Card for each token in the wallet. // This function generates a Token Card for each token in the wallet.
function generateCards (offers) { function generateCards (offers) {
console.log('generateCards() offerData: ', offers) console.log('generateCards() offerData: ', offers)
@@ -54,7 +54,7 @@ function InfoButton (props) {
<Row> <Row>
<Col xs={4}><b>Token ID</b>:</Col> <Col xs={4}><b>Token ID</b>:</Col>
<Col xs={8} style={{ wordBreak: 'break-all' }}> <Col xs={8} style={{ wordBreak: 'break-all' }}>
<a href={`https://token.fullstack.cash/?tokenid=${props.token.tokenId}`} target='_blank' rel='noreferrer'> <a href={`https://explorer.tokentiger.com/?tokenid=${props.token.tokenId}`} target='_blank' rel='noreferrer'>
{props.token.tokenId} {props.token.tokenId}
</a> </a>
</Col> </Col>
@@ -9,10 +9,12 @@ import InfoButton from './info-button'
import Jdenticon from '@chris.troutner/react-jdenticon' import Jdenticon from '@chris.troutner/react-jdenticon'
function TokenCard (props) { function TokenCard (props) {
const { token } = props const { token, appData } = props
const [icon, setIcon] = useState(token.icon) const [icon, setIcon] = useState(token.icon)
const [tokenData, setTokenData] = useState(token.tokenData) const [tokenData, setTokenData] = useState(token.tokenData)
console.log('TokenCard() appData: ', appData)
// Update icon state every token.icon and token.tokenData changes // Update icon state every token.icon and token.tokenData changes
useEffect(() => { useEffect(() => {
setIcon(token.icon) setIcon(token.icon)
+7 -2
View File
@@ -23,6 +23,8 @@ function useAppState () {
const [menuState, setMenuState] = useState(0) const [menuState, setMenuState] = useState(0)
const [wallet, setWallet] = useState(false) const [wallet, setWallet] = useState(false)
const [servers, setServers] = useState([]) const [servers, setServers] = useState([])
const [dexLib, setDexLib] = useState(false)
const [nostr, setNostr] = useState(false)
// Startup state management // Startup state management
const [asyncInitStarted, setAsyncInitStarted] = useState(false) const [asyncInitStarted, setAsyncInitStarted] = useState(false)
@@ -125,8 +127,11 @@ function useAppState () {
updateLocalStorage, updateLocalStorage,
updateBchWalletState, updateBchWalletState,
appUtil: new AppUtil(), appUtil: new AppUtil(),
currentPath: location.pathname currentPath: location.pathname,
dexLib,
setDexLib,
nostr,
setNostr
} }
} }
+31
View File
@@ -4,8 +4,11 @@
// Global npm libraries // Global npm libraries
import axios from 'axios' import axios from 'axios'
import BchDexLib from 'bch-dex-lib'
// Local libraries // Local libraries
import GistServers from './gist-servers' import GistServers from './gist-servers'
import Nostr from './nostr'
class AsyncLoad { class AsyncLoad {
constructor () { constructor () {
@@ -195,6 +198,34 @@ class AsyncLoad {
return defaultOptions return defaultOptions
} }
} }
// Load the BchDexLib library.
async getDexLib (inObj = {}) {
try {
const { bchWallet } = inObj
const dexLib = new BchDexLib({bchWallet, p2wdbRead: {}, p2wdbWrite: {}})
return dexLib
} catch (error) {
console.error('Error getting DexLib', error)
throw error
}
}
// Load the Nostr library.
async getNostrLib (inObj = {}) {
try {
const { bchWallet } = inObj
const nostrLib = new Nostr({bchWallet})
return nostrLib
} catch (error) {
console.error('Error in getNostrLib', error)
throw error
}
}
} }
function sleep (ms) { function sleep (ms) {
+110
View File
@@ -0,0 +1,110 @@
/*
Implementing nostr natively in the browser, rather than using a library
intended for node.js
*/
// Global npm libraries
import { finalizeEvent } from '@chris.troutner/nostr-tools/pure'
import { Relay } from '@chris.troutner/nostr-tools/relay'
import BchNostr from 'bch-nostr'
import * as nip19 from '@chris.troutner/nostr-tools/nip19'
class NostrBrowser {
constructor (localConfig = {}) {
if (!localConfig.bchWallet) {
throw new Error('Instance of minimal-slp-wallet must be passed as wallet property when instantiating the bch-dex-lib library.')
}
this.bchWallet = localConfig.bchWallet
this.bchNostr = new BchNostr({
relayWs: 'wss://nostr-relay.psfoundation.info',
topic: 'bch-dex-test-topic-01'
})
}
async testNostrUpload (inObj = {}) {
try {
console.log('testNostrUpload() executing.')
// console.log('this.bchWallet: ', this.bchWallet)
const { offerData, partialHex } = inObj
console.log('offerData: ', offerData)
const wif = this.bchWallet.walletInfo.privateKey
// const { privKeyBuf, nostrPubKey } =
// this.bchNostr.keys.createNostrPubKeyFromWif({ wif })
const { privKeyBuf } =
this.bchNostr.keys.createNostrPubKeyFromWif({ wif })
// Scaffold the Counter Offer from the Offer
const counterOfferData = Object.assign({}, offerData)
counterOfferData.partialTxHex = partialHex
delete counterOfferData.nostrEventId
delete counterOfferData._id
counterOfferData.offerHash = offerData.nostrEventId
// Add P2WDB specific flag for signaling that this is a new Counter Offer.
counterOfferData.dataType = 'counter-offer'
console.log(`counterOfferData: ${JSON.stringify(counterOfferData, null, 2)}`)
const nostrData = {
data: counterOfferData
}
const msg = JSON.stringify(nostrData, null, 2)
// const inObj = {
// kind: 867,
// privKeyBuf: privKeyBuf,
// nostrPubKey: nostrPubKey,
// relayWs: 'wss://nostr-relay.psfoundation.info',
// msg,
// tags: [['t', 'bch-dex-test-topic-01']]
// }
const relayWs = 'wss://nostr-relay.psfoundation.info'
const eventTemplate = {
kind: 867,
created_at: Math.floor(Date.now() / 1000),
tags: [['t', 'bch-dex-test-topic-01']],
content: msg
}
// Sign the post
const signedEvent = finalizeEvent(eventTemplate, privKeyBuf)
// console.log('signedEvent: ', signedEvent)
const eventId = signedEvent.id
// Connect to a relay.
const relay = await Relay.connect(relayWs)
// console.log(`connected to ${relay.url}`)
// Publish the message to the relay.
await relay.publish(signedEvent)
// Close the connection to the relay.
relay.close()
// const eventId = await this.bchNostr.post.uploadToNostr(inObj)
const noteId = this.eventId2note(eventId)
// const eventId = 'test1'
// const noteId = 'test2'
return { eventId, noteId }
} catch (err) {
console.log('Error in nostr.js/testNostrUpload()')
throw err
}
}
// Convert an Event ID into a `noteabc..` syntax that Astral expects.
// This can be used to generate a link to Astral to display the post.
eventId2note (eventId) {
return nip19.noteEncode(eventId)
}
}
export default NostrBrowser