xyqon 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/package.json +1 -1
- package/src/cli.js +4 -2
- package/src/index.js +52 -0
package/README.md
CHANGED
|
@@ -67,6 +67,7 @@ xyqon send \
|
|
|
67
67
|
```
|
|
68
68
|
|
|
69
69
|
The transaction is broadcast to reachable public nodes. A miner must include it in a block before the receiver sees the confirmed balance.
|
|
70
|
+
The client checks the best reachable public chain before broadcasting and refuses sends that exceed the wallet's confirmed XYQON balance.
|
|
70
71
|
|
|
71
72
|
## Create And Send Coins
|
|
72
73
|
|
|
@@ -83,6 +84,7 @@ xyqon coin send \
|
|
|
83
84
|
```
|
|
84
85
|
|
|
85
86
|
Coin creation and coin sends are signed 0 XYQON transactions. A miner must include them before the new coin or transfer appears on-chain.
|
|
87
|
+
Before broadcasting a coin transfer, the client checks the best reachable public chain and refuses sends that exceed the wallet's confirmed coin balance.
|
|
86
88
|
|
|
87
89
|
## Mint And Send NFTs
|
|
88
90
|
|
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -159,7 +159,8 @@ async function run() {
|
|
|
159
159
|
console.log(`${color('bold', 'Amount:')} ${result.transaction.amount} XYQON`);
|
|
160
160
|
console.log(`${color('bold', 'To:')} ${result.transaction.recipient}`);
|
|
161
161
|
console.log(`${color('bold', 'Transaction ID:')} ${result.transactionId}`);
|
|
162
|
-
console.log(`${color('
|
|
162
|
+
console.log(`${color('dim', 'Checked balance:')} ${result.preflight.balance} XYQON at block ${result.preflight.blockHeight}`);
|
|
163
|
+
console.log(`${color('green', 'Delivered:')} ${result.acceptedBy}/${result.peers.length} reachable nodes`);
|
|
163
164
|
console.log(color('yellow', 'The receiver balance updates after a miner includes this transaction in a block.'));
|
|
164
165
|
return;
|
|
165
166
|
}
|
|
@@ -217,7 +218,8 @@ async function run() {
|
|
|
217
218
|
console.log(`${color('bold', 'Amount:')} ${result.transaction.asset_operation.TransferCoin.amount} ${result.transaction.asset_operation.TransferCoin.symbol}`);
|
|
218
219
|
console.log(`${color('bold', 'To:')} ${result.transaction.recipient}`);
|
|
219
220
|
console.log(`${color('bold', 'Transaction ID:')} ${result.transactionId}`);
|
|
220
|
-
console.log(`${color('
|
|
221
|
+
console.log(`${color('dim', 'Checked balance:')} ${result.preflight.balance} ${result.preflight.symbol} at block ${result.preflight.blockHeight}`);
|
|
222
|
+
console.log(`${color('green', 'Delivered:')} ${result.acceptedBy}/${result.peers.length} reachable nodes`);
|
|
221
223
|
return;
|
|
222
224
|
}
|
|
223
225
|
|
package/src/index.js
CHANGED
|
@@ -8,6 +8,7 @@ export const DEFAULT_PEERS = [
|
|
|
8
8
|
'143.244.149.8:7101',
|
|
9
9
|
'147.182.138.183:7101'
|
|
10
10
|
];
|
|
11
|
+
const XYQON_EPSILON = 0.00000001;
|
|
11
12
|
|
|
12
13
|
export const DEFAULT_WALLET_PATH = 'xyqon.wallet.json';
|
|
13
14
|
|
|
@@ -524,6 +525,48 @@ export async function getBalance(addressOrWallet, seedPeers = DEFAULT_PEERS) {
|
|
|
524
525
|
};
|
|
525
526
|
}
|
|
526
527
|
|
|
528
|
+
export async function assertSpendableXyqonBalance(wallet, amount, seedPeers = DEFAULT_PEERS) {
|
|
529
|
+
const numericAmount = Number(amount);
|
|
530
|
+
const { chain, sourcePeer, peers } = await getBestChain(seedPeers);
|
|
531
|
+
const balances = calculateBalances(chain);
|
|
532
|
+
const balance = balances.get(wallet.public_key) ?? 0;
|
|
533
|
+
|
|
534
|
+
if (balance + XYQON_EPSILON < numericAmount) {
|
|
535
|
+
throw new Error(
|
|
536
|
+
`insufficient confirmed XYQON balance; balance is ${balance}, attempted to spend ${numericAmount}`
|
|
537
|
+
);
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
return {
|
|
541
|
+
balance,
|
|
542
|
+
blockHeight: chain.chain.at(-1)?.index ?? 0,
|
|
543
|
+
sourcePeer,
|
|
544
|
+
peers
|
|
545
|
+
};
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
export async function assertSpendableCoinBalance(wallet, symbol, amount, seedPeers = DEFAULT_PEERS) {
|
|
549
|
+
const normalizedSymbol = normalizeCoinSymbol(symbol);
|
|
550
|
+
const numericAmount = Number(amount);
|
|
551
|
+
const { chain, sourcePeer, peers } = await getBestChain(seedPeers);
|
|
552
|
+
const holding = listCoinHoldings(chain, wallet).find((coin) => coin.symbol === normalizedSymbol);
|
|
553
|
+
const balance = holding?.balance ?? 0;
|
|
554
|
+
|
|
555
|
+
if (balance + XYQON_EPSILON < numericAmount) {
|
|
556
|
+
throw new Error(
|
|
557
|
+
`insufficient confirmed ${normalizedSymbol} balance; balance is ${balance}, attempted to spend ${numericAmount}`
|
|
558
|
+
);
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
return {
|
|
562
|
+
symbol: normalizedSymbol,
|
|
563
|
+
balance,
|
|
564
|
+
blockHeight: chain.chain.at(-1)?.index ?? 0,
|
|
565
|
+
sourcePeer,
|
|
566
|
+
peers
|
|
567
|
+
};
|
|
568
|
+
}
|
|
569
|
+
|
|
527
570
|
export async function getCreatedCoins(addressOrWallet, seedPeers = DEFAULT_PEERS) {
|
|
528
571
|
const { chain, sourcePeer, peers } = await getBestChain(seedPeers);
|
|
529
572
|
return {
|
|
@@ -583,8 +626,10 @@ export async function broadcastTransaction(transaction, seedPeers = DEFAULT_PEER
|
|
|
583
626
|
|
|
584
627
|
export async function sendTransaction({ wallet, recipient, amount, peers = DEFAULT_PEERS }) {
|
|
585
628
|
const transaction = createSignedTransaction(wallet, recipient, amount);
|
|
629
|
+
const preflight = await assertSpendableXyqonBalance(wallet, transaction.amount, peers);
|
|
586
630
|
return {
|
|
587
631
|
transaction,
|
|
632
|
+
preflight,
|
|
588
633
|
...(await broadcastTransaction(transaction, peers))
|
|
589
634
|
};
|
|
590
635
|
}
|
|
@@ -599,8 +644,15 @@ export async function createCoin({ wallet, symbol, name, supply, peers = DEFAULT
|
|
|
599
644
|
|
|
600
645
|
export async function sendCoin({ wallet, recipient, symbol, amount, peers = DEFAULT_PEERS }) {
|
|
601
646
|
const transaction = createCoinTransferTransaction(wallet, { recipient, symbol, amount });
|
|
647
|
+
const preflight = await assertSpendableCoinBalance(
|
|
648
|
+
wallet,
|
|
649
|
+
transaction.asset_operation.TransferCoin.symbol,
|
|
650
|
+
transaction.asset_operation.TransferCoin.amount,
|
|
651
|
+
peers
|
|
652
|
+
);
|
|
602
653
|
return {
|
|
603
654
|
transaction,
|
|
655
|
+
preflight,
|
|
604
656
|
...(await broadcastTransaction(transaction, peers))
|
|
605
657
|
};
|
|
606
658
|
}
|