ETH Price: $3,376.60 (-8.24%)
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Set Owner167327922023-03-01 9:09:59678 days ago1677661799IN
0x271D1B12...A744861e6
0 ETH0.0009621434.03659854

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
PnLFixedRate

Compiler Version
v0.8.10+commit.fc410830

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, None license
File 1 of 4 : PnLFixedRate.sol
// SPDX-License-Identifier: AGPLv3
pragma solidity 0.8.10;

import {IPnL} from "IPnL.sol";
import {IGTranche} from "IGTranche.sol";
import {PnLErrors} from "PnLErrors.sol";

//  ________  ________  ________
//  |\   ____\|\   __  \|\   __  \
//  \ \  \___|\ \  \|\  \ \  \|\  \
//   \ \  \  __\ \   _  _\ \  \\\  \
//    \ \  \|\  \ \  \\  \\ \  \\\  \
//     \ \_______\ \__\\ _\\ \_______\
//      \|_______|\|__|\|__|\|_______|

// gro protocol: https://github.com/groLabs/GSquared

/// @title PnLFixedRate
/// @notice PnL - Separate contract for defining profit and loss calculation for the GTranche.
///     This implementation provides fix rate income to the Senior tranche. Fixed rate being
///     defined as a % APY for the senior tranche. The implementation gives a constant stream
///     of assets from the junior to the senior tranche, independent of yields or other system
///     wide gains for the tranche. Its recommended that the tranches underlying 4626 tokens
///     support slow release, and that this slow release is adjusted accordingly to the fixed
///     rate, as to not create intermediary loss for the junior tranche between yield generating
///     events. Note that all normal yields (from 4626 harvests) are distributed to the junior
///     tranche, and that the Senior tranche
contract PnLFixedRate is IPnL {
    int256 internal constant DEFAULT_DECIMALS = 10_000;
    int256 internal constant YEAR_IN_SECONDS = 31556952;

    // tranche logic
    uint256 constant NO_OF_TRANCHES = 2;
    address internal immutable gTranche;

    address public owner;

    struct FixedRate {
        int64 rate;
        int64 pendingRate;
        uint64 lastDistribution;
    }

    FixedRate public fixedRate;

    /*//////////////////////////////////////////////////////////////
                                EVENTS
    //////////////////////////////////////////////////////////////*/

    event LogNewFixedRate(int64 rate);
    event LogNewPendingFixedRate(int64 pendingRate);
    event LogNewFixedRateDistribution(int256 seniorProfit);
    event LogOwnershipTransferred(address oldOwner, address newOwner);

    constructor(address _gTranche) {
        gTranche = _gTranche;
        owner = msg.sender;
        fixedRate.rate = 200;
        fixedRate.lastDistribution = uint64(block.timestamp);
    }

    /*//////////////////////////////////////////////////////////////
                            SETTERS
    //////////////////////////////////////////////////////////////*/

    /// @notice Change owner of the strategy
    /// @param _owner new strategy owner
    function setOwner(address _owner) external {
        if (msg.sender != owner) revert PnLErrors.NotOwner();
        address previous_owner = msg.sender;
        owner = _owner;

        emit LogOwnershipTransferred(previous_owner, _owner);
    }

    /// @notice Sets a new fixed rate for the tranche, the
    ///     rate will take affect during the next interaction
    function setRate(int64 _rate) external {
        if (_rate < 0 || _rate > DEFAULT_DECIMALS) revert PnLErrors.BadRate();
        if (msg.sender != owner) revert PnLErrors.NotOwner();
        fixedRate.pendingRate = _rate;
        emit LogNewPendingFixedRate(_rate);
    }

    /*//////////////////////////////////////////////////////////////
                            CORE LOGIC
    //////////////////////////////////////////////////////////////*/

    /// @notice Calculate fixed rate distribution for senior tranche
    function _calc_rate(int256 _seniorBalance)
        internal
        view
        returns (int256 seniorProfit)
    {
        FixedRate storage _rates = fixedRate;
        int256 _timeDiff = int256(block.timestamp - _rates.lastDistribution);
        seniorProfit =
            (_seniorBalance * _rates.rate * _timeDiff) /
            (DEFAULT_DECIMALS * YEAR_IN_SECONDS);
    }

    /// @notice Calculate distribution of assets changes of underlying yield tokens
    /// @param _amount amount of loss to distribute
    /// @param _trancheBalances balances of current tranches in common denominator
    function distributeAssets(
        bool _loss,
        int256 _amount,
        int256[NO_OF_TRANCHES] calldata _trancheBalances
    ) external override returns (int256[NO_OF_TRANCHES] memory amounts) {
        if (msg.sender != gTranche) revert PnLErrors.NotTranche();
        if (_loss) {
            amounts = distributeLoss(_amount, _trancheBalances);
        } else {
            amounts = distributeProfit(_amount, _trancheBalances);
        }
        int64 _pendingRate = fixedRate.pendingRate;
        if (_pendingRate > 0) {
            fixedRate.rate = _pendingRate;
            fixedRate.pendingRate = 0;
            emit LogNewFixedRate(_pendingRate);
        }
        fixedRate.lastDistribution = uint64(block.timestamp);
        emit LogNewFixedRateDistribution(amounts[1]);
    }

    /// @notice Calculate distribution of negative changes of underlying yield tokens
    /// @param _amount amount of loss to distribute
    /// @param _trancheBalances balances of current tranches in common denominator
    function distributeLoss(
        int256 _amount,
        int256[NO_OF_TRANCHES] calldata _trancheBalances
    ) public view override returns (int256[NO_OF_TRANCHES] memory loss) {
        int256 seniorProfit = _calc_rate(_trancheBalances[1]);
        if (_amount + seniorProfit > _trancheBalances[0]) {
            loss[0] = _trancheBalances[0];
            loss[1] = _amount - _trancheBalances[0];
        } else {
            loss[0] = _amount + seniorProfit;
            // The senior tranche will experience negative loss == fixed rate profit
            loss[1] = -1 * seniorProfit;
        }
    }

    /// @notice Calculate distribution of positive changes of underlying yield tokens
    /// @param _amount amount of profit to distribute
    /// @param _trancheBalances balances of current tranches in common denominator
    function distributeProfit(
        int256 _amount,
        int256[NO_OF_TRANCHES] calldata _trancheBalances
    ) public view override returns (int256[NO_OF_TRANCHES] memory profit) {
        int256 _utilisation = (_trancheBalances[1] * DEFAULT_DECIMALS) /
            (_trancheBalances[0] + 1);
        if (_utilisation < int256(IGTranche(gTranche).utilisationThreshold())) {
            int256 seniorProfit = _calc_rate(_trancheBalances[1]);
            // if rate distribution is greater than profit, the junior tranche
            //  will experience negative profit, e.g. a loss
            if (_trancheBalances[0] < seniorProfit - _amount) {
                profit[0] = -_trancheBalances[0];
                profit[1] = _amount + _trancheBalances[0];
            } else {
                profit[0] = _amount - seniorProfit;
                profit[1] = seniorProfit;
            }
        } else {
            profit[0] = _amount;
        }
    }
}

File 2 of 4 : IPnL.sol
// SPDX-License-Identifier: AGPLv3
pragma solidity 0.8.10;

/// @title IPnL
/// @notice PnL interface for a dsitribution module with two tranches
interface IPnL {
    function distributeAssets(
        bool _loss,
        int256 _amount,
        int256[2] calldata _trancheBalances
    ) external returns (int256[2] memory amounts);

    function distributeLoss(int256 _amount, int256[2] calldata _trancheBalances)
        external
        view
        returns (int256[2] memory loss);

    function distributeProfit(
        int256 _amount,
        int256[2] calldata _trancheBalances
    ) external view returns (int256[2] memory profit);
}

File 3 of 4 : IGTranche.sol
// SPDX-License-Identifier: AGPLv3
pragma solidity 0.8.10;

interface IGTranche {
    function deposit(
        uint256 _amount,
        uint256 _index,
        bool _tranche,
        address recipient
    ) external returns (uint256, uint256);

    function withdraw(
        uint256 _amount,
        uint256 _index,
        bool _tranche,
        address recipient
    ) external returns (uint256, uint256);

    function finalizeMigration() external;

    function utilisationThreshold() external view returns (uint256);
}

File 4 of 4 : PnLErrors.sol
// SPDX-License-Identifier: AGPLv3
pragma solidity 0.8.10;

library PnLErrors {
    error NotOwner(); // 0x30cd7471
    error NotTranche(); // 0x40fff8ff
    error BadRate(); // 0x491dee21
}

Settings
{
  "evmVersion": "istanbul",
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "libraries": {
    "PnLFixedRate.sol": {}
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  }
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_gTranche","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"BadRate","type":"error"},{"inputs":[],"name":"NotOwner","type":"error"},{"inputs":[],"name":"NotTranche","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"int64","name":"rate","type":"int64"}],"name":"LogNewFixedRate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"int256","name":"seniorProfit","type":"int256"}],"name":"LogNewFixedRateDistribution","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"int64","name":"pendingRate","type":"int64"}],"name":"LogNewPendingFixedRate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"LogOwnershipTransferred","type":"event"},{"inputs":[{"internalType":"bool","name":"_loss","type":"bool"},{"internalType":"int256","name":"_amount","type":"int256"},{"internalType":"int256[2]","name":"_trancheBalances","type":"int256[2]"}],"name":"distributeAssets","outputs":[{"internalType":"int256[2]","name":"amounts","type":"int256[2]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"int256","name":"_amount","type":"int256"},{"internalType":"int256[2]","name":"_trancheBalances","type":"int256[2]"}],"name":"distributeLoss","outputs":[{"internalType":"int256[2]","name":"loss","type":"int256[2]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"int256","name":"_amount","type":"int256"},{"internalType":"int256[2]","name":"_trancheBalances","type":"int256[2]"}],"name":"distributeProfit","outputs":[{"internalType":"int256[2]","name":"profit","type":"int256[2]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fixedRate","outputs":[{"internalType":"int64","name":"rate","type":"int64"},{"internalType":"int64","name":"pendingRate","type":"int64"},{"internalType":"uint64","name":"lastDistribution","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"setOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"int64","name":"_rate","type":"int64"}],"name":"setRate","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60a060405234801561001057600080fd5b506040516109f13803806109f183398101604081905261002f91610090565b6001600160a01b0316608052600080546001600160a01b0319163317905560018054426001600160401b0316600160801b027fffffffffffffffff0000000000000000ffffffffffffffff00000000000000009091161760c81790556100c0565b6000602082840312156100a257600080fd5b81516001600160a01b03811681146100b957600080fd5b9392505050565b60805161090f6100e26000396000818161019001526104bb015261090f6000f3fe608060405234801561001057600080fd5b506004361061007d5760003560e01c80638da5cb5b1161005b5780638da5cb5b14610119578063b545c7a214610144578063c72b8c2d14610157578063de7006eb1461016a57600080fd5b80630c591db71461008257806313af4035146100ab578063802d1422146100c0575b600080fd5b610095610090366004610640565b61017d565b6040516100a29190610684565b60405180910390f35b6100be6100b93660046106b5565b6102ca565b005b6001546100ec90600781810b91600160401b810490910b90600160801b900467ffffffffffffffff1683565b60408051600794850b81529290930b602083015267ffffffffffffffff16918101919091526060016100a2565b60005461012c906001600160a01b031681565b6040516001600160a01b0390911681526020016100a2565b6100956101523660046106e5565b610352565b6100be610165366004610712565b6103c3565b6100956101783660046106e5565b610487565b61018561060b565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146101ce576040516340fff8ff60e01b815260040160405180910390fd5b83156101e5576101de8383610352565b90506101f2565b6101ef8383610487565b90505b600154600160401b900460070b600081131561026557600180546fffffffffffffffffffffffffffffffff191667ffffffffffffffff8316179055604051600782900b81527f2f2ad7dcdcef5b868e5a902beceddc1aaa8bb4d88c6ff32581e9487880bf3ab69060200160405180910390a15b6001805467ffffffffffffffff60801b1916600160801b4267ffffffffffffffff16021790556020828101516040519081527f2c430a19a9d69296e2fe9a9ebfea09dc60e5715c2199f99dee0371acce014f6e910160405180910390a1509392505050565b6000546001600160a01b031633146102f5576040516330cd747160e01b815260040160405180910390fd5b600080546001600160a01b0319166001600160a01b038316908117909155604080513380825260208201939093527fdb6d05f3295cede580affa301a1eb5297528f3b3f6a56b075887ce6f61c45f21910160405180910390a15050565b61035a61060b565b600061036d8360015b60200201356105a7565b9050823561037b828661074b565b131561039a578235808352610390908561078c565b60208301526103bc565b6103a4818561074b565b82526103b2816000196107cb565b8260015b60200201525b5092915050565b60008160070b12806103d957506127108160070b135b156103f75760405163491dee2160e01b815260040160405180910390fd5b6000546001600160a01b03163314610422576040516330cd747160e01b815260040160405180910390fd5b600180546fffffffffffffffff00000000000000001916600160401b67ffffffffffffffff841602179055604051600782900b81527fe8d38e7bec160e41005bc6eaf2590c64e50a8cb32a2643ef5c952c9d8b04a7da9060200160405180910390a150565b61048f61060b565b600061049d8335600161074b565b6104ad61271060208601356107cb565b6104b79190610850565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a89b0fb06040518163ffffffff1660e01b8152600401602060405180830381865afa158015610517573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061053b919061088c565b81121561059e57600061054f846001610363565b905061055b858261078c565b843512156105845761056d84356108a5565b835261057a84358661074b565b6020840152610598565b61058e818661078c565b8352602083018190525b506103bc565b838260006103b6565b600180546000919082906105cc90600160801b900467ffffffffffffffff16426108c2565b90506105de6301e185586127106107cb565b825482906105ef9060070b876107cb565b6105f991906107cb565b6106039190610850565b949350505050565b60405180604001604052806002906020820280368337509192915050565b806040810183101561063a57600080fd5b92915050565b60008060006080848603121561065557600080fd5b8335801515811461066557600080fd5b92506020840135915061067b8560408601610629565b90509250925092565b60408101818360005b60028110156106ac57815183526020928301929091019060010161068d565b50505092915050565b6000602082840312156106c757600080fd5b81356001600160a01b03811681146106de57600080fd5b9392505050565b600080606083850312156106f857600080fd5b823591506107098460208501610629565b90509250929050565b60006020828403121561072457600080fd5b81358060070b81146106de57600080fd5b634e487b7160e01b600052601160045260246000fd5b600080821280156001600160ff1b038490038513161561076d5761076d610735565b600160ff1b839003841281161561078657610786610735565b50500190565b60008083128015600160ff1b8501841216156107aa576107aa610735565b6001600160ff1b03840183138116156107c5576107c5610735565b50500390565b60006001600160ff1b03818413828413808216868404861116156107f1576107f1610735565b600160ff1b600087128281168783058912161561081057610810610735565b6000871292508782058712848416161561082c5761082c610735565b8785058712818416161561084257610842610735565b505050929093029392505050565b60008261086d57634e487b7160e01b600052601260045260246000fd5b600160ff1b82146000198414161561088757610887610735565b500590565b60006020828403121561089e57600080fd5b5051919050565b6000600160ff1b8214156108bb576108bb610735565b5060000390565b6000828210156108d4576108d4610735565b50039056fea26469706673582212201cb55aacdadad8e4656e4d72c3301665b7aa1076ba2b1a141b6b25a8e9428ba364736f6c634300080a003300000000000000000000000019a07afe97279cb6de1c9e73a13b7b0b63f7e67a

Deployed Bytecode

0x608060405234801561001057600080fd5b506004361061007d5760003560e01c80638da5cb5b1161005b5780638da5cb5b14610119578063b545c7a214610144578063c72b8c2d14610157578063de7006eb1461016a57600080fd5b80630c591db71461008257806313af4035146100ab578063802d1422146100c0575b600080fd5b610095610090366004610640565b61017d565b6040516100a29190610684565b60405180910390f35b6100be6100b93660046106b5565b6102ca565b005b6001546100ec90600781810b91600160401b810490910b90600160801b900467ffffffffffffffff1683565b60408051600794850b81529290930b602083015267ffffffffffffffff16918101919091526060016100a2565b60005461012c906001600160a01b031681565b6040516001600160a01b0390911681526020016100a2565b6100956101523660046106e5565b610352565b6100be610165366004610712565b6103c3565b6100956101783660046106e5565b610487565b61018561060b565b336001600160a01b037f00000000000000000000000019a07afe97279cb6de1c9e73a13b7b0b63f7e67a16146101ce576040516340fff8ff60e01b815260040160405180910390fd5b83156101e5576101de8383610352565b90506101f2565b6101ef8383610487565b90505b600154600160401b900460070b600081131561026557600180546fffffffffffffffffffffffffffffffff191667ffffffffffffffff8316179055604051600782900b81527f2f2ad7dcdcef5b868e5a902beceddc1aaa8bb4d88c6ff32581e9487880bf3ab69060200160405180910390a15b6001805467ffffffffffffffff60801b1916600160801b4267ffffffffffffffff16021790556020828101516040519081527f2c430a19a9d69296e2fe9a9ebfea09dc60e5715c2199f99dee0371acce014f6e910160405180910390a1509392505050565b6000546001600160a01b031633146102f5576040516330cd747160e01b815260040160405180910390fd5b600080546001600160a01b0319166001600160a01b038316908117909155604080513380825260208201939093527fdb6d05f3295cede580affa301a1eb5297528f3b3f6a56b075887ce6f61c45f21910160405180910390a15050565b61035a61060b565b600061036d8360015b60200201356105a7565b9050823561037b828661074b565b131561039a578235808352610390908561078c565b60208301526103bc565b6103a4818561074b565b82526103b2816000196107cb565b8260015b60200201525b5092915050565b60008160070b12806103d957506127108160070b135b156103f75760405163491dee2160e01b815260040160405180910390fd5b6000546001600160a01b03163314610422576040516330cd747160e01b815260040160405180910390fd5b600180546fffffffffffffffff00000000000000001916600160401b67ffffffffffffffff841602179055604051600782900b81527fe8d38e7bec160e41005bc6eaf2590c64e50a8cb32a2643ef5c952c9d8b04a7da9060200160405180910390a150565b61048f61060b565b600061049d8335600161074b565b6104ad61271060208601356107cb565b6104b79190610850565b90507f00000000000000000000000019a07afe97279cb6de1c9e73a13b7b0b63f7e67a6001600160a01b031663a89b0fb06040518163ffffffff1660e01b8152600401602060405180830381865afa158015610517573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061053b919061088c565b81121561059e57600061054f846001610363565b905061055b858261078c565b843512156105845761056d84356108a5565b835261057a84358661074b565b6020840152610598565b61058e818661078c565b8352602083018190525b506103bc565b838260006103b6565b600180546000919082906105cc90600160801b900467ffffffffffffffff16426108c2565b90506105de6301e185586127106107cb565b825482906105ef9060070b876107cb565b6105f991906107cb565b6106039190610850565b949350505050565b60405180604001604052806002906020820280368337509192915050565b806040810183101561063a57600080fd5b92915050565b60008060006080848603121561065557600080fd5b8335801515811461066557600080fd5b92506020840135915061067b8560408601610629565b90509250925092565b60408101818360005b60028110156106ac57815183526020928301929091019060010161068d565b50505092915050565b6000602082840312156106c757600080fd5b81356001600160a01b03811681146106de57600080fd5b9392505050565b600080606083850312156106f857600080fd5b823591506107098460208501610629565b90509250929050565b60006020828403121561072457600080fd5b81358060070b81146106de57600080fd5b634e487b7160e01b600052601160045260246000fd5b600080821280156001600160ff1b038490038513161561076d5761076d610735565b600160ff1b839003841281161561078657610786610735565b50500190565b60008083128015600160ff1b8501841216156107aa576107aa610735565b6001600160ff1b03840183138116156107c5576107c5610735565b50500390565b60006001600160ff1b03818413828413808216868404861116156107f1576107f1610735565b600160ff1b600087128281168783058912161561081057610810610735565b6000871292508782058712848416161561082c5761082c610735565b8785058712818416161561084257610842610735565b505050929093029392505050565b60008261086d57634e487b7160e01b600052601260045260246000fd5b600160ff1b82146000198414161561088757610887610735565b500590565b60006020828403121561089e57600080fd5b5051919050565b6000600160ff1b8214156108bb576108bb610735565b5060000390565b6000828210156108d4576108d4610735565b50039056fea26469706673582212201cb55aacdadad8e4656e4d72c3301665b7aa1076ba2b1a141b6b25a8e9428ba364736f6c634300080a0033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

00000000000000000000000019a07afe97279cb6de1c9e73a13b7b0b63f7e67a

-----Decoded View---------------
Arg [0] : _gTranche (address): 0x19A07afE97279cb6de1c9E73A13B7b0b63F7E67A

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 00000000000000000000000019a07afe97279cb6de1c9e73a13b7b0b63f7e67a


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.