Trustus
Trust-minimized method for accessing offchain data onchain. No, it's not a joke project.
Introduction
Suppose we have:
- A server with an API that provides some useful information (e.g. the weather in Philedelphia today)
- A smart contract that wants to access said information from the server
How can we implement it? How can we let the smart contract access the offchain data from the server?
One way to do it is to use Chainlink to make an HTTP GET request to the server, but this is terrible!
- We need to rely on Chainlink nodes, whose level of centralization is rather controversial
- We need to hold LINK tokens in the contract and pay the nodes for each request
- We need to implement a callback pattern, which is asynchronous and messy
Trustus offers a superior solution that is trust-minimized. Trustus-powered contracts do not rely on any third-party network of nodes, nor do they need to make payments for the requests or implement a callback pattern. The only centralized & trusted component is the server, which has to be trusted anyways, hence the term "trust-minimized".
How is this achieved? Two caveats:
- The server must implement the specific standard used by Trustus to format the data packet, as well as provide an ECDSA signature that verifies the data packet originated from the trusted server.
- The smart contract should take in the signed data packet as an input of the function that requires the offchain data and verify its validity. The contract should also keep track of which addresses are trusted to sign the data packets.
The userflow of a call to a Trustus-power smart contract looks like this:
- The user makes a request to the server to fetch the desired offchain data.
- The server returns the data packet as well as a signature signed using the server's public key, which should already registered as trusted by the smart contract.
- The user calls the smart contract, providing the data packet & signature as input.
- The smart contract verifies & consumes the data packet, and uses the offchain data during the call.
Installation
To install with DappTools:
dapp install zeframlou/trustus
To install with Foundry:
forge install zeframlou/trustus
Local development
This project uses Foundry as the development framework.
Dependencies
make install
Compilation
make build
Testing
make test
Signature generation
Trustus uses EIP-712 for signing structured data. The following is an example of signature generation using ethers.js.
const ethers = require("ethers");
const signer = ethers.Wallet.createRandom();
const domain = {
name: "Trustus",
version: "1",
chainId: 1, // ethereum mainnet
verifyingContract: "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC", // change to your Trustus contract's address
};
const types = {
VerifyPacket: [
{ name: "request", type: "bytes32" },
{ name: "deadline", type: "uint256" },
{ name: "payload", type: "bytes" },
],
};
// The data to sign
const value = {
request: ethers.utils.keccak256(
ethers.utils.toUtf8Bytes("MyRequest(string)")
), // identifier for different types of requests your Trustus contract specifies
deadline: Math.floor(Date.now() + 600), // 10 minutes in the future
payload: ethers.utils.toUtf8Bytes("Hello world!"),
};
const signature = await signer._signTypedData(domain, types, value);
console.log(signature);