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 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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xyqon",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Friendly wallet CLI and JavaScript client for the XYQON network.",
5
5
  "keywords": [
6
6
  "xyqon",
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('green', 'Broadcast:')} ${result.acceptedBy}/${result.peers.length} reachable nodes`);
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('green', 'Broadcast:')} ${result.acceptedBy}/${result.peers.length} reachable nodes`);
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
  }