lido
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Owners
        • Signed-in users
        • Everyone
        Owners Signed-in users Everyone
      • Write
        • Owners
        • Signed-in users
        • Everyone
        Owners Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee
    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Versions and GitHub Sync Sharing URL Help
Menu
Options
Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Owners
  • Owners
  • Signed-in users
  • Everyone
Owners Signed-in users Everyone
Write
Owners
  • Owners
  • Signed-in users
  • Everyone
Owners Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee
  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       owned this note    owned this note      
    Published Linked with GitHub
    Subscribed
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    Subscribe
    # 📝 Curated Module v2. Spec :::warning **This document is WIP.** Statements or schemes are not final and can not be referred to anywhere. ::: ![image](https://hackmd.io/_uploads/SJQz98D_gg.png) Curated Module v2 (CM v2) is a new chapter for the Lido protocol. Based on the solid codebase of CSM, it features new concepts like support for 0x02 validators, integration features, and many more. A robust bonding mechanism allows CM v2 to streamline Node Operator management, reduce operational complexity, and increase protocol security. > Terms validator, key, validator key, and deposit data meanings are the same within the document - [Project repo](https://github.com/lidofinance/community-staking-module) - Written in [Solidity 0.8.24](https://github.com/ethereum/solidity/tree/v0.8.24) - Developed in [Foundry](https://github.com/foundry-rs/foundry) ## General Architecture ![image](https://hackmd.io/_uploads/S1xzbgt0xl.png) The scheme above depicts CM v2's smart contracts architecture and changes made compared to CSM v2. ### Contracts #### `CuratedModule.sol` *CMv2 on the scheme* :::info Changed in CM v2 ::: `CuratedModule.sol` is a core module contract conforming to the `IStakingModule` interface. The contract inherits from the original `CSModule.sol` to allow for the extended functionality while maintaining consistency with the original CSM. It stores information about Node Operators and deposit data (DD). This contract is responsible for all interactions with the `StakingRouter`, namely, the DD management and some of the Node Operator's parameters. Node Operators manage their validator keys and other parameters they can modify through this contract. **Changes in CM v2:** - The withdrawal reporting method is updated to support 0x02 WC type. - The management system for the NodeOperators address is changed to allow DAO to set both `rewardAddress` and `managerAddress`. - Exit penalties account for the validator withdrawal balance before application to support 0x02 WC type. - Withdrawals of the slashed validators and slashing penalties are reported via ET. #### `Accounting.sol` *Accounting in the scheme* :::info Changed in CM v2 ::: `Accounting.sol` is a supplementary contract responsible for the management of bond, rewards, and penalties. It stores bond tokens as `stETH` shares, provides information about the bond required, and provides interfaces for the penalties. Node Operators claim rewards and top-up bonds using this contract. **Changes in CM v2:** - `targetLimit` is now set to 0 if the penalty amount exceeds the bond available to effectively deactivate a Node Operator. - `FeeSplits` functionality added. - Infinite bond lock record is created in case of an insufficient bond to cover poenalties. #### `Verifier.sol` *Verifier on the scheme* :::info Changed in CM v2 ::: `Verifier.sol` is a utility contract responsible for validating the CL data proofs using EIP-4788. It accepts proof of the validator withdrawals and reports these facts to the `CuratedModule.sol` if the proof is valid. **Changes in CM v2:** - A special method is added to account for validator consolidations. #### `FeeDistributor.sol` *FeeDistributor on the scheme* `FeeDistributor.sol` is a supplementary contract that stores non-claimed and non-distributed Node Operator rewards on its balance. This contract stores the latest root of a rewards distribution Merkle tree. It accepts calls from `Accounting.sol` with reward claim requests and stores data about already claimed rewards by the Node Operator. It receives non-distributed rewards from the `CuratedModule.sol` each time the `StakingRouter` mints the new portion of the module's rewards. This contract transfers excess rewards allocated by `StakingRouter` due to the variable Node Operator reward share back to the Lido treasury. #### `FeeOracle.sol` *FeeOracle on the scheme* `FeeOracle.sol` is a utility contract responsible for the execution of the CSM Oracle report once the consensus is reached in the `HashConsensus.sol` contract, namely, transforming non-distributed rewards to non-claimed rewards stored on the `FeeDistributor.sol` and reporting the latest root of rewards distribution Merkle tree to the `FeeDistributor.sol`. Alongside rewards distribution, a contract manages strike data delivery to the `Strikes.sol`. A contract is inherited from the [`BaseOracle.sol`](https://github.com/lidofinance/core/blob/master/contracts/0.8.9/oracle/BaseOracle.sol) from Lido on Ethereum (LoE) core. #### `HashConsensus.sol` *HashConsensus on the scheme* `HashConsensus.sol` is a utility contract responsible for reaching a consensus between CSM Oracle members. Uses the standard code of the [`HashConsensus`](https://github.com/lidofinance/core/blob/master/contracts/0.8.9/oracle/HashConsensus.sol) contract from Lido on Ethereum (LoE) core. #### `ParametersRegistry.sol` *ParametersRegistry on the scheme* :::info Changed in CM v2 ::: `ParametersRegistry.sol` is a utility contract that stores Node-Operator-type-related parameters fetched by the other smart contracts related to CSM. A contract requires a mandatory default value for all parameters to ensure consistency. The custom value is returned if it is set for a particular parameter. Otherwise, the default value is returned. **Changes in CM v2:** - Custom role for non-critical parameters management added. #### `Strikes.sol` *StrikesRegistry on the scheme* `Strikes.sol` is a utility contract that stores information about strikes assigned to the CSM validators by CSM Performance Oracle. It has a permissionless method to prove that a particular validator should be ejected because the number of strikes is above the threshold for this validator. It calls `Ejector.sol` to perform a strikes threshold check and eject the validator. #### `CuratedGate.sol` *CuratedGates on the scheme* :::info New in CM v2 ::: `CuratedGate.sol` is a supplementary contract that enables Node Operator creation for the vetted addresses, which serves as an entry point to `CuratedModule.sol`. Alongside Node Operator creation, a contract can assign a custom Node Operator type (bondCurveId) in `Accounting.sol`. Deployed using `CuratedGateFactory.sol` to allow the addition of the new instances later without additional code security audits. The list of curated participants is individually upgradable for each instance of the `CuratedGate.sol`. #### `CSEjector.sol` *Ejector on the scheme* `Ejector.sol` is a supplementary contract responsible for interactions with EIP-7002-powered Lido Withdrawal credentials via `VEB`. Node Operators can voluntarily eject their validators. `Strikes.sol` uses `Ejector.sol` to trigger exits for validators that have surpassed the strike threshold. #### `ExitPenalties.sol` *ExitPenalties on the scheme* `ExitPenalties.sol` is a supplementary contract responsible for processing and storing information about exit-related penalties, namely: - Delayed exit penalty. - Bad performance ejection penalty. - TE fee paid in case of a forced and involuntary exit. #### `OperatorsData.sol` *OperatorsData on the scheme* :::info New in CM v2 ::: `OperatorsData.sol` is a supplementary contract that stores Node Operator names and descriptions. Both Node Operators and the CM v2 Committee multisig can edit the values. #### `EasyTrack` `EasyTrack` is a utility contract responsible for applying the reported EL stealing penalties. A part of the common [`EasyTrack`](https://github.com/lidofinance/easy-track) setup within Lido on Ethereum (LoE). #### `GateSeal` `GateSeal` is a utility contract responsible for the one-time pause of the `CuratedModule.sol`, `Accounting.sol`, `FeeOracle.sol`, `CuratedGate.sol`, `Ejector.sol`, and `Verifier.sol` contracts to prevent possible module exploitation through zero-day vulnerabilities. Uses the [standard code](https://github.com/lidofinance/gate-seals) of the `GateSeal` contract from Lido on Ethereum (LoE). The list of sealable contracts: - `CuratedModule.sol` - `Accounting.sol` - `FeeOracle.sol` - `Verifier.sol` - `CuratedGate.sol` (multiple instances) - `Ejector.sol` ### Off-chain tools #### `CSM/CM Bot` :::info Changed in CM v2 ::: `CSM/CM Bot` is a daemon application responsible for monitoring and reporting the withdrawal events associated with the CSM and CM validators. Also responsible for validator ejection invocation due to strikes. **Changes in CM v2:** - The bot now also serves CM v2. #### `EL stealing detector` `EL stealing detector` is a daemon application or EOA or Committee Multisig responsible for detecting and reporting the EL stealing facts by the CSM validators. Assigned to CM v2 Committee Multisig and assumed to be re-assigned to the automated bot at the acceptable level of MEV monitoring software maturity to avoid false-positive activations. #### `CM Oracle` `CM Oracle` (also known as CM Performance Oracle) is a module in the common Lido on Ethereum (LoE) Oracle set. It is operated by the existing Oracles set alongside [Accounting Oracle](https://docs.lido.fi/contracts/accounting-oracle), [Validator Exit Bus Oracle](https://docs.lido.fi/contracts/validators-exit-bus-oracle), and CSM Performance Oracle. It is responsible for calculating the CM v2 Node Operators' reward distribution and strike assignment based on their performance on the CL. ## Main flows ### Create Node Operator :::info Changed in CM v2 - Node Operator creation is now done via `CuratedGates`. ::: ![image](https://hackmd.io/_uploads/Bkmvph2dlx.png) Node Operator creation uses `CuratedGate.sol` instances attached to `CuratedModule.sol` via `CREATE_NODE_OPERATOR_ROLE`. Unlike CSM, CM v2 assumes that the creation of the Node Operator is done without deposit data upload. Deposit data can be uploaded later using the flow below. Different instances of `CuratedGate.sol` represent different Node Operator types. Node Operators can either join Curated Module v2 or upgrade their Node Operator type using the `CuratedGate.sol` instance, where their address is added to the participants list. Once used, the address can not be used again. ### Upload deposit data ![image](https://hackmd.io/_uploads/SkmN08v_ll.png) Node Operators can upload deposit data after creation. Before the upload, the amount of bond needed should be fetched from the `Accounting.sol`. Depending on the selected token, this amount should be: - Attached as a payment to the transaction (ETH). - Approved to be transferred by `Accounting.sol` (stETH, wstETH). - Included in permit data approving transfers by `Accounting.sol` (stETH, wstETH). ### Delete deposit data ![image](https://hackmd.io/_uploads/HkD9kPD_ge.png) If deposit data has not been deposited yet, the Node Operator can request its deletion from `CuratedModule.sol`. `CuratedModule.sol` validates that deposit data has not yet been deposited. If deletion is possible and `keyRemovalCharge` is set for the Node Operator type, `Accounting.sol` confiscates the `keyRemovalCharge` from the Node Operator's bond. :::info `keyRemovalCharge` is expected to be 0 in CM v2. ::: ### Top-up bond without deposit data upload ![image](https://hackmd.io/_uploads/S1NoJvw_gx.png) CM v2 Node Operators can top up the bond balance at any time to have an excess bond in advance or compensate for the penalties. Top-up is done via `Accounting.sol`. Once funds are transferred to `Accounting.sol`, `CuratedModule.sol` is informed about the bond amount change, and corresponding changes in the depositable keys are performed regarding the Node Operator to account for the change in the bond balance. ### Stake allocation (deposit order) :::info Changed in CM v2 - FIFO queues replaced with the [MinFirstAllocation](https://docs.lido.fi/contracts/staking-router#allocation-algorithm) strategy extended with custom weights. ::: CM v2 relies on the [MinFirstAllocation](https://docs.lido.fi/contracts/staking-router#allocation-algorithm) strategy, similar to the one used in StakingRouter and CM v1, to determine the order in which the keys should be provided for the deposits. The main change in the strategy is that custom weights are configurable per Node Operator type. #### Basic flow ![image](https://hackmd.io/_uploads/SykbfpxJ-l.png) Once uploaded, deposit data becomes available for allocation. To allocate stake to the CM v2 Node Operators, `StakingRouter` calls the `obtainDepositData(depositsCount)` method to get the next `depositsCount` depositable keys determined by the MinFirstAllocation strategy. #### Invalid keys ![image](https://hackmd.io/_uploads/B1UJlDvdge.png) CM v2 utilizes the optimistic vetting approach. Any validator key uploaded to CM v2 is considered valid unless the opposite is reported. [DSM](https://docs.lido.fi/contracts/deposit-security-module) is responsible for detecting and reporting invalid keys through `StakingRouter`. If invalid keys are detected, a call to `decreaseOperatorVettedKeys` is expected from `StakingRouter` to `CuratedModule.sol`. As a result, the `VettedKeys` pointer will be decreased, and any new uploaded keys will not be vetted until Node Operators remove at least one key. Upon removal, the `VettedKeys` will be restored to `TotalKeys`. If the invalid keys are still present, the process will be repeated. ### Rewards distribution ![image](https://hackmd.io/_uploads/By6H2KBqle.png) `StakingRouter` mint rewards for CSM Node Operators on each report of the [`AccountingOracle`](https://docs.lido.fi/contracts/accounting-oracle). `CuratedModule.sol` transfers minted rewards to the `FeeDistributor.sol`. Once the report slot is reached for the following CM v2 Oracle report, the rewards distribution tree is calculated by each Oracle member. After reaching the quorum, a new Merkle tree root is submitted to the `FeeDistributor.sol`, the corresponding portion of the rewards is transferred from the non-distributed to the non-claimed state, and excess rewards transferred by `StakingRouter` due to variable Node Operator reward share are returned to the Lido treasury. ### Rewards claim :::info Changed in CM v2 - Optional built-in fee split added. ::: ![image](https://hackmd.io/_uploads/SJMZJ5Scgl.png) Total rewards for the CM v2 Node Operators are comprised of bond rewards and staking fees. To claim the total rewards, the Node Operator needs to bring proof of the latest `cumulativeFeeShares` in the rewards tree. With that proof `Accounting.sol` pulls the Node Operator's portion of the staking fees from the `FeeDistributor.sol` and combines it with the Node Operator's bond. After that, all bond funds exceeding the bond required for the currently active keys are available for claim. When staking fees are pulled from the `FeeDistributor.sol`, `Accounting.sol` fetches information about `FeeSplits` set for the given Node Operator and transfers corresponding fee shares to the `FeeSplitRecipients`. This allows for a seamless integration with the infrastructure providers like Obol and SVV, which charge a certain percentage of the staking rewards as a provider fee. Since there might be several `FeeSplitRecipients` (up to 5), this feature can also be used for the opt-in donations to the Protocol Guild or other public good funding services. A special `pullFeeRewards` method allows the Node Operator to transfer staking rewards to the bond without transferring them to the reward address. If there are no new rewards to pull from the `FeeDistributor.sol` Node Operator can still claim excess bond using the same flow. :::info The abbility to set a custom address for `claimRewardsXXX` methods is added to streamline reward claims management from the Node Operator side. ::: ### General penalty with confirmation :::info Changed in CM v2 - The EL rewards stealing penalty mechanism is extended to a general penalty. - If the penalty is not compensated, CM v2 will set the `targetLimit` for the Node Operator to `0`, effectively phasing out the Node Operator. ::: ![image](https://hackmd.io/_uploads/rJuNBnvCxl.png) If the Node Operator violates CM v2 participation rules that are enforced off-chain (ex. violates the [Lido on Ethereum Block Proposer Rewards Policy](https://snapshot.box/#/s:lido-snapshot.eth/proposal/0x7ac2431dc0eddcad4a02ba220a19f451ab6b064a0eaef961ed386dc573722a7f)), this fact and the corresponding penalty amount are reported to the `CuratedModule.sol` by the off-chain actor. The reported amount of the bond funds (reported penalty + fixed fee) is locked by the `Accounting.sol`. Node Operator can compensate for the penalty and the fixed fee voluntarily. If the Node Operator does not compensate for the penalty, `EasyTrack` will be started to confirm the penalty application. Once enacted, a penalty is applied (locked funds are burned), and the `targetLimit` is set to `0` for the Node Operator, effectively phasing them out. ### Validator ejection due to strikes ![image](https://hackmd.io/_uploads/BkNw_J-_xx.png) If the validator has reached the strikes threshold (`actual strikes >= threshold`) `CSM/CM Bot` will initiate validator ejection using a permissionless method. `Strikes.sol` validates the proof and makes a call to `Ejector.sol` if the number of strikes >= threshold. `Ejector.sol` notify `TWG` about the required validator ejection. Corresponding penalties are recorded in `ExitPenalties.sol`. :::info It is planned not to use this functionality in CM v2 ::: ### Voluntary validator ejection ![image](https://hackmd.io/_uploads/B1YROy-uee.png) If Node Operators want to use EIP-7002 to exit their validators, they can do so via a dedicated method in the `Ejector.sol` contract. In this case, `Ejector.sol` will notify `TWG` about the required validator ejection. ### Withdrawal reporting :::info Changed in CM v2 - The stuck penalty and bad performance penalty amounts are modified relative to the actual withdrawal balance to account for the non-full `0x02` validators. - Two separate flows are introduced for slashed and non-slashed validators to calculate the slashing penalty correctly. - An additional penalty to account for the missed rewards during slashing is introduced. ::: #### Non-slashed validators ![image](https://hackmd.io/_uploads/rkgqL7quge.png) Once the CM v2 validator is withdrawn, the CSM/CM Bot will report it using a permissionless method. The report is submitted to the `Verifier.sol` to validate proof against `beaconBlockRoot`. If the proof is valid and the validator is not slashed, the report is bypassed to the `CuratedModule.sol`. `CuratedModule.sol` marks the validator as withdrawn. There is a separate flow for the slashed validators described below. Suppose the validator is reported as stuck (late to exit) or ejected due to strikes (bad performance). In that case, the recorded stuck and/or bad performance penalties are applied, and the recorded TE fee is confiscated. If the validator was not reported as stuck or ejected due to bad performance, but the TE fee is recorded, the TE fee is ignored. If the validator's balance is below 32 ETH, the difference between 32 ETH and the validator's balance is confiscated from the bond. #### Slashed validators ![image](https://hackmd.io/_uploads/rkLiat52lg.png) If the validator is slashed, a separate flow is used. First the fact of validator slashing should be proved using `Verifier.sol`. Once slashing is proved, slashing penalty and withdrawal balance are reported usiing `EasyTrack` motion. The rest of the flow is identical to the flow for non-slashed validators described above. ### Stuck validators ejection penalty ![image](https://hackmd.io/_uploads/SkE3ePDdee.png) ![image](https://hackmd.io/_uploads/BkvagDPuxg.png) With its updated functionality, `VEBO` can now trigger exits (via `TWG`) for the validators requested for exit in the `VEBO` report. However, the time when requested validators can be ejected is not limited. Hence, `CuratedModule.sol` should be notified by `StakingRouter` about the validator exits and the time between the request and ejection. If the time exceeds the threshold, the Node Operator should be penalized for not exiting their validators in time. If Triggerable Exit (TE) was used for the validator, depending on the exit type and if the validator was delayed to exit, the TE fee should be confiscated from the Node Operator's bond. Both stuck penalty and TE fee are recorded in `ExitPenalties.sol` and applied upon validator withdrawal described above. > The validator is considered "stuck" if the proof is delivered stating that it was not exited for more than `allowedExitDelay` seconds since the moment it was requested/available for exit. `allowedExitDelay` is a parameter that can be set per-Node-Operator-type. ### Node Operator addresses management :::info Changed in CM v2 - A dedicated role capable of changing both manager and reward adresses is added. ::: Node Operators in CM v2 can manage their addresses like CSM Node Operators do. The main difference is that in CM v2, designated role members can change both manager and reward addresses. It is assumed that these changes are made directly by the Lido DAO via on-chain voting or by a designated emergency committee acting only if the Node Operator's `managerAddress` address is compromised and no longer reachable. To streamline Node Operator operations, it is proposed to set extendedManagerPermissions = true for all Node Operators in CM v2. This will allow for flexibility in address management. ## Contracts specifications TBD ## Administrative actions Curated Module v2 contracts support a set of administrative actions, including: - Changing the configuration options. - Upgrading the system's code. Each action can only be performed by a designated admin (`DEFAULT_ADMIN_ROLE`) or other role members. Only members of `DEFAULT_ADMIN_ROLE` can manage role members for the roles in CSM contracts. ## Roles to actors mapping TBD ## Upgradability TBD ## Security considerations TBD

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully