BuildAuth Surface

Auth Surface

This page enumerates every privileged function in the protocol, who can call it, and which production address SHOULD hold the role. If you are setting up a new deployment or auditing an existing one, this is the canonical reference.

For the slashing-specific subset see Slashing.

Role Registry

Roles are defined in Base.sol and granted at initialization. The deploy script (script/FullDeploy.s.sol) hands every role to the deployer EOA at first, then transfers them to production multisigs and the timelock through _applyRoleHandoff.

Note: each contract defines its own role set. Tangle and MultiAssetDelegation (MAD) do NOT share role constants; the same name on both contracts is a different keccak slot.

RoleWhereSuggested holder
DEFAULT_ADMIN_ROLEAll AccessControl contractsTangleTimelock
ADMIN_ROLETangle, MAD, and most peripheralsTangleTimelock
PAUSER_ROLETangle onlyOperations multisig
UPGRADER_ROLETangle, MBSMRegistry, TangleToken, RewardVaults, InflationPool, TangleMetrics, ServiceFeeDistributor, StreamingPaymentManagerTangleTimelock
SLASH_ADMIN_ROLETangle onlySlashing oversight multisig
MANAGER_ROLEMBSMRegistry onlyTangleTimelock
ASSET_MANAGER_ROLEMAD onlyOperations multisig
SLASHER_ROLEMAD onlyTangle (via addSlasher)
TANGLE_ROLEMAD onlyTangle (via setTangle)
MINTER_ROLETangleToken onlyTangleTimelock

MultiAssetDelegation does NOT define a UPGRADER_ROLE. Its _authorizeUpgrade is gated on ADMIN_ROLE. Its pause/unpause are gated on ADMIN_ROLE (no separate PAUSER_ROLE on MAD).

Tangle (src/Tangle.sol)

Tangle is the protocol entrypoint, composed of mixins under src/core/. Every state-changing path is gated by exactly one of:

  • A specific OZ AccessControl role
  • Service or blueprint ownership
  • Permissionless gating (open to any caller)

Contract Administration

FunctionCallerSource
pause()PAUSER_ROLEBase.sol
unpause()PAUSER_ROLEBase.sol
_authorizeUpgrade(newImpl)UPGRADER_ROLEBase.sol
setMBSMRegistry(addr)ADMIN_ROLE (when not paused)Base.sol
setMetricsRecorder(addr)ADMIN_ROLEBase.sol
setOperatorStatusRegistry(addr)ADMIN_ROLEBase.sol
setServiceFeeDistributor(addr)ADMIN_ROLEBase.sol
setPriceOracle(addr)ADMIN_ROLEBase.sol
setTreasury(addr)ADMIN_ROLE (NOT whenNotPaused)Payments.sol
setPaymentSplit(split)ADMIN_ROLE (NOT whenNotPaused)Payments.sol
setTntToken(addr)ADMIN_ROLEBase.sol
setRewardVaults(addr)ADMIN_ROLEBase.sol
setMaxBlueprintsPerOperator(n)ADMIN_ROLEBase.sol
setDefaultTntMinExposureBps(bps)ADMIN_ROLEBase.sol
setTntPaymentDiscountBps(bps)ADMIN_ROLEBase.sol
setMinServiceTtl(seconds)ADMIN_ROLEBase.sol
setMaxServiceTtl(seconds)ADMIN_ROLEBase.sol
setRequestExpiryGracePeriod(seconds)ADMIN_ROLEBase.sol
setMaxQuoteAge(seconds)ADMIN_ROLEBase.sol

Most admin setters in Base.sol are whenNotPaused. The two exceptions, both in Payments.sol, are setTreasury and setPaymentSplit. Paused governance can still rewire payment routing; this is intentional so a halted protocol can fix a known-bad treasury before resuming.

Slashing

FunctionCallerSource
proposeSlash(serviceId, op, slashBps, evidence)Service owner, blueprint owner, or BSM-declared originSlashing.sol
disputeSlash(slashId, reason) payableSlashed operator (must post bond), or SLASH_ADMIN_ROLESlashing.sol
executeSlash(slashId)Anyone (gated by isExecutable)Slashing.sol
executeSlashBatch(ids)AnyoneSlashing.sol
cancelSlash(slashId, reason)SLASH_ADMIN_ROLESlashing.sol
setSlashConfig(...)ADMIN_ROLESlashing.sol

See Slashing for the full lifecycle and runbooks.

Blueprints

FunctionCallerSource
createBlueprint(def)Anyone (when not paused), nonReentrantBlueprintsCreate.sol
updateBlueprint(id, uri, hash)Blueprint owner, nonReentrantBlueprintsManage.sol
transferBlueprint(id, newOwner)Blueprint owner, nonReentrantBlueprintsManage.sol
deactivateBlueprint(id)Blueprint owner, nonReentrantBlueprintsManage.sol
setJobEventRates(id, idxs, rates)Blueprint owner, nonReentrantBlueprintsManage.sol
setBlueprintResourceRequirements(id, reqs)Blueprint owner, nonReentrantBlueprintsManage.sol

Operators

FunctionCallerSource
registerOperator(...)Anyone with valid stake (when not paused), nonReentrantOperators.sol
unregisterOperator(id)The operator (no active services), nonReentrantOperators.sol
updateOperatorPreferences(id, key, rpc)The operatorOperators.sol

Services

FunctionCaller
requestService(...)Anyone (when not paused)
approveService(requestId, stakingPercent)Operator listed in the request (request not expired)
approveServiceWithCommitments(...)Operator listed in the request
approveServiceWithBls(requestId, stakingPercent, blsPubkey)Operator listed in the request
approveServiceWithCommitmentsAndBls(...)Operator listed in the request
rejectService(requestId)Operator listed in the request
expireServiceRequest(requestId)Anyone, after grace period (when not activated)
terminateService(serviceId)Service owner
forceRemoveOperator(serviceId, operator)Blueprint manager only

Payments

FunctionCaller
fundService(serviceId, amount) payableAnyone (re-checks manager policy and TTL)
withdrawRemainingEscrow(serviceId)Service owner, after termination
billSubscription(serviceId)Anyone, gated by interval
billSubscriptionBatch(ids)Anyone
claimReward(token)The reward beneficiary
claimRewards(tokens)The reward beneficiary

MultiAssetDelegation (src/staking/MultiAssetDelegation.sol)

Staking and delegation are a separate proxy with its own role registry. Functions are split across facets: StakingAdminFacet, StakingAssetsFacet, StakingOperatorsFacet, StakingSlashingFacet, StakingDelegationsFacet, StakingDepositsFacet, StakingViewsFacet.

Upgrade and Global Config (StakingAdminFacet)

FunctionCaller
_authorizeUpgrade(newImpl)ADMIN_ROLE (NOT a separate UPGRADER_ROLE; SHOULD be held by TangleTimelock)
pause() / unpause()ADMIN_ROLE (no separate PAUSER_ROLE on MAD)
setTangle(addr)ADMIN_ROLE — grants TANGLE_ROLE
setOperatorBondToken(token)ADMIN_ROLE — locked once any operator exists
addSlasher(addr) / removeSlasher(addr)ADMIN_ROLE — grants/revokes SLASHER_ROLE
setOperatorCommission(bps)ADMIN_ROLE (queues a 7-day timelocked commission change)
executeCommissionChange() / cancelCommissionChange()ADMIN_ROLE
setDelays(...)ADMIN_ROLE
setRewardsManager(addr) / setServiceFeeDistributor(addr)ADMIN_ROLE
rescueTokens(token, to, amount)DEFAULT_ADMIN_ROLE
sweepDust(token, to)ADMIN_ROLE
resetPendingSlashCount(op, count)ADMIN_ROLE (recovery only; default reverts unless overridden)

Asset Configuration (StakingAssetsFacet)

FunctionCaller
enableAsset(asset, config)ASSET_MANAGER_ROLE
enableAssetWithAdapter(asset, config, adapter)ASSET_MANAGER_ROLE
disableAsset(asset)ASSET_MANAGER_ROLE
registerAdapter(token, adapter)ASSET_MANAGER_ROLE
removeAdapter(token)ASSET_MANAGER_ROLE
setRequireAdapters(bool)ASSET_MANAGER_ROLE
startAdapterMigration / completeAdapterMigration / cancelAdapterMigrationASSET_MANAGER_ROLE

Slashing Entrypoints (StakingSlashingFacet)

FunctionCaller
slashForBlueprint(...)SLASHER_ROLE (Tangle is the canonical slasher)
slashForService(...)SLASHER_ROLE — per-asset commitment slashing
slash(...)SLASHER_ROLE — native consensus slash
incrementPendingSlash(operator)SLASHER_ROLE
decrementPendingSlash(operator)SLASHER_ROLE

Operator Wiring From Tangle (StakingOperatorsFacet)

FunctionCaller
addBlueprintForOperator(op, id)TANGLE_ROLE
removeBlueprintForOperator(op, id)TANGLE_ROLE

MBSMRegistry (src/MBSMRegistry.sol)

FunctionCaller
addVersion(mbsm)MANAGER_ROLE. Rejects EOA targets (mbsmAddress.code.length != 0); the caller can be any holder of the role.
pinBlueprint(blueprintId, revision)MANAGER_ROLE
unpinBlueprint(blueprintId)MANAGER_ROLE
initiateDeprecation(revision)MANAGER_ROLE
completeDeprecation(revision)MANAGER_ROLE, after grace period
queueEmergencyDeprecation(revision)MANAGER_ROLE
executeEmergencyDeprecation(revision)MANAGER_ROLE, after EMERGENCY_DEPRECATION_DELAY (24h)
cancelEmergencyDeprecation(revision)MANAGER_ROLE
setDeprecationGracePeriod(seconds)MANAGER_ROLE
_authorizeUpgrade(newImpl)UPGRADER_ROLE

MANAGER_ROLE SHOULD be the timelock. The 24h emergency deprecation delay is the floor on how fast a single role can disable an MBSM revision; combined with the timelock delay on top, a queued malicious deprecation has at least timelockDelay + 24h of observability before it lands.

Beacon stack

ValidatorPodManager

FunctionCaller
createPod()Anyone (one pod per address)
recordBeaconChainEthBalanceUpdate(podOwner, sharesDelta)Pod (the contract itself)

L2SlashingReceiver

FunctionCaller
receiveMessage(sourceChainId, sender, payload)The configured cross-chain messenger only
setAuthorizedSender(chainId, sender, authorized)Owner; authorization is timelocked (2 days)
activateAuthorizedSender(chainId, sender)Owner, after SENDER_ACTIVATION_DELAY
setMessenger(addr)Owner

L2SlashingConnector

FunctionCaller
propagateBeaconSlashing(pod, newFactor)slashingOracle OR owner (the onlySlashingOracle modifier accepts both)
propagateBeaconSlashingToChain(pod, newFactor, destChain)slashingOracle or owner
batchPropagateBeaconSlashing(...)slashingOracle or owner
setMessenger(addr)Owner
setSlashingOracle(addr)Owner
setChainConfig(...)Owner
setDefaultDestinationChain(chainId)Owner
registerPodOperator(pod, operator)Owner
batchRegisterPodOperators(...)Owner
transferOwnership(newOwner)Owner

Governance

TangleTimelock

FunctionCaller
schedule(...)PROPOSER_ROLE (TangleGovernor)
execute(...)EXECUTOR_ROLE (TangleGovernor or open)
cancel(...)CANCELLER_ROLE
updateDelay(newDelay)The timelock itself only (onlySelf), bounded [1d, 30d]
_authorizeUpgrade(newImpl)The timelock itself (onlySelf)

TangleGovernor

FunctionCaller
propose(...)Anyone with voting power above proposalThreshold
castVote(...)Token holders with voting power at the snapshotted timestamp
_authorizeUpgrade(newImpl)Through governance proposal only

TangleToken

FunctionCaller
mint(to, amount)MINTER_ROLE (timelock); subject to MAX_SUPPLY
_authorizeUpgrade(newImpl)UPGRADER_ROLE
clock()view, returns block.timestamp (ERC-6372)
RoleHolderWhy
DEFAULT_ADMIN_ROLETangleTimelockRole grants and revokes flow through governance
ADMIN_ROLETangleTimelockSetters need a delay window for community exit
UPGRADER_ROLETangleTimelockUpgrades need a delay window
PAUSER_ROLEOperations multisigFast response to active incidents
SLASH_ADMIN_ROLESlashing oversight multisigDistinct from operations to prevent conflict of interest
MANAGER_ROLE (MBSM)TangleTimelockMBSM version changes need a delay
MINTER_ROLE (TangleToken)TangleTimelockInflation flows through governance

The deployer EOA MUST hold zero roles after deployment. Verify with the on-chain audit that _applyRoleHandoff produced. See Upgrade Discipline for the post-deploy checklist.