boilerrat
    • Create new note
    • Create a note from template
      • 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
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • 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
    • Note Insights New
    • Engagement control
    • Make a copy
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Make a copy 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
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • 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
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    # Hats Research II ## Linkable Trees Branch ### SampleMultiHatter.sol ``` pragma solidity >=0.8.13; import "../HatsEligibility/IHatsEligibility.sol"; import "../Interfaces/IHats.sol"; import "utils/Auth.sol"; /// @notice designed to serve as the admin for multiple hats abstract contract SampleMultiHatter is Auth { IHats public HATS; constructor(address _hatsContract) { HATS = IHats(_hatsContract); } // DAO governance mint function (auth) function mint(uint256 _hatId, address _wearer) public virtual requiresAuth { _mint(_hatId, _wearer); } function _mint(uint256 _hatId, address _wearer) internal virtual { require(HATS.isInGoodStanding(_wearer, _hatId), "not eligible"); HATS.mintHat(_hatId, _wearer); } function createAndMint( uint256 _admin, string memory _details, uint32 _maxSupply, address _eligibility, address _toggle, address _wearer, bool _mutable, string memory _imageURI ) public virtual requiresAuth { uint256 id = HATS.createHat( _admin, _details, _maxSupply, _eligibility, _toggle, _mutable, _imageURI ); _mint(id, _wearer); } // DAO governance transfer function (auth) function transfer( uint256 _hatId, address _wearer, address _newWearer ) public virtual requiresAuth { HATS.transferHat(_hatId, _wearer, _newWearer); } } ``` --- This is a Solidity contract for a "MultiHatter", which appears to be an abstract contract (a contract that cannot be directly instantiated) that serves as an administrator for multiple "hats". The contract uses the "Auth" contract (presumably for authentication purposes) and imports three other contracts: "IHatsEligibility", "IHats", and "utils/Auth.sol". The contract has a single public variable, "HATS", which is an instance of the "IHats" contract. The contract has a constructor that takes an address as an argument and assigns this address to the "HATS" variable as an instance of the "IHats" contract. The contract has two functions for minting new hats: "mint" and "createAndMint". The "mint" function takes an unsigned integer "_hatId" and an address "_wearer" as arguments and calls an internal function "_mint" with these arguments. The "_mint" function checks if the wearer is eligible to receive the hat (using the "isInGoodStanding" function from the "IHatsEligibility" contract) and, if so, calls the "mintHat" function from the "IHats" contract to mint the hat for the wearer. The "createAndMint" function allows the creation of a new hat and minting it to a wearer in a single transaction. It takes several arguments: an unsigned integer "_admin" (presumably the address of the hat's administrator), a string "_details" (presumably details about the hat), an unsigned integer "_maxSupply" (the maximum number of hats that can be minted), an address "_eligibility" (the contract that determines hat eligibility), an address "_toggle" (the contract that can enable or disable the hat), an address "_wearer" (the intended wearer of the new hat), a boolean "_mutable" (presumably indicating whether the hat is mutable or not), and a string "_imageURI" (presumably the URI of an image for the hat). This function first calls the "createHat" function from the "IHats" contract with these arguments to create the new hat, and then calls the "_mint" function to mint the new hat to the wearer. The contract also has a function for transferring a hat from one wearer to another: "transfer". This function takes an unsigned integer "_hatId" (the ID of the hat to be transferred), an address "_wearer" (the current wearer of the hat), and an address "_newWearer" (the intended new wearer of the hat) as arguments and calls the "transferHat" function from the "IHats" contract with these arguments. I hope this helps! Let me know if you have any questions. --- ### iHatsEligibity.sol (Interface) ``` pragma solidity >=0.8.13; interface IHatsEligibility { /// @notice Returns the status of a wearer for a given hat /// @dev If standing is false, eligibility MUST also be false /// @param _wearer The address of the current or prospective Hat wearer /// @param _hatId The id of the hat in question /// @return eligible Whether the _wearer is eligible to wear the hat /// @return standing Whether the _wearer is in goog standing function getWearerStatus(address _wearer, uint256 _hatId) external view returns (bool eligible, bool standing); } ``` This is the interface for a Solidity contract called "IHatsEligibility". An interface in Solidity is a contract that defines a set of functions that other contracts can implement. In this case, the "IHatsEligibility" interface defines a single function, "getWearerStatus", which other contracts can implement in order to provide a way to check the eligibility and standing of a wearer for a given hat. The "getWearerStatus" function takes an address "_wearer" and an unsigned integer "_hatId" as arguments and returns a tuple containing two boolean values: "eligible" and "standing". The "eligible" value indicates whether the wearer is eligible to wear the hat, and the "standing" value indicates whether the wearer is in good standing. The function is marked as "view" and "external", which means that it is a read-only function that can be called from other contracts or from outside the blockchain. I hope this helps! Let me know if you have any questions. --- ### OwnableHatsEligibility.sol ``` pragma solidity >=0.8.13; import "./IHatsEligibility.sol"; import "../Interfaces/IHats.sol"; import "utils/Auth.sol"; abstract contract OwnableHatsEligibility is IHats, IHatsEligibility, Auth { event HatStandingSet( address _wearer, uint256 _hatId, bool _eligible, bool _standing ); IHats public HATS; mapping(address => mapping(uint256 => bool)) public standings; constructor(address _hatsContract) { HATS = IHats(_hatsContract); } function getWearerStatus(address _wearer, uint64 _hatId) public view returns (bool) { return standings[_wearer][_hatId]; } function setWearerStatus( address _wearer, uint256 _hatId, bool _eligible, bool _standing ) public virtual requiresAuth { standings[_wearer][_hatId] = _standing; _updateHatWearerStatus(_wearer, _hatId, _eligible, _standing); emit HatStandingSet(_wearer, _hatId, _eligible, _standing); } function _updateHatWearerStatus( address _wearer, uint256 _hatId, bool _eligible, bool _standing ) internal virtual { HATS.setHatWearerStatus(_hatId, _wearer, _eligible, _standing); } } ``` This is a Solidity contract for an "OwnableHatsEligibility" contract, which appears to be an abstract contract (a contract that cannot be directly instantiated) that provides a way to check and set the eligibility and standing of a wearer for a given hat. The contract uses three other contracts: "IHatsEligibility", "IHats", and "utils/Auth.sol". The contract has a single public variable, "HATS", which is an instance of the "IHats" contract. The contract has a constructor that takes an address as an argument and assigns this address to the "HATS" variable as an instance of the "IHats" contract. The contract has a public event called "HatStandingSet", which is triggered when the standing of a hat wearer is set. The event has four arguments: an address "_wearer" (the address of the wearer), an unsigned integer "_hatId" (the ID of the hat), a boolean "_eligible" (indicating whether the wearer is eligible to wear the hat), and a boolean "_standing" (indicating whether the wearer is in good standing). The contract has a public mapping called "standings", which maps addresses to mappings of hat IDs to boolean values. This mapping is used to store the standing of each hat wearer. The contract has two functions for checking and setting the standing of hat wearers: "getWearerStatus" and "setWearerStatus". The "getWearerStatus" function takes an address "_wearer" and an unsigned integer "_hatId" as arguments and returns the standing of the wearer for the given hat as a boolean value. The "setWearerStatus" function takes four arguments: an address "_wearer" (the address of the wearer), an unsigned integer "_hatId" (the ID of the hat), a boolean "_eligible" (indicating whether the wearer is eligible to wear the hat), and a boolean "_standing" (indicating whether the wearer is in good standing). This function updates the standing of the wearer for the given hat in the "standings" mapping and calls an internal function "_updateHatWearerStatus" with these arguments. The "_updateHatWearerStatus" function is an abstract function that other contracts can implement to specify how to update the standing of a hat wearer. --- ### iHat.sol interface ``` pragma solidity >=0.8.13; import "./IHatsIdUtilities.sol"; import "./HatsErrors.sol"; import "./HatsEvents.sol"; interface IHats is IHatsIdUtilities, HatsErrors, HatsEvents { function mintTopHat( address _target, string memory _details, string memory _imageURI ) external returns (uint256 topHatId); // function createTopHatAndHat( // string memory _details, // uint32 _maxSupply, // address _eligibility, // address _toggle, // bool _mutable, // string memory _topHatImageURI, // string memory _firstHatImageURI // ) external returns (uint256 topHatId, uint256 firstHatId); function createHat( uint256 _admin, string memory _details, uint32 _maxSupply, address _eligibility, address _toggle, bool _mutable, string memory _imageURI ) external returns (uint256 newHatId); function batchCreateHats( uint256[] memory _admins, string[] memory _details, uint32[] memory _maxSupplies, address[] memory _eligibilityModules, address[] memory _toggleModules, bool[] memory _mutables, string[] memory _imageURIs ) external returns (bool); function getNextId(uint256 _admin) external view returns (uint256); function mintHat(uint256 _hatId, address _wearer) external returns (bool); function batchMintHats(uint256[] memory _hatIds, address[] memory _wearers) external returns (bool); function setHatStatus(uint256 _hatId, bool _newStatus) external returns (bool); function checkHatStatus(uint256 _hatId) external returns (bool); function setHatWearerStatus( uint256 _hatId, address _wearer, bool _eligible, bool _standing ) external returns (bool); function checkHatWearerStatus(uint256 _hatId, address _wearer) external returns (bool); function renounceHat(uint256 _hatId) external; function transferHat( uint256 _hatId, address _from, address _to ) external; /*////////////////////////////////////////////////////////////// HATS ADMIN FUNCTIONS //////////////////////////////////////////////////////////////*/ function makeHatImmutable(uint256 _hatId) external; function changeHatDetails(uint256 _hatId, string memory _newDetails) external; function changeHatEligibility(uint256 _hatId, address _newEligibility) external; function changeHatToggle(uint256 _hatId, address _newToggle) external; function changeHatImageURI(uint256 _hatId, string memory _newImageURI) external; function changeHatMaxSupply(uint256 _hatId, uint32 _newMaxSupply) external; /*////////////////////////////////////////////////////////////// VIEW FUNCTIONS //////////////////////////////////////////////////////////////*/ function viewHat(uint256 _hatId) external view returns ( string memory details, uint32 maxSupply, uint32 supply, address eligibility, address toggle, string memory imageURI, uint16 lastHatId, bool mutable_, bool active ); function isWearerOfHat(address _user, uint256 _hatId) external view returns (bool); function isAdminOfHat(address _user, uint256 _hatId) external view returns (bool); // function isActive(uint256 _hatId) external view returns (bool); function isInGoodStanding(address _wearer, uint256 _hatId) external view returns (bool); function isEligible(address _wearer, uint256 _hatId) external view returns (bool); function getImageURIForHat(uint256 _hatId) external view returns (string memory); function balanceOf(address wearer, uint256 hatId) external view returns (uint256 balance); function uri(uint256 id) external view returns (string memory); } ``` This is the interface for a Solidity contract called "IHats". An interface in Solidity is a contract that defines a set of functions that other contracts can implement. In this case, the "IHats" interface defines a number of functions that other contracts can implement in order to provide a way to mint, create, and manage "hats" on the blockchain. The contract imports three other contracts: "IHatsIdUtilities", "HatsErrors", and "HatsEvents". It appears that the "IHatsIdUtilities" contract provides utility functions related to hat IDs, the "HatsErrors" contract defines error messages, and the "HatsEvents" contract defines events that can be emitted by the "IHats" contract. The "IHats" contract defines several functions for minting, creating, and managing hats: "mintTopHat" allows the minting of a special "top hat" with a given set of details and an image URI. "createHat" allows the creation of a new hat with a given set of details, including the hat's administrator, maximum supply, eligibility, toggle, mutability, and image URI. "batchCreateHats" allows the creation of multiple hats in a single transaction. "mintHat" allows the minting of an existing hat to a given wearer. "batchMintHats" allows the minting of multiple hats in a single transaction. "setHatStatus" allows the setting of the active status of a hat. "checkHatStatus" allows the checking of the active status of a hat. "setHatWearerStatus" allows the setting of the eligibility and standing of a hat wearer. "checkHatWearerStatus" allows the checking of the eligibility and standing of a hat wearer. "renounceHat" allows the renouncing of ownership of a hat. "transferHat" allows the transfer of ownership of a hat from one wearer to another. The "IHats" contract also defines several functions that can be called by the administrator of a hat to modify the hat's details and behavior: "makeHatImmutable" allows the administrator to make a hat immutable (i.e., unable to be modified). "changeHatDetails" allows the administrator to change the details of a hat. "changeHatEligibility" allows the administrator to change the contract that determines the eligibility of hat wearers. "changeHatToggle" allows the administrator to change the contract that can enable or disable the hat. "changeHatImageURI" allows the administrator to change the image URI of a hat. "changeHatMaxSupply" allows the administrator to change the maximum number of hats that can be minted. The "IHats" contract also defines several "view" functions, which are read-only functions that do not modify the state of the contract: "viewHat" allows the viewing of the details of a hat, including its details, maximum supply, current supply, eligibility, toggle, image URI, last hat ID, mutability, and active status. "isWearerOfHat" allows the checking of whether a given address is the current wearer of a hat. "isAdminOfHat" allows the checking of whether a given address is the administrator of a hat. "isInGoodStanding" allows the checking of whether a given address is in good standing as the wearer of a hat. "isEligible" allows the checking of whether a given address is eligible to wear a hat. "getImageURIForHat" allows the retrieval of the image URI for a given hat. "getWearers" allows the retrieval of the current wearers of a given hat. --- ### SampleHatter.sol ``` pragma solidity >=0.8.13; import "../HatsEligibility/IHatsEligibility.sol"; import "../Interfaces/IHats.sol"; import "utils/Auth.sol"; /// @notice designed to serve as the admin for multiple hats abstract contract SampleMultiHatter is Auth { IHats public HATS; constructor(address _hatsContract) { HATS = IHats(_hatsContract); } // DAO governance mint function (auth) function mint(uint256 _hatId, address _wearer) public virtual requiresAuth { _mint(_hatId, _wearer); } function _mint(uint256 _hatId, address _wearer) internal virtual { require(HATS.isInGoodStanding(_wearer, _hatId), "not eligible"); HATS.mintHat(_hatId, _wearer); } function createAndMint( uint256 _admin, string memory _details, uint32 _maxSupply, address _eligibility, address _toggle, address _wearer, bool _mutable, string memory _imageURI ) public virtual requiresAuth { uint256 id = HATS.createHat( _admin, _details, _maxSupply, _eligibility, _toggle, _mutable, _imageURI ); _mint(id, _wearer); } // DAO governance transfer function (auth) function transfer( uint256 _hatId, address _wearer, address _newWearer ) public virtual requiresAuth { HATS.transferHat(_hatId, _wearer, _newWearer); } } ``` ### Auth.sol ``` // SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; /// @notice Provides a flexible and updatable auth pattern which is completely separate from application logic. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/auth/Auth.sol) /// @author Modified from Dappsys (https://github.com/dapphub/ds-auth/blob/master/src/auth.sol) abstract contract Auth { event OwnerUpdated(address indexed user, address indexed newOwner); event AuthorityUpdated( address indexed user, Authority indexed newAuthority ); address public owner; Authority public authority; constructor(address _owner, Authority _authority) { owner = _owner; authority = _authority; emit OwnerUpdated(msg.sender, _owner); emit AuthorityUpdated(msg.sender, _authority); } modifier requiresAuth() virtual { require(isAuthorized(msg.sender, msg.sig), "UNAUTHORIZED"); _; } function isAuthorized(address user, bytes4 functionSig) internal view virtual returns (bool) { Authority auth = authority; // Memoizing authority saves us a warm SLOAD, around 100 gas. // Checking if the caller is the owner only after calling the authority saves gas in most cases, but be // aware that this makes protected functions uncallable even to the owner if the authority is out of order. return (address(auth) != address(0) && auth.canCall(user, address(this), functionSig)) || user == owner; } function setAuthority(Authority newAuthority) public virtual { // We check if the caller is the owner first because we want to ensure they can // always swap out the authority even if it's reverting or using up a lot of gas. require( msg.sender == owner || authority.canCall(msg.sender, address(this), msg.sig) ); authority = newAuthority; emit AuthorityUpdated(msg.sender, newAuthority); } function setOwner(address newOwner) public virtual requiresAuth { owner = newOwner; emit OwnerUpdated(msg.sender, newOwner); } } /// @notice A generic interface for a contract which provides authorization data to an Auth instance. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/auth/Auth.sol) /// @author Modified from Dappsys (https://github.com/dapphub/ds-auth/blob/master/src/auth.sol) interface Authority { function canCall( address user, address target, bytes4 functionSig ) external view returns (bool); } ``` The Auth contract is an abstract contract that provides a flexible and updatable authorization pattern that can be used in other contracts. It has an owner and an authority (which is an instance of a contract that implements the Authority interface). It also has two events: OwnerUpdated and AuthorityUpdated. The Auth contract has a constructor that takes an _owner and an _authority as arguments and sets the owner and authority variables to these values. It also emits the OwnerUpdated and AuthorityUpdated events. The Auth contract has a requiresAuth modifier that checks whether the caller is authorized to call the protected function by calling the isAuthorized function and passing it the caller's address and the function signature of the protected function. If the caller is not authorized, the function will revert with the message "UNAUTHORIZED". The isAuthorized function is an internal function that takes an address user and a bytes4 functionSig as arguments and returns a bool. It checks if the user is authorized to call the function by first checking if the authority contract is not the zero address (i.e., it has been set) and if the authority contract's canCall function returns true when passed the user, the Auth contract's address, and the functionSig. If either of these conditions is not met, it checks if the user is the owner of the contract. If either of these conditions is met, the function returns true, otherwise it returns false. The setAuthority function is a public function that takes an instance of a contract that implements the Authority interface as an argument and sets the authority variable to this value. It also emits the AuthorityUpdated event. It has a require statement that checks if the caller is the owner or if the current authority contract's canCall function returns true when passed the caller's address, the Auth contract's address, and the caller's function signature. This is to ensure that the authority can be changed only by the owner

    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