Skip to content

Commit

Permalink
Merge pull request #453 from HathorNetwork/master
Browse files Browse the repository at this point in the history
Start release-candidate v0.29.0-rc.1
  • Loading branch information
pedroferreira1 authored Jun 18, 2024
2 parents f273e82 + 4648701 commit c5e7ea6
Show file tree
Hide file tree
Showing 13 changed files with 561 additions and 156 deletions.
2 changes: 1 addition & 1 deletion SECURITY.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# Security

Hathor Labs has a bounty program to encourage white hat hackers to collaborate in identifying security breaches and vulnerabilities in Hathor headless wallet. To know more about this, see [https://immunefi.com/bounty/hathornetwork/](https://immunefi.com/bounty/hathornetwork/).
Hathor Labs has a bounty program to encourage white hat hackers to collaborate in identifying security breaches and vulnerabilities in Hathor headless wallet. To know more about this, see [Bug bounty program at Hathor Network](https://hathor.network/bug-bounty/).
188 changes: 162 additions & 26 deletions __tests__/integration/melt-tokens.test.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
import { transactionUtils, constants, network, scriptsUtils } from '@hathor/wallet-lib';
import { transactionUtils, constants, network, scriptsUtils, ScriptData } from '@hathor/wallet-lib';
import { TestUtils } from './utils/test-utils-integration';
import { WALLET_CONSTANTS } from './configuration/test-constants';
import { WalletHelper } from './utils/wallet-helper';

describe('melt tokens', () => {
let wallet1;
const totalMinted = 1000;
const initialHTR = 10;
let meltedAmount = 0;
let htrMelted = 0;

const tokenA = {
name: 'Token A',
symbol: 'TKA',
Expand All @@ -18,19 +23,19 @@ describe('melt tokens', () => {
await WalletHelper.startMultipleWalletsForTest([wallet1]);

// Creating a token for the tests
await wallet1.injectFunds(10, 0);
await wallet1.injectFunds(20, 0);
const tkAtx = await wallet1.createToken({
name: tokenA.name,
symbol: tokenA.symbol,
amount: 800,
amount: 1000,
address: await wallet1.getAddressAt(0),
change_address: await wallet1.getAddressAt(0)
});
tokenA.uid = tkAtx.hash;

/**
* Status:
* wallet1[0]: 2 HTR , 800 TKA
* wallet1[0]: 10 HTR , 1000 TKA
*/
});

Expand Down Expand Up @@ -151,7 +156,7 @@ describe('melt tokens', () => {
.send({
token: tokenA.uid,
address: await wallet1.getAddressAt(1),
amount: 1000
amount: totalMinted + 100,
})
.set({ 'x-wallet-id': wallet1.walletId });

Expand All @@ -173,6 +178,13 @@ describe('melt tokens', () => {
})
.set({ 'x-wallet-id': wallet1.walletId });

meltedAmount += 300;
htrMelted += 3;
/**
* Status:
* wallet1[0]: 13 HTR , 700 TKA
*/

expect(response.body.success).toBe(true);

await TestUtils.waitForTxReceived(wallet1.walletId, response.body.hash);
Expand All @@ -185,12 +197,12 @@ describe('melt tokens', () => {
const addr4htr = await wallet1.getAddressInfo(4);
const addr4tka = await wallet1.getAddressInfo(4, tokenA.uid);
expect(addr4htr.total_amount_available).toBe(0);
expect(addr4tka.total_amount_available).toBe(500);
expect(addr4tka.total_amount_available).toBe(totalMinted - meltedAmount);

const balance1htr = await wallet1.getBalance();
const balance1tka = await wallet1.getBalance(tokenA.uid);
expect(balance1htr.available).toBe(2 + 3);
expect(balance1tka.available).toBe(800 - 300);
expect(balance1htr.available).toBe(initialHTR + htrMelted);
expect(balance1tka.available).toBe(totalMinted - meltedAmount);
});

it('should melt with deposit address only', async () => {
Expand All @@ -207,6 +219,13 @@ describe('melt tokens', () => {
})
.set({ 'x-wallet-id': wallet1.walletId });

meltedAmount += 100;
htrMelted += 1;
/**
* Status:
* wallet1[0]: 14 HTR , 600 TKA
*/

expect(response.body.success).toBe(true);

await TestUtils.waitForTxReceived(wallet1.walletId, response.body.hash);
Expand All @@ -218,8 +237,8 @@ describe('melt tokens', () => {

const balance1htr = await wallet1.getBalance();
const balance1tka = await wallet1.getBalance(tokenA.uid);
expect(balance1htr.available).toBe(2 + 3 + 1);
expect(balance1tka.available).toBe(800 - 300 - 100);
expect(balance1htr.available).toBe(initialHTR + htrMelted);
expect(balance1tka.available).toBe(totalMinted - meltedAmount);
});

it('should melt with change address only', async () => {
Expand All @@ -232,19 +251,26 @@ describe('melt tokens', () => {
})
.set({ 'x-wallet-id': wallet1.walletId });

meltedAmount += 100;
htrMelted += 1;
/**
* Status:
* wallet1[0]: 15 HTR , 500 TKA
*/

expect(response.body.success).toBe(true);

await TestUtils.waitForTxReceived(wallet1.walletId, response.body.hash);

const addr8htr = await wallet1.getAddressInfo(8);
const addr8tka = await wallet1.getAddressInfo(8, tokenA.uid);
expect(addr8htr.total_amount_available).toBe(0);
expect(addr8tka.total_amount_available).toBe(300);
expect(addr8tka.total_amount_available).toBe(totalMinted - meltedAmount);

const balance1htr = await wallet1.getBalance();
const balance1tka = await wallet1.getBalance(tokenA.uid);
expect(balance1htr.available).toBe(2 + 3 + 1 + 1);
expect(balance1tka.available).toBe(800 - 300 - 100 - 100);
expect(balance1htr.available).toBe(initialHTR + htrMelted);
expect(balance1tka.available).toBe(totalMinted - meltedAmount);
});

it('should melt with mandatory parameters', async () => {
Expand All @@ -256,14 +282,21 @@ describe('melt tokens', () => {
})
.set({ 'x-wallet-id': wallet1.walletId });

meltedAmount += 100;
htrMelted += 1;
/**
* Status:
* wallet1[0]: 16 HTR , 400 TKA
*/

expect(response.body.success).toBe(true);

await TestUtils.waitForTxReceived(wallet1.walletId, response.body.hash);

const balance1htr = await wallet1.getBalance();
const balance1tka = await wallet1.getBalance(tokenA.uid);
expect(balance1htr.available).toBe(2 + 3 + 1 + 1 + 1); // 8
expect(balance1tka.available).toBe(800 - 300 - 100 - 100 - 100); // 200
expect(balance1htr.available).toBe(initialHTR + htrMelted); // 16
expect(balance1tka.available).toBe(totalMinted - meltedAmount); // 400
});

it('should not retrieve funds when melting below 100 tokens', async () => {
Expand All @@ -275,14 +308,20 @@ describe('melt tokens', () => {
})
.set({ 'x-wallet-id': wallet1.walletId });

meltedAmount += 50;
/**
* Status:
* wallet1[0]: 16 HTR , 350 TKA
*/

expect(response.body.success).toBe(true);

await TestUtils.waitForTxReceived(wallet1.walletId, response.body.hash);

const balance1htr = await wallet1.getBalance();
const balance1tka = await wallet1.getBalance(tokenA.uid);
expect(balance1htr.available).toBe(8);
expect(balance1tka.available).toBe(150);
expect(balance1htr.available).toBe(initialHTR + htrMelted);
expect(balance1tka.available).toBe(totalMinted - meltedAmount);
});

it('should retrieve funds rounded down when not melting multiples of 100', async () => {
Expand All @@ -291,18 +330,25 @@ describe('melt tokens', () => {
.send({
token: tokenA.uid,
address: await wallet1.getAddressAt(1),
amount: 100
amount: 110
})
.set({ 'x-wallet-id': wallet1.walletId });

meltedAmount += 110;
htrMelted += 1;
/**
* Status:
* wallet1[0]: 17 HTR , 240 TKA
*/

expect(response.body.success).toBe(true);

await TestUtils.waitForTxReceived(wallet1.walletId, response.body.hash);

const balance1htr = await wallet1.getBalance();
const balance1tka = await wallet1.getBalance(tokenA.uid);
expect(balance1htr.available).toBe(9);
expect(balance1tka.available).toBe(50);
expect(balance1htr.available).toBe(initialHTR + htrMelted);
expect(balance1tka.available).toBe(totalMinted - meltedAmount);
});

it('should melt and send melt output to the correct address', async () => {
Expand All @@ -313,18 +359,24 @@ describe('melt tokens', () => {
token: tokenA.uid,
address: await wallet1.getAddressAt(16),
melt_authority_address: address0,
amount: 30
amount: 20
})
.set({ 'x-wallet-id': wallet1.walletId });

meltedAmount += 20;
/**
* Status:
* wallet1[0]: 17 HTR , 220 TKA
*/

const transaction = response.body;
expect(transaction.success).toBe(true);
await TestUtils.waitForTxReceived(wallet1.walletId, response.body.hash);

const balance1htr = await wallet1.getBalance();
const balance1tka = await wallet1.getBalance(tokenA.uid);
expect(balance1htr.available).toBe(9);
expect(balance1tka.available).toBe(20);
expect(balance1htr.available).toBe(initialHTR + htrMelted);
expect(balance1tka.available).toBe(totalMinted - meltedAmount);

// Validating a new melt authority was created by default
const authorityOutputs = transaction.outputs.filter(
Expand All @@ -338,15 +390,97 @@ describe('melt tokens', () => {
expect(p2pkh.address.base58).toEqual(address0);
});

it('should melt tokens and add data outputs to the transaction', async () => {
const response = await TestUtils.request
.post('/wallet/melt-tokens')
.send({
token: tokenA.uid,
amount: 10,
data: ['foobar1', 'foobar2'],
})
.set({ 'x-wallet-id': wallet1.walletId });

meltedAmount += 10;
htrMelted -= 2; // we create 2 data outputs and no melted htr
/**
* Status:
* wallet1[0]: 15 HTR , 210 TKA
*/

expect(response.body.success).toBe(true);

await TestUtils.waitForTxReceived(wallet1.walletId, response.body.hash);

const balance1htr = await wallet1.getBalance();
const balance1tka = await wallet1.getBalance(tokenA.uid);
expect(balance1htr.available).toBe(initialHTR + htrMelted);
expect(balance1tka.available).toBe(totalMinted - meltedAmount);

const transaction = response.body;
const dataOutput1 = transaction.outputs[1];
const dataOutput2 = transaction.outputs[0];
const script1 = Array.from((new ScriptData('foobar1')).createScript());
const script2 = Array.from((new ScriptData('foobar2')).createScript());

expect(dataOutput1.token_data).toBe(0);
expect(dataOutput1.value).toBe(1);
expect(dataOutput1.script.data).toEqual(script1);

expect(dataOutput2.token_data).toBe(0);
expect(dataOutput2.value).toBe(1);
expect(dataOutput2.script.data).toEqual(script2);
});

it('should melt tokens and add data outputs to the transaction at the start of the outputs', async () => {
const response = await TestUtils.request
.post('/wallet/melt-tokens')
.send({
token: tokenA.uid,
amount: 10,
data: ['foobar'],
unshift_data: false,
})
.set({ 'x-wallet-id': wallet1.walletId });

meltedAmount += 10;
htrMelted -= 1; // we create 1 data outputs and no melted htr
/**
* Status:
* wallet1[0]: 14 HTR , 200 TKA
*/

expect(response.body.success).toBe(true);

await TestUtils.waitForTxReceived(wallet1.walletId, response.body.hash);

const balance1htr = await wallet1.getBalance();
const balance1tka = await wallet1.getBalance(tokenA.uid);
expect(balance1htr.available).toBe(initialHTR + htrMelted);
expect(balance1tka.available).toBe(totalMinted - meltedAmount);

const transaction = response.body;
const dataOutput = transaction.outputs[transaction.outputs.length - 1];
const script = Array.from((new ScriptData('foobar')).createScript());

expect(dataOutput.token_data).toBe(0);
expect(dataOutput.value).toBe(1);
expect(dataOutput.script.data).toEqual(script);
});

it('should melt allowing external authority address', async () => {
// XXX: This test should be the last test since it sends the melt authority to the burn address
if (totalMinted - meltedAmount <= 0) {
// when we reach this step the wallet should have at least 1 token to melt and end the tests
throw new Error('No tokens to melt');
}
const externalAddress = TestUtils.getBurnAddress();
const response = await TestUtils.request
.post('/wallet/melt-tokens')
.send({
token: tokenA.uid,
address: await wallet1.getAddressAt(17),
melt_authority_address: externalAddress,
amount: 20
amount: totalMinted - meltedAmount,
})
.set({ 'x-wallet-id': wallet1.walletId });

Expand All @@ -359,17 +493,19 @@ describe('melt tokens', () => {
address: await wallet1.getAddressAt(17),
melt_authority_address: externalAddress,
allow_external_melt_authority_address: true,
amount: 20
amount: totalMinted - meltedAmount,
})
.set({ 'x-wallet-id': wallet1.walletId });

htrMelted += Math.floor((totalMinted - meltedAmount) / 100);

const transaction = response2.body;
expect(transaction.success).toBe(true);
await TestUtils.waitForTxReceived(wallet1.walletId, response2.body.hash);

const balance1htr = await wallet1.getBalance();
const balance1tka = await wallet1.getBalance(tokenA.uid);
expect(balance1htr.available).toBe(9);
expect(balance1htr.available).toBe(initialHTR + htrMelted);
expect(balance1tka.available).toBe(0);

// Validating a new melt authority was created by default
Expand Down
Loading

0 comments on commit c5e7ea6

Please sign in to comment.