-
Notifications
You must be signed in to change notification settings - Fork 17
src: Add router and factory contracts #64
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| // SPDX-License-Identifier: MIT | ||
| pragma solidity ^0.8.16; | ||
|
|
||
| /** | ||
| * @title ScribeZeroValue | ||
| * | ||
| * @notice Static scribe oracle returning zero or reverting on read functions | ||
| * | ||
| * @dev Deployment: | ||
| * ```bash | ||
| * $ forge create script/offboarder/ScribeZeroValue.sol:ScribeZeroValue \ | ||
| * --keystore $KEYSTORE \ | ||
| * --password $KEYSTORE_PASSWORD \ | ||
| * --rpc-url $RPC_URL \ | ||
| * --verifier-url $ETHERSCAN_API_URL \ | ||
| * --etherscan-api-key $ETHERSCAN_API_KEY | ||
| * ``` | ||
| * | ||
| * @author Chronicle Labs, Inc | ||
| * @custom:security-contact security@chroniclelabs.org | ||
| */ | ||
| contract ScribeZeroValue { | ||
| function read() external pure returns (uint) { | ||
| revert(); | ||
| } | ||
|
|
||
| function tryRead() external pure returns (bool, uint) { | ||
| return (false, 0); | ||
| } | ||
|
|
||
| function readWithAge() external pure returns (uint, uint) { | ||
| revert(); | ||
| } | ||
|
|
||
| function tryReadWithAge() external pure returns (bool, uint, uint) { | ||
| return (false, 0, 0); | ||
| } | ||
|
|
||
| // - MakerDAO Compatibility | ||
|
|
||
| function peek() external pure returns (uint, bool) { | ||
| return (0, false); | ||
| } | ||
|
|
||
| function peep() external pure returns (uint, bool) { | ||
| return (0, false); | ||
| } | ||
|
|
||
| // - Chainlink Compatibility | ||
|
|
||
| function latestRoundData() | ||
| external | ||
| pure | ||
| returns ( | ||
| uint80 roundId, | ||
| int answer, | ||
| uint startedAt, | ||
| uint updatedAt, | ||
| uint80 answeredInRound | ||
| ) | ||
| { | ||
| roundId = 1; | ||
| answer = 0; | ||
| startedAt = 0; | ||
| updatedAt = 0; | ||
| answeredInRound = roundId; | ||
| } | ||
|
|
||
| function latestAnswer() external pure returns (int) { | ||
| int answer = 0; | ||
| return answer; | ||
|
Comment on lines
+70
to
+71
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Separated into two statements to allow |
||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| // SPDX-License-Identifier: MIT | ||
| pragma solidity ^0.8.16; | ||
|
|
||
| import {IScribe} from "./IScribe.sol"; | ||
|
|
||
| import {LibSecp256k1} from "./libs/LibSecp256k1.sol"; | ||
|
|
||
| interface IScribeFactory { | ||
| /// @dev ScribeConfig encapsulates a Scribe instance's deployment | ||
| /// configuration. | ||
| struct ScribeConfig { | ||
| string name; | ||
| bytes32 wat; | ||
| uint8 bar; | ||
| address[] authed; | ||
| address[] tolled; | ||
| LibSecp256k1.Point[] validators; | ||
| IScribe.ECDSAData[] registrationSigs; | ||
| } | ||
|
|
||
| /// @dev ScribeRouterConfig encapsulates a ScribeRouter instance's | ||
| /// deployment configuration. | ||
| struct ScribeRouterConfig { | ||
| string name; | ||
| address[] authed; | ||
| address[] tolled; | ||
| } | ||
|
|
||
| /// @notice Emitted when new Scribe instance deployed. | ||
| /// @param caller The caller's address. | ||
| /// @param scribe The deployed Scribe instance's address. | ||
| /// @param name The Scribe instance's name. | ||
| event ScribeDeployed( | ||
| address indexed caller, address indexed scribe, string name | ||
| ); | ||
|
|
||
| /// @notice Emitted when new ScribeRouter instance deployed. | ||
| /// @param caller The caller's address. | ||
| /// @param router The deployed ScribeRouter instance's address. | ||
| /// @param name The ScribeRouter instance's name. | ||
| event ScribeRouterDeployed( | ||
| address indexed caller, address indexed router, string name | ||
| ); | ||
|
|
||
| /// @notice Deploys a new Scribe and ScribeRouter instance. | ||
| /// @dev Only callable by toll'ed address. | ||
| /// @param scribeCfg The Scribe instance's deployment configuration. | ||
| /// @param routerCfg The ScribeRouter instance's deployment configuration. | ||
| /// @return The deployed Scribe instance's address. | ||
| /// @return The deployed ScribeRouter instance's address. | ||
| function plantScribeWithRouter( | ||
| ScribeConfig calldata scribeCfg, | ||
| ScribeRouterConfig calldata routerCfg | ||
| ) external returns (address, address); | ||
|
|
||
| /// @notice Deploys a new Scribe instance. | ||
| /// @dev Only callable by toll'ed address. | ||
| /// @param cfg The Scribe instance's deployment configuration. | ||
| /// @return The deployed Scribe instance's address. | ||
| function plantScribe(ScribeConfig calldata cfg) external returns (address); | ||
|
|
||
| /// @notice Deploys a new ScribeRouter instance. | ||
| /// @dev Only callable by toll'ed address. | ||
| /// @param cfg The ScribeRouter instance's deployment configuration. | ||
| /// @return The deployed ScribeRouter instance's address. | ||
| function plantRouter(ScribeRouterConfig calldata cfg) | ||
| external | ||
| returns (address); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,79 @@ | ||
| // SPDX-License-Identifier: MIT | ||
| pragma solidity ^0.8.16; | ||
|
|
||
| import {IChronicle} from "chronicle-std/IChronicle.sol"; | ||
|
|
||
| interface IScribeRouter is IChronicle { | ||
| /// @notice Emitted when the scribe address is updated. | ||
| /// @param caller The caller's address. | ||
| /// @param oldScribe The old scribe address. | ||
| /// @param newScribe The new scribe address. | ||
| event ScribeUpdated( | ||
| address indexed caller, address oldScribe, address newScribe | ||
| ); | ||
|
|
||
| /// @notice Returns the name identifier. | ||
| /// @return name The name of the oracle. | ||
| function name() external view returns (string memory name); | ||
|
|
||
| /// @notice Returns the wat identifier. | ||
| /// @return wat The wat of the oracle. | ||
| function wat() external view returns (bytes32 wat); | ||
|
|
||
| /// @notice Returns the scribe address. | ||
| /// @return scribe The scribe address. | ||
| function scribe() external view returns (address scribe); | ||
|
|
||
| /// @notice Updates the scribe contract. | ||
| /// @dev Only callable by auth'ed address. | ||
| /// @param scribe The scribe address. | ||
| function setScribe(address scribe) external; | ||
|
|
||
| // -- MakerDAO Compatibility -- | ||
|
|
||
| /// @notice Returns the oracle's current value. | ||
| /// @custom:deprecated Use `tryRead()(bool,uint)` instead. | ||
| /// @return value The oracle's current value if it exists, zero otherwise. | ||
| /// @return isValid True if value exists, false otherwise. | ||
| function peek() external view returns (uint value, bool isValid); | ||
|
|
||
| /// @notice Returns the oracle's current value. | ||
| /// @custom:deprecated Use `tryRead()(bool,uint)` instead. | ||
| /// @return value The oracle's current value if it exists, zero otherwise. | ||
| /// @return isValid True if value exists, false otherwise. | ||
| function peep() external view returns (uint value, bool isValid); | ||
|
|
||
| // -- Chainlink Compatibility -- | ||
|
|
||
| /// @notice Returns the number of decimals of the oracle's value. | ||
| /// @dev Provides partial compatibility with Chainlink's | ||
| /// IAggregatorV3Interface. | ||
| /// @return decimals The oracle value's number of decimals. | ||
| function decimals() external view returns (uint8 decimals); | ||
|
|
||
| /// @notice Returns the oracle's latest value. | ||
| /// @dev Provides partial compatibility with Chainlink's | ||
| /// IAggregatorV3Interface. | ||
| /// @return roundId 1. | ||
| /// @return answer The oracle's latest value. | ||
| /// @return startedAt 0. | ||
| /// @return updatedAt The timestamp of oracle's latest update. | ||
| /// @return answeredInRound 1. | ||
| function latestRoundData() | ||
| external | ||
| view | ||
| returns ( | ||
| uint80 roundId, | ||
| int answer, | ||
| uint startedAt, | ||
| uint updatedAt, | ||
| uint80 answeredInRound | ||
| ); | ||
|
|
||
| /// @notice Returns the oracle's latest value. | ||
| /// @dev Provides partial compatibility with Chainlink's | ||
| /// IAggregatorV3Interface. | ||
| /// @custom:deprecated See https://docs.chain.link/data-feeds/api-reference/#latestanswer. | ||
| /// @return answer The oracle's latest value. | ||
| function latestAnswer() external view returns (int answer); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,128 @@ | ||
| // SPDX-License-Identifier: BUSL-1.1 | ||
| pragma solidity ^0.8.16; | ||
|
|
||
| import {Auth} from "chronicle-std/auth/Auth.sol"; | ||
| import {Toll} from "chronicle-std/toll/Toll.sol"; | ||
|
|
||
| import {IScribeFactory} from "./IScribeFactory.sol"; | ||
|
|
||
| import {Scribe} from "./Scribe.sol"; | ||
| import {ScribeRouter} from "./ScribeRouter.sol"; | ||
|
|
||
| import {LibSecp256k1} from "./libs/LibSecp256k1.sol"; | ||
|
|
||
| /** | ||
| * @title ScribeFactory | ||
| * @custom:version 2.0.1 | ||
| * | ||
| * @notice Factory contract to deploy Scribe and ScribeRouter oracle contracts | ||
| * | ||
| * @author Chronicle Labs, Inc | ||
| * @custom:security-contact security@chroniclelabs.org | ||
| */ | ||
| contract ScribeFactory is IScribeFactory, Auth, Toll { | ||
| constructor(address initialAuthed) payable Auth(initialAuthed) {} | ||
|
|
||
| /// @inheritdoc IScribeFactory | ||
| function plantScribeWithRouter( | ||
| ScribeConfig calldata scribeCfg, | ||
| ScribeRouterConfig calldata routerCfg | ||
| ) public toll returns (address, address) { | ||
| Scribe scribe = _plantScribe(scribeCfg); | ||
| ScribeRouter router = _plantRouter(routerCfg); | ||
|
|
||
| scribe.kiss(address(router)); | ||
| router.setScribe(address(scribe)); | ||
|
|
||
| scribe.deny(address(this)); | ||
| router.deny(address(this)); | ||
|
|
||
| return (address(scribe), address(router)); | ||
| } | ||
|
|
||
| /// @inheritdoc IScribeFactory | ||
| function plantScribe(ScribeConfig calldata cfg) | ||
| public | ||
| toll | ||
| returns (address) | ||
| { | ||
| Scribe scribe = _plantScribe(cfg); | ||
|
|
||
| scribe.deny(address(this)); | ||
|
|
||
| return address(scribe); | ||
| } | ||
|
|
||
| /// @inheritdoc IScribeFactory | ||
| function plantRouter(ScribeRouterConfig calldata cfg) | ||
| public | ||
| toll | ||
| returns (address) | ||
| { | ||
| ScribeRouter router = _plantRouter(cfg); | ||
|
|
||
| router.deny(address(this)); | ||
|
|
||
| return address(router); | ||
| } | ||
|
|
||
| // -- Internal Helpers -- | ||
|
|
||
| function _plantScribe(ScribeConfig calldata cfg) internal returns (Scribe) { | ||
| // Deploy scribe. | ||
| Scribe scribe = new Scribe(address(this), cfg.wat); | ||
| emit ScribeDeployed(msg.sender, address(scribe), cfg.name); | ||
|
|
||
| // Lift validators and set bar. | ||
| scribe.lift(cfg.validators, cfg.registrationSigs); | ||
| scribe.setBar(cfg.bar); | ||
|
|
||
| // Rely authed and kiss tolled. | ||
| for (uint i; i < cfg.authed.length; i++) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. guess its possible to plant a "pre-bricked" Scribe if
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. True, imho bearable though taking into account how automated the deployments are nowadays. |
||
| scribe.rely(cfg.authed[i]); | ||
| } | ||
| for (uint i; i < cfg.tolled.length; i++) { | ||
| scribe.kiss(cfg.tolled[i]); | ||
| } | ||
|
|
||
| // Kiss zero address. | ||
| scribe.kiss(address(0)); | ||
|
|
||
| return scribe; | ||
| } | ||
|
|
||
| function _plantRouter(ScribeRouterConfig calldata cfg) | ||
| internal | ||
| returns (ScribeRouter) | ||
| { | ||
| // Deploy router. | ||
| ScribeRouter router = new ScribeRouter(address(this), cfg.name); | ||
| emit ScribeRouterDeployed(msg.sender, address(router), cfg.name); | ||
|
|
||
| // Rely authed and kiss tolled. | ||
| for (uint i; i < cfg.authed.length; i++) { | ||
| router.rely(cfg.authed[i]); | ||
| } | ||
| for (uint i; i < cfg.tolled.length; i++) { | ||
| router.kiss(cfg.tolled[i]); | ||
| } | ||
|
|
||
| // Kiss zero address. | ||
| router.kiss(address(0)); | ||
|
|
||
| return router; | ||
| } | ||
|
|
||
| // -- Overridden Toll Functions -- | ||
|
|
||
| /// @dev Defines authorization for IToll's authenticated functions. | ||
| function toll_auth() internal override(Toll) auth {} | ||
| } | ||
|
|
||
| /** | ||
| * @dev Contract overwrite to deploy contract instances with specific naming. | ||
| */ | ||
| contract ScribeFactory_COUNTER is ScribeFactory { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. doesn't follow
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah correct, I tried to not update the pattern here. IIRC |
||
| // @todo ^^^^^^^ Adjust counter of Factory instance. | ||
| constructor(address initialAuthed) ScribeFactory(initialAuthed) {} | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.