1. Home
  2. Docs
  3. SmartContracts
  4. SmartContracts Tutorials
  5. Listing Service Controller Contract

Listing Service Controller Contract

This contract is a Chainlinked contract that allows requests to be passed through to dynamic oracle contracts upon receipt of LINK via transferAndCall. This contract and its associated workflow is experimental and offers no guarantee of safety. It is ultimately up to the listing service to provide a secure and reliable API in order for node operators and requesters to interact with.

By using this contract (or a contract similar to it), a listing service can perform functions which require an on-chain verification that the node operator is running a Chainlink node with the ability to fulfill requests through the oracle contract they claim to own. This can be useful for registration of a new node operator, since there will be no history available to measure their honesty.

The steps below describe the process of a node registering with a listing service. The entity that performs the steps is indicated by a prefix:

  • [LS] for Listing Service
  • [NO] for Node Operator

Workflow – Registration Steps

  • [LS] Deploy the ListingServiceController contract.
  • [NO] Provide the listing service with the oracle contract address and the node’s MINIMUM_CONTRACT_PAYMENT value.
  • [LS] Provide the node operator with a job specification similar to the one below. Notice the post parameter’s URL contains some_unique_value, this would be generated by the listing service and provided to the node operator. Also take note that the example path, "verification", may need to be updated for the listing service’s API response.
  "initiators": [{ "type": "RunLog" }],
  "tasks": [
    { "type": "HttpPost", "params": { "post": "" }},
    { "type": "JsonParse", "params": { "path": ["verification"] }},
    { "type": "EthBytes32" },
    { "type": "EthTx" }
  • [NO] Add the given job spec to the node and provide the listing service with its JobID.
  • [LS] Generate a transaction for the node operator to confirm calling the LinkToken contract’s transferAndCall method, to the address of the listing service’s controller contract address, with the amount provided by the node operator’s MINIMUM_CONTRACT_PAYMENT value, and the data generated by the encodePayload method (using the node operator’s oracle contract address and JobId). This can currently be done on MyEtherWallet or MyCrypto by interacting with the LinkToken contract. LinkToken’s ABI is included in lib/LinkToken.json; get the contract address per-network here.
    • This transfers the amount of LINK specified from the signer’s address to the listing service controller’s contract address, which then transfers that amount to the node operator’s oracle contract and triggers a request.
  • [LS] When the request is triggered, the node will reach out to the listing service’s API with the payload below. The "address" will be that of their oracle contract address. This can be validated against what the node operator provided to during registration.
	"address": "0xe9fE10C6A75C079B09E73E56Db12b88787C2Bc0a",
	"dataPrefix": "0xe3958a2369e64b404cf4f66cc7ad1d05f9219dd310552dd1df4a7517eb652fe9",
	"functionSelector": "0x76005c26"
  • [LS] If the address validates successfully, provide a new unique value as a result to be returned to the listing service controller contract. If validation is not successful, return HTTP error 400.
  • [LS] When the node responds, that value will be emitted from the fulfill method of the listing service controller contract. Perform a final validation that the value emitted matches what was provided to the node.
  • [LS] An EthLog job specification (below) can be used to watch for events for a given address. Assume the post parameter’s URL is only accessible to the listing service’s Chainlink node.
	"initiators": [
		{ "type": "ethlog",
		  "params": { "address": "0x45639796bcd8e5993249dfe1c4f38d0b89f71caa" }}
	"tasks": [
		{ "type": "httppost",
		  "confirmations": 0,
		  "params": { "post": "" }}
  • [LS] When a log is sent to the endpoint, the data will be formatted like this:
	"address": "0x45639796bcd8e5993249dfe1c4f38d0b89f71caa",
	"blockHash": "0xdceb1d8db6f274242df5f6308619690456c7c04cc0d29f9a785b345e0c308d5d",
	"blockNumber": "0x49d144",
	"data": "0x",
	"logIndex": "0x1",
	"removed": false,
	"topics": [
	"transactionHash": "0xd6051adf57861c5c0195724de93db55b0f3a646d943f1b613a6152579053eb53",
	"transactionIndex": "0x0"
  • [LS] For topic[0] of "0xaeda80d3cc2616854f3d9b76923169659166ec99dd7565433c510ede35de3d73" (which is keccak256("RequestFulfilled(bytes32,address,bytes32)"), validate topics[2] matches the oracle address and topics[3] matches the unique value given to the node. If validation is successful, the node’s registration is complete.

Additional notes:

  • Notice the node operator doesn’t really need to do much in this process. They only need to provide info, add a job, and sign a transaction. Then as long as their node is set up correctly, the rest of the registration process is automatic for them.
  • As long as the node responds within 5 minutes, it receives its LINK payment back by being withdrawable from their oracle contract. This also means the listing service can grief nodes by simply not responding when they attempt to register. However, that would be clearly visible on-chain, since it would be seen many requests coming in, but no (or late) responses coming back.
  • Simply transferring LINK to the contract does not trigger any functions on the ListingServiceController contract. This is by-design because normal transfers do not include a data payload.


A flattened contract file is included in the lib/ directory to easily copy & paste into Remix. You will need to select the compiler version 0.4.24 for this contract.


npm install


npm test


Find linting issues with both Javascript and Solidity code:

npm run lint

Attempt to automatically fix issues with both Javascript and Solidity code:

npm run lint:fix


npm run flatten
Was this article helpful to you? Yes No

How can we help?