6.4 KiB
		
	
	
	
	
	
	
	
			
		
		
	
	GM! 🤠
In this tutorial we'll make a very simple consumer contract called SaysGm.
All this contract does is request compute from our hello-world container and
upon receiving a response, it prints everything to the console.
Note
Run this tutorial in a new directory, the end result of this tutorial will be pretty much the same as the contracts project, so refer to that if you get stuck.
Prerequisites
Installing foundry
You'll need foundry installed.
Scaffolding a new project
Create a new directory, and run forge init in it. This will create a new
project with a foundry.yaml file in it.
mkdir says-gm
cd says-gm
forge init
Installing Infernet sdk
Install our Infernet SDK via forge.
forge install ritual-net/infernet-sdk
Specifying remappings
Create a new file called remappings.txt in the root of your project.
forge-std/=lib/forge-std/src
infernet-sdk/=lib/infernet-sdk/src
This'll make it easier to import our dependencies. More explanation on remappings here.
SaysGm contract
Under the src/ directory, create a new file called SaysGm.sol with the following content:
// SPDX-License-Identifier: BSD-3-Clause-Clear
pragma solidity ^0.8.13;
import {console2} from "forge-std/console2.sol";
import {CallbackConsumer} from "infernet-sdk/consumer/Callback.sol";
contract SaysGM is CallbackConsumer {
    constructor(address coordinator) CallbackConsumer(coordinator) {}
    function sayGM() public {
        _requestCompute(
            "hello-world",
            bytes("Good morning!"),
            20 gwei,
            1_000_000,
            1
        );
    }
    function _receiveCompute(
        uint32 subscriptionId,
        uint32 interval,
        uint16 redundancy,
        address node,
        bytes calldata input,
        bytes calldata output,
        bytes calldata proof
    ) internal override {
        console2.log("\n\n"
        "_____  _____ _______ _    _         _\n"
        "|  __ \\|_   _|__   __| |  | |  /\\   | |\n"
        "| |__) | | |    | |  | |  | | /  \\  | |\n"
        "|  _  /  | |    | |  | |  | |/ /\\ \\ | |\n"
        "| | \\ \\ _| |_   | |  | |__| / ____ \\| |____\n"
        "|_|  \\_\\_____|  |_|   \\____/_/    \\_\\______|\n\n");
        console2.log("subscription Id", subscriptionId);
        console2.log("interval", interval);
        console2.log("redundancy", redundancy);
        console2.log("node", node);
        console2.log("input:");
        console2.logBytes(input);
        console2.log("output:");
        console2.logBytes(output);
        console2.log("proof:");
        console2.logBytes(proof);
    }
}
All this contract does is request compute from our hello-world container via the _requestCompute function.
An Infernet node will pick up this subscription, execute the compute, and deliver the result to our contract via
the _receiveCompute function.
Adding a Deploy Script
In the scripts directory, add a new file called Deploy.s.sol:
// SPDX-License-Identifier: BSD-3-Clause-Clear
pragma solidity ^0.8.13;
import {Script, console2} from "forge-std/Script.sol";
import {SaysGM} from "../src/SaysGM.sol";
contract Deploy is Script {
    function run() public {
        // Setup wallet
        uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
        vm.startBroadcast(deployerPrivateKey);
        // Log address
        address deployerAddress = vm.addr(deployerPrivateKey);
        console2.log("Loaded deployer: ", deployerAddress);
        address coordinator = 0x5FbDB2315678afecb367f032d93F642f64180aa3;
        // Create consumer
        SaysGM saysGm = new SaysGM(coordinator);
        console2.log("Deployed SaysHello: ", address(saysGm));
        // Execute
        vm.stopBroadcast();
        vm.broadcast();
    }
}
The coordinator address is the address of the Infernet coordinator. Our
Infernet Anvil Node already has Coordinator pre-deployed to that address.
Adding a Call Script
Create another file under the script directory called CallContract.s.sol
// SPDX-License-Identifier: BSD-3-Clause-Clear
pragma solidity ^0.8.0;
import {Script, console2} from "forge-std/Script.sol";
import {SaysGM} from "../src/SaysGM.sol";
contract CallContract is Script {
    function run() public {
        // Setup wallet
        uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
        vm.startBroadcast(deployerPrivateKey);
        SaysGM saysGm = SaysGM(0x663F3ad617193148711d28f5334eE4Ed07016602);
        saysGm.sayGM();
        vm.stopBroadcast();
    }
}
Building the Project
Before building our project, we'll need to add this line to the foundry.toml file:
via_ir = true
So your foundry.toml file should look like this. Otherwise the compiler will complain
about stack too deep errors.
Now, let's build our project.
forge build
The project should build successfully.
Deploying the Contracts
Deploy Infernet
To deploy our contracts, and later be able to call and test them, we'll need to deploy infernet, as well as
our hello-world container! Refer to the readme at the root of this project for instructions on how
to do that.
After deploying an Infernet Node locally, we'll need to run the Deploy script.
PRIVATE_KEY=0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a \
  forge script script/Deploy.s.sol:Deploy --broadcast \
  --rpc-url http://localhost:8545
The private key here is anvil's anvil's third default address which contains 10000 ETH.
Calling the Contract
Similarly, to run our CallContract.s.sol script, we'll invoke it with forge script:
PRIVATE_KEY=0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a \
  forge script script/CallContract.s.sol:Deploy --broadcast \
  --rpc-url http://localhost:8545
Using a Makefile
To make running these commands easier, we can add them to a Makefile. This allows
us to run make deploy and make call instead of typing out the full command every time.
Refer to this project's Makefile for an example.
🎉 Done!
Congratulations! You've successfully created a contract that requests compute from
our hello-world container.