Skip to content

Commit 0e7703e

Browse files
author
Yash Agrawal
committed
feat: add initial implementation of SBT contract
1 parent 833c200 commit 0e7703e

File tree

14 files changed

+229
-323
lines changed

14 files changed

+229
-323
lines changed

contracts/Admin.sol

Lines changed: 0 additions & 6 deletions
This file was deleted.

contracts/Example.sol

Lines changed: 0 additions & 16 deletions
This file was deleted.

contracts/SBTToken.sol

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
// SPDX-License-Identifier: MPL-2.0
2+
pragma solidity =0.8.9;
3+
4+
import {IERC721EnumerableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721EnumerableUpgradeable.sol";
5+
import {IERC165Upgradeable} from "@openzeppelin/contracts-upgradeable/utils/introspection/IERC165Upgradeable.sol";
6+
import {ERC721Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol";
7+
import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";
8+
import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
9+
import {Counters} from "@openzeppelin/contracts/utils/Counters.sol";
10+
11+
import {ISBTToken} from "./interfaces/ISBTToken.sol";
12+
13+
contract SBTToken is
14+
ISBTToken,
15+
IERC721EnumerableUpgradeable,
16+
ERC721Upgradeable
17+
{
18+
Counters.Counter private tokenIdCounter;
19+
20+
mapping(address => EnumerableSet.UintSet) private tokenIdsMapOfOwner;
21+
mapping(uint256 => string) private tokenUriImage;
22+
address private proxyAdmin;
23+
/// @dev EOA with minting rights.
24+
address private minter;
25+
26+
using Counters for Counters.Counter;
27+
using EnumerableSet for EnumerableSet.UintSet;
28+
29+
modifier onlyMinter() {
30+
require(minter == _msgSender(), "illegal access");
31+
_;
32+
}
33+
34+
function initialize(address _minter) external initializer {
35+
__ERC721_init("Dev Protocol sTokens V1", "DEV-STOKENS-V1");
36+
minter = _minter;
37+
}
38+
39+
/**
40+
* @dev See {IERC165-supportsInterface}.
41+
*/
42+
function supportsInterface(
43+
bytes4 interfaceId
44+
)
45+
public
46+
view
47+
virtual
48+
override(IERC165Upgradeable, ERC721Upgradeable)
49+
returns (bool)
50+
{
51+
return
52+
interfaceId == type(IERC721EnumerableUpgradeable).interfaceId ||
53+
super.supportsInterface(interfaceId);
54+
}
55+
56+
/**
57+
* @dev See {IERC721Enumerable-totalSupply}.
58+
*/
59+
function totalSupply() public view virtual override(ISBTToken, IERC721EnumerableUpgradeable) returns (uint256) {
60+
return tokenIdCounter.current();
61+
}
62+
63+
/**
64+
* @dev See {IERC721Enumerable-tokenOfOwnerByIndex}.
65+
*/
66+
function tokenOfOwnerByIndex(
67+
address _owner,
68+
uint256 index
69+
) public view virtual override(ISBTToken, IERC721EnumerableUpgradeable) returns (uint256) {
70+
// solhint-disable-next-line reason-string
71+
require(
72+
index < tokenIdsMapOfOwner[_owner].length(),
73+
"ERC721Enumerable: owner index out of bounds"
74+
);
75+
return tokenIdsMapOfOwner[_owner].at(index);
76+
}
77+
78+
/**
79+
* @dev See {IERC721Enumerable-tokenByIndex}.
80+
*/
81+
function tokenByIndex(
82+
uint256 index
83+
) public view virtual override(ISBTToken, IERC721EnumerableUpgradeable) returns (uint256) {
84+
// solhint-disable-next-line reason-string
85+
require(
86+
index < tokenIdCounter.current(),
87+
"ERC721Enumerable: global index out of bounds"
88+
);
89+
return index + 1;
90+
}
91+
92+
function owner() external view returns (address) {
93+
return ProxyAdmin(proxyAdmin).owner();
94+
}
95+
96+
function setProxyAdmin(address _proxyAdmin) external {
97+
require(proxyAdmin == address(0), "already set");
98+
proxyAdmin = _proxyAdmin;
99+
}
100+
101+
function tokenURI(
102+
uint256 _tokenId
103+
) public view override returns (string memory) {
104+
uint256 curretnTokenId = tokenIdCounter.current();
105+
require(_tokenId <= curretnTokenId, "not found");
106+
return _tokenURI(_tokenId);
107+
}
108+
109+
function currentIndex() external view override returns (uint256) {
110+
return tokenIdCounter.current();
111+
}
112+
113+
function mint(
114+
address _owner
115+
) external override onlyMinter returns (uint256 tokenId_) {
116+
tokenIdCounter.increment();
117+
uint256 currentId = tokenIdCounter.current();
118+
_mint(_owner, currentId);
119+
emit Minted(currentId, _owner);
120+
return currentId;
121+
}
122+
123+
function setTokenURIImage(
124+
uint256 _tokenId,
125+
string memory _data
126+
) external override onlyMinter {
127+
tokenUriImage[_tokenId] = _data;
128+
}
129+
130+
function tokensOfOwner(
131+
address _owner
132+
) external view override returns (uint256[] memory) {
133+
return tokenIdsMapOfOwner[_owner].values();
134+
}
135+
136+
function _tokenURI(uint256 _tokenId) private view returns (string memory) {
137+
return tokenUriImage[_tokenId];
138+
}
139+
140+
function _beforeTokenTransfer(
141+
address from,
142+
address to,
143+
uint256 tokenId,
144+
uint256 batchSize
145+
) internal virtual override {
146+
super._beforeTokenTransfer(from, to, tokenId, batchSize);
147+
148+
if (from == address(0)) {
149+
// mint
150+
tokenIdsMapOfOwner[to].add(tokenId);
151+
} else if (to == address(0)) {
152+
// burn
153+
revert("SBT is not burned");
154+
} else if (to != from) {
155+
revert("SBT is non transferrable");
156+
} else {
157+
revert("Illegal operation");
158+
}
159+
}
160+
}

contracts/UpgradeableProxy.sol

Lines changed: 0 additions & 12 deletions
This file was deleted.

contracts/interfaces/ISBTToken.sol

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// SPDX-License-Identifier: MPL-2.0
2+
pragma solidity ^0.8.9;
3+
4+
interface ISBTToken {
5+
/*
6+
* @dev The event fired when a token is minted.
7+
* @param tokenId The ID of the created new staking position
8+
* @param owner The address of the owner of the new staking position
9+
*/
10+
event Minted(uint256 tokenId, address owner);
11+
12+
/*
13+
* @dev Creates the new staking position for the caller.
14+
* Mint must be called by the minter address.
15+
* @param _owner The address of the owner of the new staking position
16+
*/
17+
function mint(address _owner) external returns (uint256);
18+
19+
/*
20+
* @dev Sets the token URI image for a token.
21+
* @notice must be called by the minter address.
22+
* @param _tokenId The token for which we are setting the image uri.
23+
* @param _data The data that is used as uri.
24+
*/
25+
function setTokenURIImage(
26+
uint256 _tokenId,
27+
string memory _data
28+
) external;
29+
30+
/*
31+
* @dev get token ids by owner
32+
* @param _owner owner address
33+
* @return uint256[] token id list
34+
*/
35+
function tokensOfOwner(
36+
address _owner
37+
) external view returns (uint256[] memory);
38+
39+
/*
40+
* @dev get current token id
41+
* @return uint256 current token id
42+
*/
43+
function currentIndex() external view returns (uint256);
44+
45+
/// @notice Count NFTs tracked by this contract
46+
/// @return A count of valid NFTs tracked by this contract, where each one of
47+
/// them has an assigned and queryable owner not equal to the zero address
48+
function totalSupply() external view returns (uint256);
49+
50+
/// @notice Enumerate valid NFTs
51+
/// @dev Throws if `_index` >= `totalSupply()`.
52+
/// @param _index A counter less than `totalSupply()`
53+
/// @return The token identifier for the `_index`th NFT,
54+
/// (sort order not specified)
55+
function tokenByIndex(uint256 _index) external view returns (uint256);
56+
57+
/// @notice Enumerate NFTs assigned to an owner
58+
/// @dev Throws if `_index` >= `balanceOf(_owner)` or if
59+
/// `_owner` is the zero address, representing invalid NFTs.
60+
/// @param _owner An address where we are interested in NFTs owned by them
61+
/// @param _index A counter less than `balanceOf(_owner)`
62+
/// @return The token identifier for the `_index`th NFT assigned to `_owner`,
63+
/// (sort order not specified)
64+
function tokenOfOwnerByIndex(
65+
address _owner,
66+
uint256 _index
67+
) external view returns (uint256);
68+
}

hardhat.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import '@typechain/hardhat'
22
import '@nomiclabs/hardhat-ethers'
33
import '@nomiclabs/hardhat-waffle'
44
import '@nomiclabs/hardhat-etherscan'
5-
import { HardhatUserConfig } from 'hardhat/config'
5+
import { type HardhatUserConfig } from 'hardhat/config'
66
import * as dotenv from 'dotenv'
77

88
dotenv.config()

scripts/.gitkeep

Whitespace-only changes.

scripts/deploy-example.ts

Lines changed: 0 additions & 26 deletions
This file was deleted.

scripts/utils.ts

Lines changed: 0 additions & 31 deletions
This file was deleted.

test/.gitkeep

Whitespace-only changes.

0 commit comments

Comments
 (0)