Skip to main content

📝 Example Project

This example project will guide you through how to use Nodary Beacons in your own contract.

Project: Analyze

  • We first start by creating our contract as described here in order to read data from Beacons.
// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;

import "@api3/airnode-protocol-v1/contracts/dapis/DapiReader.sol";


contract BeaconReaderExample is DapiReader {
constructor(address _dapiServer) DapiReader(_dapiServer) {}

function readBeaconWithId(bytes32 beaconId)
external
view
returns (int224 value, uint256 timestamp)
{
(value, timestamp) = IDapiServer(dapiServer).readDataFeedWithId(
beaconId
);
}

function readBeaconValueWithId(bytes32 beaconId)
external
view
returns (int224 value)
{
value = IDapiServer(dapiServer).readDataFeedValueWithId(beaconId);
}

function beaconIdToReaderToWhitelistStatus(
bytes32 beaconId,
address reader
)
external
view
returns (uint64 expirationTimestamp, uint192 indefiniteWhitelistCount)
{
return
IDapiServer(dapiServer).dataFeedIdToReaderToWhitelistStatus(
beaconId,
reader
);
}

// Our functions go here

}
  • We write our functions. Our main function is Analyze(). It requires 2 Beacon addresses and enough token to "analyze".
...

// Our functions go here

function someAnalysis(bytes32 coin1BeaconId, bytes32 coin2BeaconId)
public
view
returns (string memory)
{
int224 coin1Value = readBeaconValueWithId(coin1BeaconId);
int224 coin2Value = readBeaconValueWithId(coin2BeaconId);

if (coin1Value > coin2Value) {
return "coin1higher";
} else if (coin1Value == coin2Value) {
return "equal";
} else {
return "coin2higher";
}
}

event AnalysisEvent(string analysisResult);
uint256 ANALYSIS_COST = 0.05 ether;

function Analyze(bytes32 coin1BeaconId, bytes32 coin2BeaconId) external payable {

// make sure this contract is whitelisted
(uint64 expirationTs1, ) = beaconIdToReaderToWhitelistStatus(coin1BeaconId, address(this));
(uint64 expirationTs2, ) = beaconIdToReaderToWhitelistStatus(coin2BeaconId, address(this));
require(expirationTs1 > 0, "This contract is not whitelisted for coin1BeaconId!");
require(expirationTs2 > 0, "This contract is not whitelisted for coin2BeaconId!");

// make sure user send enough
uint256 receivedAmount = msg.value;
require(receivedAmount >= ANALYSIS_COST, "Need more than 0.05 ether!");

// analyze and emit
string memory analysisResult = someAnalysis(coin1BeaconId, coin2BeaconId);
emit AnalysisEvent(analysisResult);

// return extra currency to sender (user)
(bool success, ) = msg.sender.call{value: receivedAmount - ANALYSIS_COST}("");
require(success, "Failed to call!");
}
}

Final code should look like this:

// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;

import "@api3/airnode-protocol-v1/contracts/dapis/DapiReader.sol";


contract BeaconReaderExample is DapiReader {
constructor(address _dapiServer) DapiReader(_dapiServer) {}

function readBeaconWithId(bytes32 beaconId)
private
view
returns (int224 value, uint256 timestamp)
{
(value, timestamp) = IDapiServer(dapiServer).readDataFeedWithId(
beaconId
);
}

function readBeaconValueWithId(bytes32 beaconId)
private
view
returns (int224 value)
{
value = IDapiServer(dapiServer).readDataFeedValueWithId(beaconId);
}

function beaconIdToReaderToWhitelistStatus(
bytes32 beaconId,
address reader
)
private
view
returns (uint64 expirationTimestamp, uint192 indefiniteWhitelistCount)
{
return
IDapiServer(dapiServer).dataFeedIdToReaderToWhitelistStatus(
beaconId,
reader
);
}



// Our functions go here

function someAnalysis(bytes32 coin1BeaconId, bytes32 coin2BeaconId)
public
view
returns (string memory)
{
int224 coin1Value = readBeaconValueWithId(coin1BeaconId);
int224 coin2Value = readBeaconValueWithId(coin2BeaconId);

if (coin1Value > coin2Value) {
return "coin1higher";
} else if (coin1Value == coin2Value) {
return "equal";
} else {
return "coin2higher";
}
}

event AnalysisEvent(string analysisResult);
uint256 ANALYSIS_COST = 0.05 ether;

function Analyze(bytes32 coin1BeaconId, bytes32 coin2BeaconId) external payable {

// make sure this contract is whitelisted
(uint64 expirationTs1, ) = beaconIdToReaderToWhitelistStatus(coin1BeaconId, address(this));
(uint64 expirationTs2, ) = beaconIdToReaderToWhitelistStatus(coin2BeaconId, address(this));
require(expirationTs1 > 0, "This contract is not whitelisted for coin1BeaconId!");
require(expirationTs2 > 0, "This contract is not whitelisted for coin2BeaconId!");

// make sure user send enough
uint256 receivedAmount = msg.value;
require(receivedAmount >= ANALYSIS_COST, "Need more than 0.05 ether!");

// analyze and emit
string memory analysisResult = someAnalysis(coin1BeaconId, coin2BeaconId);
emit AnalysisEvent(analysisResult);

// return extra currency to sender (user)
(bool success, ) = msg.sender.call{value: receivedAmount - ANALYSIS_COST}("");
require(success, "Failed to call!");
}
}

  • We want to deploy our contract on the Polygon testnet. We can obtain the address of DapiServer.sol on the Polygon testnet here. We also need 2 Beacon addresses. We can find the list of Beacons here.

  • If everything is ready, we can use Remix to deploy our contract.

  • Click the below button to go to Remix workspace and open MyContract.sol from Remix's file explorer.

  • Once Remix workspace is loaded, go to the Solidity compiler section and compile the contract. Then, go to the Deploy & run transactions section. Connect your Metamask account on polygon-testnet (also called Mumbai Testnet). Finally select MyContract.sol, enter DapiServer.sol's address and deploy your contract.

  • Now, we need to whitelist our freshly deployed contract. You can see this to find out how. Once the contract is whitelisted, the Analyze() function should give a similar log on the Remix console to the below.

...

logs
[
{
"from": "0x071727416221e5c42DE91144a452Ee4D2d30A23c",
"topic": "0x48e8b5bc2a9491a87c4f3123e474812d43c18d496bae119f97a9cdf178347a0a",
"event": "AnalysisEvent",
"args": {
"0": "coin1higher",
"analysisResult": "coin1higher"
}
}
]
...
info

Each value that is written to chain is multiplied by a number. It is required to handle floating number since floating numbers does not exist in solidity.

caution

It should be remembered that the corresponding sponsor wallet of a Beacon should have enough amount of currency for the Beacon to be updated.