This is continuation of the story from our CTO Valery Dubrava.
Payment for the check
You must pay for using Oraclize service. The amount of payment is calculated at the rate of 0.01 USD per request + cost of gas for calling a callback with the result (at the time of writing the article). The commission is automatically written off (in the API contract code) from the balance of the contract. In our case, this is not suitable, since the same account is used by user (for savings, everyday payments and so on).
To solve this problem, Lastwill system will transfer the needed amount while calling check function.The amount should be with a margin, covering the estimated costs of the call. This amount is credited to the contract account, and is added to the amount of user funds. Before calling the request, it is checked that the credited amount will actually cover the commission oraclize (getPrice function allows you to find out the cost). So we guarantee that the user’s funds will not be spent. Lastwill covers all needed operations & checks.
Code examples.
Let’s consider several methods from the LastWill contract with comments. All the code can be viewed on our github.
function doCheck () onlyAdmin internal returns (bool) {
// if the previous check is “successful”
if (accidentOccurs) {
// return the amount needed for oraclize
msg.sender.transfer (msg.value);
// and mark the check as “successful”
return true;
}
// check that the funds have been transfered enough to call oraclize
uint price = oraclize_getPrice (“URL”);
if (price> msg.value) {
revert ();
}
// collect the request and send it to oraclize
string memory url = buildUrl (targetUser, lastCheckBlockNo, block.number);
bytes32 queryId = oraclize_query (“URL”, url);
// remember the id of the request to exclude the consequences of the error from the oraclize side
validIds [queryId] = true;
// create events for audit on the LastWill side
CheckStarted (queryId);
// we consider the remainder, and if it is — we send ourselves
uint change = msg.value — price;
if (change> 0) {
msg.sender.transfer (change);
}
// mark the check as “not successful”
return false;
}
Processing the result
// The result should look like this: [“1469624867”, “1469624584”, … ‘
function __callback (bytes32 queryId, string result) {
// Check that the sender oraclize!
if (msg.sender! = Oraclize_cbAddress ()) revert ();
// Verify that the request was not yet processed or even created by us
if (! ValidIds [queryId]) revert ();
// Mark the request as processed
delete validIds [queryId];
// Simplified logic checks for data in the request
if (bytes (result) .length == 0) {
// If there is no data again, check if the maximum interval is reached without transactions
if (block.timestamp — lastActiveTs> = checkInterval) {
// Then mark the incident as “happened”
accidentOccurs = true;
}
}
else {
// If there is a transaction, in the simplified case, take the block time
lastActiveTs = block.timestamp;
}
// Create an event that the test passed, for an audit on the LastWill side
Checked (accidentOccurs);
// If the incident occurred
if (accidentOccurs) {
// We ask LastWill to call the check method again, so that the distribution of funds
// to avoid allocating funds for the GAS call oraclize
NeedRepeatCheck (true);
}
}
Conclusion
In conclusion, we can say that the interaction with oraclize is not complicated, but it is important to notice the following points:
- Payment is from the contract which calls
- The result comes in a separate transaction
- The cost of external calls and working with strings is processing very slow and costs a lot of gas. In our case, check requires about 133,000 gas, and about 80,000 gas is spent preparing the request (query string assembly).