Alluo Explained
  • Welcome
    • 🧭 The Basics
  • Getting Started
    • πŸ’» The DeFi Web App
      • ❓ Connecting to the app
      • 🚜 Depositing into the farms
      • πŸ™Œ Other basics
      • 🏦 Importing your Mobile app wallet to Metamask
      • 🧬 Add the polygon network manually in Metamask.
      • ⛓️ Bridging Stablecoins from another chain
    • πŸ“±The Mobile app
      • πŸ—οΈ Setting up your account
      • 🏦 Depositing money into the app
      • πŸ™Œ Other basics
      • πŸ” Exporting your private key
    • πŸ“–Tech deep dive: Contract Address Library
  • Understanding Alluo
    • πŸ’΅ How does Alluo get the yield?
      • 🐰 Going deeper into the Alluo protocol rabbit hole
    • 🧐 FAQ
  • Tokens & Tokenomics
    • πŸͺ™ The tokens
    • πŸ‘¨β€πŸ”¬Tech deep dive: Interest Bearing {asset} token
      • Depositing
      • Withdrawals
      • IbAlluo on different chains
      • StIbAlluo and Superfluid
        • A closer look at the integration between IbAlluo and StIbAlluo
      • Using the IbAlluo contract directly to create streams
      • Liquidity Handler and adapters
        • Deposit process with the Liquidity Handler
        • Withdraw process with the Liquidity Handler
    • πŸ“ˆ Tokenomics
    • πŸ‘¨β€πŸ”¬Tech deep dive: Boosting yield by compounding rewards
      • Deposit into the Vault
      • Withdraw from the Vault
      • Redeem rewards
      • Automatic boosting with Alluo
      • FraxConvex Vaults
      • Managing withdrawal requests in IERC4626
  • Decentralisation and Trust
    • πŸ—³οΈ Trustless governance and execution
    • πŸ‘¨β€πŸ”¬Tech deep dive: Vote Executor Architecture
      • Off chain votes to on chain data
      • Onchain data verifcation
      • Automated execution of votes
        • Tokenomics
        • Liquidity Direction
        • Setting APYs on farms
      • Cross chain execution of votes
      • Manually submitting vote results onchain
    • ↔️Alluo Exchange
      • Interacting with the Exchange
    • vlAlluo Architecture
    • Contracts upgrades
    • Investment strategies
      • πŸ“ˆFrax Convex Finance
        • Adding new pools into the strategy
        • Investing into a pool
  • More Advanced Features
    • πŸ” Repeat payments, streaming IbAlluo
  • Product Updates
    • πŸ‘Œ Product Roadmap: Building the right products
    • πŸ’» Web App releases
    • πŸ“± Mobile App releases
    • 🏎️ Alluo Boost
  • tutorial projects
    • Example: USDC to streaming 1 IbAlluo per second
    • Example: Using IbAlluoUSD and Ricochet to do capital efficient DCA into ETH
Powered by GitBook
On this page
  • How is this decentralised?
  • How does the DAO verify submitted data?
  1. Decentralisation and Trust
  2. Tech deep dive: Vote Executor Architecture

Onchain data verifcation

Now that the data has been submitted from Github Automation, the DAO verifies it and executes the data

As described before, the data gets submitted to the Vote Executor on Ethereum mainnet. You may be concerned that Github Actions is centralised and therefore puts the system at the hands of Github. However, this completely untrue.

How is this decentralised?

Even though we automated the process using Github Actions, the vote execution system remains decentralised because ANYONE can submit data to be executed on chain.

/// @notice Allows anyone to submit data for execution of votes
/// @dev Attempts to parse at high level and then confirm hash before submitting to queue
/// @param data Payload fully encoded as required (see formatting using encoding functions below)

function submitData(bytes memory data) external {

    (bytes32 hashed, Message[] memory _messages) = abi.decode(data, (bytes32, Message[]));

    require(hashed == keccak256(abi.encode(_messages)), "Hash doesn't match");

    SubmittedData memory newSubmittedData;
    newSubmittedData.data = data;
    newSubmittedData.time = block.timestamp;
    submittedData.push(newSubmittedData);
}

By passing in data that is parsed through encoding messages using the helper view functions provided, anyone can submit data.

How does the DAO verify submitted data?

When someone submits data to be executed, they receive a hash of the data.

The DAO confirms that the data indeed reflects the outcome of the votes and only then signs this hash and submits it to the Vote Executor on chain.

VoteExecutorMaster.sol
/// @notice Allow anyone to approve data for execution given off-chain signatures
/// @dev Checks against existing sigs submitted and only allow non-duplicate multisig owner signatures to approve the payload
/// @param _dataId Id of data payload to be approved
/// @param _signs Array of off-chain EOA signatures to approve the payload.

function approveSubmittedData(uint256 _dataId, bytes[] memory _signs) external {
    (bytes32 dataHash,) = abi.decode(submittedData[_dataId].data, (bytes32, Message[]));

    address[] memory owners = IGnosis(gnosis).getOwners();

    bytes[] memory submittedSigns = submittedData[_dataId].signs;
    address[] memory uniqueSigners = new address[](owners.length);
    uint256 numberOfSigns;

    for (uint256 i; i< submittedSigns.length; i++) {
        numberOfSigns++;
        uniqueSigners[i]= _getSignerAddress(dataHash, submittedSigns[i]);
    }

    for (uint256 i; i < _signs.length; i++) {
        for (uint256 j; j < owners.length; j++) {
            if(_verify(dataHash, _signs[i], owners[j]) && _checkUniqueSignature(uniqueSigners, owners[j])){
                submittedData[_dataId].signs.push(_signs[i]);
                uniqueSigners[numberOfSigns] = owners[j];
                numberOfSigns++;
                break;
            }
        }
    }
}

Simply, the contract checks if a member of the multisig of the DAO has signed the hash and - if it is valid - it approves the data. The data requires 2 multisig signers to approve it before it can be executed using executeSpecificHash():

VoteExecutorMaster.sol
function executeSpecificData(uint256 index) external {
        (bytes32 hashed, Message[] memory messages) = abi.decode(submittedData[index].data, (bytes32, Message[]));
        require(submittedData[index].time + timeLock < block.timestamp, "Under timelock");
        require(hashExecutionTime[hashed] == 0, "Duplicate Hash");

        if(submittedData[index].signs.length >= minSigns){
            for (uint256 j; j < messages.length; j++) {
                if(messages[j].commandIndex == 0){
                    (string memory ibAlluoSymbol, uint256 newAnnualInterest, uint256 newInterestPerSecond) = abi.decode(messages[j].commandData, (string, uint256, uint256));
                    IIbAlluo ibAlluo = IIbAlluo(ibAlluoSymbolToAddress[ibAlluoSymbol]);
                    if(ibAlluo.annualInterest() != newAnnualInterest){
                       ibAlluo.setInterest(newAnnualInterest, newInterestPerSecond);
                    }
                }
                else if(messages[j].commandIndex == 1){
                    (uint256 mintAmount, uint256 period) = abi.decode(messages[j].commandData, (uint256, uint256));
                    IAlluoToken(ALLUO).mint(locker, mintAmount);
                    ILocker(locker).setReward(mintAmount / period);
                }
            }
            hashExecutionTime[hashed] = block.timestamp;
            bytes memory finalData = abi.encode(submittedData[index].data, submittedData[index].signs);
            IAnyCall(bridgingInfo.anyCallAddress).anyCall(bridgingInfo.nextChainExecutor, finalData, address(0), bridgingInfo.nextChain, 0);
        }     
}
PreviousOff chain votes to on chain dataNextAutomated execution of votes

Last updated 2 years ago

πŸ‘¨β€πŸ”¬