📝 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 theDeploy & run transactions
section. Connect your Metamask account onpolygon-testnet
(also calledMumbai Testnet
). Finally selectMyContract.sol
, enterDapiServer.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"
}
}
]
...
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.
It should be remembered that the corresponding sponsor wallet of a Beacon should have enough amount of currency for the Beacon to be updated.