mirror of
https://github.com/Permissionless-Software-Foundation/bch-dex.git
synced 2026-09-22 01:02:00 -07:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3882217e6a | ||
|
|
8cd2896115 | ||
|
|
e570519ec8 | ||
|
|
2f74b74110 | ||
|
|
fddb5499f0 | ||
|
|
fed98d51be | ||
|
|
8e3ee3a0fb | ||
|
|
e57faf8f26 | ||
|
|
61fa6b0ed6 | ||
|
|
99843061ab | ||
|
|
3a23763800 | ||
|
|
3f4d49a228 | ||
|
|
88cfadbc17 | ||
|
|
6c1da41cb3 | ||
|
|
0e6a411012 | ||
|
|
55e9e35c1f | ||
|
|
84603356ef | ||
|
|
2f6b4dfc09 | ||
|
|
b19af253ae | ||
|
|
b6c6c186a8 | ||
|
|
ae6e708f51 | ||
|
|
442f4ed752 | ||
|
|
8617cf5fd0 | ||
|
|
2e00230f79 | ||
|
|
b4d2506e81 |
Vendored
+2
-2
@@ -47,8 +47,8 @@ export default {
|
||||
useFullStackCash: process.env.USE_FULLSTACKCASH ? true : false,
|
||||
consumerUrl: process.env.CONSUMER_URL
|
||||
? process.env.CONSUMER_URL
|
||||
// : 'https://free-bch.fullstack.cash',
|
||||
: 'https://dev-consumer.psfoundation.info',
|
||||
: 'https://free-bch.fullstack.cash',
|
||||
// : 'https://dev-consumer.psfoundation.info',
|
||||
// : 'https://wa-usa-bch-consumer.fullstackcash.nl',
|
||||
|
||||
// P2WDB URL that will accept API calls from the p2wdb npm library.
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 38 KiB |
@@ -10,6 +10,7 @@
|
||||
"test:all": "export BCH_DEX=test && c8 --reporter=text mocha --exit --timeout 15000 --recursive test/unit test/e2e/automated/",
|
||||
"test:unit": "export BCH_DEX=test && c8 --reporter=text mocha --exit --timeout 15000 --recursive test/unit/",
|
||||
"test:e2e:auto": "export BCH_DEX=test && mocha --exit --timeout 30000 test/e2e/automated/",
|
||||
"start:e2e:server": "export BCH_DEX=test && node index.js",
|
||||
"test:integration": "export BCH_DEX=test && mocha --exit --timeout 45000 --recursive test/integration",
|
||||
"test:temp": "export BCH_DEX=test && mocha --exit --timeout 15000 -g '#rate-limit' test/unit/json-rpc/",
|
||||
"lint": "standard --env mocha --fix",
|
||||
|
||||
@@ -39,7 +39,16 @@ const Offer = new mongoose.Schema({
|
||||
|
||||
// Operator fee and address
|
||||
operatorAddress: { type: String },
|
||||
operatorPercentage: { type: Number }
|
||||
operatorPercentage: { type: Number },
|
||||
|
||||
// Token Data
|
||||
immutableDataCid: { type: String, default: null },
|
||||
mutableDataCid: { type: String, default: null },
|
||||
tokenIconUrl: { type: String, default: null },
|
||||
tokenCategories: { type: Array, default: [] },
|
||||
tokenTags: { type: Array, default: [] },
|
||||
userDataStr: { type: String }, // Token user data
|
||||
lastUpdatedTokenData: { type: String, default: null } // ISO timestamp of the last time token data was updated.
|
||||
})
|
||||
|
||||
export default mongoose.model('offer', Offer)
|
||||
|
||||
@@ -56,6 +56,7 @@ class WalletAdapter {
|
||||
this.completeTx = this.completeTx.bind(this)
|
||||
this.reclaimTokens = this.reclaimTokens.bind(this)
|
||||
this.moveTokensFromCustomWallet = this.moveTokensFromCustomWallet.bind(this)
|
||||
this.cid2json = this.cid2json.bind(this)
|
||||
}
|
||||
|
||||
// Open the wallet file, or create one if the file doesn't exist.
|
||||
@@ -677,6 +678,25 @@ class WalletAdapter {
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
async cid2json (urlOrCid) {
|
||||
try {
|
||||
// Input validation
|
||||
if (!urlOrCid || typeof urlOrCid !== 'string') {
|
||||
throw new Error('urlOrCid must be a string!')
|
||||
}
|
||||
// Extract the cid from the url or cid.
|
||||
const cid = urlOrCid.split('/').pop()
|
||||
console.log('cid to json: ', cid)
|
||||
const jsonRes = await this.bchWallet.cid2json({ cid })
|
||||
const json = jsonRes.json
|
||||
// console.log('json: ', json)
|
||||
return json
|
||||
} catch (err) {
|
||||
console.error('Error in wallet.js/cid2json()', err.message)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default WalletAdapter
|
||||
|
||||
@@ -29,7 +29,36 @@ class EntryRESTControllerLib {
|
||||
_this = this
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {post} /entry Create an entry
|
||||
* @apiPermission public
|
||||
* @apiName CreateEntry
|
||||
* @apiGroup REST Entry
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
* curl -H "Content-Type: application/json" -X POST -d '{"entry": "1234567890", "description": "1234567890", "slpAddress": "1234567890", "signature": "1234567890", "category": "1234567890"}' localhost:5001/entry
|
||||
*
|
||||
* @apiSuccess {Object} entry Entry object
|
||||
* @apiSuccess {String} entry.id Entry ID
|
||||
* @apiSuccess {String} entry.description Entry description
|
||||
* @apiSuccess {String} entry.slpAddress Entry slp address
|
||||
* @apiSuccess {String} entry.signature Entry signature
|
||||
* @apiSuccess {String} entry.category Entry category
|
||||
|
||||
* @apiSuccessExample {json} Success-Response:
|
||||
* HTTP/1.1 200 OK
|
||||
* {
|
||||
* "entry": {
|
||||
* "id": "1234567890",
|
||||
* "description": "1234567890",
|
||||
* "slpAddress": "1234567890",
|
||||
* "signature": "1234567890",
|
||||
* "category": "1234567890"
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
// No api-doc documentation because this wont be a public endpoint
|
||||
// Note: this is a private endpoint, needs to be authenticated
|
||||
async createEntry (ctx) {
|
||||
try {
|
||||
console.log('body: ', ctx.request.body)
|
||||
|
||||
@@ -40,11 +40,23 @@ class IpfsRESTControllerLib {
|
||||
* @api {get} /ipfs Get status on IPFS infrastructure
|
||||
* @apiPermission public
|
||||
* @apiName GetIpfsStatus
|
||||
* @apiGroup REST BCH
|
||||
* @apiGroup REST IPFS
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
* curl -H "Content-Type: application/json" -X GET localhost:5001/ipfs
|
||||
*
|
||||
* @apiSuccess {Object} status IPFS status object
|
||||
* @apiSuccess {String} status.ipfsId IPFS ID
|
||||
* @apiSuccess {String} status.multiaddrs IPFS multiaddrs
|
||||
|
||||
* @apiSuccessExample {json} Success-Response:
|
||||
* HTTP/1.1 200 OK
|
||||
* {
|
||||
* "status": {
|
||||
* "ipfsId": "1234567890",
|
||||
* "multiaddrs": ["/ip4/123.45.67.89/tcp/4001/p2p/1234567890"]
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
async getStatus (ctx) {
|
||||
try {
|
||||
@@ -58,7 +70,26 @@ class IpfsRESTControllerLib {
|
||||
}
|
||||
}
|
||||
|
||||
// Return information on IPFS peers this node is connected to.
|
||||
/**
|
||||
* @api {post} /ipfs/peers Get information on IPFS peers this node is connected to
|
||||
* @apiPermission public
|
||||
* @apiName GetIpfsPeers
|
||||
* @apiGroup REST IPFS
|
||||
*
|
||||
* @apiParam {Boolean} [showAll=false] Whether to include detailed peer data
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
* curl -H "Content-Type: application/json" -X POST localhost:5001/ipfs/peers \
|
||||
* -d '{"showAll": false}'
|
||||
*
|
||||
* @apiSuccess {Object[]} peers Array of peer objects
|
||||
* @apiSuccess {String} peers[].peer Peer ID
|
||||
* @apiSuccess {String} peers[].name Peer name
|
||||
* @apiSuccess {String} peers[].protocol Protocol used by the peer
|
||||
* @apiSuccess {String} peers[].version Peer version
|
||||
* @apiSuccess {String} peers[].connectionAddr Connection address
|
||||
* @apiSuccess {Object} [peers[].peerData] Detailed peer data (when showAll=true)
|
||||
*/
|
||||
async getPeers (ctx) {
|
||||
try {
|
||||
const showAll = ctx.request.body.showAll
|
||||
@@ -73,6 +104,24 @@ class IpfsRESTControllerLib {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {post} /ipfs/relays Get data about the known Circuit Relays
|
||||
* @apiPermission public
|
||||
* @apiName GetIpfsRelays
|
||||
* @apiGroup REST IPFS
|
||||
*
|
||||
* @apiDescription Returns information about Circuit Relays, both v1 and v2, that this node knows about. V2 relays are hydrated with peer data from the connected peers list.
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
* curl -H "Content-Type: application/json" -X POST localhost:5001/ipfs/relays
|
||||
*
|
||||
* @apiSuccess {Object} relays Object containing relay information
|
||||
* @apiSuccess {Object[]} relays.v2Relays Array of v2 Circuit Relay objects
|
||||
* @apiSuccess {String} relays.v2Relays[].ipfsId IPFS ID of the relay
|
||||
* @apiSuccess {String} relays.v2Relays[].name Name of the relay (hydrated from peer data)
|
||||
* @apiSuccess {String} relays.v2Relays[].description Description of the relay (hydrated from peer data)
|
||||
* @apiSuccess {Object[]} relays.v1Relays Array of v1 Circuit Relay configurations
|
||||
*/
|
||||
// Get data about the known Circuit Relays. Hydrate with data from peers list.
|
||||
async getRelays (ctx) {
|
||||
try {
|
||||
@@ -86,6 +135,24 @@ class IpfsRESTControllerLib {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {post} /ipfs/connect Connect to a specific IPFS peer
|
||||
* @apiPermission public
|
||||
* @apiName ConnectToIpfsPeer
|
||||
* @apiGroup REST IPFS
|
||||
*
|
||||
* @apiDescription Attempts to establish a connection to a specific IPFS peer using the provided multiaddr. Optionally returns detailed information about the connection.
|
||||
*
|
||||
* @apiParam {String} multiaddr Multiaddress of the peer to connect to (required)
|
||||
* @apiParam {Boolean} [getDetails=false] Whether to return detailed connection information
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
* curl -H "Content-Type: application/json" -X POST localhost:5001/ipfs/connect \
|
||||
* -d '{"multiaddr": "/ip4/161.35.99.207/tcp/4001/p2p/12D3KooWDtj9cfj1SKuLbDNKvKRKSsGN8qivq9M8CYpLPDpcD5pu", "getDetails": false}'
|
||||
*
|
||||
* @apiSuccess {Boolean} success Indicates whether the connection attempt was successful
|
||||
* @apiSuccess {Object} [details] Additional connection details (when getDetails=true)
|
||||
*/
|
||||
async connect (ctx) {
|
||||
try {
|
||||
const multiaddr = ctx.request.body.multiaddr
|
||||
@@ -107,7 +174,7 @@ class IpfsRESTControllerLib {
|
||||
* @api {get} /ipfs/node Get a copy of the thisNode object from helia-coord
|
||||
* @apiPermission public
|
||||
* @apiName GetThisNode
|
||||
* @apiGroup REST BCH
|
||||
* @apiGroup REST IPFS
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
* curl -H "Content-Type: application/json" -X GET localhost:5001/ipfs/node
|
||||
|
||||
@@ -38,6 +38,7 @@ class OfferRESTControllerLib {
|
||||
}
|
||||
|
||||
// No api-doc documentation because this wont be a public endpoint
|
||||
// This function has no endpoint
|
||||
async createOffer (ctx) {
|
||||
try {
|
||||
console.log('body: ', ctx.request.body)
|
||||
@@ -56,6 +57,65 @@ class OfferRESTControllerLib {
|
||||
this.handleError(ctx, err)
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @api {get} /offer/list/all/:page Get all offers
|
||||
* @apiPermission public
|
||||
* @apiName ListOffers
|
||||
* @apiGroup REST Offer
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
* curl -H "Content-Type: application/json" -X GET localhost:5000/offer/list/all/0
|
||||
*
|
||||
* @apiSuccess {Object[]} offers Array of offer objects
|
||||
* @apiSuccess {ObjectId} offers._id Offer id
|
||||
* @apiSuccess {String} offers.ticker Ticker
|
||||
* @apiSuccess {String} offers.tokenId Token id
|
||||
* @apiSuccess {String} offers.utxoTxid Utxo transaction id
|
||||
* @apiSuccess {Number} offers.utxoVout Utxo output index
|
||||
* @apiSuccess {String} offers.buyOrSell Buy or sell
|
||||
* @apiSuccess {Number} offers.numTokens Number of tokens
|
||||
* @apiSuccess {String} offers.rateInBaseUnit Rate in base unit
|
||||
* @apiSuccess {String} offers.minUnitsToExchange Minimum units to exchange
|
||||
* @apiSuccess {String} offers.offerStatus Offer status
|
||||
* @apiSuccess {String} offers.makerAddr Maker address
|
||||
* @apiSuccess {Number} offers.timestamp Timestamp
|
||||
* @apiSuccess {String} offers.displayCategory Display category
|
||||
* @apiSuccess {Boolean} offers.nsfw Nsfw
|
||||
* @apiSuccess {Array} offers.flags Flags
|
||||
* @apiSuccess {Number} offers.messageType Message type
|
||||
* @apiSuccess {Number} offers.messageClass Message class
|
||||
* @apiSuccess {String} offers.nostrEventId Nostr event id
|
||||
* @apiSuccess {String} offers.operatorAddress Operator address
|
||||
* @apiSuccess {Number} offers.operatorPercentage Operator percentage
|
||||
*
|
||||
* @apiSuccessExample {json} Success-Response:
|
||||
* HTTP/1.1 200 OK
|
||||
* {
|
||||
* "offers": [{
|
||||
* "_id": "56bd1da600a526986cf65c80",
|
||||
* "tokenId": "1234567890",
|
||||
* "utxoTxid": "1234567890",
|
||||
* "utxoVout": 0,
|
||||
* "buyOrSell": "buy",
|
||||
* "numTokens": 1,
|
||||
* "rateInBaseUnit": "100000000",
|
||||
* "minUnitsToExchange": "100000000",
|
||||
* "offerStatus": "active",
|
||||
* "makerAddr": "1234567890",
|
||||
* "timestamp": 1716883200,
|
||||
* "displayCategory": "nft",
|
||||
* "nsfw": false,
|
||||
* "flags": [],
|
||||
* "messageType": 1,
|
||||
* "messageClass": 1,
|
||||
* "nostrEventId": "1234567890",
|
||||
* "operatorAddress": "1234567890",
|
||||
* "operatorPercentage": 100
|
||||
* }]
|
||||
* }
|
||||
*
|
||||
* @apiUse TokenError
|
||||
*/
|
||||
|
||||
// curl -X GET http://localhost:5700/offer/list/all/0
|
||||
async listOffers (ctx) {
|
||||
@@ -72,6 +132,66 @@ class OfferRESTControllerLib {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} /offer/list/nft/:page Get all nft offers
|
||||
* @apiPermission public
|
||||
* @apiName ListNftOffers
|
||||
* @apiGroup REST Offer
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
* curl -H "Content-Type: application/json" -X GET localhost:5000/offer/list/nft/0
|
||||
*
|
||||
* @apiSuccess {Object[]} offers Array of offer objects
|
||||
* @apiSuccess {ObjectId} offers._id Offer id
|
||||
* @apiSuccess {String} offers.ticker Ticker
|
||||
* @apiSuccess {String} offers.tokenId Token id
|
||||
* @apiSuccess {String} offers.utxoTxid Utxo transaction id
|
||||
* @apiSuccess {Number} offers.utxoVout Utxo output index
|
||||
* @apiSuccess {String} offers.buyOrSell Buy or sell
|
||||
* @apiSuccess {Number} offers.numTokens Number of tokens
|
||||
* @apiSuccess {String} offers.rateInBaseUnit Rate in base unit
|
||||
* @apiSuccess {String} offers.minUnitsToExchange Minimum units to exchange
|
||||
* @apiSuccess {String} offers.offerStatus Offer status
|
||||
* @apiSuccess {String} offers.makerAddr Maker address
|
||||
* @apiSuccess {Number} offers.timestamp Timestamp
|
||||
* @apiSuccess {String} offers.displayCategory Display category
|
||||
* @apiSuccess {Boolean} offers.nsfw Nsfw
|
||||
* @apiSuccess {Array} offers.flags Flags
|
||||
* @apiSuccess {Number} offers.messageType Message type
|
||||
* @apiSuccess {Number} offers.messageClass Message class
|
||||
* @apiSuccess {String} offers.nostrEventId Nostr event id
|
||||
* @apiSuccess {String} offers.operatorAddress Operator address
|
||||
* @apiSuccess {Number} offers.operatorPercentage Operator percentage
|
||||
*
|
||||
* @apiSuccessExample {json} Success-Response:
|
||||
* HTTP/1.1 200 OK
|
||||
* {
|
||||
* "offers": [{
|
||||
* "_id": "56bd1da600a526986cf65c80",
|
||||
* "tokenId": "1234567890",
|
||||
* "utxoTxid": "1234567890",
|
||||
* "utxoVout": 0,
|
||||
* "buyOrSell": "buy",
|
||||
* "numTokens": 1,
|
||||
* "rateInBaseUnit": "100000000",
|
||||
* "minUnitsToExchange": "100000000",
|
||||
* "offerStatus": "active",
|
||||
* "makerAddr": "1234567890",
|
||||
* "timestamp": 1716883200,
|
||||
* "displayCategory": "nft",
|
||||
* "nsfw": false,
|
||||
* "flags": [],
|
||||
* "messageType": 1,
|
||||
* "messageClass": 1,
|
||||
* "nostrEventId": "1234567890",
|
||||
* "operatorAddress": "1234567890",
|
||||
* "operatorPercentage": 100
|
||||
* }]
|
||||
* }
|
||||
*
|
||||
* @apiUse TokenError
|
||||
*/
|
||||
|
||||
// curl -X GET http://localhost:5700/offer/list/nft/0
|
||||
async listNftOffers (ctx) {
|
||||
try {
|
||||
@@ -87,6 +207,65 @@ class OfferRESTControllerLib {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} /offer/list/fungible/:page Get all fungible offers
|
||||
* @apiPermission public
|
||||
* @apiName ListFungibleOffers
|
||||
* @apiGroup REST Offer
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
* curl -H "Content-Type: application/json" -X GET localhost:5000/offer/list/fungible/0
|
||||
*
|
||||
* @apiSuccess {Object[]} offers Array of offer objects
|
||||
* @apiSuccess {ObjectId} offers._id Offer id
|
||||
* @apiSuccess {String} offers.ticker Ticker
|
||||
* @apiSuccess {String} offers.tokenId Token id
|
||||
* @apiSuccess {String} offers.utxoTxid Utxo transaction id
|
||||
* @apiSuccess {Number} offers.utxoVout Utxo output index
|
||||
* @apiSuccess {String} offers.buyOrSell Buy or sell
|
||||
* @apiSuccess {Number} offers.numTokens Number of tokens
|
||||
* @apiSuccess {String} offers.rateInBaseUnit Rate in base unit
|
||||
* @apiSuccess {String} offers.minUnitsToExchange Minimum units to exchange
|
||||
* @apiSuccess {String} offers.offerStatus Offer status
|
||||
* @apiSuccess {String} offers.makerAddr Maker address
|
||||
* @apiSuccess {Number} offers.timestamp Timestamp
|
||||
* @apiSuccess {String} offers.displayCategory Display category
|
||||
* @apiSuccess {Boolean} offers.nsfw Nsfw
|
||||
* @apiSuccess {Array} offers.flags Flags
|
||||
* @apiSuccess {Number} offers.messageType Message type
|
||||
* @apiSuccess {Number} offers.messageClass Message class
|
||||
* @apiSuccess {String} offers.nostrEventId Nostr event id
|
||||
* @apiSuccess {String} offers.operatorAddress Operator address
|
||||
* @apiSuccess {Number} offers.operatorPercentage Operator percentage
|
||||
*
|
||||
* @apiSuccessExample {json} Success-Response:
|
||||
* HTTP/1.1 200 OK
|
||||
* {
|
||||
* "offers": [{
|
||||
* "_id": "56bd1da600a526986cf65c80",
|
||||
* "tokenId": "1234567890",
|
||||
* "utxoTxid": "1234567890",
|
||||
* "utxoVout": 0,
|
||||
* "buyOrSell": "buy",
|
||||
* "numTokens": 1,
|
||||
* "rateInBaseUnit": "100000000",
|
||||
* "minUnitsToExchange": "100000000",
|
||||
* "offerStatus": "active",
|
||||
* "makerAddr": "1234567890",
|
||||
* "timestamp": 1716883200,
|
||||
* "displayCategory": "fungible",
|
||||
* "nsfw": false,
|
||||
* "flags": [],
|
||||
* "messageType": 1,
|
||||
* "messageClass": 1,
|
||||
* "nostrEventId": "1234567890",
|
||||
* "operatorAddress": "1234567890",
|
||||
* "operatorPercentage": 100
|
||||
* }]
|
||||
* }
|
||||
*
|
||||
* @apiUse TokenError
|
||||
*/
|
||||
// curl -X GET http://localhost:5700/offer/list/fungible/0
|
||||
async listFungibleOffers (ctx) {
|
||||
try {
|
||||
@@ -102,6 +281,27 @@ class OfferRESTControllerLib {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {post} /offer/take Take an offer
|
||||
* @apiPermission public
|
||||
* @apiName TakeOffer
|
||||
* @apiGroup REST Offer
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
* curl -H "Content-Type: application/json" -X POST -d '{ "nostrEventId": "1234567890" }' localhost:5010/offer/take
|
||||
*
|
||||
* @apiSuccess {String} eventId Event id
|
||||
* @apiSuccess {String} noteId Note id
|
||||
*
|
||||
* @apiSuccessExample {json} Success-Response:
|
||||
* HTTP/1.1 200 OK
|
||||
* {
|
||||
* "eventId": "1234567890",
|
||||
* "noteId": "1234567890"
|
||||
* }
|
||||
*
|
||||
* @apiUse TokenError
|
||||
*/
|
||||
// Currently only supports 'sell' offers, and will only buy the 'numTokens'
|
||||
// listed in the offer.
|
||||
async takeOffer (ctx) {
|
||||
@@ -119,6 +319,67 @@ class OfferRESTControllerLib {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {get} /offer/list/addr/:addr List all offers being made by a given address
|
||||
* @apiPermission public
|
||||
* @apiName ListOffersByAddress
|
||||
* @apiGroup REST Offer
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
* curl -H "Content-Type: application/json" -X GET localhost:5000/offer/list/addr/bitcoincash:qrpxtnrlhfz9wsuuse7z5k2mxmvw0r3pu5qepyhmq2
|
||||
*
|
||||
*
|
||||
* @apiSuccess {Object[]} offers Array of offer objects
|
||||
* @apiSuccess {ObjectId} offers._id Offer id
|
||||
* @apiSuccess {String} offers.ticker Ticker
|
||||
* @apiSuccess {String} offers.tokenId Token id
|
||||
* @apiSuccess {String} offers.utxoTxid Utxo transaction id
|
||||
* @apiSuccess {Number} offers.utxoVout Utxo output index
|
||||
* @apiSuccess {String} offers.buyOrSell Buy or sell
|
||||
* @apiSuccess {Number} offers.numTokens Number of tokens
|
||||
* @apiSuccess {String} offers.rateInBaseUnit Rate in base unit
|
||||
* @apiSuccess {String} offers.minUnitsToExchange Minimum units to exchange
|
||||
* @apiSuccess {String} offers.offerStatus Offer status
|
||||
* @apiSuccess {String} offers.makerAddr Maker address
|
||||
* @apiSuccess {Number} offers.timestamp Timestamp
|
||||
* @apiSuccess {String} offers.displayCategory Display category
|
||||
* @apiSuccess {Boolean} offers.nsfw Nsfw
|
||||
* @apiSuccess {Array} offers.flags Flags
|
||||
* @apiSuccess {Number} offers.messageType Message type
|
||||
* @apiSuccess {Number} offers.messageClass Message class
|
||||
* @apiSuccess {String} offers.nostrEventId Nostr event id
|
||||
* @apiSuccess {String} offers.operatorAddress Operator address
|
||||
* @apiSuccess {Number} offers.operatorPercentage Operator percentage
|
||||
*
|
||||
* @apiSuccessExample {json} Success-Response:
|
||||
* HTTP/1.1 200 OK
|
||||
* {
|
||||
* "offers": [{
|
||||
* "_id": "56bd1da600a526986cf65c80",
|
||||
* "tokenId": "1234567890",
|
||||
* "utxoTxid": "1234567890",
|
||||
* "utxoVout": 0,
|
||||
* "buyOrSell": "buy",
|
||||
* "numTokens": 1,
|
||||
* "rateInBaseUnit": "100000000",
|
||||
* "minUnitsToExchange": "100000000",
|
||||
* "offerStatus": "active",
|
||||
* "makerAddr": "bitcoincash:qrpxtnrlhfz9wsuuse7z5k2mxmvw0r3pu5qepyhmq2",
|
||||
* "timestamp": 1716883200,
|
||||
* "displayCategory": "fungible",
|
||||
* "nsfw": false,
|
||||
* "flags": [],
|
||||
* "messageType": 1,
|
||||
* "messageClass": 1,
|
||||
* "nostrEventId": "1234567890",
|
||||
* "operatorAddress": "1234567890",
|
||||
* "operatorPercentage": 100
|
||||
* }]
|
||||
* }
|
||||
*
|
||||
* @apiUse TokenError
|
||||
*/
|
||||
|
||||
// List all offers being made by a given address.
|
||||
// curl -X GET http://localhost:5700/offer/list/addr/bitcoincash:qrpxtnrlhfz9wsuuse7z5k2mxmvw0r3pu5qepyhmq2
|
||||
async listOffersByAddress (ctx) {
|
||||
|
||||
@@ -29,7 +29,28 @@ class OrderRESTControllerLib {
|
||||
_this = this
|
||||
}
|
||||
|
||||
// No api-doc documentation because this wont be a public endpoint
|
||||
/**
|
||||
* @api {post} /order Create an order
|
||||
* @apiPermission User
|
||||
* @apiName CreateOrder
|
||||
* @apiGroup REST Order
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
* curl -H "Content-Type: application/json" -X POST -d '{"messageType": "1", "messageClass": "1", "tokenId": "1234567890", "buyOrSell": "buy", "rateInBaseUnit": "100000000", "minUnitsToExchange": "100000000", "numTokens": "1", "makerAddr": "1234567890"}' localhost:5001/order
|
||||
*
|
||||
* @apiSuccess {String} eventId Event id
|
||||
* @apiSuccess {String} noteId Note id
|
||||
*
|
||||
* @apiSuccessExample {json} Success-Response:
|
||||
* HTTP/1.1 200 OK
|
||||
* {
|
||||
* "eventId": "1234567890",
|
||||
* "noteId": "1234567890"
|
||||
* }
|
||||
*
|
||||
* @apiUse TokenError
|
||||
*/
|
||||
|
||||
async createOrder (ctx) {
|
||||
try {
|
||||
// console.log('body: ', ctx.request.body)
|
||||
@@ -49,6 +70,68 @@ class OrderRESTControllerLib {
|
||||
_this.handleError(ctx, err)
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @api {get} /order/list/all/:page List all orders
|
||||
* @apiPermission user
|
||||
* @apiName ListOrders
|
||||
* @apiGroup REST Order
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
* curl -H "Content-Type: application/json" -X GET localhost:5000/order/list/all/0
|
||||
*
|
||||
* @apiSuccess {Object[]} orders Array of order objects
|
||||
* @apiSuccess {ObjectId} orders._id Order id
|
||||
* @apiSuccess {String} orders.tokenId Token id
|
||||
* @apiSuccess {String} orders.ticker Ticker
|
||||
* @apiSuccess {String} orders.dataType Data type
|
||||
* @apiSuccess {String} orders.utxoTxid Utxo transaction id
|
||||
* @apiSuccess {Number} orders.utxoVout Utxo output index
|
||||
* @apiSuccess {String} orders.buyOrSell Buy or sell
|
||||
* @apiSuccess {Number} orders.numTokens Number of tokens
|
||||
* @apiSuccess {String} orders.rateInBaseUnit Rate in base unit
|
||||
* @apiSuccess {String} orders.minUnitsToExchange Minimum units to exchange
|
||||
* @apiSuccess {String} orders.offerStatus Offer status
|
||||
* @apiSuccess {String} orders.makerAddr Maker address
|
||||
* @apiSuccess {Number} orders.timestamp Timestamp
|
||||
* @apiSuccess {String} orders.displayCategory Display category
|
||||
* @apiSuccess {Boolean} orders.nsfw Nsfw
|
||||
* @apiSuccess {Array} orders.flags Flags
|
||||
* @apiSuccess {Number} orders.messageType Message type
|
||||
* @apiSuccess {Number} orders.messageClass Message class
|
||||
* @apiSuccess {String} orders.nostrEventId Nostr event id
|
||||
* @apiSuccess {String} orders.operatorAddress Operator address
|
||||
* @apiSuccess {Number} orders.operatorPercentage Operator percentage
|
||||
*
|
||||
* @apiSuccessExample {json} Success-Response:
|
||||
* HTTP/1.1 200 OK
|
||||
* {
|
||||
* "orders": [{
|
||||
* "_id": "56bd1da600a526986cf65c80",
|
||||
* "tokenId": "1234567890",
|
||||
* "ticker": "BTC",
|
||||
* "dataType": "offer",
|
||||
* "utxoTxid": "1234567890",
|
||||
* "utxoVout": 0,
|
||||
* "buyOrSell": "buy",
|
||||
* "numTokens": 1,
|
||||
* "rateInBaseUnit": "100000000",
|
||||
* "minUnitsToExchange": "100000000",
|
||||
* "offerStatus": "active",
|
||||
* "makerAddr": "1234567890",
|
||||
* "timestamp": 1716883200,
|
||||
* "displayCategory": "nft",
|
||||
* "nsfw": false,
|
||||
* "flags": [],
|
||||
* "messageType": 1,
|
||||
* "messageClass": 1,
|
||||
* "nostrEventId": "1234567890",
|
||||
* "operatorAddress": "1234567890",
|
||||
* "operatorPercentage": 100
|
||||
* }]
|
||||
* }
|
||||
*
|
||||
* @apiUse TokenError
|
||||
*/
|
||||
|
||||
// curl -X GET http://localhost:5700/order/list/all/0
|
||||
async listOrders (ctx) {
|
||||
@@ -67,6 +150,28 @@ class OrderRESTControllerLib {
|
||||
|
||||
// Delete an existing order by returning the token to the root address of
|
||||
// the DEX wallet.
|
||||
/**
|
||||
* @api {post} /order/delete Delete an order
|
||||
* @apiPermission user
|
||||
* @apiName DeleteOrder
|
||||
* @apiGroup REST Order
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
* curl -H "Content-Type: application/json" -X POST -d '{ "nostrEventId": "1234567890" }' localhost:5000/order/delete
|
||||
*
|
||||
* @apiSuccess {String} txid Transaction id
|
||||
*
|
||||
* @apiSuccessExample {json} Success-Response:
|
||||
* HTTP/1.1 200 OK
|
||||
* {
|
||||
* "txid": "1234567890"
|
||||
* }
|
||||
*
|
||||
* @apiUse TokenError
|
||||
*/
|
||||
|
||||
// curl -X POST http://localhost:5700/order/delete -d '{ "nostrEventId": "1234567890" }'
|
||||
|
||||
async deleteOrder (ctx) {
|
||||
try {
|
||||
// console.log('body: ', ctx.request.body)
|
||||
|
||||
@@ -54,7 +54,7 @@ class OrderRouter {
|
||||
// Define the routes and attach the controller.
|
||||
this.router.post('/', this.createOrder)
|
||||
this.router.get('/list/all/:page', _this.orderRESTController.listOrders)
|
||||
this.router.post('/delete', _this.orderRESTController.deleteOrder)
|
||||
this.router.post('/delete', this.deleteOrder)
|
||||
|
||||
// Attach the Controller routes to the Koa app.
|
||||
app.use(_this.router.routes())
|
||||
@@ -65,6 +65,11 @@ class OrderRouter {
|
||||
await _this.validators.ensureUser(ctx, next)
|
||||
await _this.orderRESTController.createOrder(ctx, next)
|
||||
}
|
||||
|
||||
async deleteOrder (ctx, next) {
|
||||
await _this.validators.ensureUser(ctx, next)
|
||||
await _this.orderRESTController.deleteOrder(ctx, next)
|
||||
}
|
||||
}
|
||||
|
||||
export default OrderRouter
|
||||
|
||||
@@ -31,7 +31,25 @@ class P2WDBRESTControllerLib {
|
||||
_this = this
|
||||
}
|
||||
|
||||
// No api-doc documentation because this wont be a public endpoint
|
||||
/**
|
||||
* @api {post} /p2wdb Route a P2WDB webhook
|
||||
* @apiPermission public
|
||||
* @apiName RouteWebhook
|
||||
* @apiGroup REST P2WDB
|
||||
*
|
||||
* @apiExample Example usage:
|
||||
* curl -H "Content-Type: application/json" -X POST -d '{"data": {"dataType": "offer"} } ' localhost:5001/p2wdb
|
||||
*
|
||||
* @apiSuccess {String} success Success message
|
||||
*
|
||||
* @apiSuccessExample {json} Success-Response:
|
||||
* HTTP/1.1 200 OK
|
||||
* {
|
||||
* "success": true
|
||||
* }
|
||||
*/
|
||||
|
||||
// Note: verify if this is a private endpoint, needs to be authenticated
|
||||
async routeWebhook (ctx) {
|
||||
try {
|
||||
console.log('p2wdb REST API handler: body: ', ctx.request.body)
|
||||
|
||||
@@ -129,20 +129,57 @@ class OfferUseCases {
|
||||
|
||||
// Get data about the token.
|
||||
const tokenId = offerEntity.tokenId
|
||||
// const tokenData = await this.adapters.wallet.bchWallet.getTokenData(tokenId)
|
||||
const tokenData = await this.retryQueue.addToQueue(this.adapters.wallet.bchWallet.getTokenData, tokenId)
|
||||
// console.log(`tokenData: ${JSON.stringify(tokenData, null, 2)}`)
|
||||
let tokenData = null
|
||||
try {
|
||||
tokenData = await this.retryQueue.addToQueue(this.adapters.wallet.bchWallet.getTokenData, tokenId)
|
||||
} catch (err) {
|
||||
console.error('Error in OfferUseCases/createOffer() getting token data: ', err.message)
|
||||
}
|
||||
|
||||
// Generate a 'display category' for the token. This will allow the
|
||||
// front end UI to figure out how to display the token.
|
||||
const displayCategory = this.categorizeToken(offerEntity, tokenData)
|
||||
console.log('displayCategory: ', displayCategory)
|
||||
offerEntity.displayCategory = displayCategory
|
||||
// Do additional data analysis if the token data was successfully retrieved.
|
||||
if (tokenData) {
|
||||
// Store the mutable and immutable data cids.
|
||||
const mutableDataCid = tokenData.mutableData
|
||||
const immutableDataCid = tokenData.immutableData
|
||||
offerEntity.mutableDataCid = mutableDataCid
|
||||
offerEntity.immutableDataCid = immutableDataCid
|
||||
|
||||
// Detect if user set the NSFW flag.
|
||||
// const nsfw = false
|
||||
// nsfw = await this.retryQueue.addToQueue(this.detectNsfw, tokenData)
|
||||
// offerEntity.nsfw = nsfw
|
||||
// Get the mutable data from the cid if it exists.
|
||||
if (mutableDataCid && typeof mutableDataCid === 'string') {
|
||||
let mutableData = null
|
||||
try {
|
||||
mutableData = await this.retryQueue.addToQueue(this.adapters.wallet.cid2json, mutableDataCid)
|
||||
} catch (err) {
|
||||
console.error('Error in OfferUseCases/createOffer() getting mutable data: ', err.message)
|
||||
}
|
||||
console.log('mutableData: ', mutableData)
|
||||
|
||||
if (mutableData) {
|
||||
try {
|
||||
offerEntity.tokenIconUrl = mutableData.tokenIcon
|
||||
offerEntity.tokenCategories = mutableData.category
|
||||
offerEntity.tokenTags = mutableData.tags
|
||||
offerEntity.lastUpdatedTokenData = new Date().getTime()
|
||||
|
||||
offerEntity.userDataStr = JSON.stringify(mutableData.userData)
|
||||
} catch (error) {
|
||||
// skip error
|
||||
}
|
||||
}
|
||||
}
|
||||
console.log('offerEntity: ', offerEntity)
|
||||
|
||||
// Generate a 'display category' for the token. This will allow the
|
||||
// front end UI to figure out how to display the token.
|
||||
const displayCategory = this.categorizeToken(offerEntity, tokenData)
|
||||
console.log('displayCategory: ', displayCategory)
|
||||
offerEntity.displayCategory = displayCategory
|
||||
|
||||
// Detect if user set the NSFW flag.
|
||||
// const nsfw = false
|
||||
// nsfw = await this.retryQueue.addToQueue(this.detectNsfw, tokenData)
|
||||
// offerEntity.nsfw = nsfw
|
||||
}
|
||||
|
||||
// Add offer to the local database.
|
||||
const offerModel = new this.OfferModel(offerEntity)
|
||||
@@ -150,7 +187,7 @@ class OfferUseCases {
|
||||
|
||||
return true
|
||||
} catch (err) {
|
||||
console.error('Error in createOffer()', err.message)
|
||||
console.error('\n\nError in createOffer()', err.message, '\n\n', err)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
@@ -267,7 +304,7 @@ class OfferUseCases {
|
||||
}
|
||||
}
|
||||
|
||||
async listNftOffers (page = 0, nsfw = false) {
|
||||
/* async listNftOffers (page = 0, nsfw = false) {
|
||||
try {
|
||||
const data = await this.OfferModel.find({
|
||||
displayCategory: { $ne: 'fungible' },
|
||||
@@ -287,6 +324,42 @@ class OfferUseCases {
|
||||
console.error('Error in use-cases/offer/listNftOffers()')
|
||||
throw error
|
||||
}
|
||||
} */
|
||||
|
||||
async listNftOffers (page = 0, nsfw = false) {
|
||||
try {
|
||||
const query = {
|
||||
displayCategory: { $ne: 'fungible' },
|
||||
nsfw
|
||||
}
|
||||
// Total query offers
|
||||
const totalOffers = await this.OfferModel.countDocuments(query)
|
||||
// Total pages
|
||||
const totalPages = Math.ceil(totalOffers / NFT_ENTRIES_PER_PAGE)
|
||||
|
||||
const data = await this.OfferModel.find(query)
|
||||
// Sort entries so newest entries show first.
|
||||
.sort('-timestamp')
|
||||
// Skip to the start of the selected page.
|
||||
.skip(page * NFT_ENTRIES_PER_PAGE)
|
||||
// Only return 20 results.
|
||||
.limit(NFT_ENTRIES_PER_PAGE)
|
||||
|
||||
// console.log('listNftOffers() returning this data: ', data)
|
||||
|
||||
return {
|
||||
data,
|
||||
pagination: {
|
||||
currentPage: page,
|
||||
totalPages,
|
||||
totalOffers,
|
||||
pageSize: NFT_ENTRIES_PER_PAGE
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error in use-cases/offer/listNftOffers()')
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
async listFungibleOffers (page = 0) {
|
||||
@@ -816,7 +889,7 @@ class OfferUseCases {
|
||||
try {
|
||||
// Retrieve offers array.
|
||||
const offers = await this.adapters.nostr.read()
|
||||
console.log('offers: ', offers)
|
||||
// console.log('offers: ', offers)
|
||||
|
||||
for (let i = 0; i < offers.length; i++) {
|
||||
try {
|
||||
@@ -827,7 +900,7 @@ class OfferUseCases {
|
||||
|
||||
// Append the Nostr Event ID to the offer object
|
||||
offerObj.data.nostrEventId = offer.eventId
|
||||
console.log('loadOffers() offerObj: ', offerObj)
|
||||
// console.log('loadOffers() offerObj: ', offerObj)
|
||||
|
||||
if (offerObj.data.dataType === 'offer') {
|
||||
// Try to create new offer
|
||||
|
||||
@@ -493,4 +493,35 @@ describe('#wallet', () => {
|
||||
}
|
||||
})
|
||||
})
|
||||
describe('#cid2json', () => {
|
||||
it('should throw error if cid is not provided', async () => {
|
||||
try {
|
||||
await uut.cid2json()
|
||||
assert.fail('Unexpected code path')
|
||||
} catch (error) {
|
||||
assert.equal(error.message, 'urlOrCid must be a string!')
|
||||
}
|
||||
})
|
||||
|
||||
it('should convert cid to json', async () => {
|
||||
try {
|
||||
sandbox.stub(uut.bchWallet, 'cid2json').resolves({ json: offerMockData.mutableDataMock })
|
||||
const cid = 'bafkreidr6wfd6mcmwpea7abm5uk5rrprc2wfbcvo5wdcmtlolrpjab5oqm'
|
||||
const result = await uut.cid2json(cid)
|
||||
assert.isObject(result)
|
||||
} catch (error) {
|
||||
assert.fail('Unexpected code path')
|
||||
}
|
||||
})
|
||||
it('should convert ipfs url to json', async () => {
|
||||
try {
|
||||
sandbox.stub(uut.bchWallet, 'cid2json').resolves({ json: offerMockData.mutableDataMock })
|
||||
const url = 'https://ipfs.io/ipfs/bafkreidr6wfd6mcmwpea7abm5uk5rrprc2wfbcvo5wdcmtlolrpjab5oqm'
|
||||
const result = await uut.cid2json(url)
|
||||
assert.isObject(result)
|
||||
} catch (error) {
|
||||
assert.fail('Unexpected code path')
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -83,4 +83,13 @@ describe('#Order-REST-Router', () => {
|
||||
assert.isTrue(spy.calledOnce)
|
||||
})
|
||||
})
|
||||
describe('#deleteOrder', () => {
|
||||
it('should route to controller', async () => {
|
||||
sandbox.stub(uut.validators, 'ensureUser').resolves(true)
|
||||
const spy = sandbox.stub(uut.orderRESTController, 'deleteOrder').resolves(true)
|
||||
|
||||
await uut.deleteOrder()
|
||||
assert.isTrue(spy.calledOnce)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -149,7 +149,7 @@ const localdb = {
|
||||
static findById () {}
|
||||
static find () {}
|
||||
static findOne () {}
|
||||
|
||||
static countDocuments(){}
|
||||
async save () {
|
||||
return {}
|
||||
}
|
||||
|
||||
@@ -54,6 +54,7 @@ class MockBchWallet {
|
||||
}
|
||||
};
|
||||
this.optimize = async () => { };
|
||||
this.cid2json = async () => {};
|
||||
this.ar = new AdapterRoute()
|
||||
// Environment variable is used by wallet-balance.unit.js to force an error.
|
||||
if (process.env.NO_UTXO) {
|
||||
|
||||
@@ -126,6 +126,20 @@ const fungibleTokenData01 = {
|
||||
"immutableData": "troutsblog.com",
|
||||
"mutableData": ""
|
||||
}
|
||||
const mutableDataMock = {
|
||||
schema: 'ps007-v1.0.3',
|
||||
schemaDocs: 'https://github.com/Permissionless-Software-Foundation/specifications/blob/master/ps007-token-data-schema.md',
|
||||
tokenIcon: 'https://files.tokentiger.com/ipfs/view/bafkreidr6wfd6mcmwpea7abm5uk5rrprc2wfbcvo5wdcmtlolrpjab5oqm',
|
||||
fullSizedUrl: '',
|
||||
nsfw: false,
|
||||
userData: { currentUrl: 'https://tokentiger.com' },
|
||||
jsonLd: {},
|
||||
about: 'This is AI generated art.',
|
||||
category: '',
|
||||
tags: [],
|
||||
mediaType: 'image',
|
||||
currentOwner: {},
|
||||
}
|
||||
|
||||
const offerMockData = {
|
||||
data: {
|
||||
@@ -214,5 +228,6 @@ export default {
|
||||
fungibleTokenData01,
|
||||
offerMockData,
|
||||
deserealizeTxMockNoOperatorOut,
|
||||
deserealizeTxMock
|
||||
deserealizeTxMock,
|
||||
mutableDataMock
|
||||
};
|
||||
|
||||
@@ -108,6 +108,73 @@ describe('#offer-use-case', () => {
|
||||
assert.isFalse(result)
|
||||
})
|
||||
|
||||
it('should create offer with mutable data', async () => {
|
||||
const tokenDataMock = mockData.nftTokenData01
|
||||
const offerObj = mockData.offerMockData
|
||||
const mutableDataMock = mockData.mutableDataMock
|
||||
|
||||
// Mock dependencies
|
||||
// sandbox.stub(uut.adapters.wallet.bchWallet, 'utxoIsValid').resolves(false)
|
||||
sandbox.stub(uut, 'findOfferByTxid').throws(new Error('offer not found'))
|
||||
sandbox.stub(uut.retryQueue, 'addToQueue')
|
||||
.onCall(0).resolves({}) // Utxo Status call
|
||||
.onCall(1).resolves(tokenDataMock) // Token Data call
|
||||
.onCall(2).resolves(mutableDataMock)
|
||||
|
||||
const result = await uut.createOffer(offerObj)
|
||||
assert.isTrue(result)
|
||||
})
|
||||
|
||||
it('should skip userData stringify error', async () => {
|
||||
const tokenDataMock = mockData.nftTokenData01
|
||||
const offerObj = mockData.offerMockData
|
||||
const mutableDataMock = mockData.mutableDataMock
|
||||
mutableDataMock.userData = { n: 10n }
|
||||
// Mock dependencies
|
||||
// sandbox.stub(uut.adapters.wallet.bchWallet, 'utxoIsValid').resolves(false)
|
||||
sandbox.stub(uut, 'findOfferByTxid').throws(new Error('offer not found'))
|
||||
sandbox.stub(uut.retryQueue, 'addToQueue')
|
||||
.onCall(0).resolves({}) // Utxo Status call
|
||||
.onCall(1).resolves(tokenDataMock) // Token Data call
|
||||
.onCall(2).resolves(mutableDataMock)
|
||||
|
||||
const result = await uut.createOffer(offerObj)
|
||||
assert.isTrue(result)
|
||||
})
|
||||
|
||||
it('should handle error getting token data', async () => {
|
||||
// const tokenDataMock = mockData.nftTokenData01
|
||||
const offerObj = mockData.offerMockData
|
||||
const mutableDataMock = mockData.mutableDataMock
|
||||
mutableDataMock.userData = { n: 10n }
|
||||
// Mock dependencies
|
||||
// sandbox.stub(uut.adapters.wallet.bchWallet, 'utxoIsValid').resolves(false)
|
||||
sandbox.stub(uut, 'findOfferByTxid').throws(new Error('offer not found'))
|
||||
sandbox.stub(uut.retryQueue, 'addToQueue')
|
||||
.onCall(0).resolves({}) // Utxo Status call
|
||||
.onCall(1).throws(new Error('test error'))
|
||||
|
||||
const result = await uut.createOffer(offerObj)
|
||||
assert.isTrue(result)
|
||||
})
|
||||
|
||||
it('should handle error getting mutable data', async () => {
|
||||
const tokenDataMock = mockData.nftTokenData01
|
||||
const offerObj = mockData.offerMockData
|
||||
const mutableDataMock = mockData.mutableDataMock
|
||||
mutableDataMock.userData = { n: 10n }
|
||||
// Mock dependencies
|
||||
// sandbox.stub(uut.adapters.wallet.bchWallet, 'utxoIsValid').resolves(false)
|
||||
sandbox.stub(uut, 'findOfferByTxid').throws(new Error('offer not found'))
|
||||
sandbox.stub(uut.retryQueue, 'addToQueue')
|
||||
.onCall(0).resolves({}) // Utxo Status call
|
||||
.onCall(1).resolves(tokenDataMock) // Token Data call
|
||||
.onCall(2).throws(new Error('test error')) // cid2json call
|
||||
|
||||
const result = await uut.createOffer(offerObj)
|
||||
assert.isTrue(result)
|
||||
})
|
||||
|
||||
it('should create offer', async () => {
|
||||
const tokenDataMock = mockData.simpleNftTokenData01
|
||||
const offerObj = mockData.offerMockData
|
||||
@@ -400,7 +467,7 @@ describe('#offer-use-case', () => {
|
||||
}
|
||||
})
|
||||
|
||||
it('should list orders', async () => {
|
||||
it('should list offers', async () => {
|
||||
const queryMock = {
|
||||
sort () {
|
||||
return this
|
||||
@@ -414,7 +481,11 @@ describe('#offer-use-case', () => {
|
||||
sandbox.stub(uut.OfferModel, 'find').returns(queryMock)
|
||||
|
||||
const result = await uut.listNftOffers(1, true)
|
||||
assert.isArray(result)
|
||||
assert.isObject(result)
|
||||
assert.property(result, 'data')
|
||||
assert.property(result, 'pagination')
|
||||
assert.isArray(result.data)
|
||||
assert.isObject(result.pagination)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -781,27 +852,17 @@ describe('#offer-use-case', () => {
|
||||
assert.equal(result, 'N/A')
|
||||
})
|
||||
|
||||
it('should return if utxo cant be validated', async () => {
|
||||
it('should return if utxo can not be validated', async () => {
|
||||
// Mock dependencies
|
||||
const mock = Object.assign({}, mockData.offerMockData.data)
|
||||
sandbox.stub(uut.orderUseCase, 'findOrderByUtxo').resolves(mock)
|
||||
sandbox.stub(uut.adapters.wallet.bchWallet, 'utxoIsValid').throws(new Error('test error'))
|
||||
// sandbox.stub(uut.adapters.wallet.bchWallet, 'utxoIsValid').throws(new Error('test error'))
|
||||
sandbox.stub(uut.retryQueue, 'addToQueue').throws(new Error('test error'))
|
||||
|
||||
const result = await uut.acceptCounterOffer({ data: { /** .... */ } })
|
||||
assert.equal(result, 'N/A')
|
||||
})
|
||||
|
||||
it('should handle axios error', async () => {
|
||||
// Mock dependencies
|
||||
const mock = Object.assign({}, mockData.offerMockData.data)
|
||||
const stubErr = new Error()
|
||||
stubErr.isAxiosError = true
|
||||
sandbox.stub(uut.orderUseCase, 'findOrderByUtxo').resolves(mock)
|
||||
sandbox.stub(uut.adapters.wallet.bchWallet, 'utxoIsValid').throws(stubErr)
|
||||
|
||||
const result = await uut.acceptCounterOffer({ data: { /** .... */ } })
|
||||
assert.equal(result, 'N/A')
|
||||
})
|
||||
it('should return if utxo is invalid', async () => {
|
||||
// Mock dependencies
|
||||
const mock = Object.assign({}, mockData.offerMockData.data)
|
||||
|
||||
Reference in New Issue
Block a user