Interfaces
On this page
Choose the module for the action you need: NoteCore for series and settlement, NoteLegs for balances and transfers, and the oracle and calendar interfaces for price timing. Token, vault and governance interfaces are separate references below; verify the deployed version before calling.
fact Copied from contracts/src/interfaces/ (Solidity 0.8.28). Comments abridged.
INoteCore
interface INoteCore {
enum Status { None, Subscription, Live, Autocalled, Matured, Cancelled, Unwound }
struct SeriesParams {
address underlying; // Stock Token
address feed; // AggregatorV3 for the underlying
uint16 autocallBps; // e.g. 10_000
uint16 barrierBps; // e.g. 6_500
uint16 couponFloorBps;
uint16 couponCapBps; // <= maxCouponCapBps (400)
uint16 refBps; // reference coupon for discovery
uint40[] observations; // [strike, obs1, ..., maturity], official closes
uint128 notionalCap; // quote units
uint128 minTicket; // quote units
uint40 subscriptionEnd; // <= observations[0]
}
function createSeries(SeriesParams calldata p) external returns (uint256 seriesId);
function depositCoupon(uint256 seriesId, uint256 quoteAmount) external;
function depositCouponReserved(uint256 seriesId, uint256 quoteAmount, uint16 minCouponBps) external; // reserveDepositor only; joins the book at strike only as far as the coupon stays >= minCouponBps, the rest is refunded
function depositShield(uint256 seriesId, uint256 stockAmount, uint256 prefundQuote) external;
function finalizeStrike(uint256 seriesId) external; // permissionless after observations[0]
function observe(uint256 seriesId) external; // permissionless, next pending observation
function claim(uint256 seriesId) external returns (uint256 quoteOut);
function redeem(uint256 seriesId, uint256 units) external returns (uint256 quoteOut, uint256 stockOut);
function refund(uint256 seriesId) external returns (uint256 quoteOut, uint256 stockOut);
function sweepFees(uint256 seriesId) external; // moves sweepableFees(seriesId); NoFees if zero
function onLegTransfer(uint256 seriesId, uint8 leg, address from, address to, uint256 amount) external; // only NoteLegs
function seriesStatus(uint256 seriesId) external view returns (Status);
function seriesCount() external view returns (uint256);
function reserveDepositor() external view returns (address); // the one account allowed to post reserved COUPON (the Desk); zero: none
function reserveOf(uint256 seriesId) external view returns (address account, uint256 deposit, uint16 minCouponBps, uint256 excluded); // reserve account, its deposit, the highest hurdle posted, quote excluded at strike
}
On the NoteCore contract itself: setReserveDepositor(address account) (protocol parameter, ReserveDepositorSet(previous, current)) names the reserve depositor, and effectiveCloseOf(uint40 scheduled) -> uint40 returns the close a scheduled observation rolls to when it falls on a non-trading day (Following Business Day), the timestamp from which deposits are refused.
NoteCore Recovery and Module Surface
fact Added by the Upgradeability and recovery addendum (contracts/src/core/NoteCore.sol). Owner is the 48-hour governance. createSeries reverts CoreDeprecated() when SeriesRegistry.isActive(address(this)) is false.
// Module swaps with MODULE_GRACE = 24 h; one pending change per slot (ModuleChangePending)
function setOracle(address oracle_) external; // onlyOwner, KEY_ORACLE
function setCalendar(address calendar_) external; // onlyOwner, KEY_CALENDAR
function setFeeSink(address feeSink_) external; // onlyOwner, KEY_FEE_SINK
function setKeeperReward(uint256 keeperRewardQuote_) external; // onlyOwner, KEY_KEEPER_REWARD (ParamUpdated); <= maxKeeperReward() else InvalidParams
// Automation entry point (contract only, not in INoteCore)
function crank(uint256 seriesId) external returns (INoteCore.Status); // nonReentrant; runs any due strike / observation, returns the status
// Keeper reward bounds and fee reserve
uint256 constant MAX_KEEPER_REWARD_UNITS = 100; // whole quote units
function maxKeeperReward() external view returns (uint256); // MAX_KEEPER_REWARD_UNITS * 10**quoteDecimals
function keeperReserve(uint256 seriesId) external view returns (uint256); // one keeper reward per crank still due
function sweepableFees(uint256 seriesId) external view returns (uint256); // accruedFees - keeperReserve
// Recovery Unwind (Subscription | Live only)
uint40 constant UNWIND_GRACE = 48 hours;
function proposeUnwind(uint256 seriesId) external; // onlyOwner, whenPaused
function cancelUnwind(uint256 seriesId) external; // onlyOwnerOrGuardian
function unwind(uint256 seriesId) external; // onlyOwner, whenPaused; TooEarly(proposedAt + UNWIND_GRACE) before the grace; status -> Unwound
function withdrawUnwound(uint256 seriesId) external returns (uint256 quoteOut, uint256 stockOut); // holders, never pausable
function sweepExcess(address token, address to) external; // onlyOwner; reverts NoExcess(token), UnwindPending(count)
function recordedLiabilities(address token) external view returns (uint256); // quote: totalQuoteEscrow; underlying: totalStockEscrow
// Dust write-off on terminal series (Cancelled | Autocalled | Matured | Unwound)
uint256 constant DUST_LIMIT_STOCK = 1e12; // 10**(STOCK_DECIMALS - 6)
function dustLimitQuote() external view returns (uint256); // 10**quoteDecimals / 100
function writeOffDust(uint256 seriesId, address to) external; // onlyOwner; NotDust(quote, stock), NothingToWithdraw, InvalidStatus
Errors added by this surface: TooEarly(uint40 at), NoFees(), NotDust(uint256 quoteEscrow, uint256 stockEscrow), NothingToWithdraw().
ISeriesRegistry
fact contracts/src/core/SeriesRegistry.sol, immutable, Ownable (owner = governance).
interface ISeriesRegistry {
function register(address core) external returns (uint256 version); // onlyOwner
function deprecate(uint256 version) external; // onlyOwner, irreversible
function coreOf(uint256 version) external view returns (address); // UnknownVersion
function versionOf(address core) external view returns (uint256); // 0 = not registered
function isDeprecated(uint256 version) external view returns (bool);
function isActive(address core) external view returns (bool);
function latestVersion() external view returns (uint256);
function activeVersion() external view returns (uint256); // 0 if none
function activeCore() external view returns (address);
}
INoteCoreViews
interface INoteCoreViews {
struct SeriesView {
address underlying;
address feed;
uint16 autocallBps;
uint16 barrierBps;
uint16 couponFloorBps;
uint16 couponCapBps;
uint16 refBps;
uint16 couponFeeBps; // snapshotted at creation
uint16 notionalFeeBps; // snapshotted at creation
uint40 subscriptionEnd;
uint128 notionalCap;
uint128 minTicket;
uint40[] observations;
INoteCore.Status status;
uint16 couponBps; // discovered at strike
uint32 nextObs; // next observation index
bool breached; // physical settlement
uint256 s0; // 1e8
uint256 lastPrice; // 1e8
uint256 totalCouponDeposits; // D
uint256 totalShieldStock; // 18 dec
uint256 totalShieldPrefund; // quote
uint256 matchedNotional; // N
uint256 couponIndex; // WAD
uint256 quoteEscrow;
uint256 stockEscrow;
}
function legs() external view returns (address);
function quote() external view returns (address);
function getSeries(uint256 seriesId) external view returns (SeriesView memory);
function legId(uint256 seriesId, uint8 leg) external pure returns (uint256);
function barrierHolding(uint256 seriesId) external view returns (bool);
function accruedCoupon(uint256 seriesId, address account) external view returns (uint256);
function settle(uint256 seriesId, address account) external; // permissionless lazy match
function redeemShield(uint256 seriesId, uint256 units) external returns (uint256 quoteOut, uint256 stockOut);
function previewRedeem(uint256 seriesId, uint8 leg, uint256 units) external view returns (uint256 quoteOut, uint256 stockOut);
function requiredPrefund(uint256 seriesId, uint256 stockAmount) external view returns (uint256);
}
NoteCore also exposes public state: couponFeeBps, notionalFeeBps, maxCouponCapBps, maxObservations, keeperRewardQuote, feeSink, oracle, calendar, immutables quoteToken, quoteDecimals, legsToken, STOCK_SCALE, and constants LEG_COUPON = 0, LEG_SHIELD = 1, MAX_FEE_BPS = 5000, MAX_NOTIONAL_FEE_BPS = 500, STOCK_DECIMALS = 18. Three further views are implemented on the contract rather than the interface:
struct Accounting { uint256 couponSideQuote; uint256 prefundRemaining; uint256 prefundRefundable; uint256 couponPool;
uint256 accruedFees; uint256 stockMatched; uint256 stockRefundable; uint256 stockUnmatched;
uint256 prefundUnmatched; uint256 shieldUnusedPerUnit; }
struct Position { uint256 couponDeposit; uint256 shieldStock; uint256 shieldPrefund; uint256 refundCouponQuote;
uint256 refundPrefundQuote; uint256 refundStock; uint256 claimable; uint256 couponIndexPaid; bool settled; }
function getAccounting(uint256 seriesId) external view returns (Accounting memory);
function getPosition(uint256 seriesId, address account) external view returns (Position memory);
function previewSettle(uint256 seriesId, address account) external view
returns (uint256 couponUnits, uint256 shieldUnits, uint256 refundQuote, uint256 refundStock);
Governance setters on NoteCore (all onlyOwner): setFeeSink(address), setOracle(address), setCalendar(address), setFees(uint16 couponFeeBps, uint16 notionalFeeBps), setKeeperReward(uint256), setLimits(uint16 maxCouponCapBps, uint16 maxObservations). createSeries is restricted to the owner or the configured seriesCreator (RollPolicy; setSeriesCreator(address), SeriesCreatorSet, error NotSeriesCreator).
Three automation views live on NoteCore: dueWork(uint256 seriesId) -> (bool strikeDue, bool observeDue, bool settleable), observationDue(uint256 seriesId) -> bool (calendar-only: Live, next index unprocessed and past the effective close plus grace; no feed read, ignores deferral and pause) and the constant MAX_LAZY_OBSERVATIONS = 4 (see Automation and cranks). depositCoupon and depositShield (and therefore Desk.fillCoupon) revert SubscriptionClosed from min(subscriptionEnd, effectiveObservationTs(seriesId, 0)). keeperReserve(seriesId) values each remaining crank at the reward in force at its effective close.
Observation rolling (Following Business Day) is exposed by effectiveCloseOf(uint40 scheduled) -> uint40, effectiveObservationTs(uint256 seriesId, uint256 index) -> (uint40 scheduled, uint40 effective) (reverts InvalidParams("index") out of range) and the constant MAX_OBSERVATION_ROLL_DAYS = 8; nextObservationTs returns the effective close.
NoteLegs (ERC-1155)
function mint(address to, uint256 id, uint256 amount) external; // onlyCore
function burn(address from, uint256 id, uint256 amount) external; // onlyCore
function seriesOf(uint256 id) external pure returns (uint256); // id >> 1
function legOf(uint256 id) external pure returns (uint8); // id & 1
// plus standard ERC-1155: balanceOf, balanceOfBatch, safeTransferFrom, safeBatchTransferFrom, setApprovalForAll, uri
IOracleAdapter
interface IOracleAdapter {
function observe(address feed, uint40 closeTs) external returns (uint256 price, bool ok);
function peek(address feed, uint40 closeTs) external view returns (uint256 price, bool ok);
function latestPrice(address feed) external view returns (uint256 price); // referencePrice(feed).price
function referencePrice(address feed) external view returns (uint256 price, uint40 asOf, bool live); // StalePrice(feed)
function isCancelled(address feed, uint40 closeTs) external view returns (bool);
function deferredSince(address feed, uint40 closeTs) external view returns (uint40);
}
// OracleAdapter contract surface used by the docs (MAX_ROUND_WALK_LIMIT = 500)
function setBackupFeed(address primary, address backup) external; // onlyOwner; SameFeed; DecimalsMismatch(primaryDecimals, backupDecimals); effective after MODULE_GRACE (ModuleChangePending)
function backupFeed(address primary) external view returns (address);
function backupFeedAt(address primary, uint256 at) external view returns (address);
function backupSlot(address primary) external view returns (address current, address previous, uint40 effectiveAt);
function setCalendar(address calendar_) external; // restricted; first set immediate, later sets effective after MODULE_GRACE (ModuleUpdated with CALENDAR_KEY)
function calendar() external view returns (IMarketCalendar); // calendar effective now (address(0) = flat maxLookback rule)
function calendarAt(uint256 at) external view returns (IMarketCalendar);
function calendarSlot() external view returns (address current, address previous, uint40 effectiveAt);
function setLiveMaxAge(uint40 liveMaxAge_) external; // restricted; InvalidParams on 0; LiveMaxAgeUpdated
function liveMaxAge() external view returns (uint40); // default 1 hour
function setParams(uint40 settlementWindow, uint40 maxLookback, uint16 maxDeviationBps, uint40 deferralWindow,
uint40 forceDelay, uint16 maxRoundWalk, uint40 freshLag) external; // InvalidParams when deferralWindow < 24 hours (MIN_DEFERRAL_WINDOW, internal constant)
function referencePrice(address feed) external view returns (uint256 price, uint40 asOf, bool live); // live primary, live backup, primary close, backup close, else StalePrice
uint40 constant MAX_CLOSED_GAP = 7 days;
bytes32 constant CALENDAR_KEY = keccak256("CALENDAR");
// Optional feed extension: round stores whose updatedAt is a publish time carried in the payload (PythProFeed)
// expose the block time at which each round was appended. The adapter selects backup rounds by postedAt when present.
interface IPostedRoundFeed {
function postedAt(uint80 roundId) external view returns (uint64); // reverts for unknown rounds
}
// PythProFeed posting surface
function post(bytes calldata update) external payable; // PostTooSoon unless inside [close - 10 s, close]; NotMonotonic;
// PayloadPredatesBasis(priceTs, basisAcknowledgedAt); MultiplierChanged
function acknowledgeMultiplier(uint256 multiplierWad) external; // owner; records basisAcknowledgedAt = block.timestamp
function basisAcknowledgedAt() external view returns (uint64); // 0 until the first acknowledgement
uint64 constant MIN_POST_INTERVAL = 10;
uint64 constant MAX_CLOCK_SKEW = 5;
IMarketCalendar
interface IMarketCalendar {
function isOfficialClose(uint40 ts) external view returns (bool);
function officialCloseOf(uint32 dayIndex) external view returns (uint40); // 0 if not a trading day
function isDST(uint32 dayIndex) external pure returns (bool);
function isHoliday(uint32 dayIndex) external view returns (bool);
function earlyClose(uint32 dayIndex) external view returns (uint40); // 0 if none
function sessionOpenOf(uint32 dayIndex) external view returns (uint40); // 0 if not a trading day
function isTradingDay(uint32 dayIndex) external view returns (bool);
function lastCloseAtOrBefore(uint40 ts) external view returns (uint40); // NoTradingDayInRange(ts) beyond 14 days
function nextCloseAfter(uint40 ts) external view returns (uint40); // NoTradingDayInRange(ts) beyond 14 days
function marketState(uint40 ts) external view returns (bool open, uint40 lastClose, uint40 nextOpen, uint40 nextClose);
}
// MarketCalendar constants
uint40 constant DST_OPEN_OFFSET = 13 hours + 30 minutes;
uint40 constant STD_OPEN_OFFSET = 14 hours + 30 minutes;
uint256 constant MAX_DAY_WALK = 14;
dayIndex = timestamp / 86400.
RollPolicy
fact From contracts/src/automation/RollPolicy.sol (Governed: Ownable2Step, guardian, Pausable). The issuance calendar: one series per underlying at every trading-day close. See Automation and cranks.
struct Template {
address feed;
uint16 autocallBps;
uint16 barrierBps;
uint16 couponFloorBps;
uint16 couponCapBps;
uint16 refBps;
uint128 notionalCap;
uint128 minTicket;
uint16 subscriptionTradingDays; // subscription ends at the close of the N-th trading day after today
uint16 observationCount; // >= 2
uint16 observationSpacingTradingDays; // >= 1
uint16 strikeLagTradingDays; // >= 1
uint8 maxOpenSeries; // closes of the underlying open at once, today's excluded (1..MAX_OPEN_SERIES)
uint32 maxFeedAge; // seconds
bool enabled;
}
struct Entry { uint256 seriesId; uint40 subscriptionEnd; }
// Permissionless
function roll(address underlying) external returns (uint256 seriesId); // nonReentrant, whenNotPaused
function rollAll() external returns (uint256[] memory ids); // every template whose gates pass
function rollRange(uint256 start, uint256 count) external returns (uint256[] memory ids); // window of underlyings(); InvalidRange
function fund(uint256 amount) external; // USDG into the bounty pot
// Views
function previewRoll(address underlying) external view returns (INoteCore.SeriesParams memory params, bool canRoll, bytes32 reason);
function template(address underlying) external view returns (Template memory);
function underlyings() external view returns (address[] memory); // every underlying that ever had a template
function seriesOf(address underlying) external view returns (Entry[] memory);
function seriesCount(address underlying) external view returns (uint256);
function lastSeries(address underlying) external view returns (uint256);
function hasSeries(address underlying) external view returns (bool);
function openSeriesOf(address underlying) external view returns (uint256[] memory ids); // Subscription series, newest MAX_OPEN_SERIES + 1 entries scanned
function openCount(address underlying) external view returns (uint256);
function capCount(address underlying) external view returns (uint256); // open series closing later than today's official close
function calendar() external view returns (IMarketCalendar); // core.calendar()
function lastRollAt(address underlying) external view returns (uint256);
function bounty() external view returns (uint256);
function minRollInterval() external view returns (uint256); // default 1 hours
// Owner / guardian
function setTemplate(address underlying, Template calldata t) external; // owner; InvalidTemplate(reason)
function disable(address underlying) external; // owner or guardian; UnknownUnderlying
function setBounty(uint256 usdgAmount) external;
function setMinRollInterval(uint256 interval) external; // <= MAX_ROLL_INTERVAL
function sweep(address to, uint256 amount) external;
function registerSeries(address underlying, uint256 seriesId) external; // owner; Subscription series closing within MAX_REGISTER_HORIZON, later than the last entry, fewer than MAX_OPEN_SERIES open
function unregisterLast(address underlying) external; // owner; tail series must be Cancelled or Unwound; SeriesNotUnregistrable
// Constants
uint256 constant MAX_GAP_DAYS = 14;
uint256 constant MAX_ROLL_INTERVAL = 30 days;
uint256 constant MAX_SUBSCRIPTION_TRADING_DAYS = 60;
uint256 constant MAX_SPACING_TRADING_DAYS = 60;
uint256 constant MAX_STRIKE_LAG_TRADING_DAYS = 60;
uint256 constant MAX_SCHEDULE_TRADING_DAYS = 90; // subscription + strike lag + (observations - 1) * spacing
uint256 constant MAX_REGISTER_HORIZON = 90 days;
uint256 constant MAX_OPEN_SERIES = 10;
uint256 constant MAX_UNDERLYINGS = 64;
// Errors
error TemplateDisabled(address underlying);
error AlreadyRolled(address underlying, uint256 seriesId);
error OpenCap(address underlying, uint256 open);
error TooManyUnderlyings();
error InvalidRange(uint256 start, uint256 count);
error FeedStale(address feed, uint256 asOf);
error RollCooldown(address underlying, uint256 availableAt);
error InvalidTemplate(string reason);
error CalendarGap(uint32 fromDayIndex);
error SeriesMismatch(uint256 seriesId, address underlying);
error NotSeriesCreator();
error TemplateExceedsCoreLimits(address underlying);
error UnknownUnderlying(address underlying);
error SeriesNotRegistrable(uint256 seriesId);
error CorePaused();
error CoreDeprecated();
previewRoll reasons (bytes32 short strings): Paused, TemplateDisabled, FeedStale, RollCooldown, NotSeriesCreator, CorePaused, CoreDeprecated, CoreLimits, CalendarGap, AlreadyRolled, OpenCap. params is zeroed whenever canRoll is false; the view never reverts.
IFeeSink and IRewardSink
interface IFeeSink { function notifyFee(address token, uint256 amount) external; } // push: transfer first, then notify
interface IRewardSink { function notifyReward(uint256 amount) external; } // push: transfer first, then notify
IStockToken
interface IStockToken is IERC20Metadata {
function uiMultiplier() external view returns (uint256);
function balanceOfUI(address account) external view returns (uint256);
}
The protocol reads only raw balanceOf and transfer paths; uiMultiplier is exposed for tests and front-ends.
Token Engine
fact External signatures copied from contracts/src/token/. Governance-only functions are marked onlyOwner; Governed adds setGuardian, pause (owner or guardian) and unpause (owner) to every module.
// NOTE (ERC-20 + Permit + Votes; CAP = 100_000_000e18; EPOCH = 7 days)
function setMinter(address account, bool allowed) external; // onlyOwner
function setMintCapPerEpoch(uint256 newCap) external; // onlyOwner
function mint(address to, uint256 amount) external; // minters only, whenNotPaused
function burn(uint256 amount) external;
function burnFrom(address account, uint256 amount) external;
function currentEpoch() external view returns (uint256);
function epochMintRemaining() external view returns (uint256);
// sNOTE (ERC-4626 over NOTE; STREAM_DURATION = 7 days; MAX_COOLDOWN = 30 days)
function setRewardNotifier(address notifier) external; // onlyOwner
function setCooldown(uint256 newCooldown) external; // onlyOwner
function notifyReward(uint256 amount) external; // rewardNotifier only
function unvestedRewards() external view returns (uint256);
function totalAssets() external view returns (uint256); // balance − unvestedRewards()
function deposit(uint256 assets, address receiver) external returns (uint256); // whenNotPaused
function mint(uint256 shares, address receiver) external returns (uint256); // whenNotPaused
function requestWithdraw(uint256 shares) external; // escrows shares, unlockAt = now + cooldown; never paused
function requests(address owner) external view returns (uint256 shares, uint256 unlockAt); // total pending shares and the latest unlockAt
function deferredRewards() external view returns (uint256); // rewards notified while totalSupply() == 0, streamed by the first deposit
function cancelWithdrawRequest() external; // never paused
function withdraw(uint256 assets, address receiver, address owner) external returns (uint256); // owner == msg.sender, matured request; never paused
function redeem(uint256 shares, address receiver, address owner) external returns (uint256); // owner == msg.sender, matured request; never paused
// Treasury (REDEMPTION_WINDOW = 1 day; MAX_HAIRCUT_BPS = 5_000)
function addStockAsset(address token, AggregatorV3Interface feed) external; // onlyOwner
function setAssetEnabled(address token, bool enabled) external; // onlyOwner
function setAssetFeed(address token, AggregatorV3Interface feed) external; // onlyOwner, Stock assets only (AssetNotEnabled), decimals <= 18 (InvalidFeed)
function registerLegSeries(uint256 seriesId) external; // owner or BondDepository
function setDesk(address desk_) external; // onlyOwner
function setBondDepository(address depository) external; // onlyOwner
function setMaxFeedStaleness(uint256 staleness) external; // onlyOwner
function setRedemptionParams(uint16 haircutBps, uint16 dailyCapBps) external; // onlyOwner
function mintNote(address to, uint256 amount) external; // onlyOwner
function withdrawERC20(address token, address to, uint256 amount) external; // onlyOwner; every registered asset consumes the daily budget
function withdrawLegs(uint256 seriesId, address to, uint256 units) external; // onlyOwner
function valueOf(address token, uint256 amount) external view returns (uint256); // IncompleteRound(token), StaleFeed(token), InvalidPrice(token)
function legValueFactorWad(uint256 seriesId) external view returns (uint256);
function legValueQuote(uint256 seriesId, uint256 units) external view returns (uint256);
function reserveValueQuote() external view returns (uint256);
function circulatingSupply() external view returns (uint256);
function previewRedeem(uint256 noteAmount) external view returns (uint256); // against reserveValueQuote − retainedHaircutQuote()
function retainedHaircutQuote() external view returns (uint256); // retained haircut amortised over the 1 day window, ceil rounding
function haircutRetainedStored() external view returns (uint256); // raw stored value at lastRedemptionAt
function isReferencePriced(address token) external view returns (bool); // reference close stands in for a stale or unreadable print
function isLegStaleDust(uint256 seriesId) external view returns (bool); // Live leg with no usable price carried at zero (units <= staleDustQuote)
function dailyRedemptionRemaining() external view returns (uint256);
function redeem(uint256 noteAmount, uint256 minQuoteOut) external returns (uint256 quoteOut);
function harvestSeries(uint256 seriesId) external; // permissionless; SeriesHarvested reports measured balance deltas; registers received stock as an asset
function purchaseStock(address token, uint256 amount) external returns (uint256 quotePaid); // Desk only; TransferShortfall(expected, received)
// BondDepository (MAX_DISCOUNT_CAP_BPS = 5_000; UTILISATION_WINDOW = 1 days; UTILISATION_MAX_STEP = 6 hours)
enum QuoteKind { ERC20, CouponLeg }
struct MarketParams { QuoteKind kind; address quoteToken; uint256 legSeriesId; uint256 capacity;
uint256 controlVariable; uint256 minPriceWad; uint256 maxDebt;
uint48 vestingSeconds; uint48 conclusion; }
struct Bond { uint256 marketId; uint256 payout; uint256 claimed; uint48 vestStart; uint48 vestEnd; }
function createMarket(MarketParams calldata p) external returns (uint256 id); // onlyOwner
function closeMarket(uint256 id) external; // onlyOwner
function setControlVariable(uint256 id, uint256 controlVariable) external; // onlyOwner
function setDiscountParams(uint16 k, uint16 maxDiscountBps_) external; // onlyOwner
function setDesk(IDeskUtilisation desk_) external; // onlyOwner
function marketCount() external view returns (uint256);
function market(uint256 id) external view returns (Market memory);
function bond(address user, uint256 index) external view returns (Bond memory);
function bondCount(address user) external view returns (uint256);
function currentDebt(uint256 id) external view returns (uint256); // linear decay to zero at debtDecayEnd(id)
function debtDecayEnd(uint256 id) external view returns (uint256); // size-weighted decay horizon, extended by each purchase
function quoteValueWad(uint256 id, uint256 amount) external view returns (uint256); // QuoteNotLive(token) for ERC20 stock markets while Treasury.isReferencePriced(token)
function debtRatio(uint256 id) external view returns (uint256); // WAD, debt / NOTE.totalSupply
function basePrice(uint256 id) external view returns (uint256); // max(cv × debtRatio, minPriceWad)
function redemptionFloorWad() external view returns (uint256); // Treasury redemption value of one NOTE; 0 while nothing circulates
function priceFloorWad(uint256 id) external view returns (uint256); // max(minPriceWad, redemptionFloorWad())
function utilisationAvgBps() external view returns (uint256); // stored smoothed utilisation
function utilisationAvgAt() external view returns (uint256); // timestamp of the stored value
function smoothedUtilisationBps() external view returns (uint256); // slew-limited toward Desk.laggedUtilisationBps()
function utilisationDiscountBps() external view returns (uint256); // min(min(lagged, smoothed) × k / 1e4, maxDiscountBps)
function pokeUtilisation() external; // permissionless; UtilisationUpdated
function marketPrice(uint256 id) external view returns (uint256); // max(basePrice × (1e4 − disc) / 1e4, priceFloorWad(id))
function quoteValueWad(uint256 id, uint256 amount) external view returns (uint256);
function payoutFor(uint256 id, uint256 amount) external view returns (uint256);
function pendingPayout(address user, uint256 index) external view returns (uint256);
function deposit(uint256 id, uint256 amount, uint256 maxPriceWad, address recipient)
external returns (uint256 payout, uint256 bondIndex); // ERC20 markets: TransferShortfall(expected, received)
function depositWithLimits(uint256 id, uint256 amount, uint256 maxPriceWad, uint256 minPayout, uint256 deadline, address recipient)
external returns (uint256 payout, uint256 bondIndex); // PayoutTooLow(payout, minPayout), Expired(deadline)
function redeem(uint256[] calldata indexes) external returns (uint256 total);
// RevenueRouter (IFeeSink; MIN_HALF_LIFE = 5 minutes; MAX_HALF_LIFE = 30 days; MAX_PREMIUM_BPS = 50_000;
// MIN_FILL_INTERVAL = 5 minutes; DEFAULT_MIN_FILL_INTERVAL = 30 minutes; DEFAULT_MIN_FILL_BPS = 10;
// DEFAULT_MIN_FILL_UNITS = 1; MAX_MIN_FILL_UNITS = 1_000_000)
function setSplit(uint16 buybackBps_) external; // onlyOwner
function setAuctionParams(uint256 halfLifeSeconds_, uint16 maxPremiumBps_, uint16 maxFillBps_) external; // onlyOwner; clamps minFillInterval / minFillBps
function setMinFillInterval(uint256 interval) external; // onlyOwner, [MIN_FILL_INTERVAL, halfLifeSeconds] else InvalidParams
function setMinFillBps(uint16 minFillBps_) external; // onlyOwner, 1..maxFillBps else InvalidParams
function setMinFillQuote(uint256 minFillQuote_) external; // onlyOwner, 1..MAX_MIN_FILL_UNITS whole quote units else InvalidParams
function resetAuction() external; // onlyOwner; a new round starts at the floor (AuctionReset)
function sweep(address token, address to, uint256 amount) external; // onlyOwner, not the quote token
function notifyFee(address token, uint256 amount) external; // quote token only
function sync() external; // route any un-notified quote balance
function buybackBps() external view returns (uint16);
function halfLifeSeconds() external view returns (uint256);
function maxPremiumBps() external view returns (uint16);
function maxFillBps() external view returns (uint16);
function buybackReserve() external view returns (uint256);
function lastFillTime() external view returns (uint256);
function anchorTime() external view returns (uint256); // start of the current round
function floorPriceWad() external view returns (uint256); // Treasury.previewRedeem(1 NOTE), quote WAD per NOTE
function maxPriceWad() external view returns (uint256); // floor × (1e4 + maxPremiumBps) / 1e4
function currentPriceWad() external view returns (uint256); // floor + (max − floor) × (1 − 2^(−(t − anchorTime) / halfLife))
function previewSell(uint256 noteAmount) external view returns (uint256);
function maxFillQuote() external view returns (uint256); // buybackReserve × maxFillBps / 1e4
function minFillInterval() external view returns (uint256);
function minFillBps() external view returns (uint16);
function minFillQuoteAbs() external view returns (uint256); // raw quote units; DEFAULT_MIN_FILL_UNITS when unset
function minFillQuote() external view returns (uint256); // max(buybackReserve × minFillBps / 1e4, minFillQuoteAbs)
function sellNoteForQuote(uint256 noteAmount, uint256 minQuoteOut) external returns (uint256 quoteOut);
// reverts ZeroAmount, FillTooSoon(nextAllowedAt), SlippageExceeded(out, minOut), FillExceedsCap(requested, cap), FillBelowMinimum(requested, minimum)
// emits Buyback(seller, noteAmount, quoteOut, priceWad) and AuctionReset(anchorTime): the next round starts at the floor
// Desk (ERC-4626 over USDG, ERC1155Holder; MAX_QUEUE_PROCESS = 50; REQUEST_CANCEL_GRACE = 7 days; minHold in (0, 7 days], default 1 day)
struct Caps { uint16 perSeriesCapBps; uint16 perUnderlyingCapBps; uint16 totalDeployedCapBps; }
enum RequestStatus { Open, Filled, Cancelled }
struct WithdrawRequest { address owner; uint64 requestedAt; RequestStatus status; address receiver; uint256 shares; }
function setCaps(Caps calldata caps_) external; // onlyOwner
function setMaxFeedStaleness(uint256 seconds_) external; // onlyOwner
function setQueueProcessLimit(uint256 limit) external; // onlyOwner, <= 50
function setMinHold(uint256 seconds_) external; // onlyOwner, (0, 7 days] else MinHoldOutOfBounds; MinHoldUpdated
function setStockWriteOff(address token, bool writtenOff) external; // onlyOwner; StockWriteOffSet
function setFiller(address filler_) external; // onlyOwner; the only caller of fillCoupon (zero disables fills); FillerSet
function filler() external view returns (address);
function previewFill(uint256 seriesId) external view returns (uint256 gap, uint256 room); // gap = S - D (0 when S <= D); room = min(cap headrooms, free idle); (0, 0) outside Subscription
function fillCoupon(uint256 seriesId, uint256 amount, uint16 minCouponBps) external; // filler only (NotFiller); Subscription only; S > D (ShieldNotInExcess); amount <= S - D (FillExceedsGap); caps; idle; posts CORE.depositCouponReserved(seriesId, amount, minCouponBps)
function liquidateToTreasury(address token, uint256 amount) external; // onlyOwner
function sweepToken(address token, address to, uint256 amount) external; // onlyOwner
function sweepShares(address to) external returns (uint256 shares); // onlyOwner; shares held by the Desk above escrowedShares(); SharesSwept
function writeOffSeries(uint256 seriesId, address legsTo) external; // onlyOwner; any settled status (Autocalled, Matured, Cancelled, Unwound) else NotTerminal; SeriesWrittenOff
function setPoolHolder(address account, bool pooled) external; // onlyOwner; shared pools (gauges) are neither stamped nor a stamp source; PoolHolderSet
function cancelRequestFor(uint256 id) external; // onlyOwner; open request older than REQUEST_CANCEL_GRACE (RequestTooRecent); WithdrawRequestCancelledFor
function harvest(uint256 seriesId) external; // permissionless
function requestWithdraw(uint256 shares, address receiver) external returns (uint256 id); // ExitBlocked(owner) under the exit guard or before minHold; RequestTooSmall(assets, minimum) below minRequestQuote()
function minRequestQuote() external view returns (uint256); // minimum request value at current NAV, default 1 USDG
function setMinRequestQuote(uint256 minimum) external; // onlyOwner; 1 raw unit .. 1,000 USDG (MinRequestQuoteOutOfBounds); MinRequestQuoteUpdated
function cancelWithdrawRequest(uint256 id) external;
function processQueue(uint256 n) external returns (uint256 filled); // n <= queueProcessLimit; fills credit claimable(receiver)
function claim(address to) external returns (uint256 assets); // pays claimable(msg.sender) to `to`; NothingToClaim(receiver); WithdrawClaimed
function queueLength() external view returns (uint256);
function withdrawRequest(uint256 id) external view returns (WithdrawRequest memory);
function claimable(address receiver) external view returns (uint256);
function totalClaimable() external view returns (uint256);
function escrowedShares() external view returns (uint256); // shares held for open requests
function lastDeposit(address account) external view returns (uint256);
function isPoolHolder(address account) external view returns (bool);
function activeSeries() external view returns (uint256[] memory); // series ids with deployed principal
function minHold() external view returns (uint256);
function lastStockMark(address token) external view returns (uint256); // last Treasury value per 1e18 of token
function hasUnharvestedSettled() external view returns (bool);
function idleAssets() external view returns (uint256); // USDG balance − totalClaimable
function heldStockValue() external view returns (uint256 total); // Treasury value; last mark for at most maxFeedStaleness when unpriceable, else 0
function lastStockMarkAt(address token) external view returns (uint256); // timestamp of the last good mark (0 = never marked)
function heldStocks() external view returns (address[] memory);
function retainedLegValue() external view returns (uint256 total); // COUPON legs kept after a failed redemption, at Treasury leg value, min(balance, retainedUnits)
function retainedUnits(uint256 seriesId) external view returns (uint256); // units held at the moment of retention
function maxDeposit(address) external view returns (uint256); // 0 while paused or while a held stock has no usable price and is not written off
function retainedSeries() external view returns (uint256[] memory);
function totalAssets() external view returns (uint256); // idle + deployed + heldStockValue + retainedLegValue + keeperOwed (idle already excludes claimable)
function utilisationBps() external view returns (uint256); // deployed × 1e4 / totalAssets, capped at 1e4
function laggedUtilisationBps() external view returns (uint256); // utilisation as of the previous block
// Gauge-steered caps (MIN_UNDERLYING_CAP_BPS = 100, MAX_UNDERLYING_CAP_BPS = 4_000)
function setGaugeController(address controller) external; // onlyOwner
function gaugeController() external view returns (address);
function setPerUnderlyingCapFromGauge(address underlying, uint16 bps) external; // gauge controller only; NotGaugeController, CapOutOfBounds
function effectivePerUnderlyingCapBps(address underlying) external view returns (uint16); // min(caps.perUnderlyingCapBps, gauge value)
function caps() external view returns (uint16 perSeries, uint16 perUnderlying, uint16 totalDeployed);
// DeskPolicy (Governed; BPS = 10_000; MIN_FILL_LEAD = 1 hours; MAX_FILL_LEAD = 7 days; MIN_FILL_INTERVAL = 10 minutes; MAX_FILL_INTERVAL = 24 hours; MIN_MIN_FILL = 100 USDG; MAX_MIN_FILL = 10_000 USDG; MAX_BOUNTY = 1_000 USDG)
struct Rule { bool enabled; uint16 minBarrierBps; uint16 maxBarrierBps; uint16 minCouponFloorBps; uint16 maxObservations; uint32 maxTenor; uint16 minCouponBps; }
function setRule(address underlying, Rule calldata rule) external; // onlyOwner; InvalidRule(reason); RuleSet
function disable(address underlying) external; // onlyOwnerOrGuardian; RuleDisabled
function setFillLead(uint256 lead) external; // onlyOwner; [1 hours, 7 days] else InvalidParameter; FillLeadSet
function setMinFill(uint256 amount) external; // onlyOwner; [100 USDG, 10_000 USDG] and >= bounty; MinFillSet
function setMinFillInterval(uint256 interval) external; // onlyOwner; [10 minutes, 24 hours]; MinFillIntervalSet
function setBounty(uint256 usdgAmount) external; // onlyOwner; <= min(1_000 USDG, minFill); BountySet
function fund(uint256 amount) external; // anyone; Funded
function sweep(address to, uint256 amount) external; // onlyOwner; Swept
function fill(uint256 seriesId) external returns (uint256 amount); // permissionless, nonReentrant, whenNotPaused; NotSubscription, RuleInactive, FillerUnset(seriesId) (the Desk names another filler), OutsideFillWindow(seriesId, opensAt, closesAt) (closesAt is the effective strike close when it precedes subscriptionEnd; opensAt == closesAt for a window the early close leaves no room for), SeriesOutsideRule(seriesId, reason), FillCooldown(seriesId, availableAt), DeskUnavailable, NothingToFill(seriesId, gap, room); sized to the rule hurdle, the notional cap and the SHIELD prefund capacity; calls Desk.fillCoupon(seriesId, amount, rule.minCouponBps); pays the bounty; Filled
function previewFill(uint256 seriesId) external view returns (uint256 amount, bool canFill, bytes32 reason); // never reverts; canFill is true exactly when fill would succeed in the same block (reasons include WindowClosed, BelowMinFill)
function rule(address underlying) external view returns (Rule memory);
function lastFillAt(uint256 seriesId) external view returns (uint256);
function fillLead() external view returns (uint256); // default 24 hours
function minFill() external view returns (uint256); // default 100 USDG
function minFillInterval() external view returns (uint256); // default 1 hour
function bounty() external view returns (uint256);
// UUPSModule (Treasury, BondDepository, RevenueRouter, Desk)
function version() external pure returns (string memory); // "1.0.0" at launch; Desk is "2.0.0" since permissionless fills
function upgradeToAndCall(address newImplementation, bytes calldata data) external payable; // Governance authority and delay apply.
The Market struct returned by market(id) adds bool active, uint256 totalDebt, uint48 lastDecay, uint256 sold and uint256 purchased to the MarketParams fields; capacity there is the remaining NOTE payout capacity.
Governance
fact Copied from contracts/src/governance/interfaces/ and the contract sources. Owner of every governance contract is the 48-hour governance. See Governance for behaviour.
// veNOTE (IERC5805: getVotes, getPastVotes, getPastTotalSupply, clock, CLOCK_MODE; delegation reverts DelegationNotSupported)
interface IVeNOTE is IERC5805 {
struct Point { int128 bias; int128 slope; uint256 ts; }
struct LockedBalance { int128 amount; uint256 end; uint256 stakedShares; uint256 stakedNoteEq; }
// MAXTIME = 4 * 365 days; WEEK = 7 days; unlock times floor to a week boundary
function createLock(uint256 amount, uint256 unlockTime) external; // whenNotPaused
function increaseAmount(uint256 amount) external;
function increaseUnlockTime(uint256 unlockTime) external;
function depositFor(address account, uint256 amount) external;
function lockFromStaked(uint256 shares, uint256 unlockTime) external; // sNOTE shares; unlockTime 0 for top-up
function withdraw() external; // never pausable; an expired lock withdraws even when the global
// checkpoint is behind (zero account delta), other actions revert CheckpointRequired
function checkpoint() external;
function balanceOf(address account) external view returns (uint256);
function balanceOfAt(address account, uint256 timestamp) external view returns (uint256);
function totalSupply() external view returns (uint256);
function totalSupplyAt(uint256 timestamp) external view returns (uint256);
function locked(address account) external view returns (LockedBalance memory);
function lockedEnd(address account) external view returns (uint256);
function getLastUserSlope(address account) external view returns (int128);
function userPointEpoch(address account) external view returns (uint256);
function userPointHistory(address account, uint256 index) external view returns (Point memory);
function pointHistory(uint256 index) external view returns (Point memory);
function epoch() external view returns (uint256);
function slopeChanges(uint256 timestamp) external view returns (int128);
}
// NoteGovernor / UpgradeGovernor (OpenZeppelin v5.1 Governor; standard IGovernor surface plus:)
function COUNTING_MODE() external pure returns (string memory); // "support=bravo,fractional&quorum=for,abstain¶ms=fractional"
function castVoteWithReasonAndParams(uint256 proposalId, uint8 support, string calldata reason, bytes memory params)
external returns (uint256); // support 255 + abi.encodePacked(uint128 against, uint128 for, uint128 abstain)
function proposalThreshold() external view returns (uint256); // max(absolute, pastTotalSupply(clock() - 1) * bps / 10_000)
function setProposalThresholdBps(uint256 bps) external; // onlyGovernance; InvalidBps
// Governance authority and delay apply.
// GaugeController (types: 0 SeriesGauge, 1 DeskGauge, 2 StakingGauge; WEIGHT_VOTE_DELAY = 10 days;
// CAP_FLOOR_BPS = 100; CAP_CEILING_BPS = 4_000)
interface IGaugeController {
function nGauges() external view returns (uint256);
function gauges(uint256 index) external view returns (address);
function gaugeTypes(address gauge) external view returns (int128); // UnknownGauge
function gaugeRelativeWeight(address gauge, uint256 timestamp) external view returns (uint256); // WAD
function gaugeRelativeWeightWrite(address gauge, uint256 timestamp) external returns (uint256);
}
function allGauges() external view returns (address[] memory);
function gaugeUnderlying(address gauge) external view returns (address);
function underlyings() external view returns (address[] memory);
function voteForGaugeWeights(address gauge, uint256 userWeightBps) external; // whenNotPaused; sum <= 10_000; VoteCooldown, PowerExceeded, LockExpiresTooSoon, WeightTooHigh
function voteUserSlopes(address user, address gauge) external view returns (uint256 slope, uint256 power, uint256 end);
function voteUserPower(address user) external view returns (uint256);
function lastUserVote(address user, address gauge) external view returns (uint256);
function checkpoint() external;
function checkpointGauge(address gauge) external;
function syncCaps() external; // once per week; DeskNotSet, AlreadySynced(week)
function addType(string memory name, uint256 weight) external; // onlyOwner
function changeTypeWeight(int128 typeId, uint256 weight) external; // onlyOwner
function addGauge(address gauge, int128 gaugeType, uint256 weight, address underlying) external; // onlyOwner
function changeGaugeWeight(address gauge, uint256 weight) external; // onlyOwner; GaugeHasVotes
function setDesk(IDeskGaugeCaps desk_) external; // onlyOwner
function killGauge(address gauge) external; // owner or guardian; UnknownGauge; GaugeKilled(gauge, true)
function reviveGauge(address gauge) external; // onlyOwner; UnknownGauge; GaugeKilled(gauge, false)
function isKilled(address gauge) external view returns (bool); // killed gauges read as weight 0 and reject non-zero votes (GaugeIsKilled)
// IDeskGaugeCaps (implemented by Desk)
interface IDeskGaugeCaps {
function caps() external view returns (uint16 perSeriesCapBps, uint16 perUnderlyingCapBps, uint16 totalDeployedCapBps);
function setPerUnderlyingCapFromGauge(address underlying, uint16 bps) external;
}
// EmissionSchedule (defaults 300_000e18 / 200 bps / 4 weeks / 25_000e18)
interface IEmissionSchedule {
function weeklyEmission(uint256 timestamp) external view returns (uint256);
}
function periodsElapsed(uint256 timestamp) external view returns (uint256);
function setSchedule(uint256 initialWeekly, uint256 decayBps, uint256 decayPeriodWeeks, uint256 floorWeekly) external; // onlyOwner; InvalidSchedule
// Minter
function mintWeekly() external returns (uint256 minted); // anyone, once per week, whenNotPaused; AlreadyMinted, NothingToMint; per-gauge delivery isolated; budget = min(schedule + emissionShortfall, epoch headroom)
function distribute(address gauge, uint256 amount) external; // self-call only (OnlySelf); mints and notifies one gauge
function retryGauge(address gauge) external returns (uint256 amount); // anyone, whenNotPaused; re-delivers carriedForward(gauge); NothingCarried
function currentWeek() external view returns (uint256);
function mintedWeek(uint256 week) external view returns (bool);
function mintedForWeek(uint256 week) external view returns (uint256);
function mintedToGauge(address gauge) external view returns (uint256);
function totalMinted() external view returns (uint256);
function carriedForward(address gauge) external view returns (uint256); // skipped amount awaiting retryGauge
function emissionShortfall() external view returns (uint256); // scheduled emission clipped by the epoch cap, added to the next week's budget
function totalCarriedForward() external view returns (uint256);
function setSchedule(IEmissionSchedule schedule) external; // onlyOwner
// INOTEMintable (what Minter needs from NOTE)
interface INOTEMintable is IERC20 {
function mint(address to, uint256 amount) external;
function epochMintRemaining() external view returns (uint256);
function mintCapPerEpoch() external view returns (uint256);
function currentEpoch() external view returns (uint256);
}
// Gauges (RewardGauge base; DURATION = 7 days)
interface IGauge { function notifyRewardAmount(uint256 amount) external; } // minter only
function stake(uint256 amount) external; // whenNotPaused; DeskGauge: dNOTE, StakingGauge: sNOTE, SeriesGauge: COUPON units of LEG_ID = seriesId << 1
function withdraw(uint256 amount) external; // never pausable
function exit() external; // withdraw all + getReward
function getReward() external returns (uint256 amount);
function earned(address account) external view returns (uint256);
function rewardPerToken() external view returns (uint256);
function lastTimeRewardApplicable() external view returns (uint256);
function remainingRewards() external view returns (uint256);
function setMinter(address minter_) external; // onlyOwner
// SeriesGauge coupon pass-through (COUPON_TOKEN = series quote token; CouponEqualsReward at construction if it equals NOTE)
function COUPON_TOKEN() external view returns (IERC20);
function couponPerUnitStored() external view returns (uint256);
function couponsSeen() external view returns (uint256); // coupon quote credited to the gauge so far
function couponsPulled() external view returns (uint256); // coupon quote claimed from NoteCore so far
function couponsUnallocated() external view returns (uint256); // coupons received while nothing was staked
function userCouponPerUnitPaid(address account) external view returns (uint256);
function coupons(address account) external view returns (uint256); // settled, unclaimed coupon quote
function earnedCoupons(address account) external view returns (uint256);
function claimCoupons() external returns (uint256 amount); // pulls from NoteCore as needed; NothingToClaim; CouponPaid
function sweepUnallocatedCoupons(address to) external returns (uint256 amount); // onlyOwner; NothingToClaim; UnallocatedCouponsSweptKeep exploring, or revisit this topic from the navigation.