Search
This oracle checks Google’s DNS service to determine if a given domain is owned by a given blockchain address. Each address is stored in a TXT record.
This guide explains how to call the DNS ownership oracle and verify that a given address owns a specific domain. For instance, we will confirm that the address 0xf75519f611776c22275474151a04183665b7feDe owns www5.infernos.io. Note that the source of data is Google DNS.
Topics
This guide assumes that you know how to create and deploy smart contracts on the Goerli testnet using the following tools:
You should be familiar with the Chainlink Basic Request Model. If you are new to developing smart contracts on Ethereum, see the Getting Started guide to learn the basics.
This example operates using the following steps:
constructor()
initializes the address of oracle
, the jobId
, and the fees oraclePayment
. The code example is configured for the Goerli testnet. Check the Network Details section for other networks.requestProof()
function to check that an address owns a domain name. For this example, you can use www5.infernos.io
for the _name
and 0xf75519f611776c22275474151a04183665b7feDe
for the _record
. Notice how these parameters are used to build the Chainlink request. The selector of the fulfill()
function is also passed so that the oracle knows which function to call back with the proof
.proof
. It should return true
.// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
import '@chainlink/contracts/src/v0.8/ChainlinkClient.sol';
import '@chainlink/contracts/src/v0.8/ConfirmedOwner.sol';
/**
* Request testnet LINK and ETH here: https://faucets.chain.link/
* Find information on LINK Token Contracts and get the latest ETH and LINK faucets here: https://docs.chain.link/docs/link-token-contracts/
*/
/**
* THIS IS AN EXAMPLE CONTRACT THAT USES HARDCODED VALUES FOR CLARITY.
* THIS IS AN EXAMPLE CONTRACT THAT USES UN-AUDITED CODE.
* DO NOT USE THIS CODE IN PRODUCTION.
*/
contract DnsOwnershipChainlink is ChainlinkClient, ConfirmedOwner {
using Chainlink for Chainlink.Request;
bytes32 private jobId;
bool public proof;
uint256 oraclePayment;
/**
* Network: Goerli
* Oracle:
* Name: LinkPool
* Listing URL: https://market.link/nodes/323602b9-3831-4f8d-a66b-3fb7531649eb?network=42
* Address: 0xB9756312523826A566e222a34793E414A81c88E1
* Job:
* Name: DNS Record Check
* ID: 791bd73c8a1349859f09b1cb87304f71
* Fee: 0.1 LINK
*/
constructor() ConfirmedOwner(msg.sender) {
setChainlinkToken(0x326C977E6efc84E512bB9C30f76E30c160eD06FB);
setChainlinkOracle(0xB9756312523826A566e222a34793E414A81c88E1);
jobId = '791bd73c8a1349859f09b1cb87304f71';
oraclePayment = (1 * LINK_DIVISIBILITY) / 10; // 0,1 * 10**18 (Varies by network and job)
}
/**
* Request proof to check if the address `_record` owns the DNS name `_name`
*
*/
function requestProof(string memory _name, string memory _record) public onlyOwner {
Chainlink.Request memory req = buildChainlinkRequest(jobId, address(this), this.fulfill.selector);
req.add('name', _name);
req.add('record', _record);
sendChainlinkRequest(req, oraclePayment);
}
/**
* Callback function called by the oracle to submit the `_proof` . If true, this means that the address owns the dns name
*
*/
function fulfill(bytes32 _requestId, bool _proof) public recordChainlinkFulfillment(_requestId) {
proof = _proof;
}
/**
* Allow withdraw of Link tokens from the contract
*/
function withdrawLink() public onlyOwner {
LinkTokenInterface link = LinkTokenInterface(chainlinkTokenAddress());
require(link.transfer(msg.sender, link.balanceOf(address(this))), 'Unable to transfer');
}
}
The DNS Ownership Contract example works on the Goerli Testnet. Below are the configuration for other chains.
Payment Amount: 2 LINK
LINK Token Address: 0x514910771AF9Ca656af840dff83E8264EcF986CA
Oracle Address: 0x1152c76A0B3acC9856B1d8ee9EbDf2A2d0a01cC3
JobID: 6ca2e68622bd421d98c648f056ee7c76
Payment Amount: 0.1 LINK
LINK Token Address: 0x326C977E6efc84E512bB9C30f76E30c160eD06FB
Oracle Address: 0xB9756312523826A566e222a34793E414A81c88E1
JobID: 791bd73c8a1349859f09b1cb87304f71
Payment Amount: 0.1 LINK
LINK Token address:0x404460C6A5EdE2D891e8297795264fDe62ADBB75
Oracle Address: 0x63f9459471804835E35EFeB296314153063c25E3
JobID: fb06afd5a9df4e6cb156f6b797b63a24
Payment Amount: 0.1 LINK
LINK Token Address: 0xb0897686c545045aFc77CF20eC7A532E3120E0F1
Oracle Address: 0x2984beb1d35d11B56973148A9022210Aecc26CE5
JobID: f3daed2990114e98906aaf21c4172da3
The DNS Ownership node uses a Chainlink v2 direct-request job. It is composed by the following taks:
type = "directrequest"
schemaVersion = 1
contractAddress = "0x0000000000000000000000000000000000000000"
maxTaskDuration = "0s"
observationSource = """
decode_log [type=ethabidecodelog
abi="OracleRequest(bytes32 indexed specId, address requester, bytes32 requestId, uint256 payment, address callbackAddr, bytes4 callbackFunctionId, uint256 cancelExpiration, uint256 dataVersion, bytes data)"
data="$(jobRun.logData)"
topics="$(jobRun.logTopics)"]
decode_cbor [type=cborparse data="$(decode_log.data)"]
dnsproof [type=bridge
name="dnsproof"
requestData="{\\"data\\": {\\"endpoint\\": \\"dnsProof\\", \\"name\\": $(decode_cbor.name), \\"record\\": $(decode_cbor.record)}}"]
result_parse [type=jsonparse data="$(dnsproof)" path="result"]
encode_data [type=ethabiencode
abi="(bool _result)"
data="{\\"_requestId\\": $(decode_log.requestId),\\"_result\\": $(result_parse)}"]
encode_tx [type=ethabiencode
abi="fulfillOracleRequest(bytes32 requestId, uint256 payment, address callbackAddress, bytes4 callbackFunctionId, uint256 expiration, bytes32 data)"
data="{\\"requestId\\": $(decode_log.requestId),\\"payment\\": $(decode_log.payment),\\"callbackAddress\\": $(decode_log.callbackAddr),\\"callbackFunctionId\\": $(decode_log.callbackFunctionId),\\"expiration\\": $(decode_log.cancelExpiration),\\"data\\": $(encode_data)}"]
submit_tx [type=ethtx to="0x0000000000000000000000000000000000000000" data="$(encode_tx)" minConfirmations="2"]
decode_log -> decode_cbor -> dnsproof -> result_parse -> encode_data -> encode_tx -> submit_tx
"""