diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index c94282d9..6367fc53 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -168,13 +168,7 @@ jobs: run: | cd clients/tests/web sudo chmod -R 755 ./data_bitcoin_regtest - npx vitest --browser.name=chromium --browser.headless - - name: Run Client-Side Tests - run: | - cd clients/apps/nodejs - node test_basic_workflow2.js - node test_atomic_swap.js - mocha ./test/tb04-simple-lightning-latch.mjs --exit + npx vitest --browser.name=chromium --browser.headless - name: Tear Down run: | docker-compose -f docker-compose-test.yml down diff --git a/Cargo.lock b/Cargo.lock index e5f02b0d..b8678b55 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1642,7 +1642,7 @@ checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" [[package]] name = "mercury-server" -version = "0.1.1" +version = "0.2.0" dependencies = [ "bitcoin", "chrono", diff --git a/clients/apps/nodejs/test/ta02-duplicate-deposits.mjs b/clients/apps/nodejs/test/ta02-duplicate-deposits.mjs deleted file mode 100644 index 92d73111..00000000 --- a/clients/apps/nodejs/test/ta02-duplicate-deposits.mjs +++ /dev/null @@ -1,166 +0,0 @@ -import { expect } from 'chai'; -import client_config from '../client_config.js'; -import mercurynodejslib from 'mercurynodejslib'; -import { CoinStatus } from 'mercurynodejslib/coin_enum.js'; -import { createWallet, removeDatabase, getnewaddress, generateBlock, depositCoin } from './test-utils.mjs'; - -describe('TA02 - Duplicated Deposits', function() { - - context('Withdraw Flow', () => { - it('should complete successfully', async () => { - - const clientConfig = client_config.load(); - await removeDatabase(clientConfig); - - let wallet_1_name = "w1"; - let wallet_2_name = "w2"; - let wallet1 = await createWallet(clientConfig, wallet_1_name); - let wallet2 = await createWallet(clientConfig, wallet_2_name); - - const token = await mercurynodejslib.newToken(clientConfig, wallet1.name); - const tokenId = token.token_id; - - const amount1 = 10000; - const depositInfo = await mercurynodejslib.getDepositBitcoinAddress(clientConfig, wallet1.name, amount1); - - await depositCoin(depositInfo.deposit_address, amount1); - - let amount2 = 20000; - await depositCoin(depositInfo.deposit_address, amount2); - - const coreWalletAddress = await getnewaddress(); - - await generateBlock(clientConfig.confirmationTarget, coreWalletAddress); - - const listCoins = await mercurynodejslib.listStatecoins(clientConfig, wallet1.name); - - expect(listCoins.length).to.equal(2); - - const newCoin = listCoins.find(coin => - coin.aggregated_address == depositInfo.deposit_address && - coin.status == CoinStatus.CONFIRMED - ); - - const duplicatedCoin = listCoins.find(coin => - coin.aggregated_address == depositInfo.deposit_address && - coin.status == CoinStatus.DUPLICATED - ); - - expect(newCoin).to.not.be.null; - expect(duplicatedCoin).to.not.be.null; - - expect(newCoin.duplicate_index).to.equal(0); - expect(duplicatedCoin.duplicate_index).to.equal(1); - - const transferAddress = await mercurynodejslib.newTransferAddress(clientConfig, wallet2.name, null); - - try { - await mercurynodejslib.transferSend(clientConfig, wallet1.name, newCoin.statechain_id, transferAddress.transfer_receive, false, null); - } catch (error) { - expect(error.message).to.include("Coin is duplicated. If you want to proceed, use the command '--force, -f' option. " + - "You will no longer be able to move other duplicate coins with the same statechain_id and this will cause PERMANENT LOSS of these duplicate coin funds."); - } - - const withdrawAddress = "bcrt1qn5948np2j8t68xgpceneg3ua4wcwhwrsqj8scv"; - - let txid = await mercurynodejslib.withdrawCoin(clientConfig, wallet1.name, duplicatedCoin.statechain_id, withdrawAddress, null, 1); - - expect(txid).to.be.string; - - try { - await mercurynodejslib.transferSend(clientConfig, wallet1.name, newCoin.statechain_id, transferAddress.transfer_receive, false, null); - } catch (error) { - expect(error.message).to.include("There have been withdrawals of other coins with this same statechain_id (possibly duplicates). " + - "This transfer cannot be performed because the recipient would reject it due to the difference in signature count. This coin can be withdrawn, however."); - } - - txid = await mercurynodejslib.withdrawCoin(clientConfig, wallet1.name, duplicatedCoin.statechain_id, withdrawAddress, null, 0); - - expect(txid).to.be.string; - }) - }), - - context('Transfer Flow', () => { - it('should complete successfully', async () => { - - const clientConfig = client_config.load(); - await removeDatabase(clientConfig); - - let wallet_1_name = "w1"; - let wallet_2_name = "w2"; - let wallet1 = await createWallet(clientConfig, wallet_1_name); - let wallet2 = await createWallet(clientConfig, wallet_2_name); - - const token = await mercurynodejslib.newToken(clientConfig, wallet1.name); - const tokenId = token.token_id; - - const amount1 = 10000; - const depositInfo = await mercurynodejslib.getDepositBitcoinAddress(clientConfig, wallet1.name, amount1); - - await depositCoin(depositInfo.deposit_address, amount1); - - let amount2 = 20000; - await depositCoin(depositInfo.deposit_address, amount2); - - const coreWalletAddress = await getnewaddress(); - - await generateBlock(clientConfig.confirmationTarget, coreWalletAddress); - - let listCoins = await mercurynodejslib.listStatecoins(clientConfig, wallet1.name); - - expect(listCoins.length).to.equal(2); - - const newCoin = listCoins.find(coin => - coin.aggregated_address == depositInfo.deposit_address && - coin.status == CoinStatus.CONFIRMED - ); - - let duplicatedCoin = listCoins.find(coin => - coin.aggregated_address == depositInfo.deposit_address && - coin.status == CoinStatus.DUPLICATED - ); - - expect(newCoin).to.not.be.null; - expect(duplicatedCoin).to.not.be.null; - - expect(newCoin.duplicate_index).to.equal(0); - expect(duplicatedCoin.duplicate_index).to.equal(1); - - const transferAddress = await mercurynodejslib.newTransferAddress(clientConfig, wallet2.name, null); - - let result = await mercurynodejslib.transferSend(clientConfig, wallet1.name, newCoin.statechain_id, transferAddress.transfer_receive, true, null); - expect(result).to.have.property('statechain_id'); - - let transferReceiveResult = await mercurynodejslib.transferReceive(clientConfig, wallet2.name); - - expect(transferReceiveResult.receivedStatechainIds).contains(newCoin.statechain_id); - expect(transferReceiveResult.receivedStatechainIds.length).to.equal(1); - - listCoins = await mercurynodejslib.listStatecoins(clientConfig, wallet1.name); - - const transferredCoin = listCoins.find(coin => - coin.aggregated_address === depositInfo.deposit_address && - coin.status === CoinStatus.TRANSFERRED - ); - - duplicatedCoin = listCoins.find(coin => - coin.aggregated_address === depositInfo.deposit_address && - coin.status === CoinStatus.DUPLICATED - ); - - expect(transferredCoin).to.not.be.null; - expect(transferredCoin.duplicate_index).to.equal(0); - - expect(duplicatedCoin).to.not.be.null; - expect(duplicatedCoin.duplicate_index).to.equal(1); - - try { - const withdrawAddress = "bcrt1qn5948np2j8t68xgpceneg3ua4wcwhwrsqj8scv"; - await mercurynodejslib.withdrawCoin(clientConfig, wallet1.name, duplicatedCoin.statechain_id, withdrawAddress, null, 1); - } catch (error) { - expect(error.response.status).to.equal(401); - expect(error.response.data.message).to.equal("Signature does not match authentication key."); - } - }) - }) -}) diff --git a/clients/apps/nodejs/test/tb04-simple-lightning-latch.mjs b/clients/apps/nodejs/test/tb04-simple-lightning-latch.mjs deleted file mode 100644 index 0ed4e187..00000000 --- a/clients/apps/nodejs/test/tb04-simple-lightning-latch.mjs +++ /dev/null @@ -1,594 +0,0 @@ -import { expect } from 'chai'; -import client_config from '../client_config.js'; -import mercurynodejslib from 'mercurynodejslib'; -import { CoinStatus } from 'mercurynodejslib/coin_enum.js'; -import crypto from 'crypto'; -import { sleep, createWallet, depositCoin, generateInvoice, payHoldInvoice, payInvoice, settleInvoice } from '../test_utils.js'; - -describe('TB04 - Lightning Latch', function() { - this.timeout(30000); - - context('Simple Transfer', () => { - it('should complete successfully', async () => { - - // await removeDatabase(); - const clientConfig = client_config.load(); - let wallet_1_name = "w_ln_1"; - let wallet_2_name = "w_ln_2"; - await createWallet(clientConfig, wallet_1_name); - await createWallet(clientConfig, wallet_2_name); - - const token = await mercurynodejslib.newToken(clientConfig, wallet_1_name); - const tokenId = token.token_id; - - const amount = 10000; - const depositInfo = await mercurynodejslib.getDepositBitcoinAddress(clientConfig, wallet_1_name, amount); - - const tokenList = await mercurynodejslib.getWalletTokens(clientConfig, wallet_1_name); - const usedToken = tokenList.find(token => token.token_id === tokenId); - - expect(usedToken.spent).is.true; - - await depositCoin(clientConfig, wallet_1_name, amount, depositInfo); - - const listCoins = await mercurynodejslib.listStatecoins(clientConfig, wallet_1_name); - - expect(listCoins.length).to.equal(1); - - const coin = listCoins[0]; - - expect(coin.status).to.equal(CoinStatus.CONFIRMED); - - const paymentHash = await mercurynodejslib.paymentHash(clientConfig, wallet_1_name, coin.statechain_id); - - const transferAddress = await mercurynodejslib.newTransferAddress(clientConfig, wallet_2_name, null); - - await mercurynodejslib.transferSend(clientConfig, wallet_1_name, coin.statechain_id, transferAddress.transfer_receive, false, paymentHash.batchId); - - let transferReceiveResult = await mercurynodejslib.transferReceive(clientConfig, wallet_2_name); - - expect(transferReceiveResult.isThereBatchLocked).is.true; - expect(transferReceiveResult.receivedStatechainIds).empty; - - await mercurynodejslib.confirmPendingInvoice(clientConfig, wallet_1_name, coin.statechain_id); - - transferReceiveResult = await mercurynodejslib.transferReceive(clientConfig, wallet_2_name); - - expect(transferReceiveResult.isThereBatchLocked).is.false; - expect(transferReceiveResult.receivedStatechainIds).not.empty; - - const { preimage } = await mercurynodejslib.retrievePreImage(clientConfig, wallet_1_name, coin.statechain_id, paymentHash.batchId); - - const hash = crypto.createHash('sha256') - .update(Buffer.from(preimage, 'hex')) - .digest('hex') - - expect(hash).to.equal(paymentHash.hash); - }) - }) - - context('The sender tries to get the pre-image before the batch is unlocked should fail', () => { - it('should complete successfully', async () => { - - const clientConfig = client_config.load(); - let wallet_1_name = "w_ln_3"; - let wallet_2_name = "w_ln_4"; - await createWallet(clientConfig, wallet_1_name); - await createWallet(clientConfig, wallet_2_name); - - const amount = 10000; - let token = undefined; - let tokenId = undefined; - let depositInfo = undefined; - let tokenList = undefined; - let usedToken = undefined; - let listCoins = undefined; - - token = await mercurynodejslib.newToken(clientConfig, wallet_1_name); - tokenId = token.token_id; - - depositInfo = await mercurynodejslib.getDepositBitcoinAddress(clientConfig, wallet_1_name, amount); - - tokenList = await mercurynodejslib.getWalletTokens(clientConfig, wallet_1_name); - usedToken = tokenList.find(token => token.token_id === tokenId); - - expect(usedToken.spent).is.true; - - await depositCoin(clientConfig, wallet_1_name, amount, depositInfo); - - listCoins = await mercurynodejslib.listStatecoins(clientConfig, wallet_1_name); - - expect(listCoins.length).to.equal(1); - - const coin1 = listCoins[0]; - - expect(coin1.status).to.equal(CoinStatus.CONFIRMED); - - const paymentHash1 = await mercurynodejslib.paymentHash(clientConfig, wallet_1_name, coin1.statechain_id); - - token = await mercurynodejslib.newToken(clientConfig, wallet_2_name); - tokenId = token.token_id; - - depositInfo = await mercurynodejslib.getDepositBitcoinAddress(clientConfig, wallet_2_name, amount); - - tokenList = await mercurynodejslib.getWalletTokens(clientConfig, wallet_2_name); - usedToken = tokenList.find(token => token.token_id === tokenId); - - expect(usedToken.spent).is.true; - - await depositCoin(clientConfig, wallet_2_name, amount, depositInfo); - - listCoins = await mercurynodejslib.listStatecoins(clientConfig, wallet_2_name); - - expect(listCoins.length).to.equal(1); - - const coin2 = listCoins[0]; - - expect(coin2.status).to.equal(CoinStatus.CONFIRMED); - - const paymentHash2 = await mercurynodejslib.paymentHash(clientConfig, wallet_2_name, coin2.statechain_id); - - const transferAddress1 = await mercurynodejslib.newTransferAddress(clientConfig, wallet_1_name, null); - const transferAddress2 = await mercurynodejslib.newTransferAddress(clientConfig, wallet_2_name, null); - - await mercurynodejslib.transferSend(clientConfig, wallet_1_name, coin1.statechain_id, transferAddress1.transfer_receive, false, paymentHash1.batchId); - await mercurynodejslib.transferSend(clientConfig, wallet_2_name, coin2.statechain_id, transferAddress2.transfer_receive, false, paymentHash2.batchId); - - let transferReceiveResult = await mercurynodejslib.transferReceive(clientConfig, wallet_1_name); - - expect(transferReceiveResult.isThereBatchLocked).is.true; - expect(transferReceiveResult.receivedStatechainIds).empty; - - try { - const { preimage } = await mercurynodejslib.retrievePreImage(clientConfig, wallet_1_name, coin1.statechain_id, paymentHash1.batchId); - } catch (error) { - // Assert the captured error message - const expectedMessage = 'Request failed with status code 404'; - expect(error.message).to.equal(expectedMessage); - } - - await mercurynodejslib.confirmPendingInvoice(clientConfig, wallet_1_name, coin1.statechain_id); - await mercurynodejslib.confirmPendingInvoice(clientConfig, wallet_2_name, coin2.statechain_id); - - transferReceiveResult = await mercurynodejslib.transferReceive(clientConfig, wallet_2_name); - - expect(transferReceiveResult.isThereBatchLocked).is.false; - expect(transferReceiveResult.receivedStatechainIds).not.empty; - - const { preimage } = await mercurynodejslib.retrievePreImage(clientConfig, wallet_1_name, coin1.statechain_id, paymentHash1.batchId); - - const hash = crypto.createHash('sha256') - .update(Buffer.from(preimage, 'hex')) - .digest('hex') - - expect(hash).to.equal(paymentHash1.hash); - }) - }) - - context('Statecoin sender can recover (resend their coin) after batch timeout without completion', () => { - it('should complete successfully', async () => { - - const clientConfig = client_config.load(); - let wallet_1_name = "w_ln_5"; - let wallet_2_name = "w_ln_6"; - await createWallet(clientConfig, wallet_1_name); - await createWallet(clientConfig, wallet_2_name); - - const amount = 10000; - let token = undefined; - let tokenId = undefined; - let depositInfo = undefined; - let tokenList = undefined; - let usedToken = undefined; - let listCoins = undefined; - - token = await mercurynodejslib.newToken(clientConfig, wallet_1_name); - tokenId = token.token_id; - - depositInfo = await mercurynodejslib.getDepositBitcoinAddress(clientConfig, wallet_1_name, amount); - - tokenList = await mercurynodejslib.getWalletTokens(clientConfig, wallet_1_name); - usedToken = tokenList.find(token => token.token_id === tokenId); - - expect(usedToken.spent).is.true; - - await depositCoin(clientConfig, wallet_1_name, amount, depositInfo); - - listCoins = await mercurynodejslib.listStatecoins(clientConfig, wallet_1_name); - - expect(listCoins.length).to.equal(1); - - const coin1 = listCoins[0]; - - expect(coin1.status).to.equal(CoinStatus.CONFIRMED); - - const paymentHash1 = await mercurynodejslib.paymentHash(clientConfig, wallet_1_name, coin1.statechain_id); - - token = await mercurynodejslib.newToken(clientConfig, wallet_2_name); - tokenId = token.token_id; - - depositInfo = await mercurynodejslib.getDepositBitcoinAddress(clientConfig, wallet_2_name, amount); - - tokenList = await mercurynodejslib.getWalletTokens(clientConfig, wallet_2_name); - usedToken = tokenList.find(token => token.token_id === tokenId); - - expect(usedToken.spent).is.true; - - await depositCoin(clientConfig, wallet_2_name, amount, depositInfo); - - listCoins = await mercurynodejslib.listStatecoins(clientConfig, wallet_2_name); - - expect(listCoins.length).to.equal(1); - - const coin2 = listCoins[0]; - - expect(coin2.status).to.equal(CoinStatus.CONFIRMED); - - const paymentHash2 = await mercurynodejslib.paymentHash(clientConfig, wallet_2_name, coin2.statechain_id); - - const transferAddress1 = await mercurynodejslib.newTransferAddress(clientConfig, wallet_1_name, null); - const transferAddress2 = await mercurynodejslib.newTransferAddress(clientConfig, wallet_2_name, null); - - await mercurynodejslib.transferSend(clientConfig, wallet_1_name, coin1.statechain_id, transferAddress1.transfer_receive, false, paymentHash1.batchId); - await mercurynodejslib.transferSend(clientConfig, wallet_2_name, coin2.statechain_id, transferAddress2.transfer_receive, false, paymentHash1.batchId); - - let transferReceiveResult = await mercurynodejslib.transferReceive(clientConfig, wallet_1_name); - - expect(transferReceiveResult.isThereBatchLocked).is.true; - expect(transferReceiveResult.receivedStatechainIds).empty; - - await mercurynodejslib.confirmPendingInvoice(clientConfig, wallet_1_name, coin1.statechain_id); - await mercurynodejslib.confirmPendingInvoice(clientConfig, wallet_2_name, coin2.statechain_id); - - await sleep(20000); - - let errorMessage; - console.error = (msg) => { - errorMessage = msg; - }; - - transferReceiveResult = await mercurynodejslib.transferReceive(clientConfig, wallet_2_name); - - // Assert the captured error message - const expectedMessage = 'Failed to update transfer message'; - expect(errorMessage).contains(expectedMessage); - - const transferAddress3 = await mercurynodejslib.newTransferAddress(clientConfig, wallet_1_name, null); - const transferAddress4 = await mercurynodejslib.newTransferAddress(clientConfig, wallet_2_name, null); - - await mercurynodejslib.transferSend(clientConfig, wallet_1_name, coin1.statechain_id, transferAddress3.transfer_receive, false, paymentHash2.batchId); - await mercurynodejslib.transferSend(clientConfig, wallet_2_name, coin2.statechain_id, transferAddress4.transfer_receive, false, paymentHash2.batchId); - - transferReceiveResult = await mercurynodejslib.transferReceive(clientConfig, wallet_1_name); - - await mercurynodejslib.confirmPendingInvoice(clientConfig, wallet_1_name, coin1.statechain_id); - await mercurynodejslib.confirmPendingInvoice(clientConfig, wallet_2_name, coin2.statechain_id); - - transferReceiveResult = await mercurynodejslib.transferReceive(clientConfig, wallet_2_name); - - expect(transferReceiveResult.isThereBatchLocked).is.false; - expect(transferReceiveResult.receivedStatechainIds).not.empty; - - const { preimage } = await mercurynodejslib.retrievePreImage(clientConfig, wallet_1_name, coin1.statechain_id, paymentHash1.batchId); - - const hash = crypto.createHash('sha256') - .update(Buffer.from(preimage, 'hex')) - .digest('hex') - - expect(hash).to.equal(paymentHash1.hash); - }) - }) - - context('Statecoin trade with invoice creation, payment and settlement', () => { - it('should complete successfully', async () => { - - // await removeDatabase(); - const clientConfig = client_config.load(); - let wallet_1_name = "w_ln_7"; - let wallet_2_name = "w_ln_8"; - await createWallet(clientConfig, wallet_1_name); - await createWallet(clientConfig, wallet_2_name); - - const token = await mercurynodejslib.newToken(clientConfig, wallet_1_name); - const tokenId = token.token_id; - - const amount = 10000; - const depositInfo = await mercurynodejslib.getDepositBitcoinAddress(clientConfig, wallet_1_name, amount); - - const tokenList = await mercurynodejslib.getWalletTokens(clientConfig, wallet_1_name); - const usedToken = tokenList.find(token => token.token_id === tokenId); - - expect(usedToken.spent).is.true; - - await depositCoin(clientConfig, wallet_1_name, amount, depositInfo); - - const listCoins = await mercurynodejslib.listStatecoins(clientConfig, wallet_1_name); - - expect(listCoins.length).to.equal(1); - - const coin = listCoins[0]; - - expect(coin.status).to.equal(CoinStatus.CONFIRMED); - - const paymentHash = await mercurynodejslib.paymentHash(clientConfig, wallet_1_name, coin.statechain_id); - - const invoice = await generateInvoice(paymentHash.hash, amount); - - payInvoice(invoice.payment_request); - - const transferAddress = await mercurynodejslib.newTransferAddress(clientConfig, wallet_2_name, null); - - await mercurynodejslib.transferSend(clientConfig, wallet_1_name, coin.statechain_id, transferAddress.transfer_receive, false, paymentHash.batchId); - - let transferReceiveResult = await mercurynodejslib.transferReceive(clientConfig, wallet_2_name); - - expect(transferReceiveResult.isThereBatchLocked).is.true; - expect(transferReceiveResult.receivedStatechainIds).empty; - - await mercurynodejslib.confirmPendingInvoice(clientConfig, wallet_1_name, coin.statechain_id); - - transferReceiveResult = await mercurynodejslib.transferReceive(clientConfig, wallet_2_name); - - expect(transferReceiveResult.isThereBatchLocked).is.false; - expect(transferReceiveResult.receivedStatechainIds).not.empty; - - const { preimage } = await mercurynodejslib.retrievePreImage(clientConfig, wallet_1_name, coin.statechain_id, paymentHash.batchId); - - const hash = crypto.createHash('sha256') - .update(Buffer.from(preimage, 'hex')) - .digest('hex') - - expect(hash).to.equal(paymentHash.hash); - - await settleInvoice(preimage); - }) - }) - - context('Receiver tries to transfer invoice amount to another invoice before preimage retrieval should fail', () => { - it('should complete successfully', async () => { - - // await removeDatabase(); - const clientConfig = client_config.load(); - let wallet_1_name = "w_ln_9"; - let wallet_2_name = "w_ln_10"; - await createWallet(clientConfig, wallet_1_name); - await createWallet(clientConfig, wallet_2_name); - - const token = await mercurynodejslib.newToken(clientConfig, wallet_1_name); - const tokenId = token.token_id; - - const amount = 60000; - const depositInfo = await mercurynodejslib.getDepositBitcoinAddress(clientConfig, wallet_1_name, amount); - - const tokenList = await mercurynodejslib.getWalletTokens(clientConfig, wallet_1_name); - const usedToken = tokenList.find(token => token.token_id === tokenId); - - expect(usedToken.spent).is.true; - - await depositCoin(clientConfig, wallet_1_name, amount, depositInfo); - - const listCoins = await mercurynodejslib.listStatecoins(clientConfig, wallet_1_name); - - expect(listCoins.length).to.equal(1); - - const coin = listCoins[0]; - - expect(coin.status).to.equal(CoinStatus.CONFIRMED); - - const paymentHash = await mercurynodejslib.paymentHash(clientConfig, wallet_1_name, coin.statechain_id); - - const invoice = await generateInvoice(paymentHash.hash, amount); - - payHoldInvoice(invoice.payment_request); - - const transferAddress = await mercurynodejslib.newTransferAddress(clientConfig, wallet_2_name, null); - - await mercurynodejslib.transferSend(clientConfig, wallet_1_name, coin.statechain_id, transferAddress.transfer_receive, false, paymentHash.batchId); - - const hashFromServer = await mercurynodejslib.getPaymentHash(clientConfig, paymentHash.batchId); - - expect(hashFromServer).to.equal(paymentHash.hash); - - let transferReceiveResult = await mercurynodejslib.transferReceive(clientConfig, wallet_2_name); - - expect(transferReceiveResult.isThereBatchLocked).is.true; - expect(transferReceiveResult.receivedStatechainIds).empty; - - await mercurynodejslib.confirmPendingInvoice(clientConfig, wallet_1_name, coin.statechain_id); - - transferReceiveResult = await mercurynodejslib.transferReceive(clientConfig, wallet_2_name); - - expect(transferReceiveResult.isThereBatchLocked).is.false; - expect(transferReceiveResult.receivedStatechainIds).not.empty; - - const { preimage } = await mercurynodejslib.retrievePreImage(clientConfig, wallet_1_name, coin.statechain_id, paymentHash.batchId); - - const hash = crypto.createHash('sha256') - .update(Buffer.from(preimage, 'hex')) - .digest('hex') - - expect(hash).to.equal(paymentHash.hash); - - const paymentHashSecond = "b1f55a2f2eabb08ed9d6e15a053a6ac84d04d1c017de5a42caaec98b8d2ff738" - const invoiceSecond = await generateInvoice(paymentHashSecond, amount); - - try { - await payInvoice(invoiceSecond.payment_request); - } catch (error) { - console.error('Error:', error); - expect(error.message).to.include('failed'); - } - }) - }) - - context('Statecoin sender sends coin without batch_id (receiver should still be able to receive, but no pre-image revealed)', () => { - it('should complete successfully', async () => { - - // await removeDatabase(); - const clientConfig = client_config.load(); - let wallet_1_name = "w_ln_11"; - let wallet_2_name = "w_ln_12"; - await createWallet(clientConfig, wallet_1_name); - await createWallet(clientConfig, wallet_2_name); - - const token = await mercurynodejslib.newToken(clientConfig, wallet_1_name); - const tokenId = token.token_id; - - const amount = 10000; - const depositInfo = await mercurynodejslib.getDepositBitcoinAddress(clientConfig, wallet_1_name, amount); - - const tokenList = await mercurynodejslib.getWalletTokens(clientConfig, wallet_1_name); - const usedToken = tokenList.find(token => token.token_id === tokenId); - - expect(usedToken.spent).is.true; - - await depositCoin(clientConfig, wallet_1_name, amount, depositInfo); - - const listCoins = await mercurynodejslib.listStatecoins(clientConfig, wallet_1_name); - - expect(listCoins.length).to.equal(1); - - const coin = listCoins[0]; - - expect(coin.status).to.equal(CoinStatus.CONFIRMED); - - const paymentHash = await mercurynodejslib.paymentHash(clientConfig, wallet_1_name, coin.statechain_id); - - const transferAddress = await mercurynodejslib.newTransferAddress(clientConfig, wallet_2_name, null); - - await mercurynodejslib.transferSend(clientConfig, wallet_1_name, coin.statechain_id, transferAddress.transfer_receive, false, null); - - let transferReceiveResult = await mercurynodejslib.transferReceive(clientConfig, wallet_2_name); - - expect(transferReceiveResult.isThereBatchLocked).is.false; - expect(transferReceiveResult.receivedStatechainIds).not.empty; - - await mercurynodejslib.confirmPendingInvoice(clientConfig, wallet_1_name, coin.statechain_id); - - transferReceiveResult = await mercurynodejslib.transferReceive(clientConfig, wallet_2_name); - - expect(transferReceiveResult.isThereBatchLocked).is.false; - expect(transferReceiveResult.receivedStatechainIds).is.empty; - - let hash; - try { - const { preimage } = await mercurynodejslib.retrievePreImage(clientConfig, wallet_1_name, coin.statechain_id, paymentHash.batchId); - hash = crypto.createHash('sha256') - .update(Buffer.from(preimage, 'hex')) - .digest('hex') - expect(hash).to.equal(paymentHash.hash); - } catch (error) { - console.error('Error:', error); - expect(error.message).to.include('failed'); - } - }) - }) - - context('Sender sends coin without batch_id, and then resends to a different address (to attempt to steal), and then attempts to retrieve the pre-image, should fail (and LN payment cannot be claimed)', () => { - it('should complete successfully', async () => { - - // await removeDatabase(); - const clientConfig = client_config.load(); - let wallet_1_name = "w_ln_13"; - let wallet_2_name = "w_ln_14"; - let wallet_3_name = "w_ln_15"; - await createWallet(clientConfig, wallet_1_name); - await createWallet(clientConfig, wallet_2_name); - await createWallet(clientConfig, wallet_3_name); - - const token = await mercurynodejslib.newToken(clientConfig, wallet_1_name); - const tokenId = token.token_id; - - const amount = 10000; - const depositInfo = await mercurynodejslib.getDepositBitcoinAddress(clientConfig, wallet_1_name, amount); - - const tokenList = await mercurynodejslib.getWalletTokens(clientConfig, wallet_1_name); - const usedToken = tokenList.find(token => token.token_id === tokenId); - - expect(usedToken.spent).is.true; - - await depositCoin(clientConfig, wallet_1_name, amount, depositInfo); - - const listCoins = await mercurynodejslib.listStatecoins(clientConfig, wallet_1_name); - - expect(listCoins.length).to.equal(1); - - const coin = listCoins[0]; - - expect(coin.status).to.equal(CoinStatus.CONFIRMED); - - const paymentHash = await mercurynodejslib.paymentHash(clientConfig, wallet_1_name, coin.statechain_id); - - const transferAddress = await mercurynodejslib.newTransferAddress(clientConfig, wallet_2_name, null); - - await mercurynodejslib.transferSend(clientConfig, wallet_1_name, coin.statechain_id, transferAddress.transfer_receive, false, null); - - const transferAddressSecond = await mercurynodejslib.newTransferAddress(clientConfig, wallet_3_name, null); - - await mercurynodejslib.transferSend(clientConfig, wallet_1_name, coin.statechain_id, transferAddressSecond.transfer_receive, false, null); - - let transferReceiveResult = await mercurynodejslib.transferReceive(clientConfig, wallet_3_name); - - expect(transferReceiveResult.isThereBatchLocked).is.false; - expect(transferReceiveResult.receivedStatechainIds).not.empty; - - await mercurynodejslib.confirmPendingInvoice(clientConfig, wallet_1_name, coin.statechain_id); - - transferReceiveResult = await mercurynodejslib.transferReceive(clientConfig, wallet_2_name); - - expect(transferReceiveResult.isThereBatchLocked).is.false; - expect(transferReceiveResult.receivedStatechainIds).is.empty; - - let hash; - try { - const { preimage } = await mercurynodejslib.retrievePreImage(clientConfig, wallet_1_name, coin.statechain_id, paymentHash.batchId); - hash = crypto.createHash('sha256') - .update(Buffer.from(preimage, 'hex')) - .digest('hex') - expect(hash).to.equal(paymentHash.hash); - } catch (error) { - console.error('Error:', error); - expect(error.message).to.include('failed'); - } - }) - }) - - context('Coin receiver creates a non hold invoice, and sends to sender (i.e. an invoice with the a different payment hash). Sender should be able to determine this.', () => { - it('should complete successfully', async () => { - - // await removeDatabase(); - const clientConfig = client_config.load(); - let wallet_1_name = "w_ln_16"; - await createWallet(clientConfig, wallet_1_name); - - const token = await mercurynodejslib.newToken(clientConfig, wallet_1_name); - const tokenId = token.token_id; - - const amount = 10000; - const depositInfo = await mercurynodejslib.getDepositBitcoinAddress(clientConfig, wallet_1_name, amount); - - const tokenList = await mercurynodejslib.getWalletTokens(clientConfig, wallet_1_name); - const usedToken = tokenList.find(token => token.token_id === tokenId); - - expect(usedToken.spent).is.true; - - await depositCoin(clientConfig, wallet_1_name, amount, depositInfo); - - const listCoins = await mercurynodejslib.listStatecoins(clientConfig, wallet_1_name); - - expect(listCoins.length).to.equal(1); - - const coin = listCoins[0]; - - expect(coin.status).to.equal(CoinStatus.CONFIRMED); - - const paymentHash = await mercurynodejslib.paymentHash(clientConfig, wallet_1_name, coin.statechain_id); - - const paymentHashSecond = "a3b5f72d4e8cb07cd9a6e17c054a7ac84d05e1c018fe5b43cbbef98a9d3ff839" - const invoiceSecond = await generateInvoice(paymentHashSecond, amount); - - const isInvoiceValid = await mercurynodejslib.verifyInvoice(clientConfig, paymentHash.batchId, invoiceSecond.payment_request); - expect(isInvoiceValid).is.false; - }) - }) -}) diff --git a/clients/apps/nodejs/test/test-utils.mjs b/clients/apps/nodejs/test/test-utils.mjs deleted file mode 100644 index 1365bc11..00000000 --- a/clients/apps/nodejs/test/test-utils.mjs +++ /dev/null @@ -1,50 +0,0 @@ -import { promisify } from 'node:util'; -import { exec as execCallback } from 'node:child_process'; -import mercurynodejslib from 'mercurynodejslib'; -import { promises as fs } from 'fs'; - -const exec = promisify(execCallback); - -async function createWallet(clientConfig, walletName) { - - let wallet = await mercurynodejslib.createWallet(clientConfig, walletName); - return wallet; - - // TODO: add more assertions - } - - -async function removeDatabase(clientConfig) { - try { - await fs.unlink(clientConfig.databaseFile); - } catch (error) { - if (error.code !== 'ENOENT') { - console.error('Error occurred:', error); - } - // ENOENT means "No such file or directory", so we ignore this error - } -} - -async function getnewaddress() { - const generateBlockCommand = `docker exec $(docker ps -qf "name=lnd_docker-bitcoind-1") bitcoin-cli -regtest -rpcuser=user -rpcpassword=pass getnewaddress`; - const { stdout, stderr } = await exec(generateBlockCommand); - if (stderr) { - console.error('Error:', stderr); - return null; - } - return stdout.trim(); -} - -async function generateBlock(numBlocks, address) { - const generateBlockCommand = `docker exec $(docker ps -qf "name=lnd_docker-bitcoind-1") bitcoin-cli -regtest -rpcuser=user -rpcpassword=pass generatetoaddress ${numBlocks} ${address}`; - await exec(generateBlockCommand); -} - -async function depositCoin(deposit_address, amountInSats) { - const amountInBtc = amountInSats / 100000000; - - const sendBitcoinCommand = `docker exec $(docker ps -qf "name=lnd_docker-bitcoind-1") bitcoin-cli -regtest -rpcuser=user -rpcpassword=pass sendtoaddress ${deposit_address} ${amountInBtc}`; - await exec(sendBitcoinCommand); -} - -export { createWallet, removeDatabase, getnewaddress, generateBlock, depositCoin }; \ No newline at end of file diff --git a/clients/apps/nodejs/test_atomic_swap.js b/clients/apps/nodejs/test_atomic_swap.js deleted file mode 100644 index 6156a89f..00000000 --- a/clients/apps/nodejs/test_atomic_swap.js +++ /dev/null @@ -1,856 +0,0 @@ -const assert = require('node:assert/strict'); -const mercurynodejslib = require('mercurynodejslib'); -const { CoinStatus } = require('mercurynodejslib/coin_enum'); -const { sleep, createWallet, generateBlock, depositCoin } = require('./test_utils'); -const client_config = require('./client_config'); - -async function atomicSwapSuccess(clientConfig, wallet_1_name, wallet_2_name, wallet_3_name, wallet_4_name) { - - const amount = 10000; - let token = undefined; - let tokenId = undefined; - let deposit_info = undefined; - let tokenList = undefined; - let usedToken = undefined; - - token = await mercurynodejslib.newToken(clientConfig, wallet_1_name); - tokenId = token.token_id; - - deposit_info = await mercurynodejslib.getDepositBitcoinAddress(clientConfig, wallet_1_name, amount); - - tokenList = await mercurynodejslib.getWalletTokens(clientConfig, wallet_1_name); - - usedToken = tokenList.find(token => token.token_id === tokenId); - - assert(usedToken.spent); - - await depositCoin(clientConfig, wallet_1_name, amount, deposit_info); - - let coin1 = undefined; - - console.log("coin: ", coin1); - - while (!coin1) { - const list_coins = await mercurynodejslib.listStatecoins(clientConfig, wallet_1_name); - - let coinsWithStatechainId = list_coins.filter(c => { - return c.statechain_id === deposit_info.statechain_id && c.status === CoinStatus.CONFIRMED; - }); - - if (coinsWithStatechainId.length === 0) { - console.log("Waiting for coin to be confirmed..."); - console.log(`Check the address ${deposit_info.deposit_address} ...\n`); - await sleep(5000); - generateBlock(1); - continue; - } - - coin1 = coinsWithStatechainId[0]; - break; - } - - console.log("coin: ", coin1); - - token = await mercurynodejslib.newToken(clientConfig, wallet_2_name); - tokenId = token.token_id; - - deposit_info = await mercurynodejslib.getDepositBitcoinAddress(clientConfig, wallet_2_name, amount); - - tokenList = await mercurynodejslib.getWalletTokens(clientConfig, wallet_2_name); - - usedToken = tokenList.find(token => token.token_id === tokenId); - - assert(usedToken.spent); - - await depositCoin(clientConfig, wallet_2_name, amount, deposit_info); - - let coin2 = undefined; - - console.log("coin: ", coin2); - - while (!coin2) { - const list_coins = await mercurynodejslib.listStatecoins(clientConfig, wallet_2_name); - - let coinsWithStatechainId = list_coins.filter(c => { - return c.statechain_id === deposit_info.statechain_id && c.status === CoinStatus.CONFIRMED; - }); - - if (coinsWithStatechainId.length === 0) { - console.log("Waiting for coin to be confirmed..."); - console.log(`Check the address ${deposit_info.deposit_address} ...\n`); - await sleep(5000); - generateBlock(1); - continue; - } - - coin2 = coinsWithStatechainId[0]; - break; - } - - console.log("coin: ", coin2); - - const generateBatchId = true; - - let transfer_address_w3 = await mercurynodejslib.newTransferAddress(clientConfig, wallet_3_name, generateBatchId); - let transfer_address_w4 = await mercurynodejslib.newTransferAddress(clientConfig, wallet_4_name, null); - - let coin3 = await mercurynodejslib.transferSend(clientConfig, wallet_1_name, coin1.statechain_id, transfer_address_w3.transfer_receive, false, transfer_address_w3.batchId); - console.log("coin transferSend: ", coin3); - - let coin4 = await mercurynodejslib.transferSend(clientConfig, wallet_2_name, coin2.statechain_id, transfer_address_w4.transfer_receive, false, transfer_address_w3.batchId); - console.log("coin transferSend: ", coin4); - - let transferReceiveResult = await mercurynodejslib.transferReceive(clientConfig, wallet_3_name); - console.log("transferReceiveResult: ", transferReceiveResult); - assert(transferReceiveResult.isThereBatchLocked === true); - - transferReceiveResult = await mercurynodejslib.transferReceive(clientConfig, wallet_4_name); - let received_statechain_ids_w4 = transferReceiveResult.receivedStatechainIds; - - console.log("received_statechain_ids: ", received_statechain_ids_w4); - - assert(received_statechain_ids_w4.length > 0); - assert(received_statechain_ids_w4[0] == coin4.statechain_id); - - // transferReceiveResult = await mercurynodejslib.transferReceive(clientConfig, wallet_3_name); - // received_statechain_ids_w3 = transferReceiveResult.receivedStatechainIds; - - // console.log("received_statechain_ids: ", received_statechain_ids_w3); - - // assert(received_statechain_ids_w3.length > 0); - // assert(received_statechain_ids_w3[0] == coin3.statechain_id); -} - -async function atomicSwapWithSecondBatchIdMissing(clientConfig, wallet_1_name, wallet_2_name, wallet_3_name, wallet_4_name) { - - const amount = 10000; - let token = undefined; - let tokenId = undefined; - let deposit_info = undefined; - let tokenList = undefined; - let usedToken = undefined; - - token = await mercurynodejslib.newToken(clientConfig, wallet_1_name); - tokenId = token.token_id; - - deposit_info = await mercurynodejslib.getDepositBitcoinAddress(clientConfig, wallet_1_name, amount); - - tokenList = await mercurynodejslib.getWalletTokens(clientConfig, wallet_1_name); - - usedToken = tokenList.find(token => token.token_id === tokenId); - - assert(usedToken.spent); - - await depositCoin(clientConfig, wallet_1_name, amount, deposit_info); - - let coin1 = undefined; - - console.log("coin: ", coin1); - - while (!coin1) { - const list_coins = await mercurynodejslib.listStatecoins(clientConfig, wallet_1_name); - - let coinsWithStatechainId = list_coins.filter(c => { - return c.statechain_id === deposit_info.statechain_id && c.status === CoinStatus.CONFIRMED; - }); - - if (coinsWithStatechainId.length === 0) { - console.log("Waiting for coin to be confirmed..."); - console.log(`Check the address ${deposit_info.deposit_address} ...\n`); - await sleep(5000); - generateBlock(1); - continue; - } - - coin1 = coinsWithStatechainId[0]; - break; - } - - console.log("coin: ", coin1); - - token = await mercurynodejslib.newToken(clientConfig, wallet_2_name); - tokenId = token.token_id; - - deposit_info = await mercurynodejslib.getDepositBitcoinAddress(clientConfig, wallet_2_name, amount); - - tokenList = await mercurynodejslib.getWalletTokens(clientConfig, wallet_2_name); - - usedToken = tokenList.find(token => token.token_id === tokenId); - - assert(usedToken.spent); - - await depositCoin(clientConfig, wallet_2_name, amount, deposit_info); - - let coin2 = undefined; - - console.log("coin: ", coin2); - - while (!coin2) { - const list_coins = await mercurynodejslib.listStatecoins(clientConfig, wallet_2_name); - - let coinsWithStatechainId = list_coins.filter(c => { - return c.statechain_id === deposit_info.statechain_id && c.status === CoinStatus.CONFIRMED; - }); - - if (coinsWithStatechainId.length === 0) { - console.log("Waiting for coin to be confirmed..."); - console.log(`Check the address ${deposit_info.deposit_address} ...\n`); - await sleep(5000); - generateBlock(1); - continue; - } - - coin2 = coinsWithStatechainId[0]; - break; - } - - console.log("coin: ", coin2); - - const generateBatchId = true; - - let transfer_address_w3 = await mercurynodejslib.newTransferAddress(clientConfig, wallet_3_name, generateBatchId); - let transfer_address_w4 = await mercurynodejslib.newTransferAddress(clientConfig, wallet_4_name, null); - - let coin3 = await mercurynodejslib.transferSend(clientConfig, wallet_1_name, coin1.statechain_id, transfer_address_w3.transfer_receive, false, transfer_address_w3.batchId); - console.log("coin transferSend: ", coin3); - - transfer_address_w3.batchId = ""; - - let coin4 = await mercurynodejslib.transferSend(clientConfig, wallet_2_name, coin2.statechain_id, transfer_address_w4.transfer_receive, false, transfer_address_w3.batchId); - console.log("coin transferSend: ", coin4); - - let transferReceiveResult = await mercurynodejslib.transferReceive(clientConfig, wallet_3_name); - let received_statechain_ids_w3 = transferReceiveResult.receivedStatechainIds; - - console.log("received_statechain_ids: ", received_statechain_ids_w3); - - assert(received_statechain_ids_w3.length > 0); - assert(received_statechain_ids_w3[0] == coin3.statechain_id); - - transferReceiveResult = await mercurynodejslib.transferReceive(clientConfig, wallet_4_name); - let received_statechain_ids_w4 = transferReceiveResult.receivedStatechainIds; - - console.log("received_statechain_ids: ", received_statechain_ids_w4); - - assert(received_statechain_ids_w4.length > 0); - assert(received_statechain_ids_w4[0] == coin4.statechain_id); -} - -async function atomicSwapWithoutFirstBatchId(clientConfig, wallet_1_name, wallet_2_name, wallet_3_name, wallet_4_name) { - - const amount = 10000; - let token = undefined; - let tokenId = undefined; - let deposit_info = undefined; - let tokenList = undefined; - let usedToken = undefined; - - token = await mercurynodejslib.newToken(clientConfig, wallet_1_name); - tokenId = token.token_id; - - deposit_info = await mercurynodejslib.getDepositBitcoinAddress(clientConfig, wallet_1_name, amount); - - tokenList = await mercurynodejslib.getWalletTokens(clientConfig, wallet_1_name); - - usedToken = tokenList.find(token => token.token_id === tokenId); - - assert(usedToken.spent); - - await depositCoin(clientConfig, wallet_1_name, amount, deposit_info); - - let coin1 = undefined; - - console.log("coin: ", coin1); - - while (!coin1) { - const list_coins = await mercurynodejslib.listStatecoins(clientConfig, wallet_1_name); - - let coinsWithStatechainId = list_coins.filter(c => { - return c.statechain_id === deposit_info.statechain_id && c.status === CoinStatus.CONFIRMED; - }); - - if (coinsWithStatechainId.length === 0) { - console.log("Waiting for coin to be confirmed..."); - console.log(`Check the address ${deposit_info.deposit_address} ...\n`); - await sleep(5000); - generateBlock(1); - continue; - } - - coin1 = coinsWithStatechainId[0]; - break; - } - - console.log("coin: ", coin1); - - token = await mercurynodejslib.newToken(clientConfig, wallet_2_name); - tokenId = token.token_id; - - deposit_info = await mercurynodejslib.getDepositBitcoinAddress(clientConfig, wallet_2_name, amount); - - tokenList = await mercurynodejslib.getWalletTokens(clientConfig, wallet_2_name); - - usedToken = tokenList.find(token => token.token_id === tokenId); - - assert(usedToken.spent); - - await depositCoin(clientConfig, wallet_2_name, amount, deposit_info); - - let coin2 = undefined; - - console.log("coin: ", coin2); - - while (!coin2) { - const list_coins = await mercurynodejslib.listStatecoins(clientConfig, wallet_2_name); - - let coinsWithStatechainId = list_coins.filter(c => { - return c.statechain_id === deposit_info.statechain_id && c.status === CoinStatus.CONFIRMED; - }); - - if (coinsWithStatechainId.length === 0) { - console.log("Waiting for coin to be confirmed..."); - console.log(`Check the address ${deposit_info.deposit_address} ...\n`); - await sleep(5000); - generateBlock(1); - continue; - } - - coin2 = coinsWithStatechainId[0]; - break; - } - - console.log("coin: ", coin2); - - const generateBatchId = true; - - let transfer_address_w3 = await mercurynodejslib.newTransferAddress(clientConfig, wallet_3_name, generateBatchId); - let transfer_address_w4 = await mercurynodejslib.newTransferAddress(clientConfig, wallet_4_name, null); - - let coin3 = await mercurynodejslib.transferSend(clientConfig, wallet_1_name, coin1.statechain_id, transfer_address_w3.transfer_receive, false, null); - console.log("coin transferSend: ", coin3); - - let coin4 = await mercurynodejslib.transferSend(clientConfig, wallet_2_name, coin2.statechain_id, transfer_address_w4.transfer_receive, false, transfer_address_w3.batchId); - console.log("coin transferSend: ", coin4); - - let transferReceiveResult = await mercurynodejslib.transferReceive(clientConfig, wallet_3_name); - let received_statechain_ids_w3 = transferReceiveResult.receivedStatechainIds; - - console.log("received_statechain_ids: ", received_statechain_ids_w3); - - assert(received_statechain_ids_w3.length > 0); - assert(received_statechain_ids_w3[0] == coin3.statechain_id); - - transferReceiveResult = await mercurynodejslib.transferReceive(clientConfig, wallet_4_name); - let received_statechain_ids_w4 = transferReceiveResult.receivedStatechainIds; - - console.log("received_statechain_ids: ", received_statechain_ids_w4); - - assert(received_statechain_ids_w4.length > 0); - assert(received_statechain_ids_w4[0] == coin4.statechain_id); -} - -async function atomicSwapWithTimeout(clientConfig, wallet_1_name, wallet_2_name, wallet_3_name, wallet_4_name) { - - const amount = 10000; - let token = undefined; - let tokenId = undefined; - let deposit_info = undefined; - let tokenList = undefined; - let usedToken = undefined; - - token = await mercurynodejslib.newToken(clientConfig, wallet_1_name); - tokenId = token.token_id; - - deposit_info = await mercurynodejslib.getDepositBitcoinAddress(clientConfig, wallet_1_name, amount); - - tokenList = await mercurynodejslib.getWalletTokens(clientConfig, wallet_1_name); - - usedToken = tokenList.find(token => token.token_id === tokenId); - - assert(usedToken.spent); - - await depositCoin(clientConfig, wallet_1_name, amount, deposit_info); - - let coin1 = undefined; - - console.log("coin: ", coin1); - - while (!coin1) { - const list_coins = await mercurynodejslib.listStatecoins(clientConfig, wallet_1_name); - - let coinsWithStatechainId = list_coins.filter(c => { - return c.statechain_id === deposit_info.statechain_id && c.status === CoinStatus.CONFIRMED; - }); - - if (coinsWithStatechainId.length === 0) { - console.log("Waiting for coin to be confirmed..."); - console.log(`Check the address ${deposit_info.deposit_address} ...\n`); - await sleep(5000); - generateBlock(1); - continue; - } - - coin1 = coinsWithStatechainId[0]; - break; - } - - console.log("coin: ", coin1); - - token = await mercurynodejslib.newToken(clientConfig, wallet_2_name); - tokenId = token.token_id; - - deposit_info = await mercurynodejslib.getDepositBitcoinAddress(clientConfig, wallet_2_name, amount); - - tokenList = await mercurynodejslib.getWalletTokens(clientConfig, wallet_2_name); - - usedToken = tokenList.find(token => token.token_id === tokenId); - - assert(usedToken.spent); - - await depositCoin(clientConfig, wallet_2_name, amount, deposit_info); - - let coin2 = undefined; - - console.log("coin: ", coin2); - - while (!coin2) { - const list_coins = await mercurynodejslib.listStatecoins(clientConfig, wallet_2_name); - - let coinsWithStatechainId = list_coins.filter(c => { - return c.statechain_id === deposit_info.statechain_id && c.status === CoinStatus.CONFIRMED; - }); - - if (coinsWithStatechainId.length === 0) { - console.log("Waiting for coin to be confirmed..."); - console.log(`Check the address ${deposit_info.deposit_address} ...\n`); - await sleep(5000); - generateBlock(1); - continue; - } - - coin2 = coinsWithStatechainId[0]; - break; - } - - console.log("coin: ", coin2); - - const generateBatchId = true; - - let transfer_address_w3 = await mercurynodejslib.newTransferAddress(clientConfig, wallet_3_name, generateBatchId); - let transfer_address_w4 = await mercurynodejslib.newTransferAddress(clientConfig, wallet_4_name, null); - - let coin3 = await mercurynodejslib.transferSend(clientConfig, wallet_1_name, coin1.statechain_id, transfer_address_w3.transfer_receive, false, transfer_address_w3.batchId); - console.log("coin transferSend: ", coin3); - - let coin4 = await mercurynodejslib.transferSend(clientConfig, wallet_2_name, coin2.statechain_id, transfer_address_w4.transfer_receive, false, transfer_address_w3.batchId); - console.log("coin transferSend: ", coin4); - - let transferReceiveResult = await mercurynodejslib.transferReceive(clientConfig, wallet_3_name); - let received_statechain_ids_w3 = transferReceiveResult.receivedStatechainIds; - await sleep(20000); - - assert(transferReceiveResult.isThereBatchLocked === true); - - let errorMessage; - console.error = (msg) => { - errorMessage = msg; - }; - - transferReceiveResult = await mercurynodejslib.transferReceive(clientConfig, wallet_4_name); - let received_statechain_ids_w4 = transferReceiveResult.receivedStatechainIds; - - // Assert the captured error message - const expectedMessage = 'Failed to update transfer message'; - assert.ok(errorMessage.includes(expectedMessage)); - - transfer_address_w3 = await mercurynodejslib.newTransferAddress(clientConfig, wallet_3_name, generateBatchId); - transfer_address_w4 = await mercurynodejslib.newTransferAddress(clientConfig, wallet_4_name, null); - - coin3 = await mercurynodejslib.transferSend(clientConfig, wallet_1_name, coin1.statechain_id, transfer_address_w3.transfer_receive, false, transfer_address_w3.batchId); - console.log("coin transferSend: ", coin3); - - coin4 = await mercurynodejslib.transferSend(clientConfig, wallet_2_name, coin2.statechain_id, transfer_address_w4.transfer_receive, false, transfer_address_w3.batchId); - console.log("coin transferSend: ", coin4); - - transferReceiveResult = await mercurynodejslib.transferReceive(clientConfig, wallet_3_name); - received_statechain_ids_w3 = transferReceiveResult.receivedStatechainIds; - - transferReceiveResult = await mercurynodejslib.transferReceive(clientConfig, wallet_4_name); - received_statechain_ids_w4 = transferReceiveResult.receivedStatechainIds; - - console.log("received_statechain_ids: ", received_statechain_ids_w4); - - assert(received_statechain_ids_w4.length > 0); - assert(received_statechain_ids_w4[0] == coin4.statechain_id); - - // transferReceiveResult = await mercurynodejslib.transferReceive(clientConfig, wallet_3_name); - // received_statechain_ids_w3 = transferReceiveResult.receivedStatechainIds; - - // console.log("received_statechain_ids: ", received_statechain_ids_w3); - - // assert(received_statechain_ids_w3.length > 0); - // assert(received_statechain_ids_w3[0] == coin3.statechain_id); -} - -async function atomicSwapWithFirstPartySteal(clientConfig, wallet_1_name, wallet_2_name, wallet_3_name, wallet_4_name) { - - const amount = 10000; - let token = undefined; - let tokenId = undefined; - let deposit_info = undefined; - let tokenList = undefined; - let usedToken = undefined; - - token = await mercurynodejslib.newToken(clientConfig, wallet_1_name); - tokenId = token.token_id; - - deposit_info = await mercurynodejslib.getDepositBitcoinAddress(clientConfig, wallet_1_name, amount); - - tokenList = await mercurynodejslib.getWalletTokens(clientConfig, wallet_1_name); - - usedToken = tokenList.find(token => token.token_id === tokenId); - - assert(usedToken.spent); - - await depositCoin(clientConfig, wallet_1_name, amount, deposit_info); - - let coin1 = undefined; - - console.log("coin: ", coin1); - - while (!coin1) { - const list_coins = await mercurynodejslib.listStatecoins(clientConfig, wallet_1_name); - - let coinsWithStatechainId = list_coins.filter(c => { - return c.statechain_id === deposit_info.statechain_id && c.status === CoinStatus.CONFIRMED; - }); - - if (coinsWithStatechainId.length === 0) { - console.log("Waiting for coin to be confirmed..."); - console.log(`Check the address ${deposit_info.deposit_address} ...\n`); - await sleep(5000); - generateBlock(1); - continue; - } - - coin1 = coinsWithStatechainId[0]; - break; - } - - console.log("coin: ", coin1); - - token = await mercurynodejslib.newToken(clientConfig, wallet_2_name); - tokenId = token.token_id; - - deposit_info = await mercurynodejslib.getDepositBitcoinAddress(clientConfig, wallet_2_name, amount); - - tokenList = await mercurynodejslib.getWalletTokens(clientConfig, wallet_2_name); - - usedToken = tokenList.find(token => token.token_id === tokenId); - - assert(usedToken.spent); - - await depositCoin(clientConfig, wallet_2_name, amount, deposit_info); - - let coin2 = undefined; - - console.log("coin: ", coin2); - - while (!coin2) { - const list_coins = await mercurynodejslib.listStatecoins(clientConfig, wallet_2_name); - - let coinsWithStatechainId = list_coins.filter(c => { - return c.statechain_id === deposit_info.statechain_id && c.status === CoinStatus.CONFIRMED; - }); - - if (coinsWithStatechainId.length === 0) { - console.log("Waiting for coin to be confirmed..."); - console.log(`Check the address ${deposit_info.deposit_address} ...\n`); - await sleep(5000); - generateBlock(1); - continue; - } - - coin2 = coinsWithStatechainId[0]; - break; - } - - console.log("coin: ", coin2); - - const generateBatchId = true; - - let transfer_address_w3 = await mercurynodejslib.newTransferAddress(clientConfig, wallet_3_name, generateBatchId); - let transfer_address_w4 = await mercurynodejslib.newTransferAddress(clientConfig, wallet_4_name, null); - - let coin3 = await mercurynodejslib.transferSend(clientConfig, wallet_1_name, coin1.statechain_id, transfer_address_w3.transfer_receive, false, transfer_address_w3.batchId); - console.log("coin transferSend: ", coin3); - - let coin4 = await mercurynodejslib.transferSend(clientConfig, wallet_2_name, coin2.statechain_id, transfer_address_w4.transfer_receive, false, transfer_address_w3.batchId); - console.log("coin transferSend: ", coin4); - - let transfer_address_w3_for_steal = await mercurynodejslib.newTransferAddress(clientConfig, wallet_3_name, generateBatchId); - console.log("transfer address for steal", transfer_address_w3_for_steal); - - let coin_to_steal = undefined; - try { - coin_to_steal = await mercurynodejslib.transferSend(clientConfig, wallet_1_name, coin1.statechain_id, transfer_address_w3_for_steal.transfer_receive, false, transfer_address_w3.batchId); - } catch (error) { - // Assert the captured error message - const expectedMessage = 'expected a string argument, found undefined'; - assert.ok(error.message.includes(expectedMessage)); - } - - console.log("coin to steal transferSend: ", coin_to_steal); - - let received_statechain_ids_w3 = undefined; - try { - received_statechain_ids_w3 = mercurynodejslib.transferReceive(clientConfig, wallet_3_name); - } catch (error) { - // Assert the captured error message - const expectedMessage = 'num_sigs is not correct'; - assert.ok(error.message.includes(expectedMessage)); - } - await sleep(3000); - - let received_statechain_ids_w4 = undefined; - try { - received_statechain_ids_w4 = await mercurynodejslib.transferReceive(clientConfig, wallet_4_name); - } catch (error) { - // Assert the captured error message - const expectedMessage = 'num_sigs is not correct'; - assert.ok(error.message.includes(expectedMessage)); - } - - try { - received_statechain_ids_w3 = await mercurynodejslib.transferReceive(clientConfig, wallet_3_name); - } catch (error) { - // Assert the captured error message - const expectedMessage = 'num_sigs is not correct'; - assert.ok(error.message.includes(expectedMessage)); - } -} - -async function atomicSwapWithSecondPartySteal(clientConfig, wallet_1_name, wallet_2_name, wallet_3_name, wallet_4_name) { - - const amount = 10000; - let token = undefined; - let tokenId = undefined; - let deposit_info = undefined; - let tokenList = undefined; - let usedToken = undefined; - - token = await mercurynodejslib.newToken(clientConfig, wallet_1_name); - tokenId = token.token_id; - - deposit_info = await mercurynodejslib.getDepositBitcoinAddress(clientConfig, wallet_1_name, amount); - - tokenList = await mercurynodejslib.getWalletTokens(clientConfig, wallet_1_name); - - usedToken = tokenList.find(token => token.token_id === tokenId); - - assert(usedToken.spent); - - await depositCoin(clientConfig, wallet_1_name, amount, deposit_info); - - let coin1 = undefined; - - console.log("coin: ", coin1); - - while (!coin1) { - const list_coins = await mercurynodejslib.listStatecoins(clientConfig, wallet_1_name); - - let coinsWithStatechainId = list_coins.filter(c => { - return c.statechain_id === deposit_info.statechain_id && c.status === CoinStatus.CONFIRMED; - }); - - if (coinsWithStatechainId.length === 0) { - console.log("Waiting for coin to be confirmed..."); - console.log(`Check the address ${deposit_info.deposit_address} ...\n`); - await sleep(5000); - generateBlock(1); - continue; - } - - coin1 = coinsWithStatechainId[0]; - break; - } - - console.log("coin: ", coin1); - - token = await mercurynodejslib.newToken(clientConfig, wallet_2_name); - tokenId = token.token_id; - - deposit_info = await mercurynodejslib.getDepositBitcoinAddress(clientConfig, wallet_2_name, amount); - - tokenList = await mercurynodejslib.getWalletTokens(clientConfig, wallet_2_name); - - usedToken = tokenList.find(token => token.token_id === tokenId); - - assert(usedToken.spent); - - await depositCoin(clientConfig, wallet_2_name, amount, deposit_info); - - let coin2 = undefined; - - console.log("coin: ", coin2); - - while (!coin2) { - const list_coins = await mercurynodejslib.listStatecoins(clientConfig, wallet_2_name); - - let coinsWithStatechainId = list_coins.filter(c => { - return c.statechain_id === deposit_info.statechain_id && c.status === CoinStatus.CONFIRMED; - }); - - if (coinsWithStatechainId.length === 0) { - console.log("Waiting for coin to be confirmed..."); - console.log(`Check the address ${deposit_info.deposit_address} ...\n`); - await sleep(5000); - generateBlock(1); - continue; - } - - coin2 = coinsWithStatechainId[0]; - break; - } - - console.log("coin: ", coin2); - - const generateBatchId = true; - - let transfer_address_w3 = await mercurynodejslib.newTransferAddress(clientConfig, wallet_3_name, generateBatchId); - let transfer_address_w4 = await mercurynodejslib.newTransferAddress(clientConfig, wallet_4_name, null); - - let coin3 = await mercurynodejslib.transferSend(clientConfig, wallet_1_name, coin1.statechain_id, transfer_address_w3.transfer_receive, false, transfer_address_w3.batchId); - console.log("coin transferSend: ", coin3); - - let coin4 = await mercurynodejslib.transferSend(clientConfig, wallet_2_name, coin2.statechain_id, transfer_address_w4.transfer_receive, false, transfer_address_w3.batchId); - console.log("coin transferSend: ", coin4); - - let transfer_address_w4_for_steal = await mercurynodejslib.newTransferAddress(clientConfig, wallet_4_name, generateBatchId); - console.log("transfer address for steal", transfer_address_w4_for_steal); - - let coin_to_steal = undefined; - try { - coin_to_steal = await mercurynodejslib.transferSend(clientConfig, wallet_2_name, coin2.statechain_id, transfer_address_w4_for_steal.transfer_receive, false, transfer_address_w4.batchId); - } catch (error) { - // Assert the captured error message - const expectedMessage = 'expected a string argument, found undefined'; - assert.ok(error.message.includes(expectedMessage)); - } - - console.log("coin to steal transferSend: ", coin_to_steal); - - let received_statechain_ids_w3 = undefined; - try { - received_statechain_ids_w3 = mercurynodejslib.transferReceive(clientConfig, wallet_3_name); - } catch (error) { - // Assert the captured error message - const expectedMessage = 'num_sigs is not correct'; - assert.ok(error.message.includes(expectedMessage)); - } - - let received_statechain_ids_w4 = undefined; - try { - received_statechain_ids_w4 = await mercurynodejslib.transferReceive(clientConfig, wallet_4_name); - } catch (error) { - // Assert the captured error message - const expectedMessage = 'num_sigs is not correct'; - assert.ok(error.message.includes(expectedMessage)); - } - - try { - received_statechain_ids_w3 = await mercurynodejslib.transferReceive(clientConfig, wallet_3_name); - } catch (error) { - // Assert the captured error message - const expectedMessage = 'num_sigs is not correct'; - assert.ok(error.message.includes(expectedMessage)); - } -} - -(async () => { - - try { - const clientConfig = client_config.load(); - - // Successful test - all transfers complete within batch_time complete. - let wallet_1_name = "w_atomic_1"; - let wallet_2_name = "w_atomic_2"; - let wallet_3_name = "w_atomic_3"; - let wallet_4_name = "w_atomic_4"; - await createWallet(clientConfig, wallet_1_name); - await createWallet(clientConfig, wallet_2_name); - await createWallet(clientConfig, wallet_3_name); - await createWallet(clientConfig, wallet_4_name); - await atomicSwapSuccess(clientConfig, wallet_1_name, wallet_2_name, wallet_3_name, wallet_4_name); - console.log("Completed test for Successful test - all transfers complete within batch_time complete."); - - // Second party performs transfer-sender with incorrect or missing batch-id. First party should still receive OK. - let wallet_5_name = "w_atomic_5"; - let wallet_6_name = "w_atomic_6"; - let wallet_7_name = "w_atomic_7"; - let wallet_8_name = "w_atomic_8"; - await createWallet(clientConfig, wallet_5_name); - await createWallet(clientConfig, wallet_6_name); - await createWallet(clientConfig, wallet_7_name); - await createWallet(clientConfig, wallet_8_name); - await atomicSwapWithSecondBatchIdMissing(clientConfig, wallet_5_name, wallet_6_name, wallet_7_name, wallet_8_name); - console.log("Completed test for Second party performs transfer-sender with incorrect or missing batch-id. First party should still receive OK."); - - // First party performs transfer-sender without batch_id. - let wallet_9_name = "w_atomic_9"; - let wallet_10_name = "w_atomic_10"; - let wallet_11_name = "w_atomic_11"; - let wallet_12_name = "w_atomic_12"; - await createWallet(clientConfig, wallet_9_name); - await createWallet(clientConfig, wallet_10_name); - await createWallet(clientConfig, wallet_11_name); - await createWallet(clientConfig, wallet_12_name); - await atomicSwapWithoutFirstBatchId(clientConfig, wallet_9_name, wallet_10_name, wallet_11_name, wallet_12_name); - console.log("Completed test for First party performs transfer-sender without batch_id."); - - // One party doesn't complete transfer-receiver before the timeout. - // Both wallets should be able to repeat transfer-sender and transfer-receiver back to new addresses without error, - // after the timeout. - let wallet_13_name = "w_atomic_13"; - let wallet_14_name = "w_atomic_14"; - let wallet_15_name = "w_atomic_15"; - let wallet_16_name = "w_atomic_16"; - await createWallet(clientConfig, wallet_13_name); - await createWallet(clientConfig, wallet_14_name); - await createWallet(clientConfig, wallet_15_name); - await createWallet(clientConfig, wallet_16_name); - await atomicSwapWithTimeout(clientConfig, wallet_13_name, wallet_14_name, wallet_15_name, wallet_16_name); - console.log("Completed test for One party doesn't complete transfer-receiver before the timeout."); - - // First party tries to steal within timeout - // they perform transfer-sender a second time sending back to one of their own addresses - should fail. - let wallet_17_name = "w_atomic_17"; - let wallet_18_name = "w_atomic_18"; - let wallet_19_name = "w_atomic_19"; - let wallet_20_name = "w_atomic_20"; - await createWallet(clientConfig, wallet_17_name); - await createWallet(clientConfig, wallet_18_name); - await createWallet(clientConfig, wallet_19_name); - await createWallet(clientConfig, wallet_20_name); - await atomicSwapWithFirstPartySteal(clientConfig, wallet_17_name, wallet_18_name, wallet_19_name, wallet_20_name); - console.log("Completed test for First party tries to steal within timeout"); - - // Second party tries to steal within timeout - // they perform transfer-sender a second time sending back to one of their own addresses - should fail. - let wallet_21_name = "w_atomic_21"; - let wallet_22_name = "w_atomic_22"; - let wallet_23_name = "w_atomic_23"; - let wallet_24_name = "w_atomic_24"; - await createWallet(clientConfig, wallet_21_name); - await createWallet(clientConfig, wallet_22_name); - await createWallet(clientConfig, wallet_23_name); - await createWallet(clientConfig, wallet_24_name); - await atomicSwapWithSecondPartySteal(clientConfig, wallet_21_name, wallet_22_name, wallet_23_name, wallet_24_name); - console.log("Completed test for Second party tries to steal within timeout"); - - process.exit(0); // Exit successfully - } catch (error) { - console.error("Test encountered an error:", error); - process.exit(1); // Exit with failure - } -})(); \ No newline at end of file diff --git a/clients/apps/nodejs/test_basic_workflow.js b/clients/apps/nodejs/test_basic_workflow.js deleted file mode 100644 index 35f7303c..00000000 --- a/clients/apps/nodejs/test_basic_workflow.js +++ /dev/null @@ -1,232 +0,0 @@ -const util = require('node:util'); -const exec = util.promisify(require('node:child_process').exec); -const assert = require('node:assert/strict'); -const { CoinStatus } = require('mercurynodejslib/coin_enum'); - -async function removeDatabase() { - try { - const { stdout, stderr } = await exec('rm wallet.db'); - // console.log('stdout:', stdout); - // console.error('stderr:', stderr); - } catch (e) { - // console.error(e); - } -} - -async function createWallet(wallet_name) { - const { stdout, stderr } = await exec(`node index.js create-wallet ${wallet_name}`); - let wallet = JSON.parse(stdout); - assert.equal(wallet.name, wallet_name); - // console.log('wallet:', wallet); -} - -async function newToken(wallet_name) { - const { stdout, stderr } = await exec(`node index.js new-token ${wallet_name}`); - let json = JSON.parse(stdout); - return json; -} - -async function listTokens(wallet_name) { - const { stdout, stderr } = await exec(`node index.js list-tokens ${wallet_name}`); - let json = JSON.parse(stdout); - return json; -} - -async function getDepositBitcoinAddress(wallet_name, token_id, amount) { - const { stdout, stderr } = await exec(`node index.js new-deposit-address ${wallet_name} ${token_id} ${amount}`); - let json = JSON.parse(stdout); - return json; -} - -async function listStatecoins(wallet_name) { - try { - const { stdout, stderr } = await exec(`node index.js list-statecoins ${wallet_name}`); - let json = JSON.parse(stdout); - return json; - } catch (e) { - console.log('e:', e); - return undefined; - } -} - -async function newTransferAddress(wallet_name) { - const { stdout, stderr } = await exec(`node index.js new-transfer-address ${wallet_name}`); - let json = JSON.parse(stdout); - return json.transfer_receive; -} - -async function transferSend(wallet_name, statechain_id, to_address) { - const { stdout, stderr } = await exec(`node index.js transfer-send ${wallet_name} ${statechain_id} ${to_address}`); - let json = JSON.parse(stdout); - return json; -} - -async function transferReceive(wallet_name) { - const { stdout, stderr } = await exec(`node index.js transfer-receive ${wallet_name}`); - let json = JSON.parse(stdout); - return json; -} - -async function withdraw(wallet_name, statechain_id, to_address) { - const { stdout, stderr } = await exec(`node index.js withdraw ${wallet_name} ${statechain_id} ${to_address}`); - let json = JSON.parse(stdout); - return json.txid; -} - -async function broadcastBackupTransaction(wallet_name, statechain_id, to_address) { - const { stdout, stderr } = await exec(`node index.js broadcast-backup-transaction ${wallet_name} ${statechain_id} ${to_address}`); - let json = JSON.parse(stdout); - return json; -} - -const sleep = (ms) => { - return new Promise(resolve => setTimeout(resolve, ms)); -} - -async function walletTransfersToItselfAndWithdraw(wallet_name) { - - const amount = 10000; - - const token = await newToken(wallet_name); - const tokenId = token.token_id; - - const deposit_info = await getDepositBitcoinAddress(wallet_name, amount); - - let tokenList = await listTokens(wallet_name); - - let usedToken = tokenList.find(token => token.token_id === tokenId); - - assert(usedToken.spent); - - deposit_info["amount"] = amount; - console.log("deposit_coin: ", deposit_info); - - let coin = undefined; - - while (!coin) { - const list_coins = await listStatecoins(wallet_name); - - let coinsWithStatechainId = list_coins.filter(c => { - return c.statechain_id === deposit_info.statechain_id && c.status === CoinStatus.CONFIRMED; - }); - - if (coinsWithStatechainId.length === 0) { - console.log("Waiting for coin to be confirmed..."); - console.log(`Check the address ${deposit_info.deposit_address} ...\n`); - await sleep(5000); - continue; - } - - coin = coinsWithStatechainId[0]; - - break; - } - - console.log("coin: ", coin); - - for (let i = 0; i < 10; i++) { - - let transfer_address = await newTransferAddress(wallet_name); - - console.log("transfer_address: ", transfer_address); - - coin = await transferSend(wallet_name, coin.statechain_id, transfer_address); - - console.log("coin transferSend: ", coin); - - let received_statechain_ids = await transferReceive(wallet_name); - - console.log("received_statechain_ids: ", received_statechain_ids); - - assert(received_statechain_ids.length > 0); - assert(received_statechain_ids[0] == coin.statechain_id); - } - - let withdraw_address = "tb1qwrujs6f4gyexsextpf9p50smjtht7p7ypknteu"; - - let txid = await withdraw(wallet_name, coin.statechain_id, withdraw_address); - - console.log("txid: ", txid); - -}; - -async function walletTransfersMultipleTimesToItselfAndBroadcastsBackup(wallet_name) { - for (let i = 0; i < 3; i++) { - await walletTransfersToItselfAndWithdraw(wallet_name); - } -} - -async function walletTransfersToAnotherAndBroadcastsBackupTx(wallet_1_name, wallet_2_name) { - - const amount = 10000; - - const token = await newToken(wallet_1_name); - const tokenId = token.token_id; - - const deposit_info = await getDepositBitcoinAddress(wallet_1_name, amount); - - deposit_info["amount"] = amount; - console.log("deposit_info w1: ", deposit_info); - - let tokenList = await listTokens(wallet_1_name); - - let usedToken = tokenList.find(token => token.token_id === tokenId); - - console.log("usedToken: ", usedToken); - - assert(usedToken.spent); - - let coin = undefined; - - while (!coin) { - const list_coins = await listStatecoins(wallet_1_name); - - let coinsWithStatechainId = list_coins.filter(c => { - return c.statechain_id === deposit_info.statechain_id && c.status === CoinStatus.CONFIRMED; - }); - - if (coinsWithStatechainId.length === 0) { - console.log("Waiting for coin to be confirmed..."); - console.log(`Check the address ${deposit_info.deposit_address} ...\n`); - await sleep(5000); - continue; - } - - coin = coinsWithStatechainId[0]; - - break; - } - - let transfer_address = await newTransferAddress(wallet_2_name); - - coin = await transferSend(wallet_1_name, coin.statechain_id, transfer_address); - - let received_statechain_ids = await transferReceive(wallet_2_name); - - console.log("received_statechain_ids: ", received_statechain_ids); - - assert(received_statechain_ids.length > 0); - assert(received_statechain_ids[0] == coin.statechain_id); - - let withdraw_address = "tb1qwrujs6f4gyexsextpf9p50smjtht7p7ypknteu"; - - let txids = await broadcastBackupTransaction(wallet_2_name, received_statechain_ids[0], withdraw_address); - - console.log("txids: ", txids); - -} - -(async () => { - let wallet_1_name = "w1"; - let wallet_2_name = "w2"; - - await removeDatabase(); - await createWallet(wallet_1_name); - await createWallet(wallet_2_name); - - await walletTransfersMultipleTimesToItselfAndBroadcastsBackup(wallet_1_name); - - await walletTransfersToAnotherAndBroadcastsBackupTx(wallet_1_name, wallet_2_name) - - await removeDatabase(); -})(); diff --git a/clients/apps/nodejs/test_basic_workflow2.js b/clients/apps/nodejs/test_basic_workflow2.js deleted file mode 100644 index faf64184..00000000 --- a/clients/apps/nodejs/test_basic_workflow2.js +++ /dev/null @@ -1,1072 +0,0 @@ -const assert = require('node:assert/strict'); -const mercurynodejslib = require('mercurynodejslib'); -const { CoinStatus } = require('mercurynodejslib/coin_enum'); -const client_config = require('./client_config'); -const sqlite_manager = require('../../libs/nodejs/sqlite_manager'); -const mercury_wasm = require('mercury-wasm'); -const transaction = require('../../libs/nodejs/transaction'); -const utils = require('../../libs/nodejs/utils'); -const { getDatabase, sleep, createWallet, getElectrumClient, generateBlock, depositCoin, connectElectr, disconnectElectr, disconnectMercuryServer, connectMercuryServer } = require('./test_utils'); - -async function walletTransfersToItselfAndWithdraw(clientConfig, wallet_name) { - - const token = await mercurynodejslib.newToken(clientConfig, wallet_name); - const tokenId = token.token_id; - - const amount = 10000; - const deposit_info = await mercurynodejslib.getDepositBitcoinAddress(clientConfig, wallet_name, amount); - - let tokenList = await mercurynodejslib.getWalletTokens(clientConfig, wallet_name); - - let usedToken = tokenList.find(token => token.token_id === tokenId); - - assert(usedToken.spent); - - await depositCoin(clientConfig, wallet_name, amount, deposit_info); - - let coin = undefined; - - while (!coin) { - const list_coins = await mercurynodejslib.listStatecoins(clientConfig, wallet_name); - // console.log(list_coins); - - let coinsWithStatechainId = list_coins.filter(c => { - return c.statechain_id === deposit_info.statechain_id && c.status === CoinStatus.CONFIRMED; - }); - - if (coinsWithStatechainId.length === 0) { - // console.log("Waiting for coin to be confirmed..."); - // console.log(`Check the address ${deposit_info.deposit_address} ...\n`); - await sleep(1000); - generateBlock(1); - continue; - } - - coin = coinsWithStatechainId[0]; - - break; - } - - for (let i = 0; i < 10; i++) { - let transfer_address = await mercurynodejslib.newTransferAddress(clientConfig, wallet_name, null); - - coin = await mercurynodejslib.transferSend(clientConfig, wallet_name, coin.statechain_id, transfer_address.transfer_receive, false, null); - - let transferReceiveResult = await mercurynodejslib.transferReceive(clientConfig, wallet_name); - let received_statechain_ids = transferReceiveResult.receivedStatechainIds; - - assert(received_statechain_ids.length > 0); - assert(received_statechain_ids[0] == coin.statechain_id); - } - - let withdraw_address = "bcrt1qgh48u8aj4jvjkalc28lqujyx2wveck4jsm59x9"; - - let txid = await mercurynodejslib.withdrawCoin(clientConfig, wallet_name, coin.statechain_id, withdraw_address, null, null); - - // TODO: confirm withdrawal status -} - -async function walletTransfersToItselfTillLocktimeReachesBlockHeightAndWithdraw(clientConfig, wallet_name) { - - const token = await mercurynodejslib.newToken(clientConfig, wallet_name); - const tokenId = token.token_id; - - const amount = 10000; - const deposit_info = await mercurynodejslib.getDepositBitcoinAddress(clientConfig, wallet_name, amount); - - let tokenList = await mercurynodejslib.getWalletTokens(clientConfig, wallet_name); - - let usedToken = tokenList.find(token => token.token_id === tokenId); - - assert(usedToken.spent); - - await depositCoin(clientConfig, wallet_name, amount, deposit_info); - - let coin = undefined; - - while (!coin) { - const list_coins = await mercurynodejslib.listStatecoins(clientConfig, wallet_name); - - let coinsWithStatechainId = list_coins.filter(c => { - return c.statechain_id === deposit_info.statechain_id && c.status === CoinStatus.CONFIRMED; - }); - - if (coinsWithStatechainId.length === 0) { - /* console.log("Waiting for coin to be confirmed..."); - console.log(`Check the address ${deposit_info.deposit_address} ...\n`); */ - await sleep(5000); - generateBlock(1); - continue; - } - - coin = coinsWithStatechainId[0]; - - break; - } - - const electrumClient = await getElectrumClient(clientConfig); - - let block_header = await electrumClient.request('blockchain.headers.subscribe'); - let currentBlockHeight = block_header.height; - - while (coin.locktime <= currentBlockHeight) { - let transfer_address = await mercurynodejslib.newTransferAddress(clientConfig, wallet_name, null); - - coin = await mercurynodejslib.transferSend(clientConfig, wallet_name, coin.statechain_id, transfer_address.transfer_receive, false, null); - - let transferReceiveResult = await mercurynodejslib.transferReceive(clientConfig, wallet_name); - let received_statechain_ids = transferReceiveResult.receivedStatechainIds; - - assert(received_statechain_ids.length > 0); - assert(received_statechain_ids[0] == coin.statechain_id); - - // Fetch the coin again to get the updated locktime - const list_coins = await mercurynodejslib.listStatecoins(clientConfig, wallet_name); - coin = list_coins.find(c => c.statechain_id === coin.statechain_id); - } - - let withdraw_address = "bcrt1qgh48u8aj4jvjkalc28lqujyx2wveck4jsm59x9"; - - let txid = await mercurynodejslib.withdrawCoin(clientConfig, wallet_name, coin.statechain_id, withdraw_address, null, null); - - // TODO: confirm withdrawal status -} - -async function walletTransfersToAnotherAndBroadcastsBackupTx(clientConfig, wallet_1_name, wallet_2_name) { - - const token = await mercurynodejslib.newToken(clientConfig, wallet_1_name); - const tokenId = token.token_id; - - const amount = 10000; - const deposit_info = await mercurynodejslib.getDepositBitcoinAddress(clientConfig, wallet_1_name, amount); - - let tokenList = await mercurynodejslib.getWalletTokens(clientConfig, wallet_1_name); - - let usedToken = tokenList.find(token => token.token_id === tokenId); - - assert(usedToken.spent); - - await depositCoin(clientConfig, wallet_1_name, amount, deposit_info); - - let coin = undefined; - - while (!coin) { - const list_coins = await mercurynodejslib.listStatecoins(clientConfig, wallet_1_name); - - let coinsWithStatechainId = list_coins.filter(c => { - return c.statechain_id === deposit_info.statechain_id && c.status === CoinStatus.CONFIRMED; - }); - - if (coinsWithStatechainId.length === 0) { - /* console.log("Waiting for coin to be confirmed..."); - console.log(`Check the address ${deposit_info.deposit_address} ...\n`); */ - await sleep(1000); - generateBlock(1); - continue; - } - - coin = coinsWithStatechainId[0]; - - break; - } - - let transfer_address = await mercurynodejslib.newTransferAddress(clientConfig, wallet_2_name, null); - - coin = await mercurynodejslib.transferSend(clientConfig, wallet_1_name, coin.statechain_id, transfer_address.transfer_receive, false, null); - - let transferReceiveResult = await mercurynodejslib.transferReceive(clientConfig, wallet_2_name); - let received_statechain_ids = transferReceiveResult.receivedStatechainIds; - - assert(received_statechain_ids.length > 0); - assert(received_statechain_ids[0] == coin.statechain_id); - - let withdraw_address = "bcrt1qgh48u8aj4jvjkalc28lqujyx2wveck4jsm59x9"; - - let txid = await mercurynodejslib.broadcastBackupTransaction(clientConfig, wallet_2_name, coin.statechain_id, withdraw_address, null); - - // TODO: confirm withdrawal status -} - -async function depositAndRepeatSend(clientConfig, wallet_1_name) { - - const token = await mercurynodejslib.newToken(clientConfig, wallet_1_name); - const tokenId = token.token_id; - - const amount = 10000; - const deposit_info = await mercurynodejslib.getDepositBitcoinAddress(clientConfig, wallet_1_name, amount); - - let tokenList = await mercurynodejslib.getWalletTokens(clientConfig, wallet_1_name); - - let usedToken = tokenList.find(token => token.token_id === tokenId); - - assert(usedToken.spent); - - await depositCoin(clientConfig, wallet_1_name, amount, deposit_info); - - let coin = undefined; - - while (!coin) { - const list_coins = await mercurynodejslib.listStatecoins(clientConfig, wallet_1_name); - - let coinsWithStatechainId = list_coins.filter(c => { - return c.statechain_id === deposit_info.statechain_id && c.status === CoinStatus.CONFIRMED; - }); - - if (coinsWithStatechainId.length === 0) { - // console.log("Waiting for coin to be confirmed..."); - // console.log(`Check the address ${deposit_info.deposit_address} ...\n`); - await sleep(1000); - generateBlock(1); - continue; - } - - coin = coinsWithStatechainId[0]; - break; - } - - for (let i = 0; i < 10; i++) { - let transfer_address = await mercurynodejslib.newTransferAddress(clientConfig, wallet_1_name, null); - coin = await mercurynodejslib.transferSend(clientConfig, wallet_1_name, coin.statechain_id, transfer_address.transfer_receive, false, null); - let transferReceiveResult = await mercurynodejslib.transferReceive(clientConfig, wallet_1_name); - let received_statechain_ids = transferReceiveResult.receivedStatechainIds; - - assert(received_statechain_ids.length > 0); - assert(received_statechain_ids[0] == coin.statechain_id); - } - - let transfer_address = await mercurynodejslib.newTransferAddress(clientConfig, wallet_1_name, null); - coin = await mercurynodejslib.transferSend(clientConfig, wallet_1_name, coin.statechain_id, transfer_address.transfer_receive, false, null); - - let transferReceiveResult = await mercurynodejslib.transferReceive(clientConfig, wallet_1_name); - let received_statechain_ids = transferReceiveResult.receivedStatechainIds; - - assert(received_statechain_ids.length > 0); - assert(received_statechain_ids[0] == coin.statechain_id); -} - -async function transferSenderAfterTransferReceiver(clientConfig, wallet_1_name, wallet_2_name) { - - const token = await mercurynodejslib.newToken(clientConfig, wallet_1_name); - const tokenId = token.token_id; - - const amount = 10000; - const deposit_info = await mercurynodejslib.getDepositBitcoinAddress(clientConfig, wallet_1_name, amount); - - let tokenList = await mercurynodejslib.getWalletTokens(clientConfig, wallet_1_name); - - let usedToken = tokenList.find(token => token.token_id === tokenId); - - assert(usedToken.spent); - - await depositCoin(clientConfig, wallet_1_name, amount, deposit_info); - - let coin = undefined; - - while (!coin) { - const list_coins = await mercurynodejslib.listStatecoins(clientConfig, wallet_1_name); - - let coinsWithStatechainId = list_coins.filter(c => { - return c.statechain_id === deposit_info.statechain_id && c.status === CoinStatus.CONFIRMED; - }); - - if (coinsWithStatechainId.length === 0) { - // console.log("Waiting for coin to be confirmed..."); - // console.log(`Check the address ${deposit_info.deposit_address} ...\n`); - await sleep(1000); - generateBlock(1); - continue; - } - - coin = coinsWithStatechainId[0]; - break; - } - - let transfer_address = await mercurynodejslib.newTransferAddress(clientConfig, wallet_2_name, null); - - coin = await mercurynodejslib.transferSend(clientConfig, wallet_1_name, coin.statechain_id, transfer_address.transfer_receive, false, null); - - let transferReceiveResult = await mercurynodejslib.transferReceive(clientConfig, wallet_2_name); - let received_statechain_ids = transferReceiveResult.receivedStatechainIds; - - assert(received_statechain_ids.length > 0); - assert(received_statechain_ids[0] == coin.statechain_id); - - try { - transfer_address = await mercurynodejslib.newTransferAddress(clientConfig, wallet_2_name, null); - await mercurynodejslib.transferSend(clientConfig, wallet_1_name, coin.statechain_id, transfer_address.transfer_receive, false, null); - assert.fail("Expected error when transferring from wallet one again, but no error was thrown"); - } catch (error) { - console.log("Expected error received: ", error.message); - assert(error.message.includes("Coin status must be CONFIRMED or IN_TRANSFER to transfer it. The current status is TRANSFERRED"), - `Unexpected error message: ${error.message}`); - } -} - -async function depositAndTransfer(clientConfig, wallet_name) { - - for (let i = 0; i < 10; i++) { - const token = await mercurynodejslib.newToken(clientConfig, wallet_name); - const tokenId = token.token_id; - - const amount = 10000; - const deposit_info = await mercurynodejslib.getDepositBitcoinAddress(clientConfig, wallet_name, amount); - - let tokenList = await mercurynodejslib.getWalletTokens(clientConfig, wallet_name); - - let usedToken = tokenList.find(token => token.token_id === tokenId); - - assert(usedToken.spent); - - await depositCoin(clientConfig, wallet_name, amount, deposit_info); - - let coin = undefined; - - while (!coin) { - const list_coins = await mercurynodejslib.listStatecoins(clientConfig, wallet_name); - - let coinsWithStatechainId = list_coins.filter(c => { - return c.statechain_id === deposit_info.statechain_id && c.status === CoinStatus.CONFIRMED; - }); - - if (coinsWithStatechainId.length === 0) { - // console.log("Waiting for coin to be confirmed..."); - // console.log(`Check the address ${deposit_info.deposit_address} ...\n`); - await sleep(1000); - generateBlock(1); - continue; - } - - coin = coinsWithStatechainId[0]; - - break; - } - } - - const list_coins = await mercurynodejslib.listStatecoins(clientConfig, wallet_name); - - for (let coin of list_coins) { - let transfer_address = await mercurynodejslib.newTransferAddress(clientConfig, wallet_name, null); - - coin = await mercurynodejslib.transferSend(clientConfig, wallet_name, coin.statechain_id, transfer_address.transfer_receive, false, null); - - let transferReceiveResult = await mercurynodejslib.transferReceive(clientConfig, wallet_name); - let received_statechain_ids = transferReceiveResult.receivedStatechainIds; - - assert(received_statechain_ids.length > 0); - assert(received_statechain_ids[0] == coin.statechain_id); - } -} - -async function interruptBeforeSignFirst(clientConfig, wallet_1_name, wallet_2_name) { - const token = await mercurynodejslib.newToken(clientConfig, wallet_1_name); - const tokenId = token.token_id; - - const amount = 10000; - const deposit_info = await mercurynodejslib.getDepositBitcoinAddress(clientConfig, wallet_1_name, amount); - - let tokenList = await mercurynodejslib.getWalletTokens(clientConfig, wallet_1_name); - - let usedToken = tokenList.find(token => token.token_id === tokenId); - - assert(usedToken.spent); - - await depositCoin(clientConfig, wallet_1_name, amount, deposit_info); - - let coin = undefined; - - while (!coin) { - const list_coins = await mercurynodejslib.listStatecoins(clientConfig, wallet_1_name); - - let coinsWithStatechainId = list_coins.filter(c => { - return c.statechain_id === deposit_info.statechain_id && c.status === CoinStatus.CONFIRMED; - }); - - if (coinsWithStatechainId.length === 0) { - // console.log("Waiting for coin to be confirmed..."); - // console.log(`Check the address ${deposit_info.deposit_address} ...\n`); - await sleep(1000); - generateBlock(1); - continue; - } - - coin = coinsWithStatechainId[0]; - break; - } - - let transfer_address = await mercurynodejslib.newTransferAddress(clientConfig, wallet_2_name, null); - - console.log("Disconnect mercurylayer-mercury-1 from network"); - await disconnectMercuryServer(); - - try { - coin = await mercurynodejslib.transferSend(clientConfig, wallet_1_name, coin.statechain_id, transfer_address.transfer_receive, false, null); - assert.fail("Expected error when transferring from wallet one, but no error was thrown"); - } catch (error) { - console.log("Expected error received: ", error.message); - assert(error.message.includes("connect ECONNREFUSED 0.0.0.0:8000"), - `Unexpected error message: ${error.message}`); - } - console.log("Connect mercurylayer-mercury-1 from network"); - await connectMercuryServer(); -} - -const new_transaction = async(clientConfig, electrumClient, coin, toAddress, isWithdrawal, qtBackupTx, block_height, network) => { - let coin_nonce = mercury_wasm.createAndCommitNonces(coin); - - let server_pubnonce = await transaction.signFirst(clientConfig, coin_nonce.sign_first_request_payload); - - coin.secret_nonce = coin_nonce.secret_nonce; - coin.public_nonce = coin_nonce.public_nonce; - coin.server_public_nonce = server_pubnonce; - coin.blinding_factor = coin_nonce.blinding_factor; - - const serverInfo = await utils.infoConfig(clientConfig, electrumClient); - - let new_block_height = 0; - if (block_height == null) { - const block_header = await electrumClient.request('blockchain.headers.subscribe'); // request(promise) - new_block_height = block_header.height; - } else { - new_block_height = block_height; - } - - const initlock = serverInfo.initlock; - const interval = serverInfo.interval; - const feeRateSatsPerByte = serverInfo.fee_rate_sats_per_byte; - - let partialSigRequest = mercury_wasm.getPartialSigRequest( - coin, - new_block_height, - initlock, - interval, - feeRateSatsPerByte, - qtBackupTx, - toAddress, - network, - isWithdrawal); - - const serverPartialSigRequest = partialSigRequest.partial_signature_request_payload; - - console.log("Disconnect mercurylayer-mercury-1 from network"); - await disconnectMercuryServer(); - - let serverPartialSig; - - try { - serverPartialSig = await transaction.signSecond(clientConfig, serverPartialSigRequest); - assert.fail("Expected error when signing second transaction, but no error was thrown"); - } catch (error) { - console.log("Expected error received: ", error.message); - assert(error.message.includes("Server partial signature is not available."), - `Unexpected error message: ${error.message}`); - } - - console.log("Connect mercurylayer-mercury-1 from network"); - await connectMercuryServer(); -} - -async function interruptBeforeSignSecond(clientConfig, wallet_1_name, wallet_2_name) { - const token = await mercurynodejslib.newToken(clientConfig, wallet_1_name); - const tokenId = token.token_id; - - const amount = 10000; - const deposit_info = await mercurynodejslib.getDepositBitcoinAddress(clientConfig, wallet_1_name, amount); - - let tokenList = await mercurynodejslib.getWalletTokens(clientConfig, wallet_1_name); - - let usedToken = tokenList.find(token => token.token_id === tokenId); - - assert(usedToken.spent); - - await depositCoin(clientConfig, wallet_1_name, amount, deposit_info); - - let coinDeposited = undefined; - - while (!coinDeposited) { - const list_coins = await mercurynodejslib.listStatecoins(clientConfig, wallet_1_name); - - let coinsWithStatechainId = list_coins.filter(c => { - return c.statechain_id === deposit_info.statechain_id && c.status === CoinStatus.CONFIRMED; - }); - - if (coinsWithStatechainId.length === 0) { - // console.log("Waiting for coin to be confirmed..."); - // console.log(`Check the address ${deposit_info.deposit_address} ...\n`); - await sleep(1000); - generateBlock(1); - continue; - } - - coinDeposited = coinsWithStatechainId[0]; - break; - } - - let transfer_address = await mercurynodejslib.newTransferAddress(clientConfig, wallet_2_name, null); - - const db = await getDatabase(clientConfig); - - const electrumClient = await getElectrumClient(clientConfig); - - let options = transfer_address; - - let batchId = (options && options.batch_id) || null; - - let wallet = await sqlite_manager.getWallet(db, wallet_1_name); - - const backupTxs = await sqlite_manager.getBackupTxs(db, coinDeposited.statechain_id); - - if (backupTxs.length === 0) { - throw new Error(`There is no backup transaction for the statechain id ${coinDeposited.statechain_id}`); - } - - const new_tx_n = backupTxs.length + 1; - - let coinsWithStatechainId = wallet.coins.filter(c => { - return c.statechain_id === coinDeposited.statechain_id - }); - - if (!coinsWithStatechainId || coinsWithStatechainId.length === 0) { - throw new Error(`There is no coin for the statechain id ${coinDeposited.statechain_id}`); - } - - // If the user sends to himself, he will have two coins with same statechain_id - // In this case, we need to find the one with the lowest locktime - // Sort the coins by locktime in ascending order and pick the first one - let coin = coinsWithStatechainId.sort((a, b) => a.locktime - b.locktime)[0]; - - if (coin.status != CoinStatus.CONFIRMED && coin.status != CoinStatus.IN_TRANSFER) { - throw new Error(`Coin status must be CONFIRMED or IN_TRANSFER to transfer it. The current status is ${coin.status}`); - } - - if (coin.locktime == null) { - throw new Error("Coin.locktime is null"); - } - - const blockHeader = await electrumClient.request('blockchain.headers.subscribe'); // request(promise) - const currentBlockheight = blockHeader.height; - - if (currentBlockheight > coin.locktime) { - throw new Error(`The coin is expired. Coin locktime is ${coin.locktime} and current blockheight is ${currentBlockheight}`); - } - - const statechain_id = coin.statechain_id; - const signed_statechain_id = coin.signed_statechain_id; - - const isWithdrawal = false; - const qtBackupTx = backupTxs.length; - - backupTxs.sort((a, b) => a.tx_n - b.tx_n); - - const bkp_tx1 = backupTxs[0]; - - const block_height = mercury_wasm.getBlockheight(bkp_tx1); - - const decodedTransferAddress = mercury_wasm.decodeTransferAddress(transfer_address.transfer_receive); - const new_auth_pubkey = decodedTransferAddress.auth_pubkey; - - // const new_x1 = await get_new_x1(clientConfig, statechain_id, signed_statechain_id, new_auth_pubkey, batchId); - - const signed_tx = await new_transaction(clientConfig, electrumClient, coin, transfer_address.transfer_receive, isWithdrawal, qtBackupTx, block_height, wallet.network); - - transfer_address = await mercurynodejslib.newTransferAddress(clientConfig, wallet_2_name, null); - - coin = await mercurynodejslib.transferSend(clientConfig, wallet_1_name, coin.statechain_id, transfer_address.transfer_receive, false, null); - - console.log("coin ", coin); - - let transferReceiveResult = await mercurynodejslib.transferReceive(clientConfig, wallet_2_name); - let received_statechain_ids = transferReceiveResult.receivedStatechainIds; - - console.log("received_statechain_ids: ", received_statechain_ids); - - assert(received_statechain_ids.length > 0); - assert(received_statechain_ids[0] == coin.statechain_id); - - // Coin withdrawal - let withdraw_address = "bcrt1qgh48u8aj4jvjkalc28lqujyx2wveck4jsm59x9"; - - let txid = await mercurynodejslib.withdrawCoin(clientConfig, wallet_2_name, coin.statechain_id, withdraw_address, null, null); - - console.log("txid: ", txid); -} - -async function interruptSignWithElectrumUnavailability(clientConfig, wallet_1_name, wallet_2_name) { - const token = await mercurynodejslib.newToken(clientConfig, wallet_1_name); - const tokenId = token.token_id; - - const amount = 10000; - const deposit_info = await mercurynodejslib.getDepositBitcoinAddress(clientConfig, wallet_1_name, amount); - - let tokenList = await mercurynodejslib.getWalletTokens(clientConfig, wallet_1_name); - - let usedToken = tokenList.find(token => token.token_id === tokenId); - - assert(usedToken.spent); - - await depositCoin(clientConfig, wallet_1_name, amount, deposit_info); - - let coin = undefined; - - while (!coin) { - const list_coins = await mercurynodejslib.listStatecoins(clientConfig, wallet_1_name); - - let coinsWithStatechainId = list_coins.filter(c => { - return c.statechain_id === deposit_info.statechain_id && c.status === CoinStatus.CONFIRMED; - }); - - if (coinsWithStatechainId.length === 0) { - // console.log("Waiting for coin to be confirmed..."); - // console.log(`Check the address ${deposit_info.deposit_address} ...\n`); - await sleep(1000); - generateBlock(1); - continue; - } - - coin = coinsWithStatechainId[0]; - break; - } - - let transfer_address = await mercurynodejslib.newTransferAddress(clientConfig, wallet_2_name, null); - - await sleep(5000); // wait for Electrum to disconnect - - console.log("Disconnect mercurylayer-electrs-1 from network"); - await disconnectElectr(); - - try { - coin = await mercurynodejslib.transferSend(clientConfig, wallet_1_name, coin.statechain_id, transfer_address.transfer_receive, false, null); - assert.fail("Expected error when transferring from wallet one, but no error was thrown"); - } catch (error) { - console.log("Expected error received: ", error.message); - assert(error.message.includes("connect ECONNREFUSED 0.0.0.0:50001"), - `Unexpected error message: ${error.message}`); - } - console.log("Connect mercurylayer-electrs-1 from network"); - await connectElectr(); - - await sleep(5000); // wait for Electrum to connect -} - -async function interruptTransferReceiveWithElectrumUnavailability(clientConfig, wallet_1_name, wallet_2_name) { - - const token = await mercurynodejslib.newToken(clientConfig, wallet_1_name); - const tokenId = token.token_id; - - const amount = 10000; - const deposit_info = await mercurynodejslib.getDepositBitcoinAddress(clientConfig, wallet_1_name, amount); - - let tokenList = await mercurynodejslib.getWalletTokens(clientConfig, wallet_1_name); - - let usedToken = tokenList.find(token => token.token_id === tokenId); - - assert(usedToken.spent); - - await depositCoin(clientConfig, wallet_1_name, amount, deposit_info); - - let coin = undefined; - - while (!coin) { - const list_coins = await mercurynodejslib.listStatecoins(clientConfig, wallet_1_name); - - let coinsWithStatechainId = list_coins.filter(c => { - return c.statechain_id === deposit_info.statechain_id && c.status === CoinStatus.CONFIRMED; - }); - - if (coinsWithStatechainId.length === 0) { - /* console.log("Waiting for coin to be confirmed..."); - console.log(`Check the address ${deposit_info.deposit_address} ...\n`); */ - await sleep(1000); - generateBlock(1); - continue; - } - - coin = coinsWithStatechainId[0]; - break; - } - - let transfer_address = await mercurynodejslib.newTransferAddress(clientConfig, wallet_2_name, null); - - coin = await mercurynodejslib.transferSend(clientConfig, wallet_1_name, coin.statechain_id, transfer_address.transfer_receive, false, null); - - await sleep(5000); // wait for Electrum to disconnect - - console.log("Disconnect mercurylayer-electrs-1 from network"); - await disconnectElectr(); - - try { - await mercurynodejslib.transferReceive(clientConfig, wallet_2_name); - assert.fail("Expected error when receiving into wallet two, but no error was thrown"); - } catch (error) { - console.log("Expected error received: ", error.message); - assert(error.message.includes("connect ECONNREFUSED 0.0.0.0:50001"), - `Unexpected error message: ${error.message}`); - } - console.log("Connect mercurylayer-electrs-1 from network"); - await connectElectr(); - - await sleep(5000); // wait for Electrum to connect -} - -async function interruptTransferReceiveWithMercuryServerUnavailability(clientConfig, wallet_1_name, wallet_2_name) { - - const token = await mercurynodejslib.newToken(clientConfig, wallet_1_name); - const tokenId = token.token_id; - - const amount = 10000; - const deposit_info = await mercurynodejslib.getDepositBitcoinAddress(clientConfig, wallet_1_name, amount); - - let tokenList = await mercurynodejslib.getWalletTokens(clientConfig, wallet_1_name); - - let usedToken = tokenList.find(token => token.token_id === tokenId); - - assert(usedToken.spent); - - await depositCoin(clientConfig, wallet_1_name, amount, deposit_info); - - let coin = undefined; - - while (!coin) { - const list_coins = await mercurynodejslib.listStatecoins(clientConfig, wallet_1_name); - - let coinsWithStatechainId = list_coins.filter(c => { - return c.statechain_id === deposit_info.statechain_id && c.status === CoinStatus.CONFIRMED; - }); - - if (coinsWithStatechainId.length === 0) { - /* console.log("Waiting for coin to be confirmed..."); - console.log(`Check the address ${deposit_info.deposit_address} ...\n`); */ - await sleep(5000); - generateBlock(1); - continue; - } - - coin = coinsWithStatechainId[0]; - break; - } - - let transfer_address = await mercurynodejslib.newTransferAddress(clientConfig, wallet_2_name, null); - - coin = await mercurynodejslib.transferSend(clientConfig, wallet_1_name, coin.statechain_id, transfer_address.transfer_receive, false, null); - - console.log("Disconnect mercurylayer-mercury-1 from network"); - await disconnectMercuryServer(); - - try { - let received_statechain_ids = await mercurynodejslib.transferReceive(clientConfig, wallet_2_name); - assert.fail("Expected error when receiving into wallet two, but no error was thrown"); - } catch (error) { - console.log("Expected error received: ", error.message); - assert(error.message.includes("connect ECONNREFUSED 0.0.0.0:8000"), - `Unexpected error message: ${error.message}`); - } - console.log("Connect mercurylayer-mercury-1 from network"); - await connectMercuryServer(); -} - -async function transferSendAtCoinExpiry(clientConfig, wallet_1_name, wallet_2_name) { - - const token = await mercurynodejslib.newToken(clientConfig, wallet_1_name); - const tokenId = token.token_id; - - const amount = 10000; - const deposit_info = await mercurynodejslib.getDepositBitcoinAddress(clientConfig, wallet_1_name, amount); - - let tokenList = await mercurynodejslib.getWalletTokens(clientConfig, wallet_1_name); - - let usedToken = tokenList.find(token => token.token_id === tokenId); - - assert(usedToken.spent); - - await depositCoin(clientConfig, wallet_1_name, amount, deposit_info); - - let coin = undefined; - - while (!coin) { - const list_coins = await mercurynodejslib.listStatecoins(clientConfig, wallet_1_name); - - let coinsWithStatechainId = list_coins.filter(c => { - return c.statechain_id === deposit_info.statechain_id && c.status === CoinStatus.CONFIRMED; - }); - - if (coinsWithStatechainId.length === 0) { - /* console.log("Waiting for coin to be confirmed..."); - console.log(`Check the address ${deposit_info.deposit_address} ...\n`); */ - await sleep(1000); - generateBlock(1); - continue; - } - - coin = coinsWithStatechainId[0]; - break; - } - - const electrumClient = await getElectrumClient(clientConfig); - - const blockHeader = await electrumClient.request('blockchain.headers.subscribe'); // request(promise) - const currentBlockheight = blockHeader.height; - - const blocksToBeGenerated = coin.locktime - currentBlockheight; - await generateBlock(blocksToBeGenerated); - - let transfer_address = await mercurynodejslib.newTransferAddress(clientConfig, wallet_2_name, null); - - try { - coin = await mercurynodejslib.transferSend(clientConfig, wallet_1_name, coin.statechain_id, transfer_address.transfer_receive, false, null); - assert.fail("Expected error when transferring expired coin, but no error was thrown"); - } catch (error) { - console.log("Expected error received: ", error.message); - assert(error.message.includes("The coin is expired."), - `Unexpected error message: ${error.message}`); - } -} - -async function transferReceiveAtCoinExpiry(clientConfig, wallet_1_name, wallet_2_name) { - - const token = await mercurynodejslib.newToken(clientConfig, wallet_1_name); - const tokenId = token.token_id; - - const amount = 10000; - const deposit_info = await mercurynodejslib.getDepositBitcoinAddress(clientConfig, wallet_1_name, amount); - - let tokenList = await mercurynodejslib.getWalletTokens(clientConfig, wallet_1_name); - - let usedToken = tokenList.find(token => token.token_id === tokenId); - - assert(usedToken.spent); - - await depositCoin(clientConfig, wallet_1_name, amount, deposit_info); - - let coin = undefined; - - while (!coin) { - const list_coins = await mercurynodejslib.listStatecoins(clientConfig, wallet_1_name); - - let coinsWithStatechainId = list_coins.filter(c => { - return c.statechain_id === deposit_info.statechain_id && c.status === CoinStatus.CONFIRMED; - }); - - if (coinsWithStatechainId.length === 0) { - /* console.log("Waiting for coin to be confirmed..."); - console.log(`Check the address ${deposit_info.deposit_address} ...\n`); */ - await sleep(5000); - generateBlock(1); - continue; - } - - coin = coinsWithStatechainId[0]; - break; - } - - let transfer_address = await mercurynodejslib.newTransferAddress(clientConfig, wallet_2_name, null); - - coin = await mercurynodejslib.transferSend(clientConfig, wallet_1_name, coin.statechain_id, transfer_address.transfer_receive, false, null); - - const electrumClient = await getElectrumClient(clientConfig); - - const blockHeader = await electrumClient.request('blockchain.headers.subscribe'); // request(promise) - const currentBlockheight = blockHeader.height; - - const blocksToBeGenerated = coin.locktime - currentBlockheight; - await generateBlock(blocksToBeGenerated); - - let errorMessage; - console.error = (msg) => { - errorMessage = msg; - }; - - let transferReceiveResult = await mercurynodejslib.transferReceive(clientConfig, wallet_2_name); - let received_statechain_ids = transferReceiveResult.receivedStatechainIds; - - // Assert the captured error message - const expectedMessage = 'The coin is expired.'; - assert.ok(errorMessage.includes(expectedMessage)); - - assert(received_statechain_ids.length > 0); - assert(received_statechain_ids[0] == coin.statechain_id); -} - -async function transferSendCoinExpiryBySending(clientConfig, wallet_1_name, wallet_2_name) { - - const token = await mercurynodejslib.newToken(clientConfig, wallet_1_name); - const tokenId = token.token_id; - - const amount = 10000; - const deposit_info = await mercurynodejslib.getDepositBitcoinAddress(clientConfig, wallet_1_name, amount); - - let tokenList = await mercurynodejslib.getWalletTokens(clientConfig, wallet_1_name); - - let usedToken = tokenList.find(token => token.token_id === tokenId); - - assert(usedToken.spent); - - await depositCoin(clientConfig, wallet_1_name, amount, deposit_info); - - let coin = undefined; - - while (!coin) { - const list_coins = await mercurynodejslib.listStatecoins(clientConfig, wallet_1_name); - - let coinsWithStatechainId = list_coins.filter(c => { - return c.statechain_id === deposit_info.statechain_id && c.status === CoinStatus.CONFIRMED; - }); - - if (coinsWithStatechainId.length === 0) { - /* console.log("Waiting for coin to be confirmed..."); - console.log(`Check the address ${deposit_info.deposit_address} ...\n`); */ - await sleep(5000); - generateBlock(1); - continue; - } - - coin = coinsWithStatechainId[0]; - break; - } - - const electrumClient = await getElectrumClient(clientConfig); - - const blockHeader = await electrumClient.request('blockchain.headers.subscribe'); // request(promise) - const currentBlockheight = blockHeader.height; - - const serverInfo = await utils.infoConfig(clientConfig, electrumClient); - - const blocksToBeGenerated = coin.locktime - currentBlockheight - serverInfo.interval; - await generateBlock(blocksToBeGenerated); - - let transfer_address = await mercurynodejslib.newTransferAddress(clientConfig, wallet_2_name, null); - - try { - coin = await mercurynodejslib.transferSend(clientConfig, wallet_1_name, coin.statechain_id, transfer_address.transfer_receive, false, null); - assert.fail("Expected error when transferring expired coin, but no error was thrown"); - } catch (error) { - console.log("Expected error received: ", error.message); - assert(error.message.includes("The coin is expired."), - `Unexpected error message: ${error.message}`); - } -} - -(async () => { - - try { - const clientConfig = client_config.load(); - - let wallet_1_name = "w1"; - let wallet_2_name = "w2"; - await createWallet(clientConfig, wallet_1_name); - await createWallet(clientConfig, wallet_2_name); - await walletTransfersToItselfAndWithdraw(clientConfig, wallet_1_name); - // await walletTransfersToAnotherAndBroadcastsBackupTx(clientConfig, wallet_1_name, wallet_2_name); - - - // Deposit, repeat send - let wallet_3_name = "w3"; - let wallet_4_name = "w4"; - await createWallet(clientConfig, wallet_3_name); - await createWallet(clientConfig, wallet_4_name); - await depositAndRepeatSend(clientConfig, wallet_3_name); - console.log("Completed test for Deposit, repeat send"); - - // Transfer-sender after transfer-receiver - let wallet_5_name = "w5"; - let wallet_6_name = "w6"; - await createWallet(clientConfig, wallet_5_name); - await createWallet(clientConfig, wallet_6_name); - await transferSenderAfterTransferReceiver(clientConfig, wallet_5_name, wallet_6_name); - console.log("Completed test for Transfer-sender after transfer-receiver"); - - // Deposit of 10 coins in same wallet, and transfer each one 10 times - let wallet_7_name = "w7"; - await createWallet(clientConfig, wallet_7_name); - await depositAndTransfer(clientConfig, wallet_7_name); - console.log("Completed test for Deposit of 100 coins in same wallet, and transfer each one 100 times"); - - // Test for interruption of transferSend before sign first - let wallet_8_name = "w8"; - let wallet_9_name = "w9"; - await createWallet(clientConfig, wallet_8_name); - await createWallet(clientConfig, wallet_9_name); - await interruptBeforeSignFirst(clientConfig, wallet_8_name, wallet_9_name); - console.log("Completed test for interruption of transferSend before sign first"); - - // Test for interruption of transferSend before sign second - let wallet_10_name = "w10"; - let wallet_11_name = "w11"; - await createWallet(clientConfig, wallet_10_name); - await createWallet(clientConfig, wallet_11_name); - await interruptBeforeSignSecond(clientConfig, wallet_10_name, wallet_11_name); - console.log("Completed test for interruption of transferSend before sign second"); - - // Test for interruption of sign with Electrum unavailability - let wallet_12_name = "w12"; - let wallet_13_name = "w13"; - await createWallet(clientConfig, wallet_12_name); - await createWallet(clientConfig, wallet_13_name); - await interruptSignWithElectrumUnavailability(clientConfig, wallet_12_name, wallet_13_name); - console.log("Completed test for interruption of sign with Electrum unavailability"); - - // Test for interruption of transfer receive with Electrum unavailability - let wallet_14_name = "w14"; - let wallet_15_name = "w15"; - await createWallet(clientConfig, wallet_14_name); - await createWallet(clientConfig, wallet_15_name); - await interruptTransferReceiveWithElectrumUnavailability(clientConfig, wallet_14_name, wallet_15_name); - console.log("Completed test for interruption of transfer receive with Electrum unavailability"); - - // Test for interruption of transfer receive with mercury server unavailability - let wallet_16_name = "w16"; - let wallet_17_name = "w17"; - await createWallet(clientConfig, wallet_16_name); - await createWallet(clientConfig, wallet_17_name); - await interruptTransferReceiveWithMercuryServerUnavailability(clientConfig, wallet_16_name, wallet_17_name); - console.log("Completed test for interruption of transfer receive with mercury server unavailability"); - - // Deposit, iterative self transfer - let wallet_18_name = "w18"; - await createWallet(clientConfig, wallet_18_name); - await walletTransfersToItselfTillLocktimeReachesBlockHeightAndWithdraw(clientConfig, wallet_18_name); - console.log("Completed test for Deposit, iterative self transfer"); - - // Send backup tx before expiry - let wallet_19_name = "w19"; - let wallet_20_name = "w20"; - await createWallet(clientConfig, wallet_19_name); - await createWallet(clientConfig, wallet_20_name); - try { - await walletTransfersToAnotherAndBroadcastsBackupTx(clientConfig, wallet_19_name, wallet_20_name) - assert.fail("Expected error when sending backup tx before expiry, but no error was thrown"); - } catch (error) { - console.log("Expected error received: ", error.message); - assert(error.message.includes("The coin is not expired yet."), - `Unexpected error message: ${error.message}`); - } - console.log("Completed test for send backup tx before expiry"); - - // Transfer-sender of coin at expiry - let wallet_21_name = "w21"; - let wallet_22_name = "w22"; - await createWallet(clientConfig, wallet_21_name); - await createWallet(clientConfig, wallet_22_name); - await transferSendAtCoinExpiry(clientConfig, wallet_21_name, wallet_22_name); - console.log("Completed test for Transfer-sender of coin at expiry"); - - // Transfer-receive of coin at expiry - let wallet_23_name = "w23"; - let wallet_24_name = "w24"; - await createWallet(clientConfig, wallet_23_name); - await createWallet(clientConfig, wallet_24_name); - await transferReceiveAtCoinExpiry(clientConfig, wallet_23_name, wallet_24_name); - console.log("Completed test for Transfer-receive of coin at expiry"); - - // Transfer-sender of coin that will make it expired by sending - let wallet_25_name = "w25"; - let wallet_26_name = "w26"; - await createWallet(clientConfig, wallet_25_name); - await createWallet(clientConfig, wallet_26_name); - await transferSendCoinExpiryBySending(clientConfig, wallet_25_name, wallet_26_name); - console.log("Completed test for Transfer-sender of coin that will make it expired by sending"); - - process.exit(0); // Exit successfully - } catch (error) { - console.error("Test encountered an error:", error); - process.exit(1); // Exit with failure - } -})(); diff --git a/docker-compose-hw.yml b/docker-compose-hw.yml index e9d9b8ee..a26a271e 100644 --- a/docker-compose-hw.yml +++ b/docker-compose-hw.yml @@ -44,7 +44,11 @@ services: - BITCOIN_NETWORK=testnet - LOCKHEIGHT_INIT=1000 - LH_DECREMENT=10 - - CONNECTION_STRING=postgres://postgres:postgres@db_server:5432/mercury + - DB_USER=postgres + - DB_PASSWORD=postgres + - DB_HOST=db_server + - DB_PORT=5432 + - DB_NAME=mercury ports: - "8000:8000" diff --git a/docker-compose-sim.yml b/docker-compose-sim.yml index 929d4442..594a2938 100644 --- a/docker-compose-sim.yml +++ b/docker-compose-sim.yml @@ -22,7 +22,11 @@ services: - BITCOIN_NETWORK=testnet - LOCKHEIGHT_INIT=1000 - LH_DECREMENT=10 - - CONNECTION_STRING=postgres://postgres:postgres@db_server:5432/mercury + - DB_USER=postgres + - DB_PASSWORD=postgres + - DB_HOST=db_server + - DB_PORT=5432 + - DB_NAME=mercury ports: - "8000:8000" diff --git a/docker-compose-test.yml b/docker-compose-test.yml index c629574c..c434911a 100644 --- a/docker-compose-test.yml +++ b/docker-compose-test.yml @@ -62,7 +62,11 @@ services: NETWORK: regtest LOCKHEIGHT_INIT: 1100 LH_DECREMENT: 1 - CONNECTION_STRING: postgres://postgres:pgpassword@postgres:5432/postgres + DB_USER: postgres + DB_PASSWORD: pgpassword + DB_HOST: postgres + DB_PORT: 5432 + DB_NAME: postgres BATCH_TIMEOUT: 20 ENCLAVES: '[{"url": "http://mercurylayer-enclave-sgx-1:18080", "allow_deposit": true}]' ports: @@ -70,6 +74,26 @@ services: depends_on: - postgres + token-server: + build: + context: . + dockerfile: ./token-server/Dockerfile + environment: + PROCESSOR_URL: https://api.swiss-bitcoin-pay.ch + API_KEY: aaaa + FEE: 0.0001 + UNIT: BTC + DELAY: 3600 + DB_USER: postgres + DB_PASSWORD: pgpassword + DB_HOST: postgres + DB_PORT: 5432 + DB_NAME: postgres + ports: + - "8001:8001" + depends_on: + - postgres + alice: image: lightninglabs/lndinit:v0.1.21-beta-lnd-v0.18.0-beta container_name: mercurylayer-alice-1 diff --git a/explorer/index.html b/explorer/index.html index d5a5d01c..77ab0c3a 100644 --- a/explorer/index.html +++ b/explorer/index.html @@ -42,12 +42,36 @@
+ By using this service, you agree to our + Terms and Conditions. +
diff --git a/lib/src/utils.rs b/lib/src/utils.rs index 0d49d595..c9b1e549 100644 --- a/lib/src/utils.rs +++ b/lib/src/utils.rs @@ -11,6 +11,7 @@ pub struct ServerConfig { pub initlock: u32, pub interval: u32, pub batchtimeout: u32, + pub version: String, } #[derive(Debug, Serialize, Deserialize)] @@ -26,7 +27,7 @@ pub struct InfoConfig { pub struct PubKeyInfo { pub server_pubkey: String, pub tx_n: u32, - pub updated_at: String, + pub created_at: String, } #[derive(Debug, Serialize, Deserialize)] diff --git a/server/.env_example b/server/.env_example index ba71e2f1..c32e96de 100644 --- a/server/.env_example +++ b/server/.env_example @@ -1,6 +1,10 @@ NETWORK = LOCKHEIGHT_INIT = LH_DECREMENT = -CONNECTION_STRING = +DB_USER = +DB_PASSWORD = +DB_HOST = +DB_PORT = +DB_NAME = BATCH_TIMEOUT = ENCLAVES = diff --git a/server/Cargo.toml b/server/Cargo.toml index abfb8463..c8c0a3f2 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mercury-server" -version = "0.2.0" +version = "0.2.1" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/server/Settings.toml b/server/Settings.toml index 6de0e77a..96d89dca 100644 --- a/server/Settings.toml +++ b/server/Settings.toml @@ -1,8 +1,12 @@ network = "testnet" lockheight_init = 1000 lh_decrement = 10 -connection_string = "postgresql://postgres:postgres@localhost/mercury" batch_timeout = 120 # seconds +db_user = "postgres" +db_password = "postgres" +db_host = "localhost" +db_port = 5432 +db_name = "mercury" [[enclaves]] url = "http://0.0.0.0:18080" diff --git a/server/migrations/0001_key_data_table.sql b/server/migrations/0001_key_data_table.sql index 68b39bab..082df6cd 100644 --- a/server/migrations/0001_key_data_table.sql +++ b/server/migrations/0001_key_data_table.sql @@ -55,5 +55,6 @@ CREATE TABLE public.tokens ( onchain_address varchar NULL, processor_id varchar NULL, confirmed boolean DEFAULT false, - spent boolean DEFAULT false + spent boolean DEFAULT false, + accepted boolean DEFAULT false ); \ No newline at end of file diff --git a/server/src/endpoints/utils.rs b/server/src/endpoints/utils.rs index 3cbb17e4..df9d98e9 100644 --- a/server/src/endpoints/utils.rs +++ b/server/src/endpoints/utils.rs @@ -59,10 +59,13 @@ pub async fn info_config() -> status::Custom