Blockchain / Global / Address
Contract
0xDb622e5bCc20c9D6554b8ebD8053C699580e9BB7
- Balance
- 0 SOMI
- Transactions sent
- 1
- Type
- Contract · 2,206 bytes of code
ConduitCaptain Verified
- Compiler
- solc 0.8.15+commit.e14f2714
- Language
- Solidity
- Optimization
- Yes, 200 runs
- EVM version
- —
- License
- —
- Verified
- 2026-10-12
ConduitCaptain.sol
Solidity
pragma solidity ^0.8.15;
/**
* @title ConduitCaptainInterface
* @author 0age
* @notice ConduitCaptainInterface contains function endpoints, events, and error
* declarations for the ConduitCaptain contract.
*/
interface ConduitCaptainInterface {
/**
* @dev Emit an event whenever a revoker role is updated by the owner.
*
* @param revoker The address of the new revoker role.
*/
event RevokerUpdated(address revoker);
/**
* @dev Revert with an error when attempting to set a conduit controller
* that does not contain contract code.
*/
error InvalidConduitController(address conduitController);
/**
* @dev Revert with an error when attempting to call closeChannel from an
* account that does not currently hold the revoker role.
*/
error InvalidRevoker();
/**
* @dev Revert with an error when attempting to register a revoker and
* supplying the null address.
*/
error RevokerIsNullAddress();
/**
* @notice Initiate conduit ownership transfer by assigning a new potential
* owner for the given conduit. Only callable by the owner.
*
* @param conduit The conduit for which to initiate ownership
* transfer.
* @param newPotentialOwner The new potential owner to set.
*/
function transferConduitOwnership(
address conduit,
address newPotentialOwner
) external;
/**
* @notice Clear the currently set potential owner, if any, from a conduit.
* Only callable by the owner.
*
* @param conduit The conduit for which to cancel ownership transfer.
*/
function cancelConduitOwnershipTransfer(address conduit) external;
/**
* @notice Accept ownership of a given conduit once this contract has been
* set as the current potential owner. Only callable by the owner.
*
* @param conduit The conduit for which to accept ownership transfer.
*/
function acceptConduitOwnership(address conduit) external;
/**
* @notice Open or close a channel on a given conduit, thereby allowing the
* specified account to execute transfers against that conduit.
* Extreme care must be taken when updating channels, as malicious
* or vulnerable channels can transfer any ERC20, ERC721 and ERC1155
* tokens where the token holder has granted the conduit approval.
* Only the owner may call this function.
*
* @param conduit The conduit for which to open or close the channel.
* @param channel The channel to open or close on the conduit.
* @param isOpen A boolean indicating whether to open or close the channel.
*/
function updateChannel(
address conduit,
address channel,
bool isOpen
) external;
/**
* @notice Close a channel on a given conduit, thereby preventing the
* specified account from executing transfers against that conduit.
* Only the designated revoker may call this function.
*
* @param conduit The conduit for which to close the channel.
* @param channel The channel to close on the conduit.
*/
function closeChannel(address conduit, address channel) external;
/**
* @notice Set a revoker role that can close channels. Only the owner may
* call this function.
*
* @param revoker The account to set as the revoker.
*/
function updateRevoker(address revoker) external;
/**
* @notice External view function to retrieve the address of the revoker
* role that can close channels.
*
* @return revoker The account set as the revoker.
*/
function getRevoker() external view returns (address revoker);
/**
* @notice External view function to retrieve the address of the
* ConduitController referenced by the contract
*
* @return conduitController The address of the ConduitController.
*/
function getConduitController()
external
view
returns (address conduitController);
}
/**
* @title ConduitControllerInterface
* @author 0age
* @notice ConduitControllerInterface contains relevant external function
* interfaces for a conduit controller contract.
*/
interface ConduitControllerInterface {
/**
* @notice Initiate conduit ownership transfer by assigning a new potential
* owner for the given conduit. Once set, the new potential owner
* may call `acceptOwnership` to claim ownership of the conduit.
* Only the owner of the conduit in question may call this function.
*
* @param conduit The conduit for which to initiate ownership transfer.
*/
function transferOwnership(address conduit, address newPotentialOwner)
external;
/**
* @notice Clear the currently set potential owner, if any, from a conduit.
* Only the owner of the conduit in question may call this function.
*
* @param conduit The conduit for which to cancel ownership transfer.
*/
function cancelOwnershipTransfer(address conduit) external;
/**
* @notice Accept ownership of a supplied conduit. Only accounts that the
* current owner has set as the new potential owner may call this
* function.
*
* @param conduit The conduit for which to accept ownership.
*/
function acceptOwnership(address conduit) external;
/**
* @notice Open or close a channel on a given conduit, thereby allowing the
* specified account to execute transfers against that conduit.
* Extreme care must be taken when updating channels, as malicious
* or vulnerable channels can transfer any ERC20, ERC721 and ERC1155
* tokens where the token holder has granted the conduit approval.
* Only the owner of the conduit in question may call this function.
*
* @param conduit The conduit for which to open or close the channel.
* @param channel The channel to open or close on the conduit.
* @param isOpen A boolean indicating whether to open or close the channel.
*/
function updateChannel(
address conduit,
address channel,
bool isOpen
) external;
}
/**
* @title TwoStepOwnableInterface
* @author OpenSea Protocol
* @notice TwoStepOwnableInterface contains all external function interfaces,
* events and errors for the TwoStepOwnable contract.
*/
interface TwoStepOwnableInterface {
/**
* @dev Emit an event whenever the contract owner registers a new potential
* owner.
*
* @param newPotentialOwner The new potential owner of the contract.
*/
event PotentialOwnerUpdated(address newPotentialOwner);
/**
* @dev Emit an event whenever contract ownership is transferred.
*
* @param previousOwner The previous owner of the contract.
* @param newOwner The new owner of the contract.
*/
event OwnershipTransferred(address previousOwner, address newOwner);
/**
* @dev Revert with an error when attempting to set an initial owner when
* one has already been set.
*/
error OwnerAlreadySet(address currentOwner);
/**
* @dev Revert with an error when attempting to call a function with the
* onlyOwner modifier from an account other than that of the owner.
*/
error CallerIsNotOwner();
/**
* @dev Revert with an error when attempting to register an initial owner
* and supplying the null address.
*/
error InitialOwnerIsNullAddress();
/**
* @dev Revert with an error when attempting to register a new potential
* owner and supplying the null address.
*/
error NewPotentialOwnerIsNullAddress();
/**
* @dev Revert with an error when attempting to claim ownership of the
* contract with a caller that is not the current potential owner.
*/
error CallerIsNotNewPotentialOwner();
/**
* @notice Initiate ownership transfer by assigning a new potential owner
* to this contract. Once set, the new potential owner may call
* `acceptOwnership` to claim ownership. Only the owner may call
* this function.
*
* @param newPotentialOwner The address for which to initiate ownership
* transfer to.
*/
function transferOwnership(address newPotentialOwner) external;
/**
* @notice Clear the currently set potential owner, if any. Only the owner
* of this contract may call this function.
*/
function cancelOwnershipTransfer() external;
/**
* @notice Accept ownership of this contract. Only the account that the
* current owner has set as the new potential owner may call this
* function.
*/
function acceptOwnership() external;
/**
* @notice An external view function that returns the potential owner.
*
* @return The address of the potential owner.
*/
function potentialOwner() external view returns (address);
/**
* @notice An external view function that returns the owner.
*
* @return The address of the owner.
*/
function owner() external view returns (address);
}
/**
* @title TwoStepOwnable
* @author OpenSea Protocol Team
* @notice TwoStepOwnable provides access control for inheriting contracts,
* where the ownership of the contract can be exchanged via a two step
* process. A potential owner is set by the current owner by calling
* `transferOwnership`, then accepted by the new potential owner by
* calling `acceptOwnership`.
*/
abstract contract TwoStepOwnable is TwoStepOwnableInterface {
// The address of the owner.
address private _owner;
// The address of the new potential owner.
address private _potentialOwner;
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
// Ensure that the caller is the owner.
if (msg.sender != _owner) {
revert CallerIsNotOwner();
}
// Continue with function execution.
_;
}
/**
* @notice Initiate ownership transfer by assigning a new potential owner
* to this contract. Once set, the new potential owner may call
* `acceptOwnership` to claim ownership. Only the owner may call
* this function.
*
* @param newPotentialOwner The address for which to initiate ownership
* transfer to.
*/
function transferOwnership(address newPotentialOwner)
external
override
onlyOwner
{
// Ensure the new potential owner is not an invalid address.
if (newPotentialOwner == address(0)) {
revert NewPotentialOwnerIsNullAddress();
}
// Emit an event indicating that the potential owner has been updated.
emit PotentialOwnerUpdated(newPotentialOwner);
// Set the new potential owner as the potential owner.
_potentialOwner = newPotentialOwner;
}
/**
* @notice Clear the currently set potential owner, if any. Only the owner
* of this contract may call this function.
*/
function cancelOwnershipTransfer() external override onlyOwner {
// Emit an event indicating that the potential owner has been cleared.
emit PotentialOwnerUpdated(address(0));
// Clear the current new potential owner.
delete _potentialOwner;
}
/**
* @notice Accept ownership of this contract. Only the account that the
* current owner has set as the new potential owner may call this
* function.
*/
function acceptOwnership() external override {
// Ensure the caller is the potential owner.
if (msg.sender != _potentialOwner) {
// Revert, indicating that caller is not current potential owner.
revert CallerIsNotNewPotentialOwner();
}
// Emit an event indicating that the potential owner has been cleared.
emit PotentialOwnerUpdated(address(0));
// Clear the current new potential owner.
delete _potentialOwner;
// Set the caller as the owner of this contract.
_setOwner(msg.sender);
}
/**
* @notice An external view function that returns the potential owner.
*
* @return The address of the potential owner.
*/
function potentialOwner() external view override returns (address) {
return _potentialOwner;
}
/**
* @notice A public view function that returns the owner.
*
* @return The address of the owner.
*/
function owner() public view override returns (address) {
return _owner;
}
/**
* @notice Internal function that sets the inital owner of the base
* contract. The initial owner must not already be set.
* To be called in the constructor or when initializing a proxy.
*
* @param initialOwner The address to set for initial ownership.
*/
function _setInitialOwner(address initialOwner) internal {
// Ensure that an initial owner has been supplied.
if (initialOwner == address(0)) {
revert InitialOwnerIsNullAddress();
}
// Ensure that the owner has not already been set.
if (_owner != address(0)) {
revert OwnerAlreadySet(_owner);
}
// Set the initial owner.
_setOwner(initialOwner);
}
/**
* @notice Private function that sets a new owner and emits a corresponding
* event.
*
* @param newOwner The address to assign as the new owner.
*/
function _setOwner(address newOwner) private {
// Emit an event indicating that the new owner has been set.
emit OwnershipTransferred(_owner, newOwner);
// Set the new owner.
_owner = newOwner;
}
}
/**
* @title ConduitCaptain
* @author 0age
* @notice ConduitCaptain is an owned contract where the owner can in turn update
* conduits that are owned by the contract. It allows for designating an
* account that may revoke channels from conduits.
*/
contract ConduitCaptain is TwoStepOwnable, ConduitCaptainInterface {
// Set the conduit controller as an immutable argument.
ConduitControllerInterface private immutable _CONDUIT_CONTROLLER;
// Designate a storage variable for the revoker role.
address private _revoker;
/**
* @dev Initialize contract by setting the conduit controller, the initial
* owner, and the initial revoker role.
*/
constructor(
address conduitController,
address initialOwner,
address initialRevoker
) {
// Ensure that a contract is deployed to the given conduit controller.
if (conduitController.code.length == 0) {
revert InvalidConduitController(conduitController);
}
// Set the conduit controller as an immutable argument.
_CONDUIT_CONTROLLER = ConduitControllerInterface(conduitController);
// Set the initial owner.
_setInitialOwner(initialOwner);
// Set the initial revoker.
_setRevoker(initialRevoker);
}
/**
* @notice Initiate conduit ownership transfer by assigning a new potential
* owner for the given conduit. Only callable by the owner.
*
* @param conduit The conduit for which to initiate ownership
* transfer.
* @param newPotentialOwner The new potential owner to set.
*/
function transferConduitOwnership(
address conduit,
address newPotentialOwner
) external override onlyOwner {
// Call the conduit controller to transfer conduit ownership.
_CONDUIT_CONTROLLER.transferOwnership(conduit, newPotentialOwner);
}
/**
* @notice Clear the currently set potential owner, if any, from a conduit.
* Only callable by the owner.
*
* @param conduit The conduit for which to cancel ownership transfer.
*/
function cancelConduitOwnershipTransfer(address conduit)
external
override
onlyOwner
{
// Call the conduit controller to cancel conduit ownership transfer.
_CONDUIT_CONTROLLER.cancelOwnershipTransfer(conduit);
}
/**
* @notice Accept ownership of a given conduit once this contract has been
* set as the current potential owner. Only callable by the owner.
*
* @param conduit The conduit for which to accept ownership transfer.
*/
function acceptConduitOwnership(address conduit)
external
override
onlyOwner
{
// Call the conduit controller to accept conduit ownership.
_CONDUIT_CONTROLLER.acceptOwnership(conduit);
}
/**
* @notice Open or close a channel on a given conduit, thereby allowing the
* specified account to execute transfers against that conduit.
* Extreme care must be taken when updating channels, as malicious
* or vulnerable channels can transfer any ERC20, ERC721 and ERC1155
* tokens where the token holder has granted the conduit approval.
* Only the owner may call this function.
*
* @param conduit The conduit for which to open or close the channel.
* @param channel The channel to open or close on the conduit.
* @param isOpen A boolean indicating whether to open or close the channel.
*/
function updateChannel(
address conduit,
address channel,
bool isOpen
) external override onlyOwner {
// Call the conduit controller to update channel status on the conduit.
_CONDUIT_CONTROLLER.updateChannel(conduit, channel, isOpen);
}
/**
* @notice Close a channel on a given conduit, thereby preventing the
* specified account from executing transfers against that conduit.
* Only the designated revoker may call this function.
*
* @param conduit The conduit for which to close the channel.
* @param channel The channel to close on the conduit.
*/
function closeChannel(address conduit, address channel) external override {
// Revert if the caller is not the revoker.
if (msg.sender != _revoker) {
revert InvalidRevoker();
}
// Call the conduit controller to close the channel on the conduit.
_CONDUIT_CONTROLLER.updateChannel(conduit, channel, false);
}
/**
* @notice Set a revoker role that can close channels. Only the owner may
* call this function.
*
* @param revoker The account to set as the revoker.
*/
function updateRevoker(address revoker) external override onlyOwner {
// Assign the new revoker role.
_setRevoker(revoker);
}
/**
* @notice External view function to retrieve the address of the revoker
* role that can close channels.
*
* @return revoker The account set as the revoker.
*/
function getRevoker() external view override returns (address revoker) {
return _revoker;
}
/**
* @notice External view function to retrieve the address of the
* ConduitController referenced by the contract
*
* @return conduitController The address of the ConduitController.
*/
function getConduitController()
external
view
override
returns (address conduitController)
{
return address(_CONDUIT_CONTROLLER);
}
/**
* @notice Internal function to set a revoker role that can close channels.
*
* @param revoker The account to set as the revoker.
*/
function _setRevoker(address revoker) internal {
// Revert if no address is supplied for the revoker role.
if (revoker == address(0)) {
revert RevokerIsNullAddress();
}
// Assign the new revoker role.
_revoker = revoker;
emit RevokerUpdated(revoker);
}
}ABI · 25 entries
json
[
{
"type": "constructor",
"inputs": [
{
"name": "conduitController",
"type": "address",
"internalType": "address"
},
{
"name": "initialOwner",
"type": "address",
"internalType": "address"
},
{
"name": "initialRevoker",
"type": "address",
"internalType": "address"
}
],
"stateMutability": "nonpayable"
},
{
"name": "CallerIsNotNewPotentialOwner",
"type": "error",
"inputs": []
},
{
"name": "CallerIsNotOwner",
"type": "error",
"inputs": []
},
{
"name": "InitialOwnerIsNullAddress",
"type": "error",
"inputs": []
},
{
"name": "InvalidConduitController",
"type": "error",
"inputs": [
{
"name": "conduitController",
"type": "address",
"internalType": "address"
}
]
},
{
"name": "InvalidRevoker",
"type": "error",
"inputs": []
},
{
"name": "NewPotentialOwnerIsNullAddress",
"type": "error",
"inputs": []
},
{
"name": "OwnerAlreadySet",
"type": "error",
"inputs": [
{
"name": "currentOwner",
"type": "address",
"internalType": "address"
}
]
},
{
"name": "RevokerIsNullAddress",
"type": "error",
"inputs": []
},
{
"name": "OwnershipTransferred",
"type": "event",
"inputs": [
{
"name": "previousOwner",
"type": "address",
"indexed": false,
"internalType": "address"
},
{
"name": "newOwner",
"type": "address",
"indexed": false,
"internalType": "address"
}
],
"anonymous": false
},
{
"name": "PotentialOwnerUpdated",
"type": "event",
"inputs": [
{
"name": "newPotentialOwner",
"type": "address",
"indexed": false,
"internalType": "address"
}
],
"anonymous": false
},
{
"name": "RevokerUpdated",
"type": "event",
"inputs": [
{
"name": "revoker",
"type": "address",
"indexed": false,
"internalType": "address"
}
],
"anonymous": false
},
{
"name": "acceptConduitOwnership",
"type": "function",
"inputs": [
{
"name": "conduit",
"type": "address",
"internalType": "address"
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"name": "acceptOwnership",
"type": "function",
"inputs": [],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"name": "cancelConduitOwnershipTransfer",
"type": "function",
"inputs": [
{
"name": "conduit",
"type": "address",
"internalType": "address"
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"name": "cancelOwnershipTransfer",
"type": "function",
"inputs": [],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"name": "closeChannel",
"type": "function",
"inputs": [
{
"name": "conduit",
"type": "address",
"internalType": "address"
},
{
"name": "channel",
"type": "address",
"internalType": "address"
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"name": "getConduitController",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "conduitController",
"type": "address",
"internalType": "address"
}
],
"stateMutability": "view"
},
{
"name": "getRevoker",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "revoker",
"type": "address",
"internalType": "address"
}
],
"stateMutability": "view"
},
{
"name": "owner",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "address",
"internalType": "address"
}
],
"stateMutability": "view"
},
{
"name": "potentialOwner",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "address",
"internalType": "address"
}
],
"stateMutability": "view"
},
{
"name": "transferConduitOwnership",
"type": "function",
"inputs": [
{
"name": "conduit",
"type": "address",
"internalType": "address"
},
{
"name": "newPotentialOwner",
"type": "address",
"internalType": "address"
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"name": "transferOwnership",
"type": "function",
"inputs": [
{
"name": "newPotentialOwner",
"type": "address",
"internalType": "address"
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"name": "updateChannel",
"type": "function",
"inputs": [
{
"name": "conduit",
"type": "address",
"internalType": "address"
},
{
"name": "channel",
"type": "address",
"internalType": "address"
},
{
"name": "isOpen",
"type": "bool",
"internalType": "bool"
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"name": "updateRevoker",
"type": "function",
"inputs": [
{
"name": "revoker",
"type": "address",
"internalType": "address"
}
],
"outputs": [],
"stateMutability": "nonpayable"
}
]