What is a clause on the VeChain blockchain?
A clause is part of a transaction. One transaction can have multiple clauses. A clause carries the actual data that should be written to the blockchain. The VeChain transaction model says “an array of Clause objects each of which contains fields To
, Value
and Data
to enable a single transaction to carry multiple tasks issued by the transaction sender”. This unique feature is called Multi-Task-Transaction or MTT.
In Bitcoin or Ethereum a transaction has three basic parts: “From”, “To” and “Payload”. Every transaction has one sender, one recipient and one payload for that recipient (this payload may carry multiple contractcalls for one contract).
In Vechain there are also these three parts but only the “From” is unique. With clauses, one transaction can carry payloads for multiple recipients or multiple payloads for one recipient, wether it’s the transfer of VET, VTHO or other contract data.
Once we have created a transaction with multiple clauses, it will be pretty clear!
In Part 3 a transaction was created, that send 1 VET to 0x0000000000000000000000000000000000000000.
We now will create ONE transaction that will send:
1 VET to 0x0000000000000000000000000000000000000000
1 VET to 0x0000000000000000000000000000000000000009
(Addresses lower than 0x0000000000000000000000000000000000000009 are contracts and will consume more gas than expected. Contract interaction will be covered in a later part).
Create a multi-clause-transaction
The transaction body to this is almost the same as in Part 3.
body = {
"chainTag": 39,
"blockRef": '0x0063603cdce346e6',
"expiration": 720,
"clauses": [
{
"to": '0x0000000000000000000000000000000000000000',
"value": 1000000000000000000,
"data": '0x'
},
{
"to": '0x0000000000000000000000000000000000000009'
"value": 1000000000000000000,
"data": '0x'
}
],
"gasPriceCoef": 0,
"gas": 37000,
"dependsOn": None,
"nonce": 12345678
}
There are of course differences in the body:
Blockref: Needs to be updated to the latest block (as shown in Part 2)
Clauses: (This is the part where it hit me with “What?! Is is really that easy?”) To send VET to another destination within THE SAME transaction, simply add another set of “to”, “value”, “data” to the clause-part of the body. This can be repeated until the gas-limit of the block is reached.
Gas: The more clauses a transaction contains, the more gas the transaction needs. As covered in Part 2, the calculation for this VET clauses is simple:
5000 (base-cost) + 16000 + 16000 (for non-contract-creation clauses) = 37000 gas.
Other than that, it’s the same script as in Part 3. Create a new file (4_multiclause.py) and update Blockref to your needs.
from thor_devkit import cry, transaction
import requestsbody = {
"chainTag": 39,
"blockRef": '0x006360a563534115',
"expiration": 720,
"clauses": [
{
"to": '0x0000000000000000000000000000000000000000',
"value": 1000000000000000000,
"data": '0x'
},
{
"to": '0x0000000000000000000000000000000000000009',
"value": 1000000000000000000,
"data": '0x'
}],
"gasPriceCoef": 0,
"gas": 37000,
"dependsOn": None,
"nonce": 12345678
}# Construct an unsigned transaction.
tx = transaction.Transaction(body)# Sign the transaction with a private key.
priv_key = bytes.fromhex('61faba91ef7516969e885d197f59feeb2007ea2c6057908d1696d6f056ca69d4')
message_hash = tx.get_signing_hash()
signature = cry.secp256k1.sign(message_hash, priv_key)# Set the signature on the transaction.
tx.set_signature(signature)print('Created a transaction from ' + tx.get_origin() + ' to 0x0000000000000000000000000000000000000000 with TXID: ' + tx.get_id() + '.')
print('')encoded_bytes = tx.encode()# pretty print the encoded bytes.
print('The transaction "0x' + encoded_bytes.hex() + '" will be send to the testnet node now.')tx_headers = {'Content-Type': 'application/json', 'accept': 'application/json'}tx_data = {'raw': '0x' + encoded_bytes.hex()}send_transaction = requests.post('https://testnet.veblocks.net/transactions', json=tx_data, headers=tx_headers)print('Response from Server: ' + str(send_transaction.content))
This will result in a new transaction with two clauses and two destinations!
If we open this transaction in the blockexplorer, we can see, that it says “2” on the clauses-row.
If inspected closer, it shows that VET was transfered to the addresses specified in the transaction body.
Are clauses the same as transactions?
Technically, obviously not. It’s just a part of a transaction that can not stand alone. But from a senders side, it pretty much eleminates the need for a second transaction. It’s fair to say that you can refer to the activity of the VeChain blockchain by observing the clauses and not just the transactions.
HowTo VeChain Blockchain — Part 1: Create a wallet
HowTo VeChain Blockchain — Part 2: What’s a transaction made of?
HowTo VeChain Blockchain — Part 3: Build a VET transaction
HowTo VeChain Blockchain — Part 4: Creating a multi-clause transaction
HowTo VeChain Blockchain — Part 5: Python-powered VET transfers
HowTo VeChain Blockchain — Part 6: Putting data on the Blockchain
HowTo VeChain Blockchain — Part 7.1: What is GAS and how to calculate it