diff --git a/img/qortarrr.png b/img/qortarrr.png new file mode 100644 index 00000000..db1b2b6c Binary files /dev/null and b/img/qortarrr.png differ diff --git a/qortal-ui-core/src/plugins/routes.js b/qortal-ui-core/src/plugins/routes.js index 215e653d..fbaeddb3 100644 --- a/qortal-ui-core/src/plugins/routes.js +++ b/qortal-ui-core/src/plugins/routes.js @@ -34,6 +34,7 @@ const sendLtc = api.sendLtc; const sendDoge = api.sendDoge; const sendDgb = api.sendDgb; const sendRvn = api.sendRvn; +const sendArrr = api.sendArrr; export const routes = { hello: async (req) => { @@ -411,4 +412,17 @@ export const routes = { } return response; }, + + sendArrr: async (req) => { + let response + try { + const res = await sendArrr(req.data) + response = res + } catch (e) { + console.error(e) + console.error(e.message) + response = e.message + } + return response + }, }; diff --git a/qortal-ui-crypto/api/PhraseWallet.js b/qortal-ui-crypto/api/PhraseWallet.js index 34929ee4..64baa02b 100644 --- a/qortal-ui-crypto/api/PhraseWallet.js +++ b/qortal-ui-crypto/api/PhraseWallet.js @@ -168,6 +168,21 @@ export default class PhraseWallet { } }).createWallet(new Uint8Array(rvnSeed), false, 'RVN'); + // Create Pirate Chain HD Wallet + const arrrSeed = [...addrSeed]; + const arrrWallet = new AltcoinHDWallet({ + mainnet: { + private: 0x0488ADE4, + public: 0x0488B21E, + prefix: [0x16, 0x9A] + }, + testnet: { + private: 0x04358394, + public: 0x043587CF, + prefix: [0x14, 0x51] + } + }).createWallet(new Uint8Array(arrrSeed), false, 'ARRR'); + this._addresses[nonce] = { address, btcWallet, @@ -175,6 +190,7 @@ export default class PhraseWallet { dogeWallet, dgbWallet, rvnWallet, + arrrWallet, qoraAddress, keyPair: { publicKey: addrKeyPair.publicKey, diff --git a/qortal-ui-crypto/api/api.js b/qortal-ui-crypto/api/api.js index 30ca6d27..bf40d58a 100644 --- a/qortal-ui-crypto/api/api.js +++ b/qortal-ui-crypto/api/api.js @@ -4,6 +4,6 @@ export { transactionTypes as transactions } from './transactions/transactions.js export { processTransaction, createTransaction, computeChatNonce, signChatTransaction, signArbitraryTransaction } from './createTransaction.js' -export { tradeBotCreateRequest, tradeBotRespondRequest, signTradeBotTxn, deleteTradeOffer, sendBtc, sendLtc, sendDoge, sendDgb, sendRvn } from './tradeRequest.js' +export { tradeBotCreateRequest, tradeBotRespondRequest, signTradeBotTxn, deleteTradeOffer, sendBtc, sendLtc, sendDoge, sendDgb, sendRvn, sendArrr } from './tradeRequest.js' export { cancelAllOffers } from './transactions/trade-portal/tradeoffer/cancelAllOffers.js' diff --git a/qortal-ui-crypto/api/bitcoin/AltcoinHDWallet.js b/qortal-ui-crypto/api/bitcoin/AltcoinHDWallet.js index 2050c87e..0d416d54 100644 --- a/qortal-ui-crypto/api/bitcoin/AltcoinHDWallet.js +++ b/qortal-ui-crypto/api/bitcoin/AltcoinHDWallet.js @@ -276,6 +276,8 @@ export default class AltcoinHDWallet { const privateKeyHash = seedHash.slice(0, 32); + this.seed58 = Base58.encode(privateKeyHash); + const _privateKeyHash = [...privateKeyHash] let privateKeyBigInt = BigInteger.fromByteArrayUnsigned(_privateKeyHash); @@ -687,8 +689,14 @@ export default class AltcoinHDWallet { * Derive Litecoin Legacy Address */ - // Append Address Prefix - const k = [this.versionBytes.mainnet.prefix].concat(...this.grandChildPublicKeyHash) + // Append Address Prefix + let prefix = [this.versionBytes.mainnet.prefix] + if (2 == this.versionBytes.mainnet.prefix.length) { + prefix = [this.versionBytes.mainnet.prefix[0]] + prefix.push([this.versionBytes.mainnet.prefix[1]]) + } + + const k = prefix.concat(...this.grandChildPublicKeyHash) // Derive Checksum const _addressCheckSum = new Sha256().process(new Sha256().process(new Uint8Array(k)).finish().result).finish().result @@ -859,6 +867,7 @@ export default class AltcoinHDWallet { derivedMasterPublicKey: this.masterPublicKey, _tDerivedMasterPrivateKey: this._tMasterPrivateKey, _tDerivedmasterPublicKey: this._tmasterPublicKey, + seed58: this.seed58, // derivedPrivateChildKey: this.xPrivateChildKey, // derivedPublicChildKey: this.xPublicChildKey, // derivedPrivateGrandChildKey: this.xPrivateGrandChildKey, diff --git a/qortal-ui-crypto/api/tradeRequest.js b/qortal-ui-crypto/api/tradeRequest.js index fb4a2700..f3ae00f0 100644 --- a/qortal-ui-crypto/api/tradeRequest.js +++ b/qortal-ui-crypto/api/tradeRequest.js @@ -130,3 +130,16 @@ export const sendRvn = (requestObject) => { }) } +// Send ARRR +export const sendArrr = (requestObject) => { + const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]; + + return request(`/crosschain/arrr/send?apiKey=${myNode.apiKey}`, { + method: 'POST', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json' + }, + body: JSON.stringify(requestObject) + }) +} diff --git a/qortal-ui-plugins/plugins/core/trade-portal/trade-portal.src.js b/qortal-ui-plugins/plugins/core/trade-portal/trade-portal.src.js index 215a8262..cb68bb02 100644 --- a/qortal-ui-plugins/plugins/core/trade-portal/trade-portal.src.js +++ b/qortal-ui-plugins/plugins/core/trade-portal/trade-portal.src.js @@ -40,7 +40,8 @@ class TradePortal extends LitElement { isLoadingHistoricTrades: { type: Boolean }, isLoadingOpenTrades: { type: Boolean }, isLoadingMyOpenOrders: { type: Boolean }, - theme: { type: String, reflect: true } + theme: { type: String, reflect: true }, + arrrWalletAddress: { type: String }, } } @@ -370,6 +371,10 @@ class TradePortal extends LitElement { background-image: url('/img/qortrvn.png'); } + .arrr.coinName:before { + background-image: url('/img/qortarrr.png'); + } + .coinName { display: inline-block; height: 26px; @@ -519,13 +524,30 @@ class TradePortal extends LitElement { tradeFee: "~0.006" } + let piratechain = { + name: "PIRATECHAIN", + balance: "0", + coinCode: "ARRR", + openOrders: [], + openFilteredOrders: [], + historicTrades: [], + myOrders: [], + myHistoricTrades: [], + myOfferingOrders: [], + openTradeOrders: null, + tradeOffersSocketCounter: 1, + coinAmount: this.amountString, + tradeFee: "~0.0002" + } + this.listedCoins = new Map() this.listedCoins.set("QORTAL", qortal) this.listedCoins.set("BITCOIN", bitcoin) this.listedCoins.set("LITECOIN", litecoin) this.listedCoins.set("DOGECOIN", dogecoin) this.listedCoins.set("DIGIBYTE", digibyte) - this.listedCoins.set("RAVENCOIN", ravencoin) + this.listedCoins.set("RAVENCOIN", ravencoin) + this.listedCoins.set("PIRATECHAIN", piratechain) workers.set("QORTAL", { tradesConnectedWorker: null, @@ -557,6 +579,11 @@ class TradePortal extends LitElement { handleStuckTradesConnectedWorker: null }) + workers.set("PIRATECHAIN", { + tradesConnectedWorker: null, + handleStuckTradesConnectedWorker: null + }) + this.selectedCoin = "LITECOIN" this.selectedAddress = {} this.config = {} @@ -571,6 +598,7 @@ class TradePortal extends LitElement { this.isLoadingOpenTrades = true this.isLoadingMyOpenOrders = false this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light' + this.arrrWalletAddress = '' } // TODO: Move each template to a separate components! Maybe @@ -948,6 +976,7 @@ class TradePortal extends LitElement { QORT / DOGE QORT / DGB QORT / RVN + QORT / ARRR
@@ -988,6 +1017,7 @@ class TradePortal extends LitElement { this.changeTheme() this.changeLanguage() this.updateWalletBalance() + this.fetchWalletAddress(this.selectedCoin) setTimeout(() => { this.displayTabContent('buy') @@ -1122,6 +1152,10 @@ class TradePortal extends LitElement { _url = `/crosschain/rvn/walletbalance?apiKey=${this.getApiKey()}` _body = window.parent.reduxStore.getState().app.selectedAddress.rvnWallet.derivedMasterPublicKey break + case 'PIRATECHAIN': + _url = `/crosschain/arrr/walletbalance?apiKey=${this.getApiKey()}` + _body = window.parent.reduxStore.getState().app.selectedAddress.arrrWallet.seed58 + break default: break } @@ -1141,6 +1175,26 @@ class TradePortal extends LitElement { }) } + async fetchWalletAddress(coin) { + console.log("fetchWalletAddress: " + coin) + switch (coin) { + case 'PIRATECHAIN': + let res = await parentEpml.request('apiCall', { + url: `/crosschain/arrr/walletaddress?apiKey=${this.getApiKey()}`, + method: 'POST', + body: `${window.parent.reduxStore.getState().app.selectedAddress.arrrWallet.seed58}`, + }) + if (res != null && res.error != 1201) { + this.arrrWalletAddress = res + } + break + + default: + // Not used for other coins yet + break + } + } + setForeignCoin(coin,beingInitialized) { let _this = this this.selectedCoin = coin @@ -1174,6 +1228,7 @@ class TradePortal extends LitElement { this.clearSellForm() this.clearBuyForm() this.updateWalletBalance() + this.fetchWalletAddress(coin) } displayTabContent(tab) { @@ -1628,6 +1683,49 @@ class TradePortal extends LitElement { }) } + /** + * PirateChainACCTv1 TRADEBOT STATES + * - BOB_WAITING_FOR_AT_CONFIRM + * - BOB_WAITING_FOR_MESSAGE + * - BOB_WAITING_FOR_AT_REDEEM + * - BOB_DONE + * - BOB_REFUNDED + * - ALICE_WAITING_FOR_AT_LOCK + * - ALICE_DONE + * - ALICE_REFUNDING_A + * - ALICE_REFUNDED + * + * @param {[{}]} states + */ + + const PirateChainACCTv1 = (states) => { + // Reverse the states + states.reverse() + states.forEach((state) => { + if (state.creatorAddress === this.selectedAddress.address) { + if (state.tradeState == 'BOB_WAITING_FOR_AT_CONFIRM') { + this.changeTradeBotState(state, 'PENDING') + } else if (state.tradeState == 'BOB_WAITING_FOR_MESSAGE') { + this.changeTradeBotState(state, 'LISTED') + } else if (state.tradeState == 'BOB_WAITING_FOR_AT_REDEEM') { + this.changeTradeBotState(state, 'TRADING') + } else if (state.tradeState == 'BOB_DONE') { + this.handleCompletedState(state) + } else if (state.tradeState == 'BOB_REFUNDED') { + this.handleCompletedState(state) + } else if (state.tradeState == 'ALICE_WAITING_FOR_AT_LOCK') { + this.changeTradeBotState(state, 'BUYING') + } else if (state.tradeState == 'ALICE_DONE') { + this.handleCompletedState(state) + } else if (state.tradeState == 'ALICE_REFUNDING_A') { + this.changeTradeBotState(state, 'REFUNDING') + } else if (state.tradeState == 'ALICE_REFUNDED') { + this.handleCompletedState(state) + } + } + }) + } + switch (this.selectedCoin) { case 'BITCOIN': BitcoinACCTv1(tradeStates) @@ -1644,6 +1742,9 @@ class TradePortal extends LitElement { case 'RAVENCOIN': RavencoinACCTv1(tradeStates) break + case 'PIRATECHAIN': + PirateChainACCTv1(tradeStates) + break default: break } @@ -1942,6 +2043,9 @@ class TradePortal extends LitElement { case 'RAVENCOIN': _receivingAddress = this.selectedAddress.rvnWallet.address break + case 'PIRATECHAIN': + _receivingAddress = this.arrrWalletAddress + break default: break } @@ -2011,6 +2115,9 @@ class TradePortal extends LitElement { case 'RAVENCOIN': _foreignKey = this.selectedAddress.rvnWallet.derivedMasterPrivateKey break + case 'PIRATECHAIN': + _foreignKey = this.selectedAddress.arrrWallet.seed58 + break default: break }