Contract 0x3129C041B372eE93a5A8756dc4EC6f154D85Bc9a 1

Contract Overview

Balance:
0 Ether
Txn Hash
Method
Block
From
To
Value
0x263432cd3db5345794bee9b44a3a47462af3bbe7304f43c9e52ab9f86d14a62a0x60c0604096703192021-11-19 16:04:22315 days 7 hrs ago0x2a61d3ba5030ef471c74f612962c7367eca3a62d IN  Create: AddRewardProgram0 Ether0.000429361.00000001
[ Download CSV Export 
Latest 25 internal transaction
Parent Txn Hash Block From To Value
0xab64e1af79a69536825b15c9f205a0d6a74c9a0f3970eaba6e3aae446f7c7d1b101389282022-02-09 11:33:31233 days 11 hrs ago 0x3129c041b372ee93a5a8756dc4ec6f154d85bc9a 0x648c8be548f43eca4e482c0801ebccccfb9449310 Ether
0xab64e1af79a69536825b15c9f205a0d6a74c9a0f3970eaba6e3aae446f7c7d1b101389282022-02-09 11:33:31233 days 11 hrs ago 0x661090cb830757b2d0cd53c49bf0d17a28992e5d 0x3129c041b372ee93a5a8756dc4ec6f154d85bc9a0 Ether
0x91ab4a9de8129f1e48eecbabeb42bec72fea9f610da8f2ac058fb568ea66910e99719842022-01-11 9:16:06262 days 14 hrs ago 0x3129c041b372ee93a5a8756dc4ec6f154d85bc9a 0x648c8be548f43eca4e482c0801ebccccfb9449310 Ether
0x91ab4a9de8129f1e48eecbabeb42bec72fea9f610da8f2ac058fb568ea66910e99719842022-01-11 9:16:06262 days 14 hrs ago 0x661090cb830757b2d0cd53c49bf0d17a28992e5d 0x3129c041b372ee93a5a8756dc4ec6f154d85bc9a0 Ether
0x518ea5b575b800987b8d755a107a23b732a62b6cc3fc7425a8a0bfba16a29ea899719652022-01-11 9:11:20262 days 14 hrs ago 0x3129c041b372ee93a5a8756dc4ec6f154d85bc9a 0x648c8be548f43eca4e482c0801ebccccfb9449310 Ether
0x518ea5b575b800987b8d755a107a23b732a62b6cc3fc7425a8a0bfba16a29ea899719652022-01-11 9:11:20262 days 14 hrs ago 0x661090cb830757b2d0cd53c49bf0d17a28992e5d 0x3129c041b372ee93a5a8756dc4ec6f154d85bc9a0 Ether
0x8e74fc51e0c98a25b674bff42910f5e2926dc1c22ef0b1129ef4fb8b811f6bbd98924322021-12-28 8:51:07276 days 14 hrs ago 0x3129c041b372ee93a5a8756dc4ec6f154d85bc9a 0x648c8be548f43eca4e482c0801ebccccfb9449310 Ether
0x8e74fc51e0c98a25b674bff42910f5e2926dc1c22ef0b1129ef4fb8b811f6bbd98924322021-12-28 8:51:07276 days 14 hrs ago 0x661090cb830757b2d0cd53c49bf0d17a28992e5d 0x3129c041b372ee93a5a8756dc4ec6f154d85bc9a0 Ether
0xe58a38594ce1ca628a0e3967ac747176d0131684d6f2fe5325d2f9c2158e02e397095762021-11-26 11:42:55308 days 11 hrs ago 0x3129c041b372ee93a5a8756dc4ec6f154d85bc9a 0x648c8be548f43eca4e482c0801ebccccfb9449310 Ether
0xe58a38594ce1ca628a0e3967ac747176d0131684d6f2fe5325d2f9c2158e02e397095762021-11-26 11:42:55308 days 11 hrs ago 0x661090cb830757b2d0cd53c49bf0d17a28992e5d 0x3129c041b372ee93a5a8756dc4ec6f154d85bc9a0 Ether
0xfca2901617f5bb2bb7fd4cae60405abdcd9764232787cfd73ed36de6bf0d1eab97092482021-11-26 10:20:53308 days 13 hrs ago 0x3129c041b372ee93a5a8756dc4ec6f154d85bc9a 0x648c8be548f43eca4e482c0801ebccccfb9449310 Ether
0xfca2901617f5bb2bb7fd4cae60405abdcd9764232787cfd73ed36de6bf0d1eab97092482021-11-26 10:20:53308 days 13 hrs ago 0x661090cb830757b2d0cd53c49bf0d17a28992e5d 0x3129c041b372ee93a5a8756dc4ec6f154d85bc9a0 Ether
0x2e32bbcfef94f4b96df1c1444a34b1e9ecf20a812b67616c91d02f282e2763c597091572021-11-26 9:58:07308 days 13 hrs ago 0x3129c041b372ee93a5a8756dc4ec6f154d85bc9a 0x648c8be548f43eca4e482c0801ebccccfb9449310 Ether
0x2e32bbcfef94f4b96df1c1444a34b1e9ecf20a812b67616c91d02f282e2763c597091572021-11-26 9:58:07308 days 13 hrs ago 0x661090cb830757b2d0cd53c49bf0d17a28992e5d 0x3129c041b372ee93a5a8756dc4ec6f154d85bc9a0 Ether
0xb2f97f180dc8a690cd2e4d81689036699370f0127dabd54ace6ce4ca2b679b0097091512021-11-26 9:56:37308 days 13 hrs ago 0x3129c041b372ee93a5a8756dc4ec6f154d85bc9a 0x648c8be548f43eca4e482c0801ebccccfb9449310 Ether
0xb2f97f180dc8a690cd2e4d81689036699370f0127dabd54ace6ce4ca2b679b0097091512021-11-26 9:56:37308 days 13 hrs ago 0x661090cb830757b2d0cd53c49bf0d17a28992e5d 0x3129c041b372ee93a5a8756dc4ec6f154d85bc9a0 Ether
0x1dc224871cbe6795aac381648c174f9cb23f67611abe5ce5dea5eca78fc355a797091482021-11-26 9:55:52308 days 13 hrs ago 0x3129c041b372ee93a5a8756dc4ec6f154d85bc9a 0x648c8be548f43eca4e482c0801ebccccfb9449310 Ether
0x1dc224871cbe6795aac381648c174f9cb23f67611abe5ce5dea5eca78fc355a797091482021-11-26 9:55:52308 days 13 hrs ago 0x661090cb830757b2d0cd53c49bf0d17a28992e5d 0x3129c041b372ee93a5a8756dc4ec6f154d85bc9a0 Ether
0x9d7402118eb36d8dabbb7e74d71ce156e03af0d5461f93c5751d2acca9b5bf2197091302021-11-26 9:51:22308 days 13 hrs ago 0x3129c041b372ee93a5a8756dc4ec6f154d85bc9a 0x648c8be548f43eca4e482c0801ebccccfb9449310 Ether
0x9d7402118eb36d8dabbb7e74d71ce156e03af0d5461f93c5751d2acca9b5bf2197091302021-11-26 9:51:22308 days 13 hrs ago 0x661090cb830757b2d0cd53c49bf0d17a28992e5d 0x3129c041b372ee93a5a8756dc4ec6f154d85bc9a0 Ether
0x9fbb05bb872f5253b3f49a1b985aaea126b2f60d5062f40945d28a9ee6102fe197089312021-11-26 9:01:37308 days 14 hrs ago 0x3129c041b372ee93a5a8756dc4ec6f154d85bc9a 0x648c8be548f43eca4e482c0801ebccccfb9449310 Ether
0x9fbb05bb872f5253b3f49a1b985aaea126b2f60d5062f40945d28a9ee6102fe197089312021-11-26 9:01:37308 days 14 hrs ago 0x661090cb830757b2d0cd53c49bf0d17a28992e5d 0x3129c041b372ee93a5a8756dc4ec6f154d85bc9a0 Ether
0x3f29bcbddfe384297a510006f7a8d2e1af264f8a32483da9334089f70bd8494097089022021-11-26 8:54:22308 days 14 hrs ago 0x3129c041b372ee93a5a8756dc4ec6f154d85bc9a 0x648c8be548f43eca4e482c0801ebccccfb9449310 Ether
0x3f29bcbddfe384297a510006f7a8d2e1af264f8a32483da9334089f70bd8494097089022021-11-26 8:54:22308 days 14 hrs ago 0x661090cb830757b2d0cd53c49bf0d17a28992e5d 0x3129c041b372ee93a5a8756dc4ec6f154d85bc9a0 Ether
0xf969b9368321caa24e0e87db009bb9831e8348bf8a002b4d4bf8079cc7732ed797087822021-11-26 8:24:22308 days 15 hrs ago 0x3129c041b372ee93a5a8756dc4ec6f154d85bc9a 0x648c8be548f43eca4e482c0801ebccccfb9449310 Ether
[ Download CSV Export 
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
AddRewardProgram

Compiler Version
v0.8.6+commit.11564f7e

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, GNU GPLv3 license

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2021-11-19
*/

// SPDX-License-Identifier: GPL-3.0 AND MIT
// File: contracts/TrustedCaller.sol

// SPDX-FileCopyrightText: 2021 Lido <[email protected]>

pragma solidity ^0.8.4;

/// @author psirex
/// @notice A helper contract contains logic to validate that only a trusted caller has access to certain methods.
/// @dev Trusted caller set once on deployment and can't be changed.
contract TrustedCaller {
    string private constant ERROR_TRUSTED_CALLER_IS_ZERO_ADDRESS = "TRUSTED_CALLER_IS_ZERO_ADDRESS";
    string private constant ERROR_CALLER_IS_FORBIDDEN = "CALLER_IS_FORBIDDEN";

    address public immutable trustedCaller;

    constructor(address _trustedCaller) {
        require(_trustedCaller != address(0), ERROR_TRUSTED_CALLER_IS_ZERO_ADDRESS);
        trustedCaller = _trustedCaller;
    }

    modifier onlyTrustedCaller(address _caller) {
        require(_caller == trustedCaller, ERROR_CALLER_IS_FORBIDDEN);
        _;
    }
}

// File: OpenZeppelin/[email protected]/contracts/access/IAccessControl.sol


pragma solidity ^0.8.0;

/**
 * @dev External interface of AccessControl declared to support ERC165 detection.
 */
interface IAccessControl {
    /**
     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
     *
     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
     * {RoleAdminChanged} not being emitted signaling this.
     *
     * _Available since v3.1._
     */
    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);

    /**
     * @dev Emitted when `account` is granted `role`.
     *
     * `sender` is the account that originated the contract call, an admin role
     * bearer except when using {AccessControl-_setupRole}.
     */
    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Emitted when `account` is revoked `role`.
     *
     * `sender` is the account that originated the contract call:
     *   - if using `revokeRole`, it is the admin role bearer
     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
     */
    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) external view returns (bool);

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {AccessControl-_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) external view returns (bytes32);

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function grantRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function revokeRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been granted `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `account`.
     */
    function renounceRole(bytes32 role, address account) external;
}

// File: OpenZeppelin/[email protected]/contracts/utils/Context.sol


pragma solidity ^0.8.0;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
}

// File: OpenZeppelin/[email protected]/contracts/utils/Strings.sol


pragma solidity ^0.8.0;

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        // Inspired by OraclizeAPI's implementation - MIT licence
        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol

        if (value == 0) {
            return "0";
        }
        uint256 temp = value;
        uint256 digits;
        while (temp != 0) {
            digits++;
            temp /= 10;
        }
        bytes memory buffer = new bytes(digits);
        while (value != 0) {
            digits -= 1;
            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
            value /= 10;
        }
        return string(buffer);
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        if (value == 0) {
            return "0x00";
        }
        uint256 temp = value;
        uint256 length = 0;
        while (temp != 0) {
            length++;
            temp >>= 8;
        }
        return toHexString(value, length);
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = "0";
        buffer[1] = "x";
        for (uint256 i = 2 * length + 1; i > 1; --i) {
            buffer[i] = _HEX_SYMBOLS[value & 0xf];
            value >>= 4;
        }
        require(value == 0, "Strings: hex length insufficient");
        return string(buffer);
    }
}

// File: OpenZeppelin/[email protected]/contracts/utils/introspection/IERC165.sol


pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

// File: OpenZeppelin/[email protected]/contracts/utils/introspection/ERC165.sol


pragma solidity ^0.8.0;


/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 *
 * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
 */
abstract contract ERC165 is IERC165 {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}

// File: OpenZeppelin/[email protected]/contracts/access/AccessControl.sol


pragma solidity ^0.8.0;





/**
 * @dev Contract module that allows children to implement role-based access
 * control mechanisms. This is a lightweight version that doesn't allow enumerating role
 * members except through off-chain means by accessing the contract event logs. Some
 * applications may benefit from on-chain enumerability, for those cases see
 * {AccessControlEnumerable}.
 *
 * Roles are referred to by their `bytes32` identifier. These should be exposed
 * in the external API and be unique. The best way to achieve this is by
 * using `public constant` hash digests:
 *
 * ```
 * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
 * ```
 *
 * Roles can be used to represent a set of permissions. To restrict access to a
 * function call, use {hasRole}:
 *
 * ```
 * function foo() public {
 *     require(hasRole(MY_ROLE, msg.sender));
 *     ...
 * }
 * ```
 *
 * Roles can be granted and revoked dynamically via the {grantRole} and
 * {revokeRole} functions. Each role has an associated admin role, and only
 * accounts that have a role's admin role can call {grantRole} and {revokeRole}.
 *
 * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
 * that only accounts with this role will be able to grant or revoke other
 * roles. More complex role relationships can be created by using
 * {_setRoleAdmin}.
 *
 * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
 * grant and revoke this role. Extra precautions should be taken to secure
 * accounts that have been granted it.
 */
abstract contract AccessControl is Context, IAccessControl, ERC165 {
    struct RoleData {
        mapping(address => bool) members;
        bytes32 adminRole;
    }

    mapping(bytes32 => RoleData) private _roles;

    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;

    /**
     * @dev Modifier that checks that an account has a specific role. Reverts
     * with a standardized message including the required role.
     *
     * The format of the revert reason is given by the following regular expression:
     *
     *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
     *
     * _Available since v4.1._
     */
    modifier onlyRole(bytes32 role) {
        _checkRole(role, _msgSender());
        _;
    }

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
    }

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) public view override returns (bool) {
        return _roles[role].members[account];
    }

    /**
     * @dev Revert with a standard message if `account` is missing `role`.
     *
     * The format of the revert reason is given by the following regular expression:
     *
     *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
     */
    function _checkRole(bytes32 role, address account) internal view {
        if (!hasRole(role, account)) {
            revert(
                string(
                    abi.encodePacked(
                        "AccessControl: account ",
                        Strings.toHexString(uint160(account), 20),
                        " is missing role ",
                        Strings.toHexString(uint256(role), 32)
                    )
                )
            );
        }
    }

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) public view override returns (bytes32) {
        return _roles[role].adminRole;
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
        _grantRole(role, account);
    }

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
        _revokeRole(role, account);
    }

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been granted `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `account`.
     */
    function renounceRole(bytes32 role, address account) public virtual override {
        require(account == _msgSender(), "AccessControl: can only renounce roles for self");

        _revokeRole(role, account);
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event. Note that unlike {grantRole}, this function doesn't perform any
     * checks on the calling account.
     *
     * [WARNING]
     * ====
     * This function should only be called from the constructor when setting
     * up the initial roles for the system.
     *
     * Using this function in any other way is effectively circumventing the admin
     * system imposed by {AccessControl}.
     * ====
     */
    function _setupRole(bytes32 role, address account) internal virtual {
        _grantRole(role, account);
    }

    /**
     * @dev Sets `adminRole` as ``role``'s admin role.
     *
     * Emits a {RoleAdminChanged} event.
     */
    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
        bytes32 previousAdminRole = getRoleAdmin(role);
        _roles[role].adminRole = adminRole;
        emit RoleAdminChanged(role, previousAdminRole, adminRole);
    }

    function _grantRole(bytes32 role, address account) private {
        if (!hasRole(role, account)) {
            _roles[role].members[account] = true;
            emit RoleGranted(role, account, _msgSender());
        }
    }

    function _revokeRole(bytes32 role, address account) private {
        if (hasRole(role, account)) {
            _roles[role].members[account] = false;
            emit RoleRevoked(role, account, _msgSender());
        }
    }
}

// File: contracts/RewardProgramsRegistry.sol

// SPDX-FileCopyrightText: 2021 Lido <[email protected]>

pragma solidity ^0.8.4;


/// @author psirex
/// @title Registry of allowed reward programs
/// @notice Stores list of addresses with reward programs
contract RewardProgramsRegistry is AccessControl {
    // -------------
    // EVENTS
    // -------------
    event RewardProgramAdded(address indexed _rewardProgram, string _title);
    event RewardProgramRemoved(address indexed _rewardProgram);

    // -------------
    // ROLES
    // -------------
    bytes32 public constant ADD_REWARD_PROGRAM_ROLE = keccak256("ADD_REWARD_PROGRAM_ROLE");
    bytes32 public constant REMOVE_REWARD_PROGRAM_ROLE = keccak256("REMOVE_REWARD_PROGRAM_ROLE");

    // -------------
    // ERRORS
    // -------------
    string private constant ERROR_REWARD_PROGRAM_ALREADY_ADDED = "REWARD_PROGRAM_ALREADY_ADDED";
    string private constant ERROR_REWARD_PROGRAM_NOT_FOUND = "REWARD_PROGRAM_NOT_FOUND";

    // -------------
    // VARIABLES
    // -------------

    /// @dev List of allowed reward program addresses
    address[] public rewardPrograms;

    // Position of the reward program in the `rewardPrograms` array,
    // plus 1 because index 0 means a value is not in the set.
    mapping(address => uint256) private rewardProgramIndices;

    // -------------
    // CONSTRUCTOR
    // -------------

    /// @param _admin Address which will be granted with role DEFAULT_ADMIN_ROLE
    /// @param _addRewardProgramRoleHolders List of addresses which will be
    ///     granted with role ADD_REWARD_PROGRAM_ROLE
    /// @param _removeRewardProgramRoleHolders List of addresses which will
    ///     be granted with role REMOVE_REWARD_PROGRAM_ROLE
    constructor(
        address _admin,
        address[] memory _addRewardProgramRoleHolders,
        address[] memory _removeRewardProgramRoleHolders
    ) {
        _setupRole(DEFAULT_ADMIN_ROLE, _admin);
        for (uint256 i = 0; i < _addRewardProgramRoleHolders.length; i++) {
            _setupRole(ADD_REWARD_PROGRAM_ROLE, _addRewardProgramRoleHolders[i]);
        }
        for (uint256 i = 0; i < _removeRewardProgramRoleHolders.length; i++) {
            _setupRole(REMOVE_REWARD_PROGRAM_ROLE, _removeRewardProgramRoleHolders[i]);
        }
    }

    // -------------
    // EXTERNAL METHODS
    // -------------

    /// @notice Adds address to list of allowed reward programs
    function addRewardProgram(address _rewardProgram, string memory _title)
        external
        onlyRole(ADD_REWARD_PROGRAM_ROLE)
    {
        require(rewardProgramIndices[_rewardProgram] == 0, ERROR_REWARD_PROGRAM_ALREADY_ADDED);

        rewardPrograms.push(_rewardProgram);
        rewardProgramIndices[_rewardProgram] = rewardPrograms.length;
        emit RewardProgramAdded(_rewardProgram, _title);
    }

    /// @notice Removes address from list of allowed reward programs
    /// @dev To delete a reward program from the rewardPrograms array in O(1), we swap the element to delete with the last one in
    /// the array, and then remove the last element (sometimes called as 'swap and pop').
    function removeRewardProgram(address _rewardProgram)
        external
        onlyRole(REMOVE_REWARD_PROGRAM_ROLE)
    {
        uint256 index = _getRewardProgramIndex(_rewardProgram);
        uint256 lastIndex = rewardPrograms.length - 1;

        if (index != lastIndex) {
            address lastRewardProgram = rewardPrograms[lastIndex];
            rewardPrograms[index] = lastRewardProgram;
            rewardProgramIndices[lastRewardProgram] = index + 1;
        }

        rewardPrograms.pop();
        delete rewardProgramIndices[_rewardProgram];
        emit RewardProgramRemoved(_rewardProgram);
    }

    /// @notice Returns if passed address are listed as reward program in the registry
    function isRewardProgram(address _maybeRewardProgram) external view returns (bool) {
        return rewardProgramIndices[_maybeRewardProgram] > 0;
    }

    /// @notice Returns current list of reward programs
    function getRewardPrograms() external view returns (address[] memory) {
        return rewardPrograms;
    }

    // ------------------
    // PRIVATE METHODS
    // ------------------

    function _getRewardProgramIndex(address _evmScriptFactory)
        private
        view
        returns (uint256 _index)
    {
        _index = rewardProgramIndices[_evmScriptFactory];
        require(_index > 0, ERROR_REWARD_PROGRAM_NOT_FOUND);
        _index -= 1;
    }
}

// File: contracts/libraries/EVMScriptCreator.sol

// SPDX-FileCopyrightText: 2021 Lido <[email protected]>

pragma solidity ^0.8.4;

/// @author psirex
/// @notice Contains methods for convenient creation
/// of EVMScripts in EVMScript factories contracts
library EVMScriptCreator {
    // Id of default CallsScript Aragon's executor.
    bytes4 private constant SPEC_ID = hex"00000001";

    /// @notice Encodes one method call as EVMScript
    function createEVMScript(
        address _to,
        bytes4 _methodId,
        bytes memory _evmScriptCallData
    ) internal pure returns (bytes memory _commands) {
        return
            abi.encodePacked(
                SPEC_ID,
                _to,
                uint32(_evmScriptCallData.length) + 4,
                _methodId,
                _evmScriptCallData
            );
    }

    /// @notice Encodes multiple calls of the same method on one contract as EVMScript
    function createEVMScript(
        address _to,
        bytes4 _methodId,
        bytes[] memory _evmScriptCallData
    ) internal pure returns (bytes memory _evmScript) {
        for (uint256 i = 0; i < _evmScriptCallData.length; ++i) {
            _evmScript = bytes.concat(
                _evmScript,
                abi.encodePacked(
                    _to,
                    uint32(_evmScriptCallData[i].length) + 4,
                    _methodId,
                    _evmScriptCallData[i]
                )
            );
        }
        _evmScript = bytes.concat(SPEC_ID, _evmScript);
    }

    /// @notice Encodes multiple calls to different methods within the same contract as EVMScript
    function createEVMScript(
        address _to,
        bytes4[] memory _methodIds,
        bytes[] memory _evmScriptCallData
    ) internal pure returns (bytes memory _evmScript) {
        require(_methodIds.length == _evmScriptCallData.length, "LENGTH_MISMATCH");

        for (uint256 i = 0; i < _methodIds.length; ++i) {
            _evmScript = bytes.concat(
                _evmScript,
                abi.encodePacked(
                    _to,
                    uint32(_evmScriptCallData[i].length) + 4,
                    _methodIds[i],
                    _evmScriptCallData[i]
                )
            );
        }
        _evmScript = bytes.concat(SPEC_ID, _evmScript);
    }

    /// @notice Encodes multiple calls to different contracts as EVMScript
    function createEVMScript(
        address[] memory _to,
        bytes4[] memory _methodIds,
        bytes[] memory _evmScriptCallData
    ) internal pure returns (bytes memory _evmScript) {
        require(_to.length == _methodIds.length, "LENGTH_MISMATCH");
        require(_to.length == _evmScriptCallData.length, "LENGTH_MISMATCH");

        for (uint256 i = 0; i < _to.length; ++i) {
            _evmScript = bytes.concat(
                _evmScript,
                abi.encodePacked(
                    _to[i],
                    uint32(_evmScriptCallData[i].length) + 4,
                    _methodIds[i],
                    _evmScriptCallData[i]
                )
            );
        }
        _evmScript = bytes.concat(SPEC_ID, _evmScript);
    }
}

// File: contracts/interfaces/IEVMScriptFactory.sol

// SPDX-FileCopyrightText: 2021 Lido <[email protected]>

pragma solidity ^0.8.4;

/// @author psirex
/// @notice Interface which every EVMScript factory used in EasyTrack contract has to implement
interface IEVMScriptFactory {
    function createEVMScript(address _creator, bytes memory _evmScriptCallData)
        external
        returns (bytes memory);
}

// File: contracts/EVMScriptFactories/AddRewardProgram.sol

// SPDX-FileCopyrightText: 2021 Lido <[email protected]>

pragma solidity ^0.8.4;





/// @author psirex
/// @notice Creates EVMScript to add new reward program address to RewardProgramsRegistry
contract AddRewardProgram is TrustedCaller, IEVMScriptFactory {
    // -------------
    // ERRORS
    // -------------
    string private constant ERROR_REWARD_PROGRAM_ALREADY_ADDED = "REWARD_PROGRAM_ALREADY_ADDED";

    // -------------
    // VARIABLES
    // -------------

    /// @notice Address of RewardsProgramsRegistry
    RewardProgramsRegistry public immutable rewardProgramsRegistry;

    // -------------
    // CONSTRUCTOR
    // -------------

    constructor(address _trustedCaller, address _rewardProgramsRegistry)
        TrustedCaller(_trustedCaller)
    {
        rewardProgramsRegistry = RewardProgramsRegistry(_rewardProgramsRegistry);
    }

    // -------------
    // EXTERNAL METHODS
    // -------------

    /// @notice Creates EVMScript to add new reward program address to RewardProgramsRegistry
    /// @param _creator Address who creates EVMScript
    /// @param _evmScriptCallData Encoded tuple: (address _rewardProgram)
    function createEVMScript(address _creator, bytes memory _evmScriptCallData)
        external
        view
        override
        onlyTrustedCaller(_creator)
        returns (bytes memory)
    {
        (address rewardProgramAddress, ) = _decodeEVMScriptCallData(_evmScriptCallData);
        require(
            !rewardProgramsRegistry.isRewardProgram(rewardProgramAddress),
            ERROR_REWARD_PROGRAM_ALREADY_ADDED
        );

        return
            EVMScriptCreator.createEVMScript(
                address(rewardProgramsRegistry),
                rewardProgramsRegistry.addRewardProgram.selector,
                _evmScriptCallData
            );
    }

    /// @notice Decodes call data used by createEVMScript method
    /// @param _evmScriptCallData Encoded tuple: (address _rewardProgram, string _title)
    /// @return _rewardProgram Address of new reward program
    function decodeEVMScriptCallData(bytes memory _evmScriptCallData)
        external
        pure
        returns (address, string memory)
    {
        return _decodeEVMScriptCallData(_evmScriptCallData);
    }

    // ------------------
    // PRIVATE METHODS
    // ------------------

    function _decodeEVMScriptCallData(bytes memory _evmScriptCallData)
        private
        pure
        returns (address, string memory)
    {
        return abi.decode(_evmScriptCallData, (address, string));
    }
}

Contract ABI

[{"inputs":[{"internalType":"address","name":"_trustedCaller","type":"address"},{"internalType":"address","name":"_rewardProgramsRegistry","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"_creator","type":"address"},{"internalType":"bytes","name":"_evmScriptCallData","type":"bytes"}],"name":"createEVMScript","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"_evmScriptCallData","type":"bytes"}],"name":"decodeEVMScriptCallData","outputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"rewardProgramsRegistry","outputs":[{"internalType":"contract RewardProgramsRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"trustedCaller","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]

60c060405234801561001057600080fd5b5060405161084e38038061084e83398101604081905261002f916100d2565b60408051808201909152601e81527f545255535445445f43414c4c45525f49535f5a45524f5f414444524553530000602082015282906001600160a01b0382166100955760405162461bcd60e51b815260040161008c9190610105565b60405180910390fd5b506001600160601b0319606091821b811660805291901b1660a0525061015a565b80516001600160a01b03811681146100cd57600080fd5b919050565b600080604083850312156100e557600080fd5b6100ee836100b6565b91506100fc602084016100b6565b90509250929050565b600060208083528351808285015260005b8181101561013257858101830151858201604001528201610116565b81811115610144576000604083870101525b50601f01601f1916929092016040019392505050565b60805160601c60a05160601c6106b661019860003960008181609a015281816101cd01526102a40152600081816056015261011801526106b66000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c8063268f0760146100515780633f052ae914610095578063ecf7c690146100bc578063fea21c9c146100dd575b600080fd5b6100787f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b6100787f000000000000000000000000000000000000000000000000000000000000000081565b6100cf6100ca366004610492565b6100fd565b60405161008c92919061055c565b6100f06100eb366004610419565b610113565b60405161008c9190610580565b6000606061010a836102da565b91509150915091565b6060827f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316146040518060400160405280601381526020017221a0a62622a92fa4a9afa327a92124a22222a760691b8152509061019e5760405162461bcd60e51b81526004016101959190610580565b60405180910390fd5b5060006101aa846102da565b50604051632549560760e21b81526001600160a01b0380831660048301529192507f000000000000000000000000000000000000000000000000000000000000000090911690639525581c9060240160206040518083038186803b15801561021157600080fd5b505afa158015610225573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102499190610469565b156040518060400160405280601c81526020017f5245574152445f50524f4752414d5f414c52454144595f4144444544000000008152509061029e5760405162461bcd60e51b81526004016101959190610580565b506102d17f000000000000000000000000000000000000000000000000000000000000000063fa508cef60e01b866102f2565b95945050505050565b600060608280602001905181019061010a919061038c565b6060600160e01b848351600461030891906105ec565b858560405160200161031e9594939291906104fb565b60405160208183030381529060405290509392505050565b600082601f83011261034757600080fd5b813561035a610355826105c4565b610593565b81815284602083860101111561036f57600080fd5b816020850160208301376000918101602001919091529392505050565b6000806040838503121561039f57600080fd5b82516103aa81610668565b602084015190925067ffffffffffffffff8111156103c757600080fd5b8301601f810185136103d857600080fd5b80516103e6610355826105c4565b8181528660208385010111156103fb57600080fd5b61040c826020830160208601610622565b8093505050509250929050565b6000806040838503121561042c57600080fd5b823561043781610668565b9150602083013567ffffffffffffffff81111561045357600080fd5b61045f85828601610336565b9150509250929050565b60006020828403121561047b57600080fd5b8151801515811461048b57600080fd5b9392505050565b6000602082840312156104a457600080fd5b813567ffffffffffffffff8111156104bb57600080fd5b6104c784828501610336565b949350505050565b600081518084526104e7816020860160208601610622565b601f01601f19169290920160200192915050565b6001600160e01b03198681168252606086901b6bffffffffffffffffffffffff1916600483015260e085901b811660188301528316601c820152815160009061054b816020808601908701610622565b919091016020019695505050505050565b6001600160a01b03831681526040602082018190526000906104c7908301846104cf565b60208152600061048b60208301846104cf565b604051601f8201601f1916810167ffffffffffffffff811182821017156105bc576105bc610652565b604052919050565b600067ffffffffffffffff8211156105de576105de610652565b50601f01601f191660200190565b600063ffffffff80831681851680830382111561061957634e487b7160e01b600052601160045260246000fd5b01949350505050565b60005b8381101561063d578181015183820152602001610625565b8381111561064c576000848401525b50505050565b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038116811461067d57600080fd5b5056fea26469706673582212203e4c496b77b6d3c510c1cc75887a101446b3a46ee921fdbddec038e3bfac7fe664736f6c63430008060033000000000000000000000000b9b953bb58411d7932d76a2493e309c88f9f2e13000000000000000000000000648c8be548f43eca4e482c0801ebccccfb944931

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

000000000000000000000000b9b953bb58411d7932d76a2493e309c88f9f2e13000000000000000000000000648c8be548f43eca4e482c0801ebccccfb944931

-----Decoded View---------------
Arg [0] : _trustedCaller (address): 0xB9b953Bb58411D7932D76A2493e309c88F9f2e13
Arg [1] : _rewardProgramsRegistry (address): 0x648C8Be548F43eca4e482C0801Ebccccfb944931

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000b9b953bb58411d7932d76a2493e309c88f9f2e13
Arg [1] : 000000000000000000000000648c8be548f43eca4e482c0801ebccccfb944931


Deployed ByteCode Sourcemap

24558:2427:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;587:38;;;;;;;;-1:-1:-1;;;;;3412:32:1;;;3394:51;;3382:2;3367:18;587:38:0;;;;;;;;24902:62;;;;;26459:215;;;;;;:::i;:::-;;:::i;:::-;;;;;;;;:::i;25547:686::-;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;26459:215::-;26575:7;26584:13;26622:44;26647:18;26622:24;:44::i;:::-;26615:51;;;;26459:215;;;:::o;25547:686::-;25728:12;25700:8;887:13;-1:-1:-1;;;;;876:24:0;:7;-1:-1:-1;;;;;876:24:0;;902:25;;;;;;;;;;;;;-1:-1:-1;;;902:25:0;;;868:60;;;;;-1:-1:-1;;;868:60:0;;;;;;;;:::i;:::-;;;;;;;;;;25759:28:::1;25793:44;25818:18;25793:24;:44::i;:::-;-1:-1:-1::0;25871:60:0::1;::::0;-1:-1:-1;;;25871:60:0;;-1:-1:-1;;;;;3412:32:1;;;25871:60:0::1;::::0;::::1;3394:51:1::0;25758:79:0;;-1:-1:-1;25871:22:0::1;:38:::0;;::::1;::::0;::::1;::::0;3367:18:1;;25871:60:0::1;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;25870:61;25946:34;;;;;;;;;;;;;;;;::::0;25848:143:::1;;;;;-1:-1:-1::0;;;25848:143:0::1;;;;;;;;:::i;:::-;-1:-1:-1::0;26024:201:0::1;26083:22;-1:-1:-1::0;;;26192:18:0;26024:32:::1;:201::i;:::-;26004:221:::0;25547:686;-1:-1:-1;;;;;25547:686:0:o;26762:220::-;26878:7;26887:13;26936:18;26925:49;;;;;;;;;;;;:::i;21059:409::-;21205:22;-1:-1:-1;;;21321:3:0;21350:18;:25;21379:1;21343:37;;;;:::i;:::-;21399:9;21427:18;21260:200;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;21240:220;;21059:409;;;;;:::o;14:462:1:-;56:5;109:3;102:4;94:6;90:17;86:27;76:2;;127:1;124;117:12;76:2;163:6;150:20;194:48;210:31;238:2;210:31;:::i;:::-;194:48;:::i;:::-;267:2;258:7;251:19;313:3;306:4;301:2;293:6;289:15;285:26;282:35;279:2;;;330:1;327;320:12;279:2;395;388:4;380:6;376:17;369:4;360:7;356:18;343:55;443:1;418:16;;;436:4;414:27;407:38;;;;422:7;66:410;-1:-1:-1;;;66:410:1:o;481:771::-;578:6;586;639:2;627:9;618:7;614:23;610:32;607:2;;;655:1;652;645:12;607:2;687:9;681:16;706:31;731:5;706:31;:::i;:::-;805:2;790:18;;784:25;756:5;;-1:-1:-1;832:18:1;821:30;;818:2;;;864:1;861;854:12;818:2;887:22;;940:4;932:13;;928:27;-1:-1:-1;918:2:1;;969:1;966;959:12;918:2;998;992:9;1023:48;1039:31;1067:2;1039:31;:::i;1023:48::-;1094:2;1087:5;1080:17;1134:7;1129:2;1124;1120;1116:11;1112:20;1109:33;1106:2;;;1155:1;1152;1145:12;1106:2;1168:54;1219:2;1214;1207:5;1203:14;1198:2;1194;1190:11;1168:54;:::i;:::-;1241:5;1231:15;;;;;597:655;;;;;:::o;1257:455::-;1334:6;1342;1395:2;1383:9;1374:7;1370:23;1366:32;1363:2;;;1411:1;1408;1401:12;1363:2;1450:9;1437:23;1469:31;1494:5;1469:31;:::i;:::-;1519:5;-1:-1:-1;1575:2:1;1560:18;;1547:32;1602:18;1591:30;;1588:2;;;1634:1;1631;1624:12;1588:2;1657:49;1698:7;1689:6;1678:9;1674:22;1657:49;:::i;:::-;1647:59;;;1353:359;;;;;:::o;1717:277::-;1784:6;1837:2;1825:9;1816:7;1812:23;1808:32;1805:2;;;1853:1;1850;1843:12;1805:2;1885:9;1879:16;1938:5;1931:13;1924:21;1917:5;1914:32;1904:2;;1960:1;1957;1950:12;1904:2;1983:5;1795:199;-1:-1:-1;;;1795:199:1:o;1999:320::-;2067:6;2120:2;2108:9;2099:7;2095:23;2091:32;2088:2;;;2136:1;2133;2126:12;2088:2;2176:9;2163:23;2209:18;2201:6;2198:30;2195:2;;;2241:1;2238;2231:12;2195:2;2264:49;2305:7;2296:6;2285:9;2281:22;2264:49;:::i;:::-;2254:59;2078:241;-1:-1:-1;;;;2078:241:1:o;2324:257::-;2365:3;2403:5;2397:12;2430:6;2425:3;2418:19;2446:63;2502:6;2495:4;2490:3;2486:14;2479:4;2472:5;2468:16;2446:63;:::i;:::-;2563:2;2542:15;-1:-1:-1;;2538:29:1;2529:39;;;;2570:4;2525:50;;2373:208;-1:-1:-1;;2373:208:1:o;2586:657::-;-1:-1:-1;;;;;;2890:15:1;;;2878:28;;2943:2;2939:15;;;-1:-1:-1;;2935:53:1;2931:1;2922:11;;2915:74;2853:3;3023:16;;;3019:25;;3014:2;3005:12;;2998:47;3075:15;;3070:2;3061:12;;3054:37;3114:13;;2821:3;;3136:60;3114:13;3184:2;3175:12;;;;3158:15;;3136:60;:::i;:::-;3216:16;;;;3234:2;3212:25;;2829:414;-1:-1:-1;;;;;;2829:414:1:o;3456:316::-;-1:-1:-1;;;;;3633:32:1;;3615:51;;3702:2;3697;3682:18;;3675:30;;;-1:-1:-1;;3722:44:1;;3747:18;;3739:6;3722:44;:::i;3777:217::-;3924:2;3913:9;3906:21;3887:4;3944:44;3984:2;3973:9;3969:18;3961:6;3944:44;:::i;4461:275::-;4532:2;4526:9;4597:2;4578:13;;-1:-1:-1;;4574:27:1;4562:40;;4632:18;4617:34;;4653:22;;;4614:62;4611:2;;;4679:18;;:::i;:::-;4715:2;4708:22;4506:230;;-1:-1:-1;4506:230:1:o;4741:186::-;4789:4;4822:18;4814:6;4811:30;4808:2;;;4844:18;;:::i;:::-;-1:-1:-1;4910:2:1;4889:15;-1:-1:-1;;4885:29:1;4916:4;4881:40;;4798:129::o;4932:325::-;4971:3;4999:10;5036:2;5033:1;5029:10;5066:2;5063:1;5059:10;5097:3;5093:2;5089:12;5084:3;5081:21;5078:2;;;5144:10;5139:3;5135:20;5132:1;5125:31;5179:4;5176:1;5169:15;5207:4;5204:1;5197:15;5078:2;5238:13;;4979:278;-1:-1:-1;;;;4979:278:1:o;5262:258::-;5334:1;5344:113;5358:6;5355:1;5352:13;5344:113;;;5434:11;;;5428:18;5415:11;;;5408:39;5380:2;5373:10;5344:113;;;5475:6;5472:1;5469:13;5466:2;;;5510:1;5501:6;5496:3;5492:16;5485:27;5466:2;;5315:205;;;:::o;5525:127::-;5586:10;5581:3;5577:20;5574:1;5567:31;5617:4;5614:1;5607:15;5641:4;5638:1;5631:15;5657:131;-1:-1:-1;;;;;5732:31:1;;5722:42;;5712:2;;5778:1;5775;5768:12;5712:2;5702:86;:::o

Swarm Source

ipfs://3e4c496b77b6d3c510c1cc75887a101446b3a46ee921fdbddec038e3bfac7fe6
Block Transaction Difficulty Gas Used Reward
Block Uncle Number Difficulty Gas Used Reward
Loading

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.