4
1
mirror of https://github.com/Qortal/qortal-ui.git synced 2025-02-11 17:55:51 +00:00

Added qortalRequests

- Added IS_USING_GATEWAY
- Added SHOW_ACTIONS
- Added ENCRYPT_QORTAL_GROUP_DATA
- Added DECRYPT_QORTAL_GROUP_DATA
- Added ENCRYPT_DATA_WITH_SHARING_KEY
- Added DECRYPT_DATA_WITH_SHARING_KEY
- Added CREATE_TRADE_BUY_ORDER
- Added CREATE_TRADE_SELL_ORDER
- Added CANCEL_TRADE_SELL_ORDER
- Fixed SIGN_TRANSACTION
This commit is contained in:
AlphaX-Qortal 2025-02-03 16:11:13 +01:00
parent f3874fdc72
commit 34cb1bcb38
6 changed files with 1749 additions and 181 deletions

View File

@ -54,3 +54,67 @@ export const mimeToExtensionMap = {
"application/x-gzip": ".gz", "application/x-gzip": ".gz",
"application/x-bzip2": ".bz2", "application/x-bzip2": ".bz2",
} }
export const listOfAllQortalRequests = [
'IS_USING_GATEWAY',
'ADMIN_ACTION',
'SHOW_ACTIONS',
'CREATE_AND_COPY_EMBED_LINK',
'GET_USER_ACCOUNT',
'REGISTER_NAME',
'UPDATE_NAME',
'ENCRYPT_DATA',
'DECRYPT_DATA',
'ENCRYPT_QORTAL_GROUP_DATA',
'DECRYPT_QORTAL_GROUP_DATA',
'ENCRYPT_DATA_WITH_SHARING_KEY',
'DECRYPT_DATA_WITH_SHARING_KEY',
'CREATE_TRADE_BUY_ORDER',
'CREATE_TRADE_SELL_ORDER',
'CANCEL_TRADE_SELL_ORDER',
'GET_LIST_ITEMS',
'ADD_LIST_ITEMS',
'DELETE_LIST_ITEM',
'GET_FRIENDS_LIST',
'LINK_TO_QDN_RESOURCE',
'QDN_RESOURCE_DISPLAYED',
'SET_TAB_NOTIFICATIONS',
'PUBLISH_QDN_RESOURCE',
'PUBLISH_MULTIPLE_QDN_RESOURCES',
'VOTE_ON_POLL',
'CREATE_POLL',
'OPEN_NEW_TAB',
'NOTIFICATIONS_PERMISSION',
'SEND_LOCAL_NOTIFICATION',
'SEND_CHAT_MESSAGE',
'JOIN_GROUP',
'LEAVE_GROUP',
'INVITE_TO_GROUP',
'CANCEL_GROUP_INVITE',
'KICK_FROM_GROUP',
'BAN_FROM_GROUP',
'CANCEL_GROUP_BAN',
'ADD_GROUP_ADMIN',
'REMOVE_GROUP_ADMIN',
'SAVE_FILE',
'GET_HOSTED_DATA',
'DELETE_HOSTED_DATA',
'DEPLOY_AT',
'GET_PROFILE_DATA',
'SET_PROFILE_DATA',
'OPEN_PROFILE',
'GET_USER_WALLET',
'GET_WALLET_BALANCE',
'GET_USER_WALLET_INFO',
'GET_CROSSCHAIN_SERVER_INFO',
'GET_TX_ACTIVITY_SUMMARY',
'GET_FOREIGN_FEE',
'UPDATE_FOREIGN_FEE',
'GET_SERVER_CONNECTION_HISTORY',
'SET_CURRENT_FOREIGN_SERVER',
'ADD_FOREIGN_SERVER',
'REMOVE_FOREIGN_SERVER',
'GET_DAY_SUMMARY',
'SIGN_TRANSACTION',
'SEND_COIN'
]

View File

@ -1,3 +1,4 @@
import Base58 from '../../../../crypto/api/deps/Base58'
import nacl from '../../../../crypto/api/deps/nacl-fast.js' import nacl from '../../../../crypto/api/deps/nacl-fast.js'
import ed2curve from '../../../../crypto/api/deps/ed2curve.js' import ed2curve from '../../../../crypto/api/deps/ed2curve.js'
@ -33,10 +34,14 @@ export const fileToBase64 = (file) => new Promise(async (resolve, reject) => {
if (!reader) { if (!reader) {
reader = new FileReader() reader = new FileReader()
} }
await semaphore.acquire() await semaphore.acquire()
reader.readAsDataURL(file) reader.readAsDataURL(file)
reader.onload = () => { reader.onload = () => {
const dataUrl = reader.result const dataUrl = reader.result
if (typeof dataUrl === "string") { if (typeof dataUrl === "string") {
const base64String = dataUrl.split(',')[1] const base64String = dataUrl.split(',')[1]
reader.onload = null reader.onload = null
@ -49,6 +54,7 @@ export const fileToBase64 = (file) => new Promise(async (resolve, reject) => {
} }
semaphore.release() semaphore.release()
} }
reader.onerror = (error) => { reader.onerror = (error) => {
reader.onload = null reader.onload = null
reader.onerror = null reader.onerror = null
@ -73,9 +79,11 @@ export function base64ToUint8Array(base64) {
const binaryString = atob(base64) const binaryString = atob(base64)
const len = binaryString.length const len = binaryString.length
const bytes = new Uint8Array(len) const bytes = new Uint8Array(len)
for (let i = 0; i < len; i++) { for (let i = 0; i < len; i++) {
bytes[i] = binaryString.charCodeAt(i) bytes[i] = binaryString.charCodeAt(i)
} }
return bytes return bytes
} }
@ -226,6 +234,102 @@ export const encryptDataGroup = ({ data64, publicKeys }) => {
} }
} }
export const encryptDataGroupNew = (data64, publicKeys, privateKey, userPublicKey, customSymmetricKey) => {
let combinedPublicKeys = [...publicKeys, userPublicKey]
const decodedPrivateKey = Base58.decode(privateKey)
const publicKeysDuplicateFree = [...new Set(combinedPublicKeys)]
const Uint8ArrayData = base64ToUint8Array(data64)
if (!(Uint8ArrayData instanceof Uint8Array)) {
throw new Error("The Uint8ArrayData you've submitted is invalid")
}
try {
// Generate a random symmetric key for the message.
let messageKey
if(customSymmetricKey){
messageKey = base64ToUint8Array(customSymmetricKey)
} else {
messageKey = new Uint8Array(32)
crypto.getRandomValues(messageKey)
}
if(!messageKey) throw new Error('Cannot create symmetric key')
const nonce = new Uint8Array(24)
crypto.getRandomValues(nonce)
// Encrypt the data with the symmetric key.
const encryptedData = nacl.secretbox(Uint8ArrayData, nonce, messageKey)
// Generate a keyNonce outside of the loop.
const keyNonce = new Uint8Array(24)
crypto.getRandomValues(keyNonce)
// Encrypt the symmetric key for each recipient.
let encryptedKeys = []
publicKeysDuplicateFree.forEach((recipientPublicKey) => {
const publicKeyUnit8Array = Base58.decode(recipientPublicKey)
const convertedPrivateKey = ed2curve.convertSecretKey(decodedPrivateKey)
const convertedPublicKey = ed2curve.convertPublicKey(publicKeyUnit8Array)
const sharedSecret = new Uint8Array(32)
// the length of the sharedSecret will be 32 + 16
// When you're encrypting data using nacl.secretbox, it's adding an authentication tag to the result, which is 16 bytes long. This tag is used for verifying the integrity and authenticity of the data when it is decrypted
nacl.lowlevel.crypto_scalarmult(sharedSecret, convertedPrivateKey, convertedPublicKey)
// Encrypt the symmetric key with the shared secret.
const encryptedKey = nacl.secretbox(messageKey, keyNonce, sharedSecret)
encryptedKeys.push(encryptedKey)
})
const str = "qortalGroupEncryptedData"
const strEncoder = new TextEncoder()
const strUint8Array = strEncoder.encode(str)
// Convert sender's public key to Uint8Array and add to the message
const senderPublicKeyUint8Array = Base58.decode(userPublicKey)
// Combine all data into a single Uint8Array.
// Calculate size of combinedData
let combinedDataSize = strUint8Array.length + nonce.length + keyNonce.length + senderPublicKeyUint8Array.length + encryptedData.length + 4
let encryptedKeysSize = 0
encryptedKeys.forEach((key) => {
encryptedKeysSize += key.length
})
combinedDataSize += encryptedKeysSize
let combinedData = new Uint8Array(combinedDataSize)
combinedData.set(strUint8Array)
combinedData.set(nonce, strUint8Array.length)
combinedData.set(keyNonce, strUint8Array.length + nonce.length)
combinedData.set(senderPublicKeyUint8Array, strUint8Array.length + nonce.length + keyNonce.length)
combinedData.set(encryptedData, strUint8Array.length + nonce.length + keyNonce.length + senderPublicKeyUint8Array.length)
// Initialize offset for encryptedKeys
let encryptedKeysOffset = strUint8Array.length + nonce.length + keyNonce.length + senderPublicKeyUint8Array.length + encryptedData.length
encryptedKeys.forEach((key) => {
combinedData.set(key, encryptedKeysOffset)
encryptedKeysOffset += key.length
})
const countArray = new Uint8Array(new Uint32Array([publicKeysDuplicateFree.length]).buffer)
combinedData.set(countArray, combinedData.length - 4)
return uint8ArrayToBase64(combinedData)
} catch (error) {
console.log('error', error)
throw new Error("Error in encrypting data")
}
}
export function uint8ArrayStartsWith(uint8Array, string) { export function uint8ArrayStartsWith(uint8Array, string) {
const stringEncoder = new TextEncoder() const stringEncoder = new TextEncoder()
const stringUint8Array = stringEncoder.encode(string) const stringUint8Array = stringEncoder.encode(string)
@ -317,3 +421,100 @@ export function decryptGroupData(data64EncryptedData) {
} }
throw new Error("Unable to decrypt data") throw new Error("Unable to decrypt data")
} }
export function decryptGroupDataNew(data64EncryptedData, privateKey) {
const allCombined = base64ToUint8Array(data64EncryptedData)
const str = "qortalGroupEncryptedData"
const strEncoder = new TextEncoder()
const strUint8Array = strEncoder.encode(str)
// Extract the nonce
const nonceStartPosition = strUint8Array.length
// Nonce is 24 bytes
const nonceEndPosition = nonceStartPosition + 24
const nonce = allCombined.slice(nonceStartPosition, nonceEndPosition)
// Extract the shared keyNonce
const keyNonceStartPosition = nonceEndPosition
// Nonce is 24 bytes
const keyNonceEndPosition = keyNonceStartPosition + 24
const keyNonce = allCombined.slice(keyNonceStartPosition, keyNonceEndPosition)
// Extract the sender's public key
const senderPublicKeyStartPosition = keyNonceEndPosition
// Public keys are 32 bytes
const senderPublicKeyEndPosition = senderPublicKeyStartPosition + 32
const senderPublicKey = allCombined.slice(senderPublicKeyStartPosition, senderPublicKeyEndPosition)
// Calculate count first
// 4 bytes before the end, since count is stored in Uint32 (4 bytes)
const countStartPosition = allCombined.length - 4
const countArray = allCombined.slice(countStartPosition, countStartPosition + 4)
const count = new Uint32Array(countArray.buffer)[0]
// Then use count to calculate encryptedData
// start position of encryptedData
const encryptedDataStartPosition = senderPublicKeyEndPosition
const encryptedDataEndPosition = allCombined.length - ((count * (32 + 16)) + 4)
const encryptedData = allCombined.slice(encryptedDataStartPosition, encryptedDataEndPosition)
// Extract the encrypted keys
// 32+16 = 48
const combinedKeys = allCombined.slice(encryptedDataEndPosition, encryptedDataEndPosition + (count * 48))
if (!privateKey) {
throw new Error("Unable to retrieve keys")
}
const decodedPrivateKey = Base58.decode(privateKey)
const convertedPrivateKey = ed2curve.convertSecretKey(decodedPrivateKey)
const convertedSenderPublicKey = ed2curve.convertPublicKey(senderPublicKey)
const sharedSecret = new Uint8Array(32)
nacl.lowlevel.crypto_scalarmult(sharedSecret, convertedPrivateKey, convertedSenderPublicKey)
for (let i = 0; i < count; i++) {
const encryptedKey = combinedKeys.slice(i * 48, (i + 1) * 48)
console.log("Encrypted KEY", encryptedKey)
console.log("KEY NONCE", keyNonce)
console.log("SHARED SECRET", sharedSecret)
// Decrypt the symmetric key.
const decryptedKey = nacl.secretbox.open(encryptedKey, keyNonce, sharedSecret)
// If decryption was successful, decryptedKey will not be null.
if (decryptedKey) {
// Decrypt the data using the symmetric key.
const decryptedData = nacl.secretbox.open(encryptedData, nonce, decryptedKey)
// If decryption was successful, decryptedData will not be null.
if (decryptedData) {
return {decryptedData, count}
}
}
}
throw new Error("Unable to decrypt data")
}
export const base64ToBlobUrl = (base64, mimeType = "image/png") => {
const binary = atob(base64)
const array = []
for (let i = 0; i < binary.length; i++) {
array.push(binary.charCodeAt(i))
}
const blob = new Blob([new Uint8Array(array)], { type: mimeType })
return URL.createObjectURL(blob)
}
export let groupSecretkeys = {}
export function roundUpToDecimals(number, decimals = 8) {
const factor = Math.pow(10, decimals)
return Math.ceil(+number * factor) / factor
}

View File

@ -1,62 +1,46 @@
// IS_USING_GATEWAY
export const IS_USING_GATEWAY = 'IS_USING_GATEWAY'
// ADMIN_ACTION
export const ADMIN_ACTION = 'ADMIN_ACTION'
// SHOW_ACTIONS
export const SHOW_ACTIONS = 'SHOW_ACTIONS'
// CREATE_AND_COPY_EMBED_LINK
// GET_USER_ACCOUNT // GET_USER_ACCOUNT
export const GET_USER_ACCOUNT = 'GET_USER_ACCOUNT' export const GET_USER_ACCOUNT = 'GET_USER_ACCOUNT'
// LINK_TO_QDN_RESOURCE // REGISTER_NAME
export const LINK_TO_QDN_RESOURCE = 'LINK_TO_QDN_RESOURCE' // UPDATE_NAME
// QDN_RESOURCE_DISPLAYED // ENCRYPT_DATA
export const QDN_RESOURCE_DISPLAYED = 'QDN_RESOURCE_DISPLAYED' export const ENCRYPT_DATA = 'ENCRYPT_DATA'
// PUBLISH_QDN_RESOURCE // DECRYPT_DATA
export const PUBLISH_QDN_RESOURCE = 'PUBLISH_QDN_RESOURCE' export const DECRYPT_DATA = 'DECRYPT_DATA'
// SEND_CHAT_MESSAGE // ENCRYPT_QORTAL_GROUP_DATA
export const SEND_CHAT_MESSAGE = 'SEND_CHAT_MESSAGE' export const ENCRYPT_QORTAL_GROUP_DATA = 'ENCRYPT_QORTAL_GROUP_DATA'
// JOIN_GROUP // DECRYPT_QORTAL_GROUP_DATA
export const JOIN_GROUP = 'JOIN_GROUP' export const DECRYPT_QORTAL_GROUP_DATA = 'DECRYPT_QORTAL_GROUP_DATA'
// DEPLOY_AT // ENCRYPT_DATA_WITH_SHARING_KEY
export const DEPLOY_AT = 'DEPLOY_AT' export const ENCRYPT_DATA_WITH_SHARING_KEY = 'ENCRYPT_DATA_WITH_SHARING_KEY'
// GET_USER_WALLET // DECRYPT_DATA_WITH_SHARING_KEY
export const GET_USER_WALLET = 'GET_USER_WALLET' export const DECRYPT_DATA_WITH_SHARING_KEY = 'DECRYPT_DATA_WITH_SHARING_KEY'
// GET_USER_WALLET_INFO // CREATE_TRADE_BUY_ORDER
export const GET_USER_WALLET_INFO = 'GET_USER_WALLET_INFO' export const CREATE_TRADE_BUY_ORDER = 'CREATE_TRADE_BUY_ORDER'
// GET_CROSSCHAIN_SERVER_INFO // CREATE_TRADE_SELL_ORDER
export const GET_CROSSCHAIN_SERVER_INFO = 'GET_CROSSCHAIN_SERVER_INFO' export const CREATE_TRADE_SELL_ORDER = 'CREATE_TRADE_SELL_ORDER'
// GET_TX_ACTIVITY_SUMMARY // CANCEL_TRADE_SELL_ORDER
export const GET_TX_ACTIVITY_SUMMARY = 'GET_TX_ACTIVITY_SUMMARY' export const CANCEL_TRADE_SELL_ORDER = 'CANCEL_TRADE_SELL_ORDER'
// GET_FOREIGN_FEE action
export const GET_FOREIGN_FEE = 'GET_FOREIGN_FEE';
// UPDATE_FOREIGN_FEE action
export const UPDATE_FOREIGN_FEE = 'UPDATE_FOREIGN_FEE';
// GET_SERVER_CONNECTION_HISTORY
export let GET_SERVER_CONNECTION_HISTORY = "GET_SERVER_CONNECTION_HISTORY";
// SET_CURRENT_FOREIGN_SERVER
export let SET_CURRENT_FOREIGN_SERVER = "SET_CURRENT_FOREIGN_SERVER";
// ADD_FOREIGN_SERVER
export let ADD_FOREIGN_SERVER = "ADD_FOREIGN_SERVER";
// REMOVE_FOREIGN_SERVER
export let REMOVE_FOREIGN_SERVER = "REMOVE_FOREIGN_SERVER";
// GET_WALLET_BALANCE action
export const GET_WALLET_BALANCE = 'GET_WALLET_BALANCE'
// SEND_COIN
export const SEND_COIN = 'SEND_COIN'
// PUBLISH_MULTIPLE_QDN_RESOURCES
export const PUBLISH_MULTIPLE_QDN_RESOURCES = 'PUBLISH_MULTIPLE_QDN_RESOURCES'
// GET_LIST_ITEMS // GET_LIST_ITEMS
export const GET_LIST_ITEMS = 'GET_LIST_ITEMS' export const GET_LIST_ITEMS = 'GET_LIST_ITEMS'
@ -67,21 +51,30 @@ export const ADD_LIST_ITEMS = 'ADD_LIST_ITEMS'
// DELETE_LIST_ITEM // DELETE_LIST_ITEM
export const DELETE_LIST_ITEM = 'DELETE_LIST_ITEM' export const DELETE_LIST_ITEM = 'DELETE_LIST_ITEM'
// ENCRYPT_DATA // GET_FRIENDS_LIST
export const ENCRYPT_DATA = 'ENCRYPT_DATA' export const GET_FRIENDS_LIST = 'GET_FRIENDS_LIST'
// DECRYPT_DATA // LINK_TO_QDN_RESOURCE
export const DECRYPT_DATA = 'DECRYPT_DATA' export const LINK_TO_QDN_RESOURCE = 'LINK_TO_QDN_RESOURCE'
// DECRYPT_DATA_GROUP // QDN_RESOURCE_DISPLAYED
export const DECRYPT_DATA_GROUP = 'DECRYPT_DATA_GROUP' export const QDN_RESOURCE_DISPLAYED = 'QDN_RESOURCE_DISPLAYED'
// SAVE_FILE
export const SAVE_FILE = 'SAVE_FILE'
// SET_TAB_NOTIFICATIONS // SET_TAB_NOTIFICATIONS
export const SET_TAB_NOTIFICATIONS = 'SET_TAB_NOTIFICATIONS' export const SET_TAB_NOTIFICATIONS = 'SET_TAB_NOTIFICATIONS'
// PUBLISH_QDN_RESOURCE
export const PUBLISH_QDN_RESOURCE = 'PUBLISH_QDN_RESOURCE'
// PUBLISH_MULTIPLE_QDN_RESOURCES
export const PUBLISH_MULTIPLE_QDN_RESOURCES = 'PUBLISH_MULTIPLE_QDN_RESOURCES'
// VOTE_ON_POLL
export const VOTE_ON_POLL= 'VOTE_ON_POLL'
// CREATE_POLL
export const CREATE_POLL= 'CREATE_POLL'
// OPEN_NEW_TAB // OPEN_NEW_TAB
export const OPEN_NEW_TAB = 'OPEN_NEW_TAB' export const OPEN_NEW_TAB = 'OPEN_NEW_TAB'
@ -91,11 +84,29 @@ export const NOTIFICATIONS_PERMISSION = 'NOTIFICATIONS_PERMISSION'
// SEND_LOCAL_NOTIFICATION // SEND_LOCAL_NOTIFICATION
export const SEND_LOCAL_NOTIFICATION = 'SEND_LOCAL_NOTIFICATION' export const SEND_LOCAL_NOTIFICATION = 'SEND_LOCAL_NOTIFICATION'
// VOTE_ON_POLL // SEND_CHAT_MESSAGE
export const VOTE_ON_POLL= 'VOTE_ON_POLL' export const SEND_CHAT_MESSAGE = 'SEND_CHAT_MESSAGE'
// CREATE_POLL // JOIN_GROUP
export const CREATE_POLL= 'CREATE_POLL' export const JOIN_GROUP = 'JOIN_GROUP'
// LEAVE_GROUP
// INVITE_TO_GROUP
// CANCEL_GROUP_INVITE
// KICK_FROM_GROUP
// BAN_FROM_GROUP
// CANCEL_GROUP_BAN
// ADD_GROUP_ADMIN
// REMOVE_GROUP_ADMIN
// SAVE_FILE
export const SAVE_FILE = 'SAVE_FILE'
// GET_HOSTED_DATA
// DELETE_HOSTED_DATA
// DEPLOY_AT
export const DEPLOY_AT = 'DEPLOY_AT'
// GET_PROFILE_DATA // GET_PROFILE_DATA
export const GET_PROFILE_DATA = 'GET_PROFILE_DATA' export const GET_PROFILE_DATA = 'GET_PROFILE_DATA'
@ -103,17 +114,47 @@ export const GET_PROFILE_DATA = 'GET_PROFILE_DATA'
// SET_PROFILE_DATA // SET_PROFILE_DATA
export const SET_PROFILE_DATA= 'SET_PROFILE_DATA' export const SET_PROFILE_DATA= 'SET_PROFILE_DATA'
// GET_DAY_SUMMARY
export const GET_DAY_SUMMARY = 'GET_DAY_SUMMARY'
// GET_FRIENDS_LIST
export const GET_FRIENDS_LIST = 'GET_FRIENDS_LIST'
// OPEN_PROFILE // OPEN_PROFILE
export const OPEN_PROFILE = 'OPEN_PROFILE' export const OPEN_PROFILE = 'OPEN_PROFILE'
// ADMIN_ACTION // GET_USER_WALLET
export const ADMIN_ACTION = 'ADMIN_ACTION' export const GET_USER_WALLET = 'GET_USER_WALLET'
// GET_WALLET_BALANCE
export const GET_WALLET_BALANCE = 'GET_WALLET_BALANCE'
// GET_USER_WALLET_INFO
export const GET_USER_WALLET_INFO = 'GET_USER_WALLET_INFO'
// GET_CROSSCHAIN_SERVER_INFO
export const GET_CROSSCHAIN_SERVER_INFO = 'GET_CROSSCHAIN_SERVER_INFO'
// GET_TX_ACTIVITY_SUMMARY
export const GET_TX_ACTIVITY_SUMMARY = 'GET_TX_ACTIVITY_SUMMARY'
// GET_FOREIGN_FEE
export const GET_FOREIGN_FEE = 'GET_FOREIGN_FEE'
// UPDATE_FOREIGN_FEE
export const UPDATE_FOREIGN_FEE = 'UPDATE_FOREIGN_FEE'
// GET_SERVER_CONNECTION_HISTORY
export let GET_SERVER_CONNECTION_HISTORY = 'GET_SERVER_CONNECTION_HISTORY'
// SET_CURRENT_FOREIGN_SERVER
export let SET_CURRENT_FOREIGN_SERVER = 'SET_CURRENT_FOREIGN_SERVER'
// ADD_FOREIGN_SERVER
export let ADD_FOREIGN_SERVER = 'ADD_FOREIGN_SERVER'
// REMOVE_FOREIGN_SERVER
export let REMOVE_FOREIGN_SERVER = 'REMOVE_FOREIGN_SERVER'
// GET_DAY_SUMMARY
export const GET_DAY_SUMMARY = 'GET_DAY_SUMMARY'
// SIGN_TRANSACTION // SIGN_TRANSACTION
export const SIGN_TRANSACTION = 'SIGN_TRANSACTION' export const SIGN_TRANSACTION = 'SIGN_TRANSACTION'
// SEND_COIN
export const SEND_COIN = 'SEND_COIN'

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,8 @@
import { get } from '../../../core/translate' import { get } from '../../../core/translate'
import { appendBuffer } from './utilities'
import Base58 from '../../../crypto/api/deps/Base58'
import nacl from '../../../crypto/api/deps/nacl-fast.js'
import ed2curve from '../../../crypto/api/deps/ed2curve.js'
const getApiKey = () => { const getApiKey = () => {
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node] const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
@ -71,6 +75,10 @@ export class RequestQueueWithPromise {
} }
} }
export const requestQueueMemberNames = new RequestQueueWithPromise(5)
export const requestQueueAdminMemberNames = new RequestQueueWithPromise(5)
export const requestQueueGetAtAddresses = new RequestQueueWithPromise(10)
export class Loader { export class Loader {
constructor() { constructor() {
this.loader = document.createElement("div") this.loader = document.createElement("div")
@ -664,6 +672,178 @@ export class WarningModal {
export const modalHelper = ModalHelper.getInstance() export const modalHelper = ModalHelper.getInstance()
export const warningModal = WarningModal.getInstance() export const warningModal = WarningModal.getInstance()
export class TradeBotRespondRequest {
constructor() {
// ...
}
createTransaction(txnReq) {
this.atAddress(txnReq.atAddress)
this.foreignKey(txnReq.foreignKey)
this.receivingAddress(txnReq.receivingAddress)
return this.txnRequest()
}
atAddress(atAddress) {
this._atAddress = atAddress
}
foreignKey(foreignKey) {
this._foreignKey = foreignKey
}
receivingAddress(receivingAddress) {
this._receivingAddress = receivingAddress
}
txnRequest() {
return {
atAddress: this._atAddress,
foreignKey: this._foreignKey,
receivingAddress: this._receivingAddress
}
}
}
export class TradeBotRespondMultipleRequest {
constructor() {
// ...
}
createTransaction(txnReq) {
this.addresses(txnReq.addresses)
this.foreignKey(txnReq.foreignKey)
this.receivingAddress(txnReq.receivingAddress)
return this.txnRequest()
}
addresses(addresses) {
this._addresses = addresses
}
foreignKey(foreignKey) {
this._foreignKey = foreignKey
}
receivingAddress(receivingAddress) {
this._receivingAddress = receivingAddress
}
txnRequest() {
return {
addresses: this._addresses,
foreignKey: this._foreignKey,
receivingAddress: this._receivingAddress
}
}
}
export class TradeBotCreateRequest {
constructor() {
// ...
}
createTransaction(txnReq) {
this.creatorPublicKey(txnReq.creatorPublicKey)
this.qortAmount(txnReq.qortAmount)
this.fundingQortAmount(txnReq.fundingQortAmount)
this.foreignBlockchain(txnReq.foreignBlockchain)
this.foreignAmount(txnReq.foreignAmount)
this.tradeTimeout(txnReq.tradeTimeout)
this.receivingAddress(txnReq.receivingAddress)
return this.txnRequest()
}
creatorPublicKey(creatorPublicKey) {
this._creatorPublicKey = creatorPublicKey
}
qortAmount(qortAmount) {
this._qortAmount = qortAmount
}
fundingQortAmount(fundingQortAmount) {
this._fundingQortAmount = fundingQortAmount
}
foreignBlockchain(foreignBlockchain) {
this._foreignBlockchain = foreignBlockchain
}
foreignAmount(foreignAmount) {
this._foreignAmount = foreignAmount
}
tradeTimeout(tradeTimeout) {
this._tradeTimeout = tradeTimeout
}
receivingAddress(receivingAddress) {
this._receivingAddress = receivingAddress
}
txnRequest() {
return {
creatorPublicKey: this._creatorPublicKey,
qortAmount: this._qortAmount,
fundingQortAmount: this._fundingQortAmount,
foreignBlockchain: this._foreignBlockchain,
foreignAmount: this._foreignAmount,
tradeTimeout: this._tradeTimeout,
receivingAddress: this._receivingAddress
}
}
}
export class DeleteTradeOffer {
constructor() {
// ...
}
createTransaction(txnReq) {
this.creatorPublicKey(txnReq.creatorPublicKey)
this.atAddress(txnReq.atAddress)
return this.txnRequest()
}
creatorPublicKey(creatorPublicKey) {
this._creatorPublicKey = creatorPublicKey
}
atAddress(atAddress) {
this._atAddress = atAddress
}
txnRequest() {
return {
creatorPublicKey: this._creatorPublicKey,
atAddress: this._atAddress
}
}
}
export const processTransactionV2 = async (bytes) => {
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
const nodeUrl = `${myNode.protocol}://${myNode.domain}:${myNode.port}`
const url = `${nodeUrl}/transactions/process?apiVersion=2`
const doProcess = await fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: bytes
})
const res = await doProcess.json()
return res
}
export const publishData = async ({ export const publishData = async ({
registeredName, registeredName,
path, path,
@ -924,3 +1104,438 @@ export const publishData = async ({
throw new Error(error.message) throw new Error(error.message)
} }
} }
export const getPublishesFromAdmins = async (admins, groupId) => {
const queryString = admins.map((name) => `name=${name}`).join("&")
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
const nodeUrl = `${myNode.protocol}://${myNode.domain}:${myNode.port}`
const url = `${nodeUrl}/arbitrary/resources/searchsimple?mode=ALL&service=DOCUMENT_PRIVATE&identifier=symmetric-qchat-group-${groupId}&exactmatchnames=true&limit=0&reverse=true&${queryString}&prefix=true`
const response = await fetch(url)
if (!response.ok) {
consoöe.error("network error")
return false
}
const adminData = await response.json()
const filterId = adminData.filter((data) => data.identifier === `symmetric-qchat-group-${groupId}`)
if (filterId.length === 0) {
return false
}
const sortedData = filterId.sort((a, b) => {
// Get the most recent date for both a and b
const dateA = a.updated ? new Date(a.updated) : new Date(a.created)
const dateB = b.updated ? new Date(b.updated) : new Date(b.created)
// Sort by most recent
return dateB.getTime() - dateA.getTime()
})
return sortedData[0]
}
export const getGroupAdmins = async (groupNumber) => {
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
const nodeUrl = `${myNode.protocol}://${myNode.domain}:${myNode.port}`
const url = `${nodeUrl}/groups/members/${groupNumber}?limit=0&onlyAdmins=true`
const response = await fetch(url)
const groupData = await response.json()
let members = []
let membersAddresses = []
let both = []
const getMemNames = groupData.members.map(async (member) => {
if (member.member) {
const name = await requestQueueAdminMemberNames.enqueue(() => {
return getNameInfo(member.member)
})
if (name) {
members.push(name)
both.push({ name, address: member.member })
}
membersAddresses.push(member.member)
}
return true
})
await Promise.all(getMemNames)
return { names: members, addresses: membersAddresses, both }
}
export const getPublishesFromAdminsAdminSpace = async (admins, groupId) => {
const queryString = admins.map((name) => `name=${name}`).join("&")
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
const nodeUrl = `${myNode.protocol}://${myNode.domain}:${myNode.port}`
const url = `${nodeUrl}/arbitrary/resources/searchsimple?mode=ALL&service=DOCUMENT_PRIVATE&identifier=admins-symmetric-qchat-group-${groupId}&exactmatchnames=true&limit=0&reverse=true&${queryString}&prefix=true`
const response = await fetch(url)
if (!response.ok) {
consoöe.error("network error")
return false
}
const adminData = await response.json()
const filterId = adminData.filter((data) => data.identifier === `admins-symmetric-qchat-group-${groupId}`)
if (filterId.length === 0) {
return false
}
const sortedData = filterId.sort((a, b) => {
// Get the most recent date for both a and b
const dateA = a.updated ? new Date(a.updated) : new Date(a.created)
const dateB = b.updated ? new Date(b.updated) : new Date(b.created)
// Sort by most recent
return dateB.getTime() - dateA.getTime()
})
return sortedData[0]
}
export const isRunningGateway = async () => {
let isGateway = true
const gateways = ['ext-node.qortal.link']
const nodeInfo = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
if (nodeInfo && (nodeInfo.domain && !gateways.some(gateway => nodeInfo.domain.includes(gateway)))) {
isGateway = false
}
return isGateway
}
export const getForeignKey = (foreignBlockchain) => {
switch (foreignBlockchain) {
case "LITECOIN":
return window.parent.reduxStore.getState().app.selectedAddress.ltcWallet.derivedMasterPrivateKey
case "DOGECOIN":
return window.parent.reduxStore.getState().app.selectedAddress.dogeWallet.derivedMasterPrivateKey
case "BITCOIN":
return window.parent.reduxStore.getState().app.selectedAddress.btcWallet.derivedMasterPrivateKey
case "DIGIBYTE":
return window.parent.reduxStore.getState().app.selectedAddress.dgbWallet.derivedMasterPrivateKey
case "RAVENCOIN":
return window.parent.reduxStore.getState().app.selectedAddress.rvnWallet.derivedMasterPrivateKey
case "PIRATECHAIN":
return window.parent.reduxStore.getState().app.selectedAddress.arrrWallet.seed58
default:
return null
}
}
export async function getQortalBalanceInfo() {
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
const nodeUrl = `${myNode.protocol}://${myNode.domain}:${myNode.port}`
const address = window.parent.reduxStore.getState().app.selectedAddress.address
const url = `${nodeUrl}/addresses/balance/${address}`
const res = await fetch(url)
if (!response.ok) throw new Error("Cannot fetch Qortal balance")
const balance = await res.json()
return (Number(balance) / 1e8).toFixed(8)
}
export async function getBitcoinBalanceInfo() {
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
const nodeUrl = `${myNode.protocol}://${myNode.domain}:${myNode.port}`
const myApiKey = myNode.apiKey
const url = `${nodeUrl}/crosschain/btc/walletbalance?apiKey=${myApiKey}`
const res = await fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: `${window.parent.reduxStore.getState().app.selectedAddress.btcWallet.derivedMasterPublicKey}`
})
if (!res.ok) throw new Error("Cannot fetch Bitcoin balance")
const balance = await res.json()
return (Number(balance) / 1e8).toFixed(8)
}
export async function getLitecoinBalanceInfo() {
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
const nodeUrl = `${myNode.protocol}://${myNode.domain}:${myNode.port}`
const myApiKey = myNode.apiKey
const url = `${nodeUrl}/crosschain/ltc/walletbalance?apiKey=${myApiKey}`
const res = await fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: `${window.parent.reduxStore.getState().app.selectedAddress.ltcWallet.derivedMasterPublicKey}`
})
if (!res.ok) throw new Error("Cannot fetch Litecoin balance")
const balance = await res.json()
return (Number(balance) / 1e8).toFixed(8)
}
export async function createBuyOrderTx({ crosschainAtInfo, isGateway, foreignBlockchain }) {
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
const nodeUrl = `${myNode.protocol}://${myNode.domain}:${myNode.port}`
const myApiKey = myNode.apiKey
let txn
let url
let message
let responseVar
let responseMessage
try {
if (!isGateway) {
const address = window.parent.reduxStore.getState().app.selectedAddress.address
if (foreignBlockchain === 'PIRATECHAIN') {
message = {
atAddress: crosschainAtInfo[0].qortalAtAddress,
foreignKey: getForeignKey(foreignBlockchain),
receivingAddress: address
}
} else {
message = {
addresses: crosschainAtInfo.map((order)=> order.qortalAtAddress),
foreignKey: getForeignKey(foreignBlockchain),
receivingAddress: address
}
}
if (foreignBlockchain === 'PIRATECHAIN') {
txn = new TradeBotRespondRequest().createTransaction(message)
url = `${nodeUrl}/crosschain/tradebot/respond?apiKey=${myApiKey}`
} else {
txn = new TradeBotRespondMultipleRequest().createTransaction(message)
url = `${nodeUrl}/crosschain/tradebot/respondmultiple?apiKey=${myApiKey}`
}
const responseFetch = await fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(txn)
})
const res = await responseFetch.json()
if(res.error && res.message) {
console.error(res.message)
throw new Error(res.message)
}
if (!responseFetch.ok) {
console.error('Failed to submit buy order')
throw new Error('Failed to submit buy order')
}
if (res === false) {
responseVar = { response: res, success: false }
} else {
responseVar = { response: res, success: true }
}
if (responseVar.success) {
responseMessage = {
callResponse: responseVar.success,
extra: {
message: "Buy order message sended successfully!",
atAddresses: foreignBlockchain === 'PIRATECHAIN' ? [crosschainAtInfo[0].qortalAtAddress] : crosschainAtInfo.map((order)=> order.qortalAtAddress),
senderAddress: address,
node: nodeUrl
}
}
} else {
responseMessage = {
callResponse: responseVar.success,
extra: {
message: "Unable to execute buy order!",
atAddresses: foreignBlockchain === 'PIRATECHAIN' ? [crosschainAtInfo[0].qortalAtAddress] : crosschainAtInfo.map((order)=> order.qortalAtAddress),
senderAddress: address,
node: nodeUrl
}
}
}
return responseMessage
} else {
responseVar = { response: false, success: false }
responseMessage = {
callResponse: responseVar.success,
extra: {
message: "Unable to send buy order message over Gateway!",
atAddresses: foreignBlockchain === 'PIRATECHAIN' ? [crosschainAtInfo[0].qortalAtAddress] : crosschainAtInfo.map((order)=> order.qortalAtAddress),
senderAddress: address,
node: nodeUrl
}
}
return responseMessage
}
} catch (error) {
throw new Error(error.message)
}
}
export const getPirateWalletAddress = async (seed58) => {
const myApiKey = getApiKey()
const mySeed58 = seed58
let res = await parentEpml.request('apiCall', {
url: `/crosschain/arrr/walletaddress?apiKey=${myApiKey}`,
method: 'POST',
body: `${mySeed58}`
})
if (res != null && res.error != 1201) {
return res
}
return mySeed58
}
export const getUserWalletFunc = async (coin) => {
let userWallet = {}
switch (coin) {
case "QORT":
userWallet["address"] = window.parent.reduxStore.getState().app.selectedAddress.address
userWallet["publickey"] = Base58.encode(window.parent.reduxStore.getState().app.selectedAddress.keyPair.publicKey)
userWallet["privatekey"] = Base58.encode(window.parent.reduxStore.getState().app.selectedAddress.keyPair.privateKey)
break
case "BTC":
case "BITCOIN":
userWallet["address"] = window.parent.reduxStore.getState().app.selectedAddress.btcWallet.address
userWallet["publickey"] = window.parent.reduxStore.getState().app.selectedAddress.btcWallet.derivedMasterPublicKey
userWallet["privatekey"] = window.parent.reduxStore.getState().app.selectedAddress.btcWallet.derivedMasterPrivateKey
break
case "LTC":
case "LITECOIN":
userWallet["address"] = window.parent.reduxStore.getState().app.selectedAddress.ltcWallet.address
userWallet["publickey"] = window.parent.reduxStore.getState().app.selectedAddress.ltcWallet.derivedMasterPublicKey
userWallet["privatekey"] = window.parent.reduxStore.getState().app.selectedAddress.ltcWallet.derivedMasterPrivateKey
break
case "DOGE":
case "DOGECOIN":
userWallet["address"] = window.parent.reduxStore.getState().app.selectedAddress.dogeWallet.address
userWallet["publickey"] = window.parent.reduxStore.getState().app.selectedAddress.dogeWallet.derivedMasterPublicKey
userWallet["privatekey"] = window.parent.reduxStore.getState().app.selectedAddress.dogeWallet.derivedMasterPrivateKey
break
case "DGB":
case "DIGIBYTE":
userWallet["address"] = window.parent.reduxStore.getState().app.selectedAddress.dgbWallet.address
userWallet["publickey"] = window.parent.reduxStore.getState().app.selectedAddress.dgbWallet.derivedMasterPublicKey
userWallet["privatekey"] = window.parent.reduxStore.getState().app.selectedAddress.dgbWallet.derivedMasterPrivateKey
break
case "RVN":
case "RAVENCOIN":
userWallet["address"] = window.parent.reduxStore.getState().app.selectedAddress.rvnWallet.address
userWallet["publickey"] = window.parent.reduxStore.getState().app.selectedAddress.rvnWallet.derivedMasterPublicKey
userWallet["privatekey"] = window.parent.reduxStore.getState().app.selectedAddress.rvnWallet.derivedMasterPrivateKey
break
case "ARRR":
case "PIRATECHAIN":
const arrrAddress = await getPirateWalletAddress(window.parent.reduxStore.getState().app.selectedAddress.arrrWallet.seed58)
userWallet["address"] = arrrAddress
userWallet["publickey"] = ""
userWallet["privatekey"] = ""
break
default:
break
}
return userWallet
}
export const signTransaction = async (unsignedTxn, keyPair) => {
if (!unsignedTxn) {
throw new Error('Unsigned Transaction Bytes not defined')
}
if (!keyPair) {
throw new Error('keyPair not defined')
}
const unsignedTxBytes = Base58.decode(unsignedTxn)
const signature = nacl.sign.detached(unsignedTxBytes, keyPair.privateKey)
const signedTxBytes = appendBuffer(unsignedTxBytes, signature)
return Base58.encode(signedTxBytes)
}
export const tradeBotCreateRequest = async (body, keyPair) => {
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
const nodeUrl = `${myNode.protocol}://${myNode.domain}:${myNode.port}`
const myApiKey = myNode.apiKey
const url = `${nodeUrl}/crosschain/tradebot/create?apiKey=${myApiKey}`
const txn = new TradeBotCreateRequest().createTransaction(body)
const bodyToString = JSON.stringify(txn)
const unsignedTxnResponse = await fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: bodyToString
})
if (!unsignedTxnResponse.ok) throw new Error("Unable to create tradebot")
const unsignedTxn = await unsignedTxnResponse.text()
const signedTxnBytes = await signTransaction(unsignedTxn, keyPair)
const resProcess = await processTransactionV2(signedTxnBytes)
if (resProcess.signature) {
return resProcess
} else {
throw new Error("Failed to Create Sell Order. Try again!")
}
}
export const cancelTradeOfferTradeBot = async (body, keyPair) => {
const txn = new DeleteTradeOffer().createTransaction(body)
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
const nodeUrl = `${myNode.protocol}://${myNode.domain}:${myNode.port}`
const myApiKey = myNode.apiKey
const url = `${nodeUrl}/crosschain/tradeoffer?apiKey=${myApiKey}`
const bodyToString = JSON.stringify(txn)
const deleteTradeBotResponse = await fetch(url, {
method: "DELETE",
headers: {
"Content-Type": "application/json"
},
body: bodyToString
})
if (!deleteTradeBotResponse.ok) throw new Error("Unable to update tradebot")
const unsignedTxn = await deleteTradeBotResponse.text()
const signedTxnBytes = await signTransaction(unsignedTxn, keyPair)
const resProcess = await processTransactionV2(signedTxnBytes)
if (resProcess.signature) {
return resProcess
} else {
throw new Error("Failed to Cancel Sell Order. Try again!")
}
}

View File

@ -0,0 +1,65 @@
export const int32ToBytes = (word) => {
var byteArray = []
for (var b = 0; b < 32; b += 8) {
byteArray.push((word >>> (24 - b % 32)) & 0xFF)
}
return byteArray
}
export const stringtoUTF8Array = (message) => {
if (typeof message === 'string') {
var s = unescape(encodeURIComponent(message))
message = new Uint8Array(s.length)
for (var i = 0; i < s.length; i++) {
message[i] = s.charCodeAt(i) & 0xff
}
}
return message
}
export const appendBuffer = (buffer1, buffer2) => {
buffer1 = new Uint8Array(buffer1)
buffer2 = new Uint8Array(buffer2)
let tmp = new Uint8Array(buffer1.byteLength + buffer2.byteLength)
tmp.set(buffer1, 0)
tmp.set(buffer2, buffer1.byteLength)
return tmp
}
export const int64ToBytes = (int64) => {
var byteArray = [0, 0, 0, 0, 0, 0, 0, 0]
for (var index = 0; index < byteArray.length; index++) {
var byte = int64 & 0xff
byteArray[byteArray.length - index - 1] = byte
int64 = (int64 - byte) / 256
}
return byteArray
}
export const hexToBytes = (hexString) => {
return new Uint8Array(hexString.match(/.{1,2}/g).map(byte => parseInt(byte, 16)))
}
export const stringToHex = (bytes) => {
return bytes.reduce((str, byte) => str + byte.toString(16).padStart(2, '0'), '')
}
export const equal = (buf1, buf2) => {
if (buf1.byteLength != buf2.byteLength) return false
var dv1 = new Uint8Array(buf1)
var dv2 = new Uint8Array(buf2)
for (var i = 0; i != buf1.byteLength; i++) {
if (dv1[i] != dv2[i]) return false
}
return true
}
export const bytesToHex = (byteArray) => {
var _byteArrayToHex = []
for (var index = 0; index < byteArray.length; index++) {
_byteArrayToHex.push((byteArray[index] >>> 4).toString(16))
_byteArrayToHex.push((byteArray[index] & 15).toString(16));
}
return _byteArrayToHex.join("")
}