Rivalz Network
  • Introducing Rivalz
  • ROME - Swarm Protocol
    • rAgent Creation
    • What is a PAG?
    • ROME Rewards
      • ROME Season 1 - 25,000,000 $RIZ in rewards
    • Swarms and Swarm Staking
    • Lending Market
    • User Guide - ROME Dashboard
      • PAG
      • Reputation & Rewards
      • Swarm Project Creation
      • Swarm Staking
      • Borrow Market
      • Lending Guide
  • rClients (ROME 🏛️)
    • rClient CLI Guide
  • OCY - DATA
  • ADCS - CONNECTIVITY
    • Overview
    • Core components
    • Create an Adapter
    • Create your consumer smart contract
    • How to automate your contract execution with Gelato
    • How to Become a Provider
    • Developer
  • NOSTRINGS - IDENTITY
  • VORD - APPLICATION
    • VORD
    • Sidelined
    • AI-Powered Telegram Bots (Coming Soon)
  • Rivalz Alliance & Ecosystem
  • Intel Incentivized Testnet
  • zNode (Validators)
    • zNode Utility
    • Running a zNode
    • Delegating a zNode
      • Rivalz zNode - NodeOps Delegation
    • zNode Burn Event (Ended)
  • RIZ Token
    • RIZ Overview & Contracts
    • Airdrop and Eligibility Requirements
      • Airdrop User Guide
      • Claim Page Guide
    • zNode RIZ Drop
    • $RIZ Tokenomics
    • $RIZ Staking User Guide
    • $wRIZ Staking User Guide
    • Stake to Aerodrome Liquidity Pool
    • Wrapping and Unwrapping $wRIZ User Guide
  • Roadmap
  • Official Links
Powered by GitBook
On this page
  • Step-by-step guide on how to approach building the application
  • 3. Deploy the consumer contract
  • 4. How the Meme Coin Trend Application works
  • FullCode Example
  1. ADCS - CONNECTIVITY

Dapp Example

Last updated 1 month ago

To help you better understand how a Dapp - ADCS works, let’s dive into the following example together Meme Coin Trend Application.

The Meme Coin Trend application utilizes cutting-edge AI and blockchain technology to monitor trending meme coins and analyze market data in real time. With an integrated AI agent, the platform autonomously trades meme coins using insights gathered from the ADCS network, ensuring efficient and data-driven trading decisions.

Step-by-step guide on how to approach building the application

1. Adapter Definition:

Visit to learn How to create an adaptor.

You need to define an adapter that outlines the necessary parameters.

  • Provider: Meme Coin Trend

  • Network: Base

  • Category : Meme Coin

  • Output Type : StringAndBool

  • Adaptor Name (String): Meme Coin Trend.

  • Description(String): Get a trending meme coin and make decisions which meme coin should buy.

  • Prompt: Retrieve the current trending meme coins and analyze market conditions to recommend which meme coin should be bought.

Once an adaptor is created, the system will generate a unique JobID.

Oxd7....2352 is the JobID for your Meme Coin Trend Adaptor.

2. Setup Your Consumer Contract:

Depending on the type of outputData you have defined in the adaptor, your consumer contract must inherit from the appropriate ADCS fulfillment contract. Here the outputData is StringandBool so the consumer contract will inherit the ADCSConsumerFulfillStringAndBool.

Copy

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "../ADCSConsumerFulfill.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol";
import "@uniswap/v3-periphery/contracts/interfaces/IPeripheryPayments.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
contract MockTradeMemeCoin is ADCSConsumerFulfillStringAndBool,Ownable { }

Struct

MemeCoin is a custom data type used to to represent a meme coin with three properties:

 struct MemeCoin {
        string name;
        address addr;
        uint8 decimals;
    }

Contract Variables:

The memeCoins variable represents an array of MemeCoin structs, allowing the contract to store multiple meme coins

MemeCoin[] public memeCoins 

Constructor:

constructor(
        address _coordinator,
        address _weth,
        address _swapRouter
    ) ADCSConsumerBase(_coordinator) Ownable(msg.sender) {
        WETH = _weth;
        swapRouter = ISwapRouter(_swapRouter);
    }

ADCSConsumerBase is an abstract contract that serves as the base for consumer contracts interacting with the ADCS coordinator. It initializes data requests and verifies the fulfillment.

The constructor takes the Coordinator contract's address (_coordinator) as input and passes it to the base contract. The Coordinator manages the interaction between oracles and consumers, facilitating the flow of data requests and responses.

_weth: the address of the WETH (Wrapped Ether) token contract.

_swapRouter: the address of the Uniswap V3 swap router contract, used to interact with the Uniswap decentralized exchange (DEX) to swap tokens

Different Coordinator contract addresses are provided, each tailored to handle a specific output type, such as uint256, bool, or bytes. This allows consumers to interact with oracles in a way that matches the data type of the responses they expect.

Main functions

Request Functions:

function requestTradeMemeCoin(
        bytes32 jobId,
        uint256 callbackGasLimit
    ) external returns (uint256 requestId) {
        bytes32 typeId = keccak256(abi.encodePacked("stringAndbool"));
        ADCS.Request memory req = buildRequest(jobId, typeId);
        requestId = COORDINATOR.requestData(callbackGasLimit, req);
        emit DataRequested(requestId);
        return requestId;
    }

This function Initiates a data request to the ADCS network and requests :

  • _callbackGasLimit: The maximum amount of gas a user is willing to pay for completing the function.

  • _jobId: The jobID that the consuming contract is registered to.

  • The function uses the buildRequest() function to create a request, adds the necessary parameters, and sends it to the Coordinator.

Fulfillment Functions:

function fulfillDataRequest(
        uint256 requestId,
        StringAndBool memory response
    ) internal virtual override {
        string memory tokenName = response.name;
        bool result = response.response;
        // Find memecoin address and decimals by name
        tradeMemeCoin(requestId, tokenName, result);
    }

This function is called by the ADCS coordinator to fulfill the data request and trigger a trade.

TradeMemeCoin Function:

function tradeMemeCoin(uint256 requestId, string memory tokenName, bool result) internal {
        // Find memecoin address and decimals by name
        address memeTokenAddress;
        uint8 tokenDecimals;
        for (uint i = 0; i < memeCoins.length; i++) {
            if (keccak256(bytes(memeCoins[i].name)) == keccak256(bytes(tokenName))) {
                memeTokenAddress = memeCoins[i].addr;
                tokenDecimals = memeCoins[i].decimals;
                break;
            }
        }
        if (memeTokenAddress == address(0)) {
            emit MemecoinNotFound(tokenName);
            return;
        }

        // Execute trade through Uniswap V3
        if (result) {
            // buy memecoin with eth
            IERC20(WETH).approve(address(swapRouter), wethAmountForTrade);
            swapRouter.exactInputSingle(
                ISwapRouter.ExactInputSingleParams({
                    tokenIn: WETH,
                    tokenOut: memeTokenAddress,
                    fee: 3000,
                    recipient: address(this),
                    deadline: block.timestamp + 15 minutes,
                    amountIn: wethAmountForTrade,
                    amountOutMinimum: 0,
                    sqrtPriceLimitX96: 0
                })
            );

            emit TradeSuccess(requestId, wethAmountForTrade, true);
        } else {
            // sell memecoin for eth
            // First approve router to spend our tokens
            uint256 memeCoinAmountInWei = memeCoinAmount * (10 ** tokenDecimals);
            IERC20(memeTokenAddress).approve(address(swapRouter), memeCoinAmountInWei);

            swapRouter.exactInputSingle(
                ISwapRouter.ExactInputSingleParams({
                    tokenIn: memeTokenAddress, // memecoin token
                    tokenOut: WETH, // eth
                    fee: 3000, // 0.3% fee tier
                    recipient: address(this),
                    deadline: block.timestamp + 15 minutes,
                    amountIn: memeCoinAmountInWei,
                    amountOutMinimum: 0, // Set minimum amount out to 0 (should use proper slippage in production)
                    sqrtPriceLimitX96: 0
                })
            );
            emit TradeSuccess(requestId, memeCoinAmountInWei, false);
        }
    }

The tradeMemeCoin function executes the buy or sell trade on Uniswap V3 based on the data received and triggered by the fulfillDataRequest function.

After processing the received data, the tradeMemeCoin function is called with the tokenName and the result (true/false).

  • If result is true, the contract performs a buy trade by swapping WETH (Wrapped Ether) for the specified meme coin on Uniswap V3.

  • If result is false, the contract performs a sell trade by swapping the meme coin for WETH on Uniswap V3.

addMemeCoin Function: Adds a new memecoin to the list of tradable tokens

function addMemeCoin(string memory name, address addr, uint8 decimals) external onlyOwner {
        memeCoins.push(MemeCoin({name: name, addr: addr, decimals: decimals}));
    }

setWethAmountForTrade Function: Sets the amount of WETH to use for trading.

function setWethAmountForTrade(uint256 amount) external onlyOwner {
        wethAmountForTrade = amount;
    }

3. Deploy the consumer contract

4. How the Meme Coin Trend Application works

When receiving a request from the consumer contract, the system listens for the request and then identifies an appropriate AI to process the data.

  1. The AI system processes the request, identifying the meme coin (e.g., "Shiba Inu") and making a recommendation (e.g., buy or sell).

  2. The Coordinator contract receives the result from the AI system and calls the fulfillDataRequest() function in the consumer contract, passing the processed result (token name and recommendation).

  3. The consumer contract processes the result in the fulfillDataRequest() function, which identifies the meme coin (via the name) and calls the tradeMemeCoin() function to execute the buy or sell action.

  4. The contract interacts with the Uniswap V3 router to perform the trade, and once completed, the TradeSuccess event is emitted.

FullCode Example

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "../ADCSConsumerFulfill.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol";
import "@uniswap/v3-periphery/contracts/interfaces/IPeripheryPayments.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

contract MockTradeMemeCoin is ADCSConsumerFulfillStringAndBool, Ownable {
    using ADCS for ADCS.Request;

    // Store the last received response for testing
    bytes public lastResponse;
    uint256 public lastRequestId;
    uint256 public wethAmountForTrade = 1000000000000000; // 0.001 WETH
    uint256 public memeCoinAmount = 100; // 100 memecoin

    struct MemeCoin {
        string name;
        address addr;
        uint8 decimals;
    }

    MemeCoin[] public memeCoins;

    event DataRequested(uint256 indexed requestId);
    event DataFulfilled(uint256 indexed requestId, bytes response);
    event MemecoinNotFound(string tokenName);
    event TradeSuccess(uint256 indexed requestId, uint256 amountIn, bool isBuy);

    address public immutable WETH;
    ISwapRouter public immutable swapRouter;

    constructor(
        address _coordinator,
        address _weth,
        address _swapRouter
    ) ADCSConsumerBase(_coordinator) Ownable(msg.sender) {
        WETH = _weth;
        swapRouter = ISwapRouter(_swapRouter);
    }

    function setWethAmountForTrade(uint256 amount) external onlyOwner {
        wethAmountForTrade = amount;
    }

    /**
     * @notice Add a new memecoin to the list
     * @param name The name of the memecoin
     * @param addr The contract address of the memecoin
     * @param decimals The decimals of the memecoin
     */
    function addMemeCoin(string memory name, address addr, uint8 decimals) external onlyOwner {
        memeCoins.push(MemeCoin({name: name, addr: addr, decimals: decimals}));
    }

    /**
     * @notice Get the total number of memecoins in the list
     * @return The length of the memecoins array
     */
    function getMemeCoinCount() external view returns (uint256) {
        return memeCoins.length;
    }

    /**
     * @notice Get a memecoin by index
     * @param index The index in the memecoins array
     * @return name The memecoin name
     * @return addr The memecoin contract address
     * @return decimals The decimals of the memecoin
     */
    function getMemeCoin(
        uint256 index
    ) external view returns (string memory name, address addr, uint8 decimals) {
        require(index < memeCoins.length, "Index out of bounds");
        MemeCoin memory coin = memeCoins[index];
        return (coin.name, coin.addr, coin.decimals);
    }

    // Function to request bytes data
    function requestTradeMemeCoin(
        bytes32 jobId,
        uint256 callbackGasLimit
    ) external returns (uint256 requestId) {
        bytes32 typeId = keccak256(abi.encodePacked("stringAndbool"));
        ADCS.Request memory req = buildRequest(jobId, typeId);
        requestId = COORDINATOR.requestData(callbackGasLimit, req);
        emit DataRequested(requestId);
        return requestId;
    }

    function fulfillDataRequest(
        uint256 requestId,
        StringAndBool memory response
    ) internal virtual override {
        string memory tokenName = response.name;
        bool result = response.response;
        // Find memecoin address and decimals by name
        tradeMemeCoin(requestId, tokenName, result);
    }

    function tradeMemeCoin(uint256 requestId, string memory tokenName, bool result) internal {
        // Find memecoin address and decimals by name
        address memeTokenAddress;
        uint8 tokenDecimals;
        for (uint i = 0; i < memeCoins.length; i++) {
            if (keccak256(bytes(memeCoins[i].name)) == keccak256(bytes(tokenName))) {
                memeTokenAddress = memeCoins[i].addr;
                tokenDecimals = memeCoins[i].decimals;
                break;
            }
        }
        if (memeTokenAddress == address(0)) {
            emit MemecoinNotFound(tokenName);
            return;
        }

        // Execute trade through Uniswap V3
        if (result) {
            // buy memecoin with eth
            IERC20(WETH).approve(address(swapRouter), wethAmountForTrade);
            swapRouter.exactInputSingle(
                ISwapRouter.ExactInputSingleParams({
                    tokenIn: WETH,
                    tokenOut: memeTokenAddress,
                    fee: 3000,
                    recipient: address(this),
                    deadline: block.timestamp + 15 minutes,
                    amountIn: wethAmountForTrade,
                    amountOutMinimum: 0,
                    sqrtPriceLimitX96: 0
                })
            );

            emit TradeSuccess(requestId, wethAmountForTrade, true);
        } else {
            // sell memecoin for eth
            // First approve router to spend our tokens
            uint256 memeCoinAmountInWei = memeCoinAmount * (10 ** tokenDecimals);
            IERC20(memeTokenAddress).approve(address(swapRouter), memeCoinAmountInWei);

            swapRouter.exactInputSingle(
                ISwapRouter.ExactInputSingleParams({
                    tokenIn: memeTokenAddress, // memecoin token
                    tokenOut: WETH, // eth
                    fee: 3000, // 0.3% fee tier
                    recipient: address(this),
                    deadline: block.timestamp + 15 minutes,
                    amountIn: memeCoinAmountInWei,
                    amountOutMinimum: 0, // Set minimum amount out to 0 (should use proper slippage in production)
                    sqrtPriceLimitX96: 0
                })
            );
            emit TradeSuccess(requestId, memeCoinAmountInWei, false);
        }
    }

    receive() external payable {}

    function withdraw() external onlyOwner {
        payable(owner()).transfer(address(this).balance);
    }

    function withdrawToken(address token) external onlyOwner {
        IERC20(token).transfer(owner(), IERC20(token).balanceOf(address(this)));
    }
}

After defining all necessary functions, the global state, and the Coordinator contract for your consumer contract, the next step is to deploy the contract to the blockchain. .

We've also built some examples to help you easily understand what you can do with ADCS network .

Learn more here
here
here