Implementing Rosetta Data API of VeChainThor BlockChain
- Clone the repo
git clone https://github.com/vechain/rosetta.git
cd rosettaThe project uses a multi-stage Docker build process for optimal deployment. This configuration:
- Builds the Thor binary and Node.js application in separate stages
- Mounts a local data directory for persistence
- Exposes all necessary ports for the Rosetta API and Thor node
- Sets up environment variables for network type and run mode
To use docker-compose:
# Build and start the container
docker-compose up -d
# View logs
docker-compose logs -f rosetta-server
# Stop the container
docker-compose downThe configuration can be customized by modifying the docker-compose.yml file:
- Change the data directory path in the volumes section
- Modify the exposed ports if needed
- Adjust environment variables (NETWORK and MODE)
- Update the build context if needed
version: '3.8'
services:
rosetta-server:
build:
context: .
volumes:
- ./data:/data # Points to your local directory
ports:
- "8080:8080" # Rosetta API
- "8669:8669" # Thor node
- "11235:11235" # P2P
- "11235:11235/udp" # P2P UDP
environment:
- NETWORK=main
- MODE=online
restart: unless-stoppedThe project includes end-to-end tests that verify the Rosetta API implementation:
# Install dependencies
npm ci
# Prepare data directory
mkdir -p rosetta_data
chmod -R 777 rosetta_data
# Run e2e tests for solo network
npm run test:e2e:soloThe tests will automatically:
- Build Docker images with the default Thor version
- Start a fresh solo network from genesis
- Run all test suites
- Clean up containers and volumes
To test Rosetta against a specific Thor branch or version, use the THOR_REPO and THOR_VERSION build arguments:
# Test against a specific Thor branch
THOR_REPO=https://github.com/vechain/thor.git \
THOR_VERSION=your-branch-name \
docker compose build --no-cache
# Then run tests
npm run test:e2e:soloNote: Build arguments (THOR_REPO, THOR_VERSION) must be set during docker compose build, not when starting containers. They determine which Thor version gets compiled into the image.
# Start services with default Thor
npm run start:solo
# Stop services
npm run stop
# View logs
docker compose logs -f rosetta-server
# Clean everything and rebuild
docker compose down -v
rm -rf ./rosetta_data/*
docker compose build --no-cacheThis implementation is meant to cover this reference.
| Method | Endpoint | Implemented | Description | Mode |
|---|---|---|---|---|
| POST | /account/balance | Yes | Get an Account Balance | online |
| POST | /account/coins | No |
| Method | Endpoint | Implemented | Description | Mode |
|---|---|---|---|---|
| POST | /block | Yes | Get a Block | online |
| POST | /block/transaction | Yes | Get a Block Transaction | online |
| Method | Endpoint | Implemented | Description | Mode |
|---|---|---|---|---|
| POST | /call | No | Make a Network-Specific Procedure Call |
| Method | Endpoint | Implemented | Description | Mode |
|---|---|---|---|---|
| POST | /construction/combine | Yes | Create Network Transaction from Signatures | online & offline |
| POST | /construction/derive | Yes | Derive an AccountIdentifier from a PublicKey | online & offline |
| POST | /construction/hash | Yes | Get the Hash of a Signed Transaction | online & offline |
| POST | /construction/metadata | Yes | Get Metadata for Transaction Construction | online |
| POST | /construction/parse | Yes | Parse a Transaction | online & offline |
| POST | /construction/payloads | Yes | Generate an Unsigned Transaction and Signing Payloads | online & offline |
| POST | /construction/preprocess | Yes | Create a Request to Fetch Metadata | online & offline |
| POST | /construction/submit | Yes | Submit a Signed Transaction | online |
| Method | Endpoint | Implemented | Description | Mode |
|---|---|---|---|---|
| POST | /events/blocks | Yes | [INDEXER] Get a range of BlockEvents | online |
| Method | Endpoint | Implemented | Description | Mode |
|---|---|---|---|---|
| POST | /mempool | Yes | Get All Pool Transactions from the Node | |
| POST | /mempool/transaction | Yes | Get a Pool Transaction from the Node |
| Method | Endpoint | Implemented | Description | Mode |
|---|---|---|---|---|
| POST | /network/list | Yes | Get List of Available Networks | online & offline |
| POST | /network/options | Yes | Get Network Options | online & offline |
| POST | /network/status | Yes | Get Network Status | online |
| Method | Endpoint | Implemented | Description | Mode |
|---|---|---|---|---|
| POST | /search/transactions | Yes | [INDEXER] Search for Transactions | online |
- VeChain Rosetta implement support Fee Delegation (VIP-191).
- The exchange will transfer currencies from hot wallet to the safe cold wallet from time to time. When there's not enough VTHO in the hot wallet or want to transfer all currencies includ VTHO, the exchange can use VIP191 function to pay the transaction fee.
- Step 1: Create a VIP191 payload
Create a VIP191 payload, add FeeDelegation operation to operations, account is fee delegator address, amount.value default 0.
{
"network_identifier": {
"blockchain": "vechainthor",
"network": "test"
},
"operations": [
{
"operation_identifier": {
"index": 0,
"network_index": 0
},
"type": "Transfer",
"status": "None",
"account": {
"address": "0x16277a1ff38678291c41d1820957c78bb5da59ce"
},
"amount": {
"value": "10000",
"currency": {
"symbol": "VET",
"decimals": 18
},
"metadata": {}
}
},
{
"operation_identifier": {
"index": 0,
"network_index": 1
},
"type": "Transfer",
"status": "None",
"account": {
"address": "0xc05c334533c673582616ac2bf404b6c55efa1087"
},
"amount": {
"value": "-10000",
"currency": {
"symbol": "VET",
"decimals": 18
},
"metadata": {}
}
},
{
"operation_identifier": {
"index": 0,
"network_index": 2
},
"type": "FeeDelegation",
"status": "None",
"account": {
"address": "0x4251630dc820e90a5a6d14d79cac7acb93917983"
},
"amount": {
"value": "-210000000000000000",
"currency": {
"symbol": "VTHO",
"decimals": 18,
"metadata": {
"contractAddress": "0x0000000000000000000000000000456E65726779"
}
},
"metadata": {}
}
}
]
}- Step 2: Call /construction/preprocess
When calling /construction/preprocess use VIP191 payloads, the api will return options and two required_public_keys, the first is transaction origin's public key,the second is fee delegation payer's public key.
{
"options": {
"clauses": [
{
"to": "0x16277a1ff38678291c41d1820957c78bb5da59ce",
"value": "10000",
"data": "0x00"
}
]
},
"required_public_keys": [
{
"address": "0xc05c334533c673582616ac2bf404b6c55efa1087"
},
{
"address": "0x4251630dc820e90a5a6d14d79cac7acb93917983"
}
]
}- Step 3: Call /construction/metadata
Use step 2 return value to call /construction/metadata, the api will calculate the gas online, return metadata and suggested_fee.
{
"metadata": {
"blockRef": "0x00d88b4ab127a39e",
"chainTag": 39,
"gas": 25200
},
"suggested_fee": [
{
"value": "2520000000",
"currency": {
"symbol": "VTHO",
"decimals": 18,
"metadata": {
"contractAddress": "0x0000000000000000000000000000456E65726779"
}
}
}
]
}- Step 4: Call /construction/payloads
{
"network_identifier": {
"blockchain": "vechainthor",
"network": "test"
},
"operations": [
{
"operation_identifier": {
"index": 0,
"network_index": 0
},
"type": "Transfer",
"status": "None",
"account": {
"address": "0x16277a1ff38678291c41d1820957c78bb5da59ce"
},
"amount": {
"value": "10000",
"currency": {
"symbol": "VET",
"decimals": 18
},
"metadata": {}
}
},
{
"operation_identifier": {
"index": 0,
"network_index": 1
},
"type": "Transfer",
"status": "None",
"account": {
"address": "0xc05c334533c673582616ac2bf404b6c55efa1087"
},
"amount": {
"value": "-10000",
"currency": {
"symbol": "VET",
"decimals": 18
},
"metadata": {}
}
},
{
"operation_identifier": {
"index": 0,
"network_index": 2
},
"type": "FeeDelegation",
"status": "None",
"account": {
"address": "0x4251630dc820e90a5a6d14d79cac7acb93917983"
},
"amount": {
"value": "-210000000000000000",
"currency": {
"symbol": "VTHO",
"decimals": 18,
"metadata": {
"contractAddress": "0x0000000000000000000000000000456E65726779"
}
},
"metadata": {}
}
}
],
"metadata": {
"blockRef": "0x00d88b4ab127a39e",
"chainTag": 39,
"gas": 25200
},
"public_keys": [
{
"hex_bytes": "02d992bd203d2bf888389089db13d2d0807c1697091de377998efe6cf60d66fbb3",
"curve_type": "secp256k1"
},
{
"hex_bytes": "03a7e5b27bf35f3b1a863851a02b4d722927cd12f92bfb21f69c81c22fc4a1c6d3",
"curve_type": "secp256k1"
}
]
}The api will return unsigned_transaction and payloads.
{
"unsigned_transaction": "0xf85d278800d88b4ab127a39e81b4dad99416277a1ff38678291c41d1820957c78bb5da59ce822710808262708827c7571b85f5271594c05c334533c673582616ac2bf404b6c55efa1087944251630dc820e90a5a6d14d79cac7acb93917983",
"payloads": [
{
"address": "0xc05c334533c673582616ac2bf404b6c55efa1087",
"hex_bytes": "3fec5f2cfdd172e1372879992644513578a9917355488e23d5abf846990c1fe2",
"signature_type": "ecdsa_recovery"
},
{
"address": "0x4251630dc820e90a5a6d14d79cac7acb93917983",
"hex_bytes": "16ff81dd942a6e42c6a352dbcf5615693c3659feb35cdc177d27a2851b73ee40",
"signature_type": "ecdsa_recovery"
}
]
}- Step 5: Sign with transaction orgin and fee delegation payer private keys and call
/construction/combine
{
"network_identifier": {
"blockchain": "vechainthor",
"network": "test"
},
"unsigned_transaction": "0xf85d278800d852ba843f1d4181b4dad99416277a1ff38678291c41d1820957c78bb5da59ce8227108082627088556581012357229594c05c334533c673582616ac2bf404b6c55efa1087944251630dc820e90a5a6d14d79cac7acb93917983",
"signatures": [
{
"signing_payload": {
"address": "0xc05c334533c673582616ac2bf404b6c55efa1087",
"hex_bytes": "3fec5f2cfdd172e1372879992644513578a9917355488e23d5abf846990c1fe2",
"signature_type": "ecdsa_recovery"
},
"public_key": {
"hex_bytes": "02d992bd203d2bf888389089db13d2d0807c1697091de377998efe6cf60d66fbb3",
"curve_type": "secp256k1"
},
"signature_type": "ecdsa_recovery",
"hex_bytes": "4ad82781abf5866020c9bf6a7b07f94ba4bb9e95ac1ca3c858ded24c08b6856213589bac265f656a87da255b855cfab9a96020d450593df2481015188ae7927000"
},
{
"signing_payload": {
"address": "0x4251630dc820e90a5a6d14d79cac7acb93917983",
"hex_bytes": "16ff81dd942a6e42c6a352dbcf5615693c3659feb35cdc177d27a2851b73ee40",
"signature_type": "ecdsa_recovery"
},
"public_key": {
"hex_bytes": "036aafc0aa461c6b2de2ca8a254ebc6685946a08dd7656dbb935ce4ce5cfac355b",
"curve_type": "secp256k1"
},
"signature_type": "ecdsa_recovery",
"hex_bytes": "7d6df64de2c4084b7809bdeba85784c6d031dd943e96271ac1cd22f3da9b5c3f2e610ec2d50e576583cff2d386fd6f7069b2883ca023b6000575ec0fcf4ddc9800"
}
]
}