RestakingDeveloper DocsCreating a LRT on Tangle

Creating a LRT Vault on Tangle

Overview

This tutorial walks through creating a Liquid Restaking Token (LRT) Vault on Tangle Network using the reference implementation from the tangle-lrt repository. LRT vaults allow users to receive liquid tokens representing their staked assets while participating in Tangle’s restaking mechanism.

Prerequisites

  • Basic knowledge of Solidity and EVM development
  • Foundry installed for smart contract development
  • MetaMask wallet connected to Tangle Network
  • Some test tokens for deployment (on testnet)

Install Foundry:

curl -L https://foundry.paradigm.xyz | bash
foundryup

Understanding the Components

The Tangle Liquid Restaking implementation consists of the following key components:

  1. Vault Contract (TangleLiquidRestakingVault): An ERC4626-compliant vault that:

    • Manages deposits and withdrawals
    • Implements reward distribution with index-based accounting
    • Handles delegation through the MultiAssetDelegation precompile
    • Provides liquid token representation of staked assets
  2. MultiAssetDelegation Wrapper: Interfaces with Tangle’s MultiAssetDelegation precompile at 0x0000000000000000000000000000000000000822

  3. Rewards Wrapper: Interfaces with Tangle’s Rewards precompile at 0x0000000000000000000000000000000000000825

Core features include:

Step 1: Setting Up the Project

First, clone the reference implementation:

git clone https://github.com/tangle-network/lrt
cd lrt
forge soldeer update -d

Step 2: Core Implementation Details

Reward Distribution System

The vault implements a sophisticated reward distribution system using index-based accounting:

Delegation Management

The vault handles delegation through the MultiAssetDelegation precompile, managing deposits and withdrawals:

Step 3: Testing the Implementation

Create test files in the test directory using Foundry’s Solidity testing framework. Here’s an example test structure:

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.20;
 
import "forge-std/Test.sol";
import "../src/TangleLiquidRestakingVault.sol";
 
contract TangleLiquidRestakingVaultTest is Test {
    TangleLiquidRestakingVault vault;
    address baseToken;
    bytes32 operator;
    uint64[] blueprintSelection;
 
    function setUp() public {
        // Setup test environment
        baseToken = address(new ERC20("Test Token", "TEST"));
        operator = bytes32(uint256(1));
        blueprintSelection = new uint64[](1);
        blueprintSelection[0] = 1;
 
        // Deploy vault
        vault = new TangleLiquidRestakingVault(
            baseToken,
            operator,
            blueprintSelection,
            MULTI_ASSET_DELEGATION_CONTRACT,
            "Liquid Restaked Test",
            "lrTEST"
        );
    }
 
    function testDeposit() public {
        uint256 amount = 1000e18;
        deal(baseToken, address(this), amount);
 
        ERC20(baseToken).approve(address(vault), amount);
        vault.deposit(amount, address(this));
 
        assertEq(vault.balanceOf(address(this)), amount);
    }
}

Run the tests using Forge:

forge test -vv

Step 4: Deployment

The vault can be deployed using Forge’s deployment capabilities:

  1. Create a deployment script in script/DeployVault.s.sol:
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.20;
 
import "forge-std/Script.sol";
import "../src/TangleLiquidRestakingVault.sol";
 
contract DeployVault is Script {
    function run() external {
        uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
        vm.startBroadcast(deployerPrivateKey);
 
        // Deploy vault
        bytes32 operator = bytes32(uint256(vm.envUint("OPERATOR_ID")));
        uint64[] memory blueprintSelection = new uint64[](1);
        blueprintSelection[0] = uint64(vm.envUint("BLUEPRINT_ID"));
 
        TangleLiquidRestakingVault vault = new TangleLiquidRestakingVault(
            vm.envAddress("BASE_TOKEN"),
            operator,
            blueprintSelection,
            MULTI_ASSET_DELEGATION_CONTRACT,
            "Liquid Restaked Token",
            "LRT"
        );
 
        vm.stopBroadcast();
    }
}
  1. Configure deployment variables in .env:
TANGLE_RPC_URL="https://testnet-rpc.tangle.tools"  # or mainnet
PRIVATE_KEY="your-private-key"
BASE_TOKEN="0x..."
OPERATOR_ID="1"  # your operator ID
BLUEPRINT_ID="1"  # your blueprint ID
  1. Deploy using Forge:
forge script script/DeployVault.s.sol:DeployVault --rpc-url $TANGLE_RPC_URL --broadcast

Step 5: Interacting with the Vault

The vault exposes several key functions for user interaction:

Deposits and Withdrawals

Reward Management

Security Considerations

The vault implements several security measures:

  1. Access Control: Uses Solmate’s Owned for admin functions
  2. Reward Accounting: Index-based accounting prevents double-claiming
  3. Withdrawal Process: Two-step withdrawal process with unstaking period
  4. Math Safety: Uses FixedPointMathLib for safe calculations

Key security features from the contract:

/// @notice Scale factor for reward index calculations
uint256 private constant REWARD_FACTOR = 1e18;
 
/// @notice Uses mulDivUp for final reward calculation
uint256 newRewards = snapshot.shareBalance.mulDivUp(indexDelta, REWARD_FACTOR);
 
/// @notice Validates withdrawal amounts
if (scheduledWithdrawAmount[owner] < assets) revert NoScheduledAmount();

For more information on the MultiAssetDelegation precompile and its features, see the precompile documentation.