KRNL Platform Guidebook
KRNL Platformkrnl.xyz
  • Introduction
    • Introduction
    • How Does kOS Work?
  • Setup
    • Getting Started with KRNL
    • Quick Start (CLI)
    • Quick Start (Online IDE)
      • Quick Start (Remix IDE)
      • Quick Start (Atlas IDE)
    • create-krnl-app
    • Platform Registration
  • Kernel
    • What are Kernels?
    • Kernel Registration
      • Kernel Registration (on-chain)
      • Kernel Registration (off-chain)
    • Supported OpenAPI (Off-chain Kernel)
    • Staking
  • Smart Contract
    • Steps for Smart Contract Developers
    • Choosing Kernel(s)
    • Token Authority
      • What is a Token Authority?
      • How to Build a Token Authority?
      • Generic Token Authority
      • How to Deploy a Token Authority on Oasis?
    • Decoding Kernel Responses in Solidity
    • How to Integrate Your Smart Contract with kOS?
    • Smart Contract Registration
  • DApp
    • dApp Registration
    • KRNL SDK Installation
    • Usage
    • KRNL Node RPC
  • Miscellaneous
    • Overview
    • What is the KRNL Platform?
    • What are You Trying to BUIDL?
    • Smart Contract Fundamentals
      • Why Do I Have to Register a Smart Contract?
      • How to Deploy a Smart Contract?
    • Recommended Kernels List
  • Helpful Resources
    • New to Web3?
    • Dictionary
    • Testnet Faucets
    • How to Get Etherscan API Key?
  • Litepaper
    • Litepaper
      • Overview
      • Problem Statement
      • Current State Does Not Solve the Problem
      • Introducing Kernels
      • Ecosystem of Kernels
      • The KRNL Operating System (kOS)
      • Decentralization and Security Considerations
      • Use Cases for KRNL
  • Appendices
    • FAQ
    • Bounty Program
    • Social Medias
    • Thank You
  • Workshop
    • KRNL Workshop
Powered by GitBook
On this page
  • Disclaimer
  • Prerequisites
  • Goal
  • Kernel
  • Kernel A (Exchange Rate)
  • Kernel B (Allowlist)
  • Smart Contract
  • dApp
  • Result
  • Bounty
  • Other Resources
  • Helper *wink wink*

Was this helpful?

  1. Workshop

Speed's Workshop

Last updated 18 days ago

Was this helpful?

Disclaimer

The content of this page may be updated over time. Therefore, it is more important to understand how kOS functions than to remember the specific steps for using our technology from this page.


Prerequisites

Wallet & Network

  1. Sepolia

  1. Oasis Sapphire testnet

  1. Arbitrum Sepolia

Funds

  • SepoliaETH token ≈ 0.1 SepoliaETH

  • Oasis Sapphire testnet token ≈ 0.6 TEST

  • Arbitrum Sepolia token ≈ 0.1 ETH (or else)

Testnet Faucets

Etherscan API Key & Arbiscan API Key

How to Get Etherscan API Key?

How Does kOS Work?

How Does kOS Work?

Overview

Overview

Goal

Speed will walk through the overall setup.

This guide focuses on how to secure the bounty reward. *wink wink* 😉😉


Kernel

Information for Remix verification plug-in

API URL
https://api-sepolia.arbiscan.io/

Explorer URL
https://sepolia.arbiscan.io

Kernel A (Exchange Rate)

Exchange.sol

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.24;

contract Exchange {
    
    // From 1st of April 2025
    uint256 ethToUsdc = 1834; // static value, the real oracle exchange rate would be dynamic based on time

    function getExchangeRate() view external returns (uint256) {
        // This is just a mocking code for fetching data from an oracle source.
        // The actual production grade code would have more security checks/layers.
        // However, in this workshop, we are going to simplify pretty much all the logics of oracle code.
        // Things would then be cut-down into just returning the exchange rate.
        return ethToUsdc;
    }
}

Deploy

In this workshop, we will use Arbitrum Sepolia (chain ID 421614) network.

You may choose to deploy on other networks such as Base Sepolia, Optimism Sepolia, or Sepolia.

Register

Kernel B (Allowlist)

Allowlist.sol

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.24;

contract Allowlist {

    // Declare mapping in Solidity
    // Some people might call this mapping as:
    // dict (Python)
    // map (JavaScript)
    // hash (Ruby)
    mapping (address => bool) private allowMapping;

    // "checkAllowlist" will be registered as on-chain kernel
    function checkAllowlist(address walletAddressInput) view external returns (bool) {
        // Simple logic to check if your wallet address is in Allowlist or not
        if (allowMapping[walletAddressInput] == true) {
            return true;
        } else {
            return false;
        }
    }

    // For registering yourself to be in Allowlist
    function registerAllowlist() external {
        allowMapping[msg.sender] = true;
    }
}

Deploy

In this workshop, we will use Arbitrum Sepolia (chain ID 421614) network.

You may choose to deploy on other networks such as Base Sepolia, Optimism Sepolia, or Sepolia.

Register

Add yourself to the Allowlist

https://sepolia.arbiscan.io/address/0x123

Smart Contract

Clone Template

git clone https://github.com/KRNL-Labs/krnl-toolkit.git

Fill .env (especially on KERNEL_ID part)


ETHERSCAN_API_KEY= # REQUIRED

# PRIVATE KEYS; they can be the same private key
PRIVATE_KEY_OASIS= # REQUIRED; no need 0x prefix, can be the same as Sepolia
PRIVATE_KEY_SEPOLIA= # REQUIRED; no need 0x prefix, can be the same as Oasis

# SELECTED KERNEL IDS FOR REGISTERING SMART CONTRACT
# KERNEL_ID=337, 123, 456
KERNEL_ID=337 <<<<<<<<<<<<<< CHANGE THIS TO BE THE ONES THAT YOU REGISTERED





# OPTIONAL
INFURA_PROJECT_ID= # OPTIONAL FOR SEPOLIA

Modify TokenAuthority.sol

Directory: krnl-toolkit/smart-contracts/hardhat/contracts

TokenAuthority.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol";
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import "@oasisprotocol/sapphire-contracts/contracts/Sapphire.sol";
import "@oasisprotocol/sapphire-contracts/contracts/EthereumUtils.sol";
// ===============================
// Search for "HERE"
// ===============================

contract TokenAuthority is Ownable {
    Keypair private signingKeypair;
    Keypair private accessKeypair;
    bytes32 private signingKeypairRetrievalPassword;
    // https://api.docs.oasis.io/sol/sapphire-contracts/contracts/Sapphire.sol/library.Sapphire.html#secp256k1--secp256r1
    struct Keypair {
        bytes pubKey;
        bytes privKey;
    }
    struct Execution {
        uint256 kernelId;
        bytes result;
        bytes proof;
        bool isValidated;
        bool opinion;
        string opinionDetails;
        string err;
    }

    mapping(address => bool) private whitelist; // krnlNodePubKey to bool
    mapping(bytes32 => bool) private runtimeDigests; // runtimeDigest to bool
    mapping(uint256 => bool) private kernels; // kernelId to bool

    constructor(address initialOwner) Ownable(initialOwner) {
        signingKeypair = _generateKey();
        accessKeypair = _generateKey();
        
        // HERE
        // Set allowed kernel(s)
        // kernels[REPLACE_WITH_KERNEL_ID] = true;
        // kernels[REPLACE_WITH_KERNEL_ID] = true

        // Set node whitelist
        whitelist[address(0xc770EAc29244C1F88E14a61a6B99d184bfAe93f5)] = true;
        // Set runtime digest
        runtimeDigests[
            0x876924e18dd46dd3cbcad570a87137bbd828a7d0f3cad309f78ad2c9402eeeb7
        ] = true;
        // v0.0.3
        runtimeDigests[
            0xa02c15786858a1b8ac0c421f451b5dc0e5e370c4c1d738a9fc9c1c141979da21
        ] = true;
    }

    modifier onlyAuthorized(bytes calldata auth) {
        (
            bytes32 entryId,
            bytes memory accessToken,
            bytes32 runtimeDigest,
            bytes memory runtimeDigestSignature,
            uint256 nonce,
            uint256 blockTimeStamp,
            bytes memory authSignature
        ) = abi.decode(
                auth,
                (bytes32, bytes, bytes32, bytes, uint256, uint256, bytes)
            );
        require(_verifyAccessToken(entryId, accessToken));
        _;
    }
    modifier onlyValidated(bytes calldata executionPlan) {
        require(_verifyExecutionPlan(executionPlan));
        _;
    }
    modifier onlyAllowedKernel(uint256 kernelId) {
        require(kernels[kernelId]);
        _;
    }


    function _validateExecution(
        bytes calldata executionPlan
    ) external view returns (bytes memory) {
        Execution[] memory _executions = abi.decode(
            executionPlan,
            (Execution[])
        );

        for (uint256 i = 0; i < _executions.length; i++) {
            // HERE
            _executions[i].isValidated = true;
            _executions[i].opinion = true;
        }
        
        return abi.encode(_executions);
    }

    function _generateKey() private view returns (Keypair memory) {
        bytes memory seed = Sapphire.randomBytes(32, "");
        (bytes memory pubKey, bytes memory privKey) = Sapphire
            .generateSigningKeyPair(
                Sapphire.SigningAlg.Secp256k1PrehashedKeccak256,
                seed
            );
        return Keypair(pubKey, privKey);
    }

    function _verifyAccessToken(
        bytes32 entryId,
        bytes memory accessToken
    ) private view returns (bool) {
        bytes memory digest = abi.encodePacked(keccak256(abi.encode(entryId)));
        return
            Sapphire.verify(
                Sapphire.SigningAlg.Secp256k1PrehashedKeccak256,
                accessKeypair.pubKey,
                digest,
                "",
                accessToken
            );
    }

    function _verifyRuntimeDigest(
        bytes32 runtimeDigest,
        bytes memory runtimeDigestSignature
    ) private view returns (bool) {
        address recoverPubKeyAddr = ECDSA.recover(
            runtimeDigest,
            runtimeDigestSignature
        );
        return whitelist[recoverPubKeyAddr];
    }

    function _verifyExecutionPlan(
        bytes calldata executionPlan
    ) private pure returns (bool) {
        Execution[] memory executions = abi.decode(
            executionPlan,
            (Execution[])
        );
        for (uint256 i = 0; i < executions.length; i++) {
            if (!executions[i].isValidated) {
                return false;
            }
        }
        return true;
    }

    function _getFinalOpinion(
        bytes calldata executionPlan
    ) private pure returns (bool) {
        Execution[] memory executions = abi.decode(
            executionPlan,
            (Execution[])
        );
        for (uint256 i = 0; i < executions.length; i++) {
            if (!executions[i].opinion) {
                return false;
            }
        }
        return true;
    }

    function setSigningKeypair(
        bytes calldata pubKey,
        bytes calldata privKey
    ) external onlyOwner {
        signingKeypair = Keypair(pubKey, privKey);
    }

    function setSigningKeypairRetrievalPassword(
        string calldata _password
    ) external onlyOwner {
        signingKeypairRetrievalPassword = keccak256(
            abi.encodePacked(_password)
        );
    }

    function getSigningKeypairPublicKey()
        external
        view
        returns (bytes memory, address)
    {
        address signingKeypairAddress = EthereumUtils
            .k256PubkeyToEthereumAddress(signingKeypair.pubKey);
        return (signingKeypair.pubKey, signingKeypairAddress);
    }

    function getSigningKeypairPrivateKey(
        string calldata _password
    ) external view onlyOwner returns (bytes memory) {
        require(
            signingKeypairRetrievalPassword ==
                keccak256(abi.encodePacked(_password))
        );
        return signingKeypair.privKey;
    }

    function setWhitelist(
        address krnlNodePubKey,
        bool allowed
    ) external onlyOwner {
        whitelist[krnlNodePubKey] = allowed;
    }

    function setRuntimeDigest(
        bytes32 runtimeDigest,
        bool allowed
    ) external onlyOwner {
        runtimeDigests[runtimeDigest] = allowed;
    }

    function setKernel(uint256 kernelId, bool allowed) external onlyOwner {
        kernels[kernelId] = allowed;
    }

    function registerdApp(
        bytes32 entryId
    ) external view returns (bytes memory) {
        bytes memory digest = abi.encodePacked(keccak256(abi.encode(entryId)));
        bytes memory accessToken = Sapphire.sign(
            Sapphire.SigningAlg.Secp256k1PrehashedKeccak256,
            accessKeypair.privKey,
            digest,
            ""
        );
        return accessToken;
    }

    function isKernelAllowed(
        bytes calldata auth,
        uint256 kernelId
    ) external view onlyAuthorized(auth) returns (bool) {
        // HERE
        // All kernels are allowed
        // Not recommended for production
        return true;
    }

    // example use case: only give 'true' opinion when all kernels are executed with expected results and proofs
    function getOpinion(
        bytes calldata auth,
        bytes calldata executionPlan
    ) external view onlyAuthorized(auth) returns (bytes memory) {
        try this._validateExecution(executionPlan) returns (
            bytes memory result
        ) {
            return result;
        } catch {
            return executionPlan;
        }
    }

    function sign(
        bytes calldata auth,
        address senderAddress,
        bytes calldata executionPlan,
        bytes calldata functionParams,
        bytes calldata kernelParams,
        bytes calldata kernelResponses
    )
        external
        view
        onlyValidated(executionPlan)
        onlyAuthorized(auth)
        returns (bytes memory, bytes32, bytes memory, bool)
    {
        (
            bytes32 id,
            bytes memory accessToken,
            bytes32 runtimeDigest,
            bytes memory runtimeDigestSignature,
            uint256 nonce,
            uint256 blockTimeStamp,
            bytes memory authSignature // id, accessToken, runtimeDigest, runtimeDigestSignature, nonce, blockTimeStamp, authSignature
        ) = abi.decode(
                auth,
                (bytes32, bytes, bytes32, bytes, uint256, uint256, bytes)
            );
        // Compute kernelResponsesDigest
        bytes32 kernelResponsesDigest = keccak256(
            abi.encodePacked(kernelResponses, senderAddress)
        );
        bytes memory kernelResponsesSignature = Sapphire.sign(
            Sapphire.SigningAlg.Secp256k1PrehashedKeccak256,
            signingKeypair.privKey,
            abi.encodePacked(kernelResponsesDigest),
            ""
        );
        (, SignatureRSV memory kernelResponsesRSV) = EthereumUtils
            .toEthereumSignature(
                signingKeypair.pubKey,
                kernelResponsesDigest,
                kernelResponsesSignature
            );
        bytes memory kernelResponsesSignatureEth = abi.encodePacked(
            kernelResponsesRSV.r,
            kernelResponsesRSV.s,
            uint8(kernelResponsesRSV.v)
        );
        bytes32 functionParamsDigest = keccak256(functionParams);
        // Compute kernelParamsDigest
        bytes32 kernelParamsDigest = keccak256(
            abi.encodePacked(kernelParams, senderAddress)
        );
        bool finalOpinion = _getFinalOpinion(executionPlan);
        // Compute dataDigest
        bytes32 dataDigest = keccak256(
            abi.encodePacked(
                functionParamsDigest,
                kernelParamsDigest,
                senderAddress,
                nonce,
                finalOpinion
            )
        );
        bytes memory signature = Sapphire.sign(
            Sapphire.SigningAlg.Secp256k1PrehashedKeccak256,
            signingKeypair.privKey,
            abi.encodePacked(dataDigest),
            ""
        );
        (, SignatureRSV memory rsv) = EthereumUtils.toEthereumSignature(
            signingKeypair.pubKey,
            dataDigest,
            signature
        );
        bytes memory signatureToken = abi.encodePacked(
            rsv.r,
            rsv.s,
            uint8(rsv.v)
        );
        return (
            kernelResponsesSignatureEth,
            kernelParamsDigest,
            signatureToken,
            finalOpinion
        );
    }
}

Modify Sample.sol

Sample.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.24;

import {KRNL, KrnlPayload, KernelParameter, KernelResponse} from "./KRNL.sol";

// This contract uses Mocking ETH and Mocking USDC
// The Mocking ETH and Mocking USDC are just numbers in this contact
// You will not lose any real ETH or USDC by using this contract
// The tokens are not ERC-20, they are just numbers in this contract
// In order to submit our bounty reward, you may take this contract as an example
// However, the code will need to be more robust and secure

contract Sample is KRNL {
    // Token Authority public key as a constructor
    constructor(address _tokenAuthorityPublicKey) KRNL(_tokenAuthorityPublicKey) {}

    // Results from kernel will be emitted through this event
    event Broadcast(address sender, uint256 exchangeRate, bool allowlist);

    // Mapping to store the balance of Mocking USDC for wallet address
    mapping (address => uint256) public balanceList;

    // Protected function
    function protectedFunction(
        KrnlPayload memory krnlPayload,
        uint256 input
    )
        external
        onlyAuthorized(krnlPayload, abi.encode(input))
    {
        // Decode response from kernel
        KernelResponse[] memory kernelResponses = abi.decode(krnlPayload.kernelResponses, (KernelResponse[]));
        
        // Response variables for kernels
        uint256 exchangeRate;
        bool allowlist;

        // Decoding exchange rate and allowlist from kernels
        for (uint i; i < kernelResponses.length; i ++) {
            // HERE
            if (kernelResponses[i].kernelId == REPLACE_WITH_EXCHANGE_RATE_KERNEL_ID) {
                exchangeRate = abi.decode(kernelResponses[i].result, (uint256));
            }
            // HERE
            if (kernelResponses[i].kernelId == REPLACE_WITH_ALLOWLIST_KERNEL_ID) {
                allowlist = abi.decode(kernelResponses[i].result, (bool));
            }
        }
        // End of decoding kernel responses

        // Checking if wallet address is in allowlist or not
        if (allowlist == true) {
            // If yes, the Mocking ETH token will be converted to Mocking USDC
            balanceList[msg.sender] = balanceList[msg.sender] + (input * exchangeRate);
        }

        // If wallet address is not in Allowlist, we still emit the event
        // The kernel responses can still be seen in the event logs
        emit Broadcast(msg.sender, exchangeRate, allowlist);
    }

    // Function to see the balance of Mocking USDC
    function seeUsdcBalance(address walletAddressToCheckBalance) external view returns (uint256) {
        return balanceList[walletAddressToCheckBalance];
    }
}

Install Dependencies

npm install

Deploy, Verify, and Register

npm run hdvr

Output

...
...
...
======================================
=====SUMMARY=====
Registered Smart Contract ID:  789789
dApp ID:  123456
Please visit this page for Entry ID, Access Token, and Kernel Payload

 https://app.platform.lat/dapp/123456

Tips 1: Entry ID and Access Token are similar to x-api-key or Bearer Token of Web2
Tips 2: Kernel Payload is the template of parameter(s) that needs to be sent to kernel ID(s): [ 1111, 2222 ]
======================================

dApp

Next.js (TypeScript)

Create Next.js (TypeScript)

npx create-next-app@latest

Install KRNL SDK

npm install krnl-sdk

Then paste this code in src/app/page.tsx

'use client'
import { ethers } from "krnl-sdk";
import { useState } from "react";

export default function Home() {
    const entryId = "REPLACE_WITH_ENTRY_ID"
    const accessToken = "REPLACE_WITH_ACCESS_TOKEN"
    const deployedContractAddress = "REPLACE_WITH_DEPLOYED_CONTRACT_ADDRESS"
    const exchangeKernelId = "REPLACE_WITH_EXCHANGE_KERNEL_ID"
    const allowlistKernelId = "REPLACE_WITH_ALLOWLIST_KERNEL_ID"
    const amountOfEthToConvertToUsdc = 10 // or any amount that you need

    const abiCoder = new ethers.AbiCoder();

    const [isConnected, setIsConnected] = useState(false);
    const [signer, setSigner] = useState<ethers.JsonRpcSigner | null>(null);
    const [walletAddress, setWalletAddress] = useState<string | null>(null);
    const [transactionHash, setTransactionHash] = useState<string | null>(null);
    const [transactionAttempted, setTransactionAttempted] = useState(false);
    const [chainId, setChainId] = useState<bigint | null>(null);
    const [encodedWalletAddress, setEncodedWalletAddress] = useState<string | null>(null);
    
    const connectWallet = async () => {
      const provider = new ethers.BrowserProvider(window.ethereum);
      const signer = await provider.getSigner();
      const signerAddress = await signer.getAddress();
      const chainId = await provider.getNetwork();
      const encodedWalletAddress = abiCoder.encode(["address"], [`${signerAddress}`]);
      setChainId(chainId.chainId);
      setIsConnected(true);
      setSigner(signer);
      setWalletAddress(signerAddress);
      setEncodedWalletAddress(encodedWalletAddress);
    }

    const disconnectWallet = async () => {
        setIsConnected(false);
        setSigner(null);
        setWalletAddress(null);
        setChainId(null);
        setEncodedWalletAddress(null);
    }

    const functionParams = abiCoder.encode(["uint256"], [amountOfEthToConvertToUsdc]);

    const krnlNodeProvider = new ethers.JsonRpcProvider("https://v0-0-3-rpc.node.lat");

    const functionInterface = new ethers.Interface([
        "function protectedFunction(tuple(bytes auth, bytes kernelResponses, bytes kernelParams),uint256)"
    ]);

    const makeTransaction = async () => {
        setTransactionAttempted(true);
        if (!signer) {
            console.log("No signer found");
            return;
        }
        console.log("STARTING MAKING TRANSACTION")

        const kernelRequestData: any = {
            "senderAddress": `${walletAddress}`,
            "kernelPayload": {
                [allowlistKernelId]: {
                    "functionParams": `${encodedWalletAddress}`
                },
                [exchangeKernelId]: {
                    "functionParams": ""
                }
            }
        }
        console.log("CALLING executeKernels")
        const executeResult = await krnlNodeProvider.executeKernels(entryId,
                                                                accessToken,
                                                                kernelRequestData,
                                                                functionParams);
        console.log("SUCCESS executeKernels")
        const krnlPayload = [
            executeResult.auth,
            executeResult.kernel_responses,
            executeResult.kernel_params
        ];
        console.log("CALLING TO SMART CONTRACT")
        const txPayload = functionInterface.encodeFunctionData("protectedFunction", [krnlPayload, 10]);

        const tx = await signer.sendTransaction({
            to: deployedContractAddress,
            data: txPayload
        });
        const transactionHash = await tx.wait();
        console.log("TRANSACTION FINISHED")
        setTransactionHash(transactionHash?.hash || null);
    }
    
    return (
        <div>
            <h1>dApp template</h1>
            <br/>
            <h1>
                Wallet: {isConnected ? walletAddress : "Not Connected"}
            </h1>
            <br/>
            <h1>
                Chain ID: {chainId ? chainId : "Not Connected"}
            </h1>
            <br/>
            <button onClick={isConnected ? disconnectWallet : connectWallet}>
                {isConnected ? "Disconnect Wallet" : "Connect Wallet"}
            </button>
            <br/>
            <br/>
            <button onClick={makeTransaction}>Make Transaction</button>
            {transactionAttempted && (
                <h1>
                    Transaction Hash: {transactionHash ? transactionHash : "Making Transaction..."}
                </h1>
            )}
        </div>
    )
}

Run dApp

npm run dev
KRNL Sandbox (for simplicity)

https://sandbox.platform.lat/krnlflow

Custom - User Defined Contract

Custom - User Defined Contract

Smart Contract Address
YOUR_SMART_CONTRACT_ADDRESS

Function Signature
protectedFunction(KrnlPayload,uint256)

RpcEndpoint
https://v0-0-3-rpc.node.lat

EntryID
YOUR_ENTRY_ID

Access Token
YOUR_ACCESS_TOKEN

Kernel Request Data
{
  "senderAddress": "0xYOUR_WALLET_ADDRESS",
  "kernelPayload": {
    "CHANGE_TO_ALLOWLIST_KERNEL_ID": {
      "functionParams": "0x000000000000000000000000REPLACE_WITH_WALLET_ADDRESS_NO_0x"
    },
    "CHANGE_TO_EXCHANGE_RATE_KERNEL_ID": {
      "functionParams": ""
    }
  }
}

Function Params
Any positive number

Result

How Does kOS Work?

Bounty

Bounty Program

Other Resources

Litepaper

Litepaper

Kernel

For integrating Web API with kOS

Supported OpenAPI (Off-chain Kernel)

For other on-chain kernels, the supported blockchain networks (current):

  • Ethereum (mainnet)

  • Sepolia

  • Base

  • Base Sepolia

  • Optimism

  • Optimism Sepolia

  • Arbitrum

  • Arbitrum Sepolia

Smart Contract

Decoding different data types (from kernel responses) with Solidity

Decoding Kernel Responses in Solidity

Already have your own Solidity smart contract?

How to Integrate Your Smart Contract with kOS?

dApp

Usage

Helper *wink wink*

You may use this idea to apply for bounty.

This entire kOS flow is not good because:

  • Exchange rate kernel (oracle) is static

  • Allowlist kernel (KYC) does not contain any security check/proof

  • Token Authority allows all kernels without any restriction

  • Smart contract (Sample.sol) convert numbers and not ERC-20 token(s)

  • dApp is very static (fixed amount of Mock ETH to convert)

  • dApp's interface looks plain

  • There might be some mistakes/vulnerabilities in some part of the code

Oasis Sapphire Testnet RPC and Chain settings | ChainList
Bridge to Sepolia
https://app.platform.lat/kernelapp.platform.lat
https://app.platform.lat/kernelapp.platform.lat
Logo
Arbitrum Sepolia RPC and Chain settings | ChainList
Arbitrum (ETH) Blockchain ExplorerArbitrum (ETH) Blockchain Explorer
Logo
Logo
Logo