Skip to content

Instantly share code, notes, and snippets.

@shobhitic
Last active January 5, 2023 20:08
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save shobhitic/bf54a3d5d99bf68b1c2a12befef1da30 to your computer and use it in GitHub Desktop.
Save shobhitic/bf54a3d5d99bf68b1c2a12befef1da30 to your computer and use it in GitHub Desktop.
Soulbound tokens or Account Bound Tokens - https://youtu.be/_6Zt70PZbAs
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./EIP4973.sol";
contract ABT is ERC4973 {
address public owner;
uint256 public count = 0;
constructor () ERC4973("MyToken", "MTK") {
owner = msg.sender;
}
function burn(uint256 _tokenId) external override {
require(ownerOf(_tokenId) == msg.sender || msg.sender == owner, "You can't revoke this token");
_burn(_tokenId);
}
function issue(address _issuee, string calldata _uri) external onlyOwner {
_mint(_issuee, count, _uri);
count += 1;
}
modifier onlyOwner() {
require(msg.sender == owner, "Not the owner");
_;
}
}
// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.6;
import "@openzeppelin/contracts/utils/introspection/ERC165.sol";
import {IERC721Metadata} from "./IERC721Metadata.sol";
import {IERC4973} from "./IERC4973.sol";
abstract contract ERC4973 is ERC165, IERC721Metadata, IERC4973 {
string private _name;
string private _symbol;
mapping(uint256 => address) private _owners;
mapping(uint256 => string) private _tokenURIs;
constructor(
string memory name_,
string memory symbol_
) {
_name = name_;
_symbol = symbol_;
}
function supportsInterface(bytes4 interfaceId) public view override returns (bool) {
return
interfaceId == type(IERC721Metadata).interfaceId ||
interfaceId == type(IERC4973).interfaceId ||
super.supportsInterface(interfaceId);
}
function name() public view virtual override returns (string memory) {
return _name;
}
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
require(_exists(tokenId), "tokenURI: token doesn't exist");
return _tokenURIs[tokenId];
}
function _exists(uint256 tokenId) internal view virtual returns (bool) {
return _owners[tokenId] != address(0);
}
function ownerOf(uint256 tokenId) public view virtual returns (address) {
address owner = _owners[tokenId];
require(owner != address(0), "ownerOf: token doesn't exist");
return owner;
}
function _mint(
address to,
uint256 tokenId,
string calldata uri
) internal virtual returns (uint256) {
require(!_exists(tokenId), "mint: tokenID exists");
_owners[tokenId] = to;
_tokenURIs[tokenId] = uri;
emit Attest(to, tokenId);
return tokenId;
}
function _burn(uint256 tokenId) internal virtual {
address owner = ownerOf(tokenId);
delete _owners[tokenId];
delete _tokenURIs[tokenId];
emit Revoke(owner, tokenId);
}
}
// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.6;
/// @title Account-bound tokens
/// @dev See https://eips.ethereum.org/EIPS/eip-4973
/// Note: the ERC-165 identifier for this interface is 0x6352211e.
interface IERC4973 /* is ERC165, ERC721Metadata */ {
/// @dev This emits when a new token is created and bound to an account by
/// any mechanism.
/// Note: For a reliable `_from` parameter, retrieve the transaction's
/// authenticated `from` field.
event Attest(address indexed _to, uint256 indexed _tokenId);
/// @dev This emits when an existing ABT is revoked from an account and
/// destroyed by any mechanism.
/// Note: For a reliable `_from` parameter, retrieve the transaction's
/// authenticated `from` field.
event Revoke(address indexed _to, uint256 indexed _tokenId);
/// @notice Find the address bound to an ERC4973 account-bound token
/// @dev ABTs assigned to zero address are considered invalid, and queries
/// about them do throw.
/// @param _tokenId The identifier for an ABT
/// @return The address of the owner bound to the ABT
function ownerOf(uint256 _tokenId) external view returns (address);
/// @notice Destroys `tokenId`. At any time, an ABT receiver must be able to
/// disassociate themselves from an ABT publicly through calling this
/// function.
/// @dev Must emit a `event Revoke` with the `address _to` field pointing to
/// the zero address.
/// @param _tokenId The identifier for an ABT
function burn(uint256 _tokenId) external;
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol)
pragma solidity ^0.8.0;
/**
* @title ERC-721 Non-Fungible Token Standard, optional metadata extension
* @dev See https://eips.ethereum.org/EIPS/eip-721
*/
interface IERC721Metadata {
/**
* @dev Returns the token collection name.
*/
function name() external view returns (string memory);
/**
* @dev Returns the token collection symbol.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
*/
function tokenURI(uint256 tokenId) external view returns (string memory);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment