Developer Reference

This page documents the public interface of the DinoPrimary contract:

  • Solidity interface (high-level)

  • Function-by-function behavior (with access control & revert reasons)

  • Events & custom errors

Admin concepts (roles, issuerSafe, preminted, rules, etc.) are described on the Admin & Management page; here we focus on how to call the contract.

Contract & Imports

import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { IERC3643 } from "@erc3643org/erc-3643/contracts/ERC-3643/IERC3643.sol";
import { AggregatorV3Interface } from "@chainlink/contracts/src/v0.8/shared/interfaces/AggregatorV3Interface.sol";
import { IDinoPrimary } from "./interfaces/IDinoPrimary.sol";
import { IFeeCollector } from "./interfaces/IFeeCollector.sol";

contract DinoPrimary is IDinoPrimary { /* ... */ }

Each asset has its own instance of DinoPrimary, typically deployed and initialized via DinoFactory.

State Variables (Public Getters)

DinoPrimary exposes a few public variables:

IERC3643 public erc3643;
address  public issuerSafe;
bool     public preminted;
IFeeCollector public ecosystemFeeCollector;

uint256 public nonce;
mapping(address => PaymentToken) public approvedPaymentTokens;
  • erc3643() – underlying ERC-3643 token for this primary rail.

  • issuerSafe() – address receiving subscription proceeds and paying redemptions.

  • preminted()true if supply is pre-minted in a treasury and transferred; false if DinoPrimary mints/burns.

  • ecosystemFeeCollector() – protocol fee collector.

  • nonce() – incremented per subscription / redemption; also emitted in events.

  • approvedPaymentTokens(token) – returns price feed and stability info for a payment token.

You won’t write to these directly – use the admin functions and rely on DinoFactory for initialization.

Solidity Interface

interface IDinoPrimary {
    // --- Lifecycle / Setup ---

    function initialize(
        address _erc3643,
        address _issuerSafe,
        bool _preminted,
        address _accessManager,
        address _ecosystemFeeCollector
    ) external;

    // --- Investor functions ---

    function subscribe(
        uint256 amount,
        address paymentToken
    ) external returns (uint256 nonce);

    function redeem(
        uint256 amount,
        address paymentToken
    ) external returns (uint256 nonce);

    // --- Preview helpers (read-only) ---

    function previewSubscribeWithExactErc3643(
        uint256 erc3643Amount,
        address paymentToken
    ) external view returns (uint256 paymentTokenAmount);

    function previewSubscribeWithExactToken(
        uint256 paymentTokenAmount,
        address paymentToken
    ) external view returns (uint256 erc3643Amount);

    function previewRedeemWithExactErc3643(
        uint256 erc3643Amount,
        address paymentToken
    ) external view returns (uint256 paymentTokenAmount);

    function previewRedeemWithExactToken(
        uint256 paymentTokenAmount,
        address paymentToken
    ) external view returns (uint256 erc3643Amount);

    // --- Payment token management (TOKEN_MANAGER_ROLE) ---

    function addPaymentToken(
        address token,
        address priceFeed,
        bool isStable
    ) external;

    function removePaymentToken(
        address token
    ) external;

    function updatePaymentToken(
        address token,
        address priceFeed,
        bool isStable
    ) external;

    function getPaymentTokens()
        external
        view
        returns (address[] memory);

    function getPaymentTokenCount()
        external
        view
        returns (uint256);

    // --- Rules (RULES_MANAGER_ROLE) ---

    function updateSubscriptionRules(
        uint256 dateOpened,
        uint256 dateClosed,
        uint256 minAmount,
        uint256 maxAmount
    ) external;

    function updateRedemptionRules(
        uint256 dateOpened,
        uint256 dateClosed,
        uint256 minAmount,
        uint256 maxAmount,
        uint16 redemptionMalus
    ) external;

    function subscriptionRules()
        external
        view
        returns (
            bool isOpen,
            uint256 dateOpened,
            uint256 dateClosed,
            uint256 minAmount,
            uint256 maxAmount
        );

    function redemptionRules()
        external
        view
        returns (
            bool isOpen,
            uint256 dateOpened,
            uint256 dateClosed,
            uint256 minAmount,
            uint256 maxAmount,
            uint16 malus
        );

    // --- Admin (ADMIN_ROLE) ---

    function updateIssuerSafe(address newIssuerSafe) external;

    function updatePreminted(bool _preminted) external;
}

Access control (roles) is enforced by AccessManaged via an AccessManager contract; see Admin & Management for role mapping.

Investor Functions

subscribe

function subscribe(
    uint256 amount,
    address paymentToken
) external nonReentrant returns (uint256 nonce);

Description

Subscribes amount of ERC-3643 tokens using paymentToken as consideration.

  • For preminted assets:

    • Transfers amount of ERC-3643 from issuerSafe to msg.sender.

  • For non-preminted assets:

    • Mints amount of ERC-3643 to msg.sender.

In both cases:

  • Calculates total cost using a price feed implementing the AggregatorV3Interface.

  • Transfers paymentToken from investor to issuerSafe.

  • Collects protocol fee via ecosystemFeeCollector.

  • Emits Subscribed(nonce, investor, paymentToken, amount, totalCost).

Reverts if:

  • Subscriptions are closed (SubscriptionClosed).

  • amount < minAmount or amount > maxAmount (AmountBelowMinimum / AmountAboveMaximum).

  • paymentToken is not approved (PaymentTokenNotApproved).

  • ERC-3643 transfer / mint is not compliant (TransferNotCompliant, InvestorNotQualified).

  • Price feed issues (InvalidPriceFeed).

  • Fee collection fails (e.g. missing approval / balance on fee token).

redeem

function redeem(
    uint256 amount,
    address paymentToken
) external nonReentrant returns (uint256 nonce);

Description

Redeems amount of ERC-3643 tokens back to the issuer, and pays the investor in paymentToken.

  • For preminted assets:

    • Transfers ERC-3643 from msg.sender back to issuerSafe.

  • For non-preminted assets:

    • Burns ERC-3643 from msg.sender (DinoPrimary is an authorized agent).

Then:

  • Computes payment amount based on NAV / price feed.

  • Applies redemption malus (haircut) if configured.

  • Transfers paymentToken from issuerSafe to investor.

  • Collects protocol fee.

  • Emits Redeemed(nonce, investor, paymentToken, amount, paymentAmount).

Reverts if:

  • Redemptions are closed (RedemptionClosed).

  • amount < minAmount or amount > maxAmount (AmountBelowMinimum / AmountAboveMaximum).

  • paymentToken not approved.

  • Investor or transfer not compliant.

  • Price feed invalid.

  • issuerSafe doesn’t have enough paymentToken balance / allowance.

  • Fee collection fails (e.g. missing approval / balance on fee token).

Preview Functions (Read-Only Quotes)

These functions do not modify state and allow UIs or off-chain systems to quote amounts without executing the operation.

previewSubscribeWithExactErc3643

function previewSubscribeWithExactErc3643(
    uint256 erc3643Amount,
    address paymentToken
) external view returns (uint256 paymentTokenAmount);

Returns how much paymentToken is required to subscribe erc3643Amount of the asset.

previewSubscribeWithExactToken

function previewSubscribeWithExactToken(
    uint256 paymentTokenAmount,
    address paymentToken
) external view returns (uint256 erc3643Amount);

Returns how many ERC-3643 tokens the investor would receive when paying paymentTokenAmount.

previewRedeemWithExactErc3643

function previewRedeemWithExactErc3643(
    uint256 erc3643Amount,
    address paymentToken
) external view returns (uint256 paymentTokenAmount);

Returns net payment after applying redemption malus for redeeming erc3643Amount.

previewRedeemWithExactToken

function previewRedeemWithExactToken(
    uint256 paymentTokenAmount,
    address paymentToken
) external view returns (uint256 erc3643Amount);

Returns how many ERC-3643 tokens the investor needs to redeem to receive paymentTokenAmount after malus.

Payment Token Management

addPaymentToken

function addPaymentToken(
    address token,
    address priceFeed,
    bool isStable
) external;

Registers a new payment token:

  • token – ERC-20 used for payments.

  • priceFeedAggregatorV3Interface for token vs pricing currency.

  • isStabletrue if the token is considered stable (e.g. fully backed stablecoin).

Reverts if:

  • token is zero address (ZeroAddress).

  • Token already added (PaymentTokenAlreadyAdded).

removePaymentToken

function removePaymentToken(address token) external;

Removes a payment token. It will no longer be accepted for new subscriptions or redemptions.

Reverts if:

  • Token is not in the approved set (PaymentTokenNotApproved).

updatePaymentToken

function updatePaymentToken(
    address token,
    address priceFeed,
    bool isStable
) external;

Updates price feed and stability flag for an existing payment token.

Reverts if token is not approved.

getPaymentTokens / getPaymentTokenCount

function getPaymentTokens()
    external
    view
    returns (address[] memory);

function getPaymentTokenCount()
    external
    view
    returns (uint256);

Allow enumerating all approved payment tokens, on top of the approvedPaymentTokens(token) getter.

Rules Management

updateSubscriptionRules

function updateSubscriptionRules(
    uint256 dateOpened,
    uint256 dateClosed,
    uint256 minAmount,
    uint256 maxAmount
) external;

Sets subscription period and per-tx min/max.

  • dateOpened – unix timestamp when subscriptions start.

  • dateClosed – unix timestamp when subscriptions end (0 = no end).

  • minAmount / maxAmount – per-call bounds for amount.

Reverts if minAmount > maxAmount (InvalidAmounts).

updateRedemptionRules

function updateRedemptionRules(
    uint256 dateOpened,
    uint256 dateClosed,
    uint256 minAmount,
    uint256 maxAmount,
    uint16 redemptionMalus
) external;

Same as subscription rules, plus:

  • redemptionMalus – in basis points (e.g. 100 = 1%, 500 = 5%) applied as haircut on redemptions.

subscriptionRules

function subscriptionRules()
    external
    view
    returns (
        bool isOpen,
        uint256 dateOpened,
        uint256 dateClosed,
        uint256 minAmount,
        uint256 maxAmount
    );

Returns current subscription rule set and whether the window is open at block.timestamp.

redemptionRules

function redemptionRules()
    external
    view
    returns (
        bool isOpen,
        uint256 dateOpened,
        uint256 dateClosed,
        uint256 minAmount,
        uint256 maxAmount,
        uint16 malus
    );

Same for redemptions, including the currently configured malus.

Admin Functions

updateIssuerSafe

function updateIssuerSafe(address newIssuerSafe) external;

Updates the address that:

  • Receives subscription proceeds.

  • Pays redemptions.

Reverts if newIssuerSafe is zero address.

updatePreminted

function updatePreminted(bool _preminted) external;

Toggles mode:

  • true – transfer from issuerSafe (treasury).

  • false – mint/burn via ERC-3643 permissions.

Emits PremintedUpdated.

Events

  • event IssuerSafeUpdated(address indexed oldIssuerSafe, address indexed newIssuerSafe)

  • event PremintedUpdated(address indexed updatedBy, bool preminted)

  • event PaymentTokenAdded(address indexed token, address priceFeed, bool isStable)

  • event PaymentTokenRemoved(address indexed token)

  • event PaymentTokenUpdated(address indexed token, address priceFeed, bool isStable)

  • event SubscriptionRulesUpdated(uint256 dateOpened, uint256 dateClosed, uint256 minAmount, uint256 maxAmount, address indexed updatedBy)

  • event RedemptionRulesUpdated(uint256 dateOpened, uint256 dateClosed, uint256 minAmount, uint256 maxAmount, uint16 redemptionMalus, address indexed updatedBy)

  • event Subscribed(uint256 indexed nonce, address indexed investor, address indexed paymentToken, uint256 amount, uint256 totalCost)

  • event Redeemed(uint256 indexed nonce, address indexed investor, address indexed paymentToken, uint256 amount, uint256 paymentAmount)

Plus inherited:

  • AuthorityUpdated(address authority) from AccessManaged.

Custom Errors (from ErrorsLib)

DinoPrimary relies on a shared error library. Relevant errors include:

  • ZeroAddress() – one of the addresses is zero.

  • SubscriptionClosed() – subscription window not open.

  • RedemptionClosed() – redemption window not open.

  • AmountBelowMinimum(uint256 amount, uint256 min)

  • AmountAboveMaximum(uint256 amount, uint256 max)

  • PaymentTokenAlreadyAdded(address token)

  • PaymentTokenNotApproved(address token)

  • InvalidAmounts()minAmount > maxAmount in rules updates.

  • InvalidPriceFeed() – price feed returns non-positive value.

  • InvestorNotQualified(address investor) – identity / eligibility issue.

  • TransferNotCompliant() – ERC-3643 compliance prevents transfer/mint/burn.

These are meant to be developer-friendly and easily mapped to front-end error messages.

Last updated