Developing Contracts in C++
C++ WASM Contract Development in C++
Much similar to EOS, developers can use C++ to develop smart contracts on the Ontology platform. Let us take a look at a sample Hello World app.
Sample Code
Smart Contract Entry Point
The Ontology WASM CDT Compiler encapsulates the required features for entry point and parameter processing. Thus, developers do not need to define entry point methods.
The entry point method can be called in the following manner:
The next important part of the contract would be the external interface. This interface would make the contract's services available to external parties. In the sample code above we use the sayHello()
method to demonstrate the same.
This "Hello World" will be printed out in the node log records at the respective "debug level". Practically speaking, the printf()
method can only be used for debugging. A more realistic smart contract would need to implement many more complex features.
Smart Contract API
Ontology WASM provides an API that contains the following methods that allow communication with the blockchain system.
API
Parameter
Return Value
Description
timestamp
None
uint64
Current UNIX timestamp
block_height
None
uint32
Current block height
self_address
None
address
Contract address
caller_address
None
address
Invocation address (Same as self_address
if invocation is not external)
entry_address
None
address
Entry contract address (Same as self_address
if invocation is not external)
check_witness
address
bool
Check the signature of the incoming address
current_blockhash
None
H256
Current block hash
current_txhash
None
H256
Current transaction hash
notify
string
void
Send even notification
call_native
address, params, result
void
Invoke native contract
call_contract
address, params, result
void
Invoke ordinary contract (WASM/NeoVM)
storage_get
key, result
void
Fetch stored data
storage_put
key, value
void
Write data on the chain
storage_delete
key
void
Delete stored data
contract_create
code, vmtype, name, version, author, email, desc
address
Create new contract
contract_migrate
code, vmtype, name, version, author, email, desc
address
Migrate (upgrade) contract
contract_delete
address
void
Delete contract
Let us develop a slightly more complicated WASM contract to demonstrate how to use the API.
Red Envelope Smart Contract
Giving and receiving red envelopes is a part of China's tradition on important festivals and occasions. Red envelopes can now be sent and received using many different tools including social networking and IM platforms such as WeChat. The amount collected can also be deposited to bank accounts.
Let us try an create a smart contract that works the way WeChat's red envelope mechanism works. ONT, ONG, and other OEP-4 standard cryptocurrencies and tokenized assets can be transferred in the form of red envelopes. The amount received is transferred to the receiver's wallet account.
1. Creating a New Contract
First, we need to create a new contract file and rename it to redEnvelope.cpp
.
In this contract we will be implementing three API methods.
createRedEnvlope
: To create a new red envelope
queryEnvlope
: Query existing red envelope details
claimEnvlope
: To claim a red envelope
We need to store certain important data. Data is store in the form of key-value pairs withing the scope of the contract. The key to these data need to set the prefix to make querying more convenient.
Since our contract supports the two native assets ONT and ONG, we can define the contract addresses of these these two assets.
Note: Unlike a standard smart contact where the contract address is calculated based on contract hash, the address of the native contract is fixed.
We need to store the red envelope information in the contract, such as asset related information (token contract address, red envelope total amount, no. of red envelopes, etc.)
The macros defined in CDT can be used to serialize the struct
type data before storage.
The preparation is almost complete, and at this point we can start coding the specific API logic.
2. Creating a Red Envelope
A new red envelope is created by defining the creator's address, no. of red envelopes, red envelope amount, and the asset token address.
Verify whether the creator has signed the action, and rollback the transaction if not.
With respect to ontio_assert(expr, errormsg)
, when expr
is false
, an exception is thrown and the process is quit.
If the red envelope asset is ONT, the amount of ONT must be equal to or greater than the no. of red envelopes, since the asset is indivisible (cannot be smaller than 1). So this condition ensures that each red envelope contains at least 1 ONT.
For every red envelope creator, we need to maintain the record of the total number of red envelopes created and sent by them.
A red envelope hash is generated for each red envelope. This hash value serves as a unique identifier.
A tokenized asset it imported to the contract based on its type. The self_address()
method can be used to fetch the address of the invocation. The amount of token imported to the contract is based on the token type input by the user.
Note: The transfer operation for the two native assets ONT and ONG is carried out using the ont::transfer
API method provided in the CDT. Other OEP-4 based tokens need to be transferred using the standard cross-contract invocation methods.
Note: A smart contract address can receive assets of any type, just as a wallet address can. However, the contract address is generated based on the binary code hash of the contract code, and so the assets stored in the contract address cannot be manipulated without the corresponding private key. Hence, If asset related operations are not set within the contract, there is no way to control the assets stored in it.
The contract information is saved.
Next, the red envelope creation event is sent to the chain since this is an asynchronous event with respect to contract invocation. Upon successful execution, the contract notifies the client regarding the event. The specific format of this notification can be defined by the developer.
With this a simple red envelope is created. The next step is to implement the method that can query the red envelope information.
3. Querying Red Envelope Information
The query logic for the red envelope is simple. The stored red envelope data needs to be fetched, re-formatted, and returned.
And finally, the users can claim the red envelope based on the red envelope hash (an ID).
Note: For read-only operations of the smart contract, such as information query, the results can be fetched using pre-execution. Unlike the normal execution process, pre-execution does not require wallet authentication and does not consume ONG.
4. Claiming Red Envelope
We have successfully imported the assets to the smart contract. At this point, the ID can be shared with other users and they can start claiming the red envelope.
Claiming a red envelope requires the claiming party's account address and the red envelope's hash.
Similarly, the claiming party's signature needs to be verified to ensure that a person may only claim a red envelope themselves, and not by proxy. Also, each user is allowed to claim a red envelope only once.
Using the red envelope hash it's data can be fetched and can be determine whether a red envelope has been fully claimed.
The claim is added to the claim records.
This part of the program logic is a little lengthy. Here, the logic is to calculate the amount of asset claimed from the red envelope. If it is the last red packet, then the amount left is the amount in the last red packet. Otherwise, the remaining asset amount is calculated using a random number generated using the current block hash. This remaining asset amount is then updated in the red envelope information.
Based on the claimed asset, the calculated amount of the corresponding asset is transferred to the claim account address from the contract.
The claim records are stored and the updated red envelope information is stored along with the notification of the event being sent out.
As stated above, the claimEnvlope()
method is the only way to move an asset out of this contract. Hence, we establish that the assets stored in the contract are safe.
The simple logic for the red envelope system is complete. The entire smart contract sample code is available here for reference.
Testing a Smart Contract
Using the CLI
Please refer to: https://github.com/ontio/ontology-wasm-cdt-cpp/blob/master/How_To_Run_ontologywasm_node.md
Using the Golang SDK
Please refer to: https://github.com/ontio/ontology-wasm-cdt-cpp/blob/master/example/other/main.go
This example serves to demonstrate how a complete Ontology WASM contract uses API methods to interact with the blockchain. If a complete product is to be developed using this technology, there would be several other considerations such as privacy related concerns for the red envelope. Anyone can monitor a red envelope events to get the hash, and then claim it. This issue can be solved by fixing the addresses, and thereby the users who can claim a red packet. Interested developers can make the necessary changes to the code and test it out.
Last updated