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()–trueif supply is pre-minted in a treasury and transferred;falseifDinoPrimarymints/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.
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
subscribefunction 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
amountof ERC-3643 fromissuerSafetomsg.sender.
For non-preminted assets:
Mints
amountof ERC-3643 tomsg.sender.
In both cases:
Calculates total cost using a price feed implementing the AggregatorV3Interface.
Transfers
paymentTokenfrom investor toissuerSafe.Collects protocol fee via
ecosystemFeeCollector.Emits
Subscribed(nonce, investor, paymentToken, amount, totalCost).
Reverts if:
Subscriptions are closed (
SubscriptionClosed).amount < minAmountoramount > maxAmount(AmountBelowMinimum/AmountAboveMaximum).paymentTokenis 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
redeemfunction 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.senderback toissuerSafe.
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
paymentTokenfromissuerSafeto investor.Collects protocol fee.
Emits
Redeemed(nonce, investor, paymentToken, amount, paymentAmount).
Reverts if:
Redemptions are closed (
RedemptionClosed).amount < minAmountoramount > maxAmount(AmountBelowMinimum/AmountAboveMaximum).paymentTokennot approved.Investor or transfer not compliant.
Price feed invalid.
issuerSafedoesn’t have enoughpaymentTokenbalance / 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
previewSubscribeWithExactErc3643function previewSubscribeWithExactErc3643(
uint256 erc3643Amount,
address paymentToken
) external view returns (uint256 paymentTokenAmount);Returns how much paymentToken is required to subscribe erc3643Amount of the asset.
previewSubscribeWithExactToken
previewSubscribeWithExactTokenfunction previewSubscribeWithExactToken(
uint256 paymentTokenAmount,
address paymentToken
) external view returns (uint256 erc3643Amount);Returns how many ERC-3643 tokens the investor would receive when paying paymentTokenAmount.
previewRedeemWithExactErc3643
previewRedeemWithExactErc3643function previewRedeemWithExactErc3643(
uint256 erc3643Amount,
address paymentToken
) external view returns (uint256 paymentTokenAmount);Returns net payment after applying redemption malus for redeeming erc3643Amount.
previewRedeemWithExactToken
previewRedeemWithExactTokenfunction 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.
These helpers are ideal for front-ends: quote first, then call subscribe / redeem using the same parameters.
Payment Token Management
Requires TOKEN_MANAGER_ROLE via AccessManager.
addPaymentToken
addPaymentTokenfunction addPaymentToken(
address token,
address priceFeed,
bool isStable
) external;Registers a new payment token:
token– ERC-20 used for payments.priceFeed– AggregatorV3Interface fortokenvs pricing currency.isStable–trueif the token is considered stable (e.g. fully backed stablecoin).
Reverts if:
tokenis zero address (ZeroAddress).Token already added (
PaymentTokenAlreadyAdded).
removePaymentToken
removePaymentTokenfunction 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
updatePaymentTokenfunction 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
getPaymentTokens / getPaymentTokenCountfunction 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
Requires RULES_MANAGER_ROLE via AccessManager.
updateSubscriptionRules
updateSubscriptionRulesfunction 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 foramount.
Reverts if minAmount > maxAmount (InvalidAmounts).
updateRedemptionRules
updateRedemptionRulesfunction 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
subscriptionRulesfunction 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
redemptionRulesfunction 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
Require ADMIN_ROLE via AccessManager.
updateIssuerSafe
updateIssuerSafefunction updateIssuerSafe(address newIssuerSafe) external;Updates the address that:
Receives subscription proceeds.
Pays redemptions.
Reverts if newIssuerSafe is zero address.
updatePreminted
updatePremintedfunction updatePreminted(bool _preminted) external;Toggles mode:
true– transfer fromissuerSafe(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)fromAccessManaged.
Custom Errors (from ErrorsLib)
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 > maxAmountin 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