The contract we use as an example here is for sending red packets, which is used when users send crypto assets as gifts. The core functions are:
Send red packets
Receive red packets
Before sending red packets, the user need to determine the amount of tokens to be sent and the number of red packets. For instance, 100 tokens will be sent in 10 red packets (to 10 different wallets). For ease of understanding, each red packet contains the same amount, i.e., each contains 10 tokens.
Consequently, we define the data structure:
EIP20Interface public token; // support token addressuint public nextPacketId; // the next redpacket ID// packetId -> Packet, store all the redpacketmapping(uint => Packet) public packets;//packetId -> address -> bool, store receive redpacket recordmapping(uint =>mapping(address => bool)) public receiveRecords;struct Packet { uint[] assetAmounts;// Number of tokens per copy uint receivedIndex; // Number of red packets received}
Define Contract Events
When executing the contract, we can trace the process by adding events.
Here we design two events:
When the user send a red packet, the contract generates an ID for the red packets, which will be sent through this event notification:
event SendRedPacket(uint packetId, uint amount);
2. When a user receives a red packet, this event notification is sent to record the ID and token amount of the received red packet:
Sends red packets. Any system is able to call the function and send certain amount of tokens to the contract address. Other addresses can receive red packets from this contract address.
Note: Before invoking this function, the contract has to be authorized to transfer tokens from users' addresses. To do so, call the approve method of the token first.
Receives red packets. Any address can call this function by red packet ID to receive a red packet, meaning that you need to specify which one to receive.
functionreceivePacket(uint packetId) publicpayablereturns (bool) {require(packetId < nextPacketId,"not the redpacket"); Packet memory p = packets[packetId];if (p.assetAmounts.length<1) {returnfalse; }require(p.receivedIndex <p.assetAmounts.length-1,"It's over");require(receiveRecords[packetId][address(msg.sender)] ==false,"has received");p.receivedIndex =p.receivedIndex +1; bool res =token.universalTransfer(msg.sender,p.assetAmounts[p.receivedIndex]);require(res,"token transfer failed"); packets[packetId] = p; receiveRecords[packetId][address(msg.sender)] ==true; emit ReceiveRedPacket(packetId,p.assetAmounts[p.receivedIndex]);returntrue;}
accounts field takes the array of selected private key. There should be enough ONG balance in the corresponding address to pay for transactions. You can apply for TestNet ONG here.
File Preparation
Add the contract file in the contracts folder. To support ERC-20 token transfer, we also need EIP20Interface.sol, UniversalERC20.sol, and TokenDemo.sol which you can download from here.