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
  1. Decentralisation and Trust
  2. Tech deep dive: Vote Executor Architecture

Cross chain execution of votes

Multiple VoteExecutor contracts on different chains

PreviousSetting APYs on farmsNextManually submitting vote results onchain

Last updated 2 years ago

Executing votes on multiple chains

As described in previous sections, once the data is submitted and approved on Ethereum Mainnet, there are actions that must occur on other chains - such as Polygon.

We have satellite contracts that receive data through cross chain messaging, which then execute what is necessary.

At the end of executeSpecificData, there is an AnyCall (Multichain Crosschain Messaging) to the next executor in the list (on a different chain such as Polygon).

VoteExecutorMaster.so
IAnyCall(messagingInfo.anyCallAddress).anyCall(messagingInfo.nextChainExecutor, finalData, address(0), messagingInfo.nextChain, 0);

Then the satellite 'slave' contract on a different chain receives the call

VoteExecutorSlave.sol
/// @notice Receives SMPC call from Multichain and executes command after security checks
/// @dev Format of function name and return params are necessary (see docs: https://docs.multichain.org/developer-guide/anycall/anycall-v6/how-to-integrate-anycall-v6)
// Carry out two security checks:
// 1.) Confirm that the hash has been signed by the multisig 
// 2.) Confirm that anyCall has been triggered by our VoteExecutorMaster contract
/// @param _data Data sent through by SMPC
/// @return success Required by Multichain
/// @return result Required by Multichain
function anyExecute(bytes memory _data) external returns (bool success, bytes memory result) {
    (bytes memory message, bytes[] memory signs) = abi.decode(_data, (bytes, bytes[]));
    (bytes32 hashed, Message[] memory _messages, uint256 timestamp) = abi.decode(message, (bytes32, Message[], uint256));
    require(hashed == keccak256(abi.encode(_messages, timestamp)), "Hash doesn't match");
    require(_checkSignedHashes(signs, hashed), "Hash has not been approved");
    require(IAnyCallExecutor(messagingInfo.anyCallExecutor).context().from == voteExecutorMaster, "Origin of message invalid");
    require(hashExecutionTime[hashed] ==0, "Duplicate hash" );
    execute(_messages);
    executionHistory.push(_data);
    hashExecutionTime[hashed] = block.timestamp;
    if (messagingInfo.nextChain != 0) {
        IAnyCall(messagingInfo.anyCallAddress).anyCall(messagingInfo.nextChainExecutor, _data, address(0), messagingInfo.nextChain, 0);
    }
    success=true;
    result="";
    emit MessageReceived(hashed);
}

This contract carries out a couple security checks:

  1. That the data is correctly parseable

  2. That the Multichain call has indeed originated from our contract (check through Multichain contracts for legitimacy)

  3. That the data has indeed been approved by the DAO multisig (to confirm that cross chain messaging has not been malicious)

This ensures that the data has not been manipulated on transit between chains.

Then, analagous to how execution for data works on the main chain, the VoteExecutorSlave executes the data necessary for the current chain (Polygon for example).

Executing
/// @notice Executes all messages received after authentication
/// @dev Loops through each command in the array and executes it.
/// @param _messages Array of messages
function execute(Message[] memory _messages) internal {
    
    for (uint256 i; i < _messages.length; i++) {
        Message memory currentMessage =  _messages[i];
        if (currentMessage.commandIndex == 0) {
            (string memory ibAlluoSymbol, uint256 newAnnualInterest, uint256 newInterestPerSecond) = abi.decode(currentMessage.commandData, (string, uint256, uint256));
            _changeAPY(newAnnualInterest, newInterestPerSecond, ibAlluoSymbol);
        }

        else if(currentMessage.commandIndex == 2) {
            // Handle all withdrawals first and then add all deposit actions to an array to be executed afterwards
            (address strategyAddress, uint256 delta, uint256 chainId, address strategyPrimaryToken, address exitToken, bytes memory data) = abi.decode(currentMessage.commandData, (address, uint256, uint256, address,address, bytes));
            if (chainId == generalBridgingInfo.currentChain) {
                IAlluoStrategy(strategyAddress).exitAll(data, delta, strategyPrimaryToken, address(this), false);
            }
        }
        else if(currentMessage.commandIndex == 3) {
            // Add all deposits to the queue.
            (address strategyAddress, uint256 delta, uint256 chainId, address strategyPrimaryToken, address entryToken, bytes memory data) = abi.decode(currentMessage.commandData, (address, uint256, uint256, address,address, bytes));
            if (chainId == generalBridgingInfo.currentChain) {
                console.log("Deposit added", strategyAddress, delta);
                tokenToDepositQueue[strategyPrimaryToken].depositList.push(Deposit(strategyAddress, delta, strategyPrimaryToken, entryToken, data));
            }
        }
    }ataa
}
πŸ‘¨β€πŸ”¬
The black arrows indicate multichain anyCall messaging