Authpaper Sales Smart Contract Part 4 Sending out AUPC and marketing reward
In the previous articles, we have talked about different parts of the contract, default function, which is called when supporters pay ETH, oraclizeAPI, getting the upline information to determine the price and marketing award.
With the information on hand, purchaseAUPC() is called to calculate how much AUPC should send out, and call the sendUpline() function to distribute the marketing reward right away.
We will talk about these two functions in this article.
For those who would like to view the whole contract, it can be found here: https://github.com/SolonAuthpaper/AUPC_sales_contract
Let’s us take a look on the first part of the purchaseAUPC() function.
First of all, this function is internal. It means it cannot be called directly by outside parties, it can only be called inside other functions of the contract. Hence you can feel safe to do things as the inputs should be sanitized properly in the public functions.
The first four lines of codes check if the request fits the condition. You may notice that there is a checking on how much ETH is settled. It looks strange as the payment should be settled right after the payment, right? It turns out not necessary the case. If an user pays the ETH multiple times in a short period of time, it is possible that oraclizeAPI sends the same callback for one payment multiple times. There is a potential double distribution problem. We added the settled amount checking to avoid double distribution happens.
We then calculate the discount according to the scheme:
If your referral is on the top, you will have 5% discount. Two levels referral will have 5% + 3% = 8% discount, three levels will have 10% discount. Any additional levels will have additional 1% discount. The maximum discount is 15%.
Notice that the amount of AUPC to distribute, amountAUPC, is multiplied by 10¹⁸. It is because when we divide the amount by AUPC price, the output will be 1 when we suppose to distribute 1 AUPC. This will round down all decimal places. So we multiple it by 10¹⁸ first before dividing. It is OK as AUPC has 18 decimal places. The potential problem of integer overflow is checked in the next line of code.
The smart contract by itself does not hold any AUPC, so it is distributing AUPC on behalf of the coin owner. So we call the AUPC.transferFrom() to send out AUPC. It is a good practice as you can limit the amount one smart contract can sell, and if something goes wrong the lost of AUPC is limited or none.
After distribution, recording and sending out an event, there is an assert function to make sure correct amount of AUPC is sent out.
Assert function has one thing similar with require: They both will fail the transaction and undo everything done in the transaction when the condition is false. However, require() is used to check conditions only, so it may fail if someone input wrong data. Assert() is normally used for internal error checking, failing assert function indicates there is a bug in the contract. Besides, if the condition inside a require function is failed, the transaction gas is returned to caller. If condition inside an assert function is failed, the transaction gas will still be consumed even all changes are undone.
After distribution, the function will then check if the upline information is stored in the same day. If the upline information is ready, call the sendUpline function. If not, call another oraclize query to the server for the upline information.
That’s why in the oraclize callback there is another set of code to handle upline query result.
The sendUpline function sends out both ETH and AUPC as marketing rewards. So we need to handle with extra care.
In this function, we first calculate the AUPC and ETH to send out according to the marketing referral scheme:
If the first three levels referrers are holding AUPC at the time of purchase, they will be awarded AUPC and ether as present. The first level will have 10% token and 5% ether of the purchased amount, the second level will have 6% token and 3% ether, and the third level will have 4% token and 2% ether.
As you can see in the code, we explicitly calculate the distribution rate and exit the function directly when the level is above 3. We also hard code in the server side that if there is no upline for the purchase, send out the contract owner address.
Sending out ETH is different from AUPC. The .transfer does not return any value so we cannot put it into require() function. We also need to assert both AUPC and ETH are sent correctly.
The last part of the function check if the upline has further upline. Notice that if the upline is already the top one (level 3), a query will still be made. The query result, with level = 4, will be passed to this function and ends without distributing reward.
The journey from sending in ETH to distribute the AUPC and marketing rewards ends here. In the next article we will talk about the supporting functions and cautious to make when writing a contract.