Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
2eb09cd
docs: adds nix to readme
raul-oliveira May 29, 2025
fcd260d
Merge pull request #321 from HathorNetwork/release-candidate
luislhl Nov 24, 2025
ccc55bb
Merge pull request #322 from HathorNetwork/release
luislhl Nov 25, 2025
736d1cc
chore: Testnet Playground CI/CD and fix in NFT utils (#312)
luislhl Nov 28, 2025
1de8db0
chore: added a composite index to tx_output to reduce query time (#326)
andreabadesso Dec 1, 2025
e6e6f98
fix: wallet-service dev config (#308)
luislhl Dec 2, 2025
847437e
chore(daemon): updated reorg last event id to match latest fullnode e…
andreabadesso Dec 17, 2025
e4f05e7
feat(daemon): accepting FULL_NODE_CRASHED event on zod (#335)
andreabadesso Dec 22, 2025
fc1ff9d
fix(wallet-service): we must return zero-balances for tokens the user…
andreabadesso Dec 22, 2025
cbf77ba
fix: detecting diff error swallowing (#332)
andreabadesso Dec 23, 2025
dd2abbe
CI: remove nano-testnets (#327)
luislhl Dec 23, 2025
4eae9f9
Merge branch 'master' into raul-oliveira/add-nix-to-readme
raul-oliveira Jan 5, 2026
974e4f7
Merge pull request #260 from HathorNetwork/raul-oliveira/add-nix-to-r…
raul-oliveira Jan 5, 2026
0a33679
fix(daemon): added poa block to isBlock check (#337)
andreabadesso Jan 8, 2026
b097ecc
feat: token creation event (#325)
andreabadesso Jan 9, 2026
5203872
fix(daemon): PoA blocks don't have outputs (#340)
andreabadesso Jan 12, 2026
d2e0979
fix(wallet-service): updated several apis to use mysql transactions a…
andreabadesso Jan 14, 2026
cb3ecda
feat(db): added indexes related to sync (#341)
andreabadesso Jan 15, 2026
fb72c84
feat(daemon): using the exp backoff util on metadataDiff (#343)
andreabadesso Jan 19, 2026
a850d21
feat(wallet-service): added an api to find out if a wallet is using m…
andreabadesso Jan 19, 2026
feeff4d
feat: fee based tokens (#338)
raul-oliveira Jan 21, 2026
1f27a37
feat: store first_block on transactions (#350)
andreabadesso Jan 28, 2026
d81d8ad
feat: increase seqnum (#351)
andreabadesso Jan 28, 2026
03e8ae4
feat(wallet-service): added a new param to the getUtxos endpoint to …
andreabadesso Jan 28, 2026
2a3f7cd
chore: bump to 1.11.0 (#352)
andreabadesso Jan 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 32 additions & 96 deletions .codebuild/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -154,93 +154,6 @@ deploy_hathor_network_account() {
fi;
}

deploy_nano_testnet() {
# Deploys the releases and release-candidates to our nano-testnet environment

# We deploy only the Lambdas here, because the daemon used in nano-testnet is the same as
# the one built in the hathor-network account, since it runs there as well

echo "Building git ref ${GIT_REF_TO_DEPLOY}..."

# This will match both releases and release-candidates
if expr "${GIT_REF_TO_DEPLOY}" : "v.*" >/dev/null; then
make migrate;
make deploy-lambdas-nano-testnet;

send_slack_message "New version deployed to nano-testnet-alpha: ${GIT_REF_TO_DEPLOY}"
elif expr "${MANUAL_DEPLOY}" : "true" >/dev/null; then
make migrate;
make deploy-lambdas-nano-testnet;

send_slack_message "Branch manually deployed to nano-testnet-alpha: ${GIT_REF_TO_DEPLOY}"
elif expr "${ROLLBACK}" : "true" >/dev/null; then
make migrate;
make deploy-lambdas-nano-testnet;

send_slack_message "Rollback performed on nano-tesnet-alpha to: ${GIT_REF_TO_DEPLOY}";
else
echo "We don't deploy ${GIT_REF_TO_DEPLOY} to nano-testnet-alpha. Nothing to do.";
fi;
}

deploy_nano_testnet_bravo() {
# Deploys the releases and release-candidates to our nano-testnet-bravo environment

# We deploy only the Lambdas here, because the image for the daemon used in nano-testnet is
# the same as the one built in the hathor-network account, since it runs there as well

echo "Building git ref ${GIT_REF_TO_DEPLOY}..."

# This will match both releases and release-candidates
if expr "${GIT_REF_TO_DEPLOY}" : "v.*" >/dev/null; then
make migrate;
make deploy-lambdas-nano-testnet-bravo;

send_slack_message "New version deployed to nano-testnet-bravo: ${GIT_REF_TO_DEPLOY}"
elif expr "${MANUAL_DEPLOY}" : "true" >/dev/null; then
make migrate;
make deploy-lambdas-nano-testnet-bravo;

send_slack_message "Branch manually deployed to nano-testnet-bravo: ${GIT_REF_TO_DEPLOY}"
elif expr "${ROLLBACK}" : "true" >/dev/null; then
make migrate;
make deploy-lambdas-nano-testnet-bravo;

send_slack_message "Rollback performed on nano-tesnet-bravo to: ${GIT_REF_TO_DEPLOY}";
else
echo "We don't deploy ${GIT_REF_TO_DEPLOY} to nano-testnet-bravo. Nothing to do.";
fi;
}

deploy_nano_testnet_hackaton() {
# Deploys the releases and release-candidates to our nano-testnet-hackaton environment

# We deploy only the Lambdas here, because the daemon used in nano-testnet-hackaton is the same as
# the one built in the hathor-network account, since it runs there as well

echo "Building git ref ${GIT_REF_TO_DEPLOY}..."

# This will match both releases and release-candidates
if expr "${GIT_REF_TO_DEPLOY}" : "v.*" >/dev/null; then
make migrate;
make deploy-lambdas-nano-testnet-hackaton;

send_slack_message "New version deployed to nano-testnet-hackaton: ${GIT_REF_TO_DEPLOY}"
elif expr "${MANUAL_DEPLOY}" : "true" >/dev/null; then
make migrate;
make deploy-lambdas-nano-testnet-hackaton;

send_slack_message "Branch manually deployed to nano-testnet-hackaton: ${GIT_REF_TO_DEPLOY}"
elif expr "${ROLLBACK}" : "true" >/dev/null; then
make migrate;
make deploy-lambdas-nano-testnet-hackaton;

send_slack_message "Rollback performed on nano-tesnet-hackaton to: ${GIT_REF_TO_DEPLOY}";
else
echo "We don't deploy ${GIT_REF_TO_DEPLOY} to nano-testnet-hackaton. Nothing to do.";
fi;
}

deploy_ekvilibro_mainnet() {
# Deploys the releases to our ekvilibro-mainnet environment

Expand Down Expand Up @@ -303,6 +216,35 @@ deploy_ekvilibro_testnet() {
fi;
}

deploy_testnet_playground() {
# Deploys the release-candidates and releases to our testnet-playground environment

# We deploy only the Lambdas here, because the daemon used in testnet-playground is the same as
# the one built in the hathor-network account, since it runs there as well

echo "Building git ref ${GIT_REF_TO_DEPLOY}..."

# This will match release-candidates or releases
if expr "${GIT_REF_TO_DEPLOY}" : "v.*" >/dev/null; then
make migrate;
make deploy-lambdas-testnet-playground;

send_slack_message "New version deployed to testnet-playground: ${GIT_REF_TO_DEPLOY}"
elif expr "${MANUAL_DEPLOY}" : "true" >/dev/null; then
make migrate;
make deploy-lambdas-testnet-playground;

send_slack_message "Branch manually deployed to testnet-playground: ${GIT_REF_TO_DEPLOY}"
elif expr "${ROLLBACK}" : "true" >/dev/null; then
make migrate;
make deploy-lambdas-testnet-playground;

send_slack_message "Rollback performed on testnet-playground to: ${GIT_REF_TO_DEPLOY}";
else
echo "We don't deploy ${GIT_REF_TO_DEPLOY} to testnet-playground. Nothing to do.";
fi;
}


# Check the first argument for the desired deploy
option=$1
Expand All @@ -312,21 +254,15 @@ case $option in
hathor-network)
deploy_hathor_network_account
;;
nano-testnet)
deploy_nano_testnet
;;
nano-testnet-bravo)
deploy_nano_testnet_bravo
;;
nano-testnet-hackaton)
deploy_nano_testnet_hackaton
;;
ekvilibro-testnet)
deploy_ekvilibro_testnet
;;
ekvilibro-mainnet)
deploy_ekvilibro_mainnet
;;
testnet-playground)
deploy_testnet_playground
;;
*)
echo "Invalid option: $option"
exit 1
Expand Down
2 changes: 1 addition & 1 deletion .codebuild/buildspec.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ env:
TX_HISTORY_MAX_COUNT: 50
CREATE_NFT_MAX_RETRIES: 3
dev_DEFAULT_SERVER: "https://wallet-service.private-nodes.india.testnet.hathor.network/v1a/"
dev_WS_DOMAIN: "ws.dev.wallet-service.india.testnet.hathor.network"
dev_WS_DOMAIN: "ws.wallet-service.india.testnet.hathor.network"
dev_NETWORK: "testnet"
dev_LOG_LEVEL: "debug"
dev_NFT_AUTO_REVIEW_ENABLED: "true"
Expand Down
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ deploy-lambdas-testnet-hotel:
deploy-lambdas-testnet-india:
AWS_SDK_LOAD_CONFIG=1 yarn workspace wallet-service run serverless deploy --stage india --region eu-central-1

.PHONY: deploy-lambdas-testnet-playground
deploy-lambdas-testnet-playground:
AWS_SDK_LOAD_CONFIG=1 yarn workspace wallet-service run serverless deploy --stage playground --region eu-central-1 --aws-profile testnet-playground

.PHONY: deploy-lambdas-mainnet-staging
deploy-lambdas-mainnet-staging:
AWS_SDK_LOAD_CONFIG=1 yarn workspace wallet-service run serverless deploy --stage mainnet-stg --region eu-central-1
Expand Down
29 changes: 25 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,35 @@ Refer to https://github.com/HathorNetwork/rfcs/blob/master/projects/wallet-servi
### Local environment

#### System dependencies
```
Node: 22x
yarn: v4 (yarn-berry)
```

You need nodejs installed on your enviroment, we suggest the latest Active LTS version (v18.x.x).
#### Install nix (preferred)

#### Clone the project and install dependencies
For a better developer experience we suggest nix usage for managing the enviroment. Visit this [link](https://nixos.org/download/#download-nix) to download it.

`git clone https://github.com/HathorNetwork/hathor-wallet-service-sync_daemon.git`
To enable the commands `nix develop` and `nix build` using flakes, add the following to your `/etc/nix/nix.conf` file:

```
# see https://nixos.org/manual/nix/stable/command-ref/conf-file
sandbox = true
experimental-features = nix-command flakes
```

`npm install`
#### Clone the project and install dependencies
```sh
$ git clone https://github.com/HathorNetwork/hathor-wallet-service.git
```
To initialize nix dev environment:
```sh
$ nix develop
```
then, install the depencies:
```sh
yarn
```

#### Add env variables or an .env file to the repository:

Expand Down
39 changes: 39 additions & 0 deletions db/migrations/20251128000000-create-token-creation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
'use strict';

/** @type {import('sequelize-cli').Migration} */
module.exports = {
async up(queryInterface, Sequelize) {
await queryInterface.createTable('token_creation', {
token_id: {
type: Sequelize.STRING(64),
allowNull: false,
primaryKey: true,
references: {
model: 'token',
key: 'id',
},
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
},
tx_id: {
type: Sequelize.STRING(64),
allowNull: false,
comment: 'Transaction ID that created the token (regular or nano contract)',
},
created_at: {
type: Sequelize.DATE,
allowNull: false,
defaultValue: Sequelize.literal('CURRENT_TIMESTAMP'),
},
});

// Add index on tx_id for efficient lookups when voiding transactions
await queryInterface.addIndex('token_creation', ['tx_id'], {
name: 'token_creation_tx_id_idx',
});
},

async down(queryInterface, Sequelize) {
await queryInterface.dropTable('token_creation');
},
};
39 changes: 39 additions & 0 deletions db/migrations/20251201104138-add-tx-output-utxo-lookup-index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
'use strict';

module.exports = {
up: async (queryInterface) => {
// Check if index exists
const [indexes] = await queryInterface.sequelize.query(`
SELECT COUNT(DISTINCT index_name) as count
FROM information_schema.statistics
WHERE table_schema = DATABASE()
AND table_name = 'tx_output'
AND index_name = 'idx_tx_output_utxo_lookup';
`);

// Only create if it doesn't exist
if (indexes[0].count === 0) {
await queryInterface.sequelize.query(`
CREATE INDEX idx_tx_output_utxo_lookup
ON tx_output (address, token_id, spent_by, voided, locked, authorities);
`);
}
},

down: async (queryInterface) => {
// Check if index exists before dropping
const [indexes] = await queryInterface.sequelize.query(`
SELECT COUNT(DISTINCT index_name) as count
FROM information_schema.statistics
WHERE table_schema = DATABASE()
AND table_name = 'tx_output'
AND index_name = 'idx_tx_output_utxo_lookup';
`);

if (indexes[0].count > 0) {
await queryInterface.sequelize.query(`
DROP INDEX idx_tx_output_utxo_lookup ON tx_output;
`);
}
},
};
21 changes: 21 additions & 0 deletions db/migrations/20251212000000-add-first-block-to-token-creation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
'use strict';

/** @type {import('sequelize-cli').Migration} */
module.exports = {
async up(queryInterface, Sequelize) {
await queryInterface.addColumn('token_creation', 'first_block', {
type: Sequelize.STRING(64),
allowNull: true,
comment: 'First block hash that confirmed the nano contract execution that created this token',
});

await queryInterface.addIndex('token_creation', ['first_block'], {
name: 'token_creation_first_block_idx',
});
},

async down(queryInterface) {
await queryInterface.removeIndex('token_creation', 'token_creation_first_block_idx');
await queryInterface.removeColumn('token_creation', 'first_block');
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
'use strict';

module.exports = {
up: async (queryInterface) => {
// Check if index exists
const [indexes] = await queryInterface.sequelize.query(`
SELECT COUNT(DISTINCT index_name) as count
FROM information_schema.statistics
WHERE table_schema = DATABASE()
AND table_name = 'tx_output'
AND index_name = 'idx_tx_output_locked_heightlock';
`);

// Only create if it doesn't exist
if (indexes[0].count === 0) {
await queryInterface.sequelize.query(`
CREATE INDEX idx_tx_output_locked_heightlock
ON tx_output (locked, heightlock);
`);
}
},

down: async (queryInterface) => {
// Check if index exists before dropping
const [indexes] = await queryInterface.sequelize.query(`
SELECT COUNT(DISTINCT index_name) as count
FROM information_schema.statistics
WHERE table_schema = DATABASE()
AND table_name = 'tx_output'
AND index_name = 'idx_tx_output_locked_heightlock';
`);

if (indexes[0].count > 0) {
await queryInterface.sequelize.query(`
DROP INDEX idx_tx_output_locked_heightlock ON tx_output;
`);
}
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
'use strict';

module.exports = {
up: async (queryInterface) => {
// Check if index exists
const [indexes] = await queryInterface.sequelize.query(`
SELECT COUNT(DISTINCT index_name) as count
FROM information_schema.statistics
WHERE table_schema = DATABASE()
AND table_name = 'tx_output'
AND index_name = 'idx_tx_output_locked_timelock';
`);

// Only create if it doesn't exist
if (indexes[0].count === 0) {
await queryInterface.sequelize.query(`
CREATE INDEX idx_tx_output_locked_timelock
ON tx_output (locked, timelock);
`);
}
},

down: async (queryInterface) => {
// Check if index exists before dropping
const [indexes] = await queryInterface.sequelize.query(`
SELECT COUNT(DISTINCT index_name) as count
FROM information_schema.statistics
WHERE table_schema = DATABASE()
AND table_name = 'tx_output'
AND index_name = 'idx_tx_output_locked_timelock';
`);

if (indexes[0].count > 0) {
await queryInterface.sequelize.query(`
DROP INDEX idx_tx_output_locked_timelock ON tx_output;
`);
}
},
};
Loading
Loading