Technical Guide | Teach you to discuss Wasm contract development: (C++)
First, Hello World
#include<ontiolib/ontio.hpp>#include<stdio.h> Using namespace ontio;class hello:public contract { Public: Using contract::contract: Void sayHello(){ Printf("hello world!"); } }; ONTIO_DISPATCH(hello, (sayHello));
1.1 Contract entry
ONTIO_DISPATCH(hello, (sayHello));
In the above example, we only support the sayHello method for the time being:
- Getting started with blockchain | Ethereum 2.0 terminology at a glance
- Defects of the heaviest chain rule: "The Crown Prince" in the "Public Ancestral Blocks"
- Technical Perspectives | Reflections on Citation Dynamic Language Object Models in Virtual Machines
Printf("hello world!");
This "Hello world!" will be printed in the node's log with debug information. In practical applications, printf can only be used for debugging purposes, an actual smart contract that requires more complex functions.
1.2 Smart Contract API
Second, the red envelope contract
Let's take a more complex example to demonstrate how to develop a complete Wasm smart contract through these APIs.
In many cases, we will make red packets through various apps, such as WeChat and other chat tools. We can send a red envelope to a friend, or you can grab a red envelope sent by someone else, and the money received will be credited to your personal WeChat account.
Similar to WeChat's process, we will try to create a smart contract. Users can use this contract to send ONT, ONG or standard OEP-4 Token asset red packets to his friends, while the red packets that friends grab can be directly transferred to their wallet accounts.
2.1 Creating a contract
First, we need to create a new contract source file, temporarily named redEnvelope.cpp. We need three interfaces for this contract:
- createRedEnvelope: create a red envelope
- queryEnvelope: Query red envelope information
- claimEnvelope: grab red envelope
#include<ontiolib/ontio.hpp> Using namespace ontio; Class redEnvelope: public contract{ } ONTIO_DISPATCH(redEnvelope, (createRedEnvelope)(queryEnvelope)(claimEnvelope))
Std::string rePrefix = "RE_PREFIX_"; Std::string sentPrefix = "SENT_COUNT_"; Std::string claimPrefix = "CLAIM_PREFIX_";
Address ONTAddress = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1};
Address ONGAddress = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2};
Struct receiveRecord{
Address account; //user address asset amount; //the amount of the rushed ONTLIB_SERIALIZE(receiveRecord,(account)(amount))
};
Struct EnvelopeStruct{
Address tokenAddress; / / asset token address asset totalAmount; / / red packet total amount asset totalPackageCount; / / red packets total assets remainAmount; / / current remaining amount of assets remainPackageCount; / / current remaining red packets number std:: vector <struct receiveRecord > records; //The record that has been robbed ONTLIB_SERIALIZE( EnvelopeStruct, (tokenAddress)(totalAmount)(totalPackageCount)(remainAmount)(remainPackageCount)(records) )
};
ONTLIB_SERIALIZE(receiveRecord,(account)(amount))
2.2 Creating a red envelope
Bool createRedEnvelope(address owner,asses packcount, asset amount,address tokenAddr ){
Return true;
}
Ontio_assert(check_witness(owner),"checkwitness failed");
If (isONTToken(tokenAddr)){
Ontio_assert(amount >= packcount,"ont amount should greater than packcount");
}
Key sentkey = make_key(sentPrefix,owner.tohexstring());
Asset sentcount = 0;
Storage_get(sentkey,sentcount);
Sentcount += 1;
Storage_put(sentkey,sentcount);
H256 hash ;
Hash256(make_key(owner,sentcount),hash);
Key rekey = make_key(rePrefix,hash256ToHexstring(hash));
Address selfaddr = self_address();
If (isONTToken(tokenAddr)){
Bool result = ont::transfer(owner,selfaddr ,amount);
Ontio_assert(result,"transfer native token failed!");
}else if (isONGToken(tokenAddr)){
Bool result = ong::transfer(owner,selfaddr ,amount);
Ontio_assert(result,"transfer native token failed!");
}else{
Std::vector<char> params = pack(std::string("transfer"),owner,selfaddr,amount);
Bool res;
Call_contract(tokenAddr,params, res );
Ontio_assert(res,"transfer oep4 token failed!");
}
NOTE 1 : For the two native assets, ONT and ONG, Ontology Wasm CDT provides the ont::transfer API for transfer operations; while OEP-4 assets need to be transferred according to the normal cross-contract call method.
NOTE 2 : Like the normal wallet address, the contract address can accept any type of asset. But the contract address is generated by the binary code hash compiled by the contract, so there is no corresponding private key, and you can't manipulate the assets in the contract at will. If you don't set the operation on the asset in the contract , it means you will Unable to control this part of the asset.
7. Save the contract information in the store:
Struct EnvelopeStruct es ; es.tokenAddress = tokenAddr; es.totalAmount = amount; es.totalPackageCount = packcount; es.remainAmount = amount; es.remainPackageCount = packcount; Es.records = {}; Storage_put(rekey, es);
Char buffer [100]; Sprintf(buffer, "{\"states\":[\"%s\", \"%s\", \"%s\"]}","createEnvelope",owner.tohexstring().c_str() ,hash256ToHexstring(hash).c_str()); Notify(buffer); Return true;
2.3 Querying Red Packets
Std::string queryEnvelope(std::string hash){
Key rekey = make_key(rePrefix, hash);
Struct EnvelopeStruct es;
Storage_get(rekey, es);
Return formatEnvelope(es);
}
2.4 Receiving a red envelope
We have successfully transferred the asset to the smart contract, and then we can send the ID of the red envelope to your friends to get the red envelope.
1. To receive the red envelope, you need to enter the recipient's account and red envelope hash:
Bool claimEnvelope(address account, std::string hash){ Return true; }
Ontio_assert(check_witness(account),"checkwitness failed"); Key claimkey = make_key(claimPrefix,hash,account); Asset claimed = 0 ; Storage_get(claimkey,claimed); Ontio_assert(claimed == 0,"you have claimed this Envelope!");
Key rekey = make_key(rePrefix,hash);
Struct EnvelopeStruct es;
Storage_get(rekey,es);
Ontio_assert(es.remainAmount > 0, "the Envelope has been claimed over!");
Ontio_assert(es.remainPackageCount > 0, "the Envelope has been claimed over!");
Struct receiveRecord record ;
Record.account = account;
Asset claimAmount = 0;
If (es.remainPackageCount == 1){
claimAmount = es.remainAmount;
Record.amount = claimAmount;
}else{
H256 random = current_blockhash() ;
Char part[8];
Memcpy(part,&random,8);
Uint64_t random_num = *(uint64_t*)part;
Uint32_t percent = random_num % 100 + 1;
claimAmount = es.remainAmount * percent / 100;
//ont case
If (claimAmount == 0){
claimAmount = 1;
}else if(isONTToken(es.tokenAddress)){
If ( (es.remainAmount - claimAmount) < (es.remainPackageCount - 1)){
claimAmount = es.remainAmount - es.remainPackageCount + 1;
}
}
Record.amount = claimAmount;
}
es.remainAmount -= claimAmount;
es.remainPackageCount -= 1;
Es.records.push_back(record);
Address selfaddr = self_address();
If (isONTToken(es.tokenAddress)){
Bool result = ont::transfer(selfaddr,account ,claimAmount);
Ontio_assert(result,"transfer ont token failed!");
} else if (isONGToken(es.tokenAddress)){
Bool result = ong::transfer(selfaddr,account ,claimAmount);
Ontio_assert(result,"transfer ong token failed!");
} else{
Std::vector<char> params = pack(std::string("transfer"),selfaddr,account,claimAmount);
Bool res = false;
Call_contract(es.tokenAddress,params, res );
Ontio_assert(res,"transfer oep4 token failed!");
}
Storage_put(claimkey,claimAmount);
Storage_put(rekey,es);
Char buffer [100];
Std::sprintf(buffer, "{\"states\":[\"%s\",\"%s\",\"%s\",\"%lld\"]}","claimEnvelope" , hash.c_str(), account.tohexstring().c_str(), claimAmount);
Notify(buffer);
Return true;
2.5 contract test
There are two ways to test a contract:
- Use the CLI
Please refer to: https://github.com/ontio/ontology-wasm-cdt-cpp/blob/master/How_To_Run_ontologywasm_node.md
Please refer to: https://github.com/ontio/ontology-wasm-cdt-cpp/blob/master/example/other/main.go
Third, summary
This example is just to show how to write a complete Ontology Wasm smart contract, how to interact with the underlying blockchain by calling the API. If you want to be a formal product, you need to solve the privacy problem of the red envelope: Everyone can get the red envelope hash by monitoring the contract event, which means everyone can grab the red envelope. A simpler solution is to specify which accounts can be picked up when creating a red envelope. If you are interested, you can also try to modify the test.
We welcome more Wasm technology enthusiasts to join the ontology development community to create a technological ecosystem.
We will continue to update Blocking; if you have any questions or suggestions, please contact us!
Was this article helpful?
93 out of 132 found this helpful
Related articles
- Technical Guide | Teach you to discuss Wasm contract development
- Getting started with IPFS | 50 questions about IPFS (4)
- How To | Install IPFS and IPFS Clusters on Raspberry PI
- PoD-Tiny – the simplest protocol for zero-trust transactions
- Technical Guide | Using Pubma to perform chaotic testing of the network
- Ethereum 2.0: Randomness
- Technical Guide | Understanding the Generalized Plasma Technology Structure – part I