├── pytest.ini
├── requirements.txt
├── src
└── codefordao
│ ├── libraries
│ ├── Structs.cairo
│ ├── merkle.cairo
│ └── utils.cairo
│ ├── modules
│ └── Payroll.cairo
│ └── core
│ ├── Governor.cairo
│ ├── Treasury.cairo
│ ├── Module.cairo
│ ├── Share.cairo
│ └── Membership.cairo
├── pyproject.toml
├── setup.py
├── setup.cfg
├── LICENSE
├── tests
├── test_ERC20.py
├── test_ERC721.py
└── utils.py
├── .gitignore
└── README.md
/pytest.ini:
--------------------------------------------------------------------------------
1 | [pytest]
2 | asyncio_mode = auto
3 | log_cli = true
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | wheel
2 | cairo-lang
3 | cairo-nile
4 | pytest-cairo
5 | tox
6 | immutablex-starknet
7 | git+https://github.com/OpenZeppelin/cairo-contracts.git
--------------------------------------------------------------------------------
/src/codefordao/libraries/Structs.cairo:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 |
3 | %lang starknet
4 |
5 | struct ContractAddressType:
6 | member membership: felt
7 | member governor: felt
8 | member treasury: felt
9 | member share_token: felt
10 | member share_governor: felt
11 | end
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [build-system]
2 | # AVOID CHANGING REQUIRES: IT WILL BE UPDATED BY PYSCAFFOLD!
3 | requires = ["setuptools>=46.1.0", "setuptools_scm[toml]>=5", "wheel"]
4 | build-backend = "setuptools.build_meta"
5 |
6 | [tool.setuptools_scm]
7 | # See configuration details in https://github.com/pypa/setuptools_scm
8 | version_scheme = "no-guess-dev"
--------------------------------------------------------------------------------
/src/codefordao/modules/Payroll.cairo:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 |
3 | %lang starknet
4 |
5 | from starkware.cairo.common.cairo_builtins import HashBuiltin
6 |
7 | #
8 | # Initializer
9 | #
10 | @constructor
11 | func constructor{
12 | syscall_ptr: felt*,
13 | pedersen_ptr: HashBuiltin*,
14 | range_check_ptr
15 | }(
16 | ):
17 | return ()
18 | end
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | from setuptools import setup
2 |
3 | if __name__ == "__main__":
4 | try:
5 | setup(use_scm_version={"version_scheme": "no-guess-dev"})
6 | except: # noqa
7 | print(
8 | "\n\nAn error occurred while building the project, "
9 | "please ensure you have the most updated version of setuptools, "
10 | "setuptools_scm and wheel with:\n"
11 | " pip install -U setuptools setuptools_scm wheel\n\n"
12 | )
13 | raise
--------------------------------------------------------------------------------
/setup.cfg:
--------------------------------------------------------------------------------
1 | [metadata]
2 | name = codefordao-cairo-contracts
3 | version = attr: codefordao-cairo-contracts.__version__
4 | description = CodeforDAO contracts in Cairo lang
5 | author = GUO Yu
6 | author_email = contact@codefordao.org
7 | license = MIT
8 | long_description = file: README.md
9 | long_description_content_type = text/markdown; charset=UTF-8
10 | url = https://github.com/CodeforDAO/cairo-contracts
11 | platforms = any
12 | classifiers =
13 | Operating System :: OS Independent
14 |
15 | [options]
16 | zip_safe = False
17 | packages = find_namespace:
18 | include_package_data = True
19 | package_dir =
20 | =src
21 |
22 | install_requires =
23 | importlib-metadata>=4.0
24 |
25 | [options.packages.find]
26 | where = src
27 | exclude =
28 | tests
29 |
30 | [options.package_data]
31 | codefordao = "*.cairo"
32 |
33 | [options.extras_require]
34 | testing =
35 | setuptools
36 | tox
37 | pytest
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 CodeforDAO
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/tests/test_ERC20.py:
--------------------------------------------------------------------------------
1 | """erc20.cairo test file."""
2 | import pytest
3 | from starkware.starknet.testing.starknet import Starknet
4 | from utils import (
5 | cached_contract, get_contract_def, to_uint, str_to_felt
6 | )
7 |
8 | # testing vars
9 | OWNER = 42
10 | NAME = str_to_felt("MyToken")
11 |
12 | @pytest.fixture
13 | def contract_defs():
14 | erc20_def = get_contract_def('ERC20.cairo')
15 | return erc20_def
16 |
17 | @pytest.fixture
18 | async def erc20_init(contract_defs):
19 | erc20_def = contract_defs
20 | starknet = await Starknet.empty()
21 | erc20 = await starknet.deploy(
22 | contract_def=erc20_def,
23 | constructor_calldata=[OWNER]
24 | )
25 | return (
26 | starknet.state,
27 | erc20,
28 | )
29 |
30 | @pytest.fixture
31 | def erc20_factory(contract_defs, erc20_init):
32 | erc20_def = contract_defs
33 | state, erc20 = erc20_init
34 | _state = state.copy()
35 | erc20 = cached_contract(_state, erc20_def, erc20)
36 | return erc20
37 |
38 | @pytest.mark.asyncio
39 | async def test_initial_data(erc20_factory):
40 | erc20 = erc20_factory
41 | execution_info = await erc20.name().call()
42 | assert execution_info.result.name == NAME
--------------------------------------------------------------------------------
/tests/test_ERC721.py:
--------------------------------------------------------------------------------
1 | """ERC721.cairo test file."""
2 | import pytest
3 | from starkware.starknet.testing.starknet import Starknet
4 | from utils import (
5 | cached_contract, get_contract_def, str_to_felt
6 | )
7 |
8 | # testing vars
9 | OWNER = 42
10 | NAME = str_to_felt("MyToken")
11 |
12 | @pytest.fixture
13 | def contract_defs():
14 | erc721_def = get_contract_def('ERC721.cairo')
15 | return erc721_def
16 |
17 | @pytest.fixture
18 | async def erc721_init(contract_defs):
19 | erc721_def = contract_defs
20 | starknet = await Starknet.empty()
21 | erc721 = await starknet.deploy(
22 | contract_def=erc721_def,
23 | constructor_calldata=[OWNER]
24 | )
25 | return (
26 | starknet.state,
27 | erc721,
28 | )
29 |
30 | @pytest.fixture
31 | def erc721_factory(contract_defs, erc721_init):
32 | erc721_def = contract_defs
33 | state, erc721 = erc721_init
34 | _state = state.copy()
35 | erc721 = cached_contract(_state, erc721_def, erc721)
36 | return erc721
37 |
38 | @pytest.mark.asyncio
39 | async def test_initial_data(erc721_factory):
40 | erc721 = erc721_factory
41 | execution_info = await erc721.name().call()
42 | assert execution_info.result.name == NAME
--------------------------------------------------------------------------------
/src/codefordao/libraries/merkle.cairo:
--------------------------------------------------------------------------------
1 | %lang starknet
2 |
3 | from starkware.cairo.common.cairo_builtins import HashBuiltin
4 | from starkware.cairo.common.hash import hash2
5 | from starkware.cairo.common.math_cmp import is_le_felt
6 |
7 | # verifies a merkle proof
8 | func merkle_verify{
9 | pedersen_ptr: HashBuiltin*,
10 | range_check_ptr
11 | }(
12 | leaf: felt,
13 | root: felt,
14 | proof_len: felt,
15 | proof: felt*
16 | ) -> (res: felt):
17 | let (calc_root) = calc_merkle_root(leaf, proof_len, proof)
18 | # check if calculated root is equal to expected
19 | if calc_root == root:
20 | return (1)
21 | else:
22 | return (0)
23 | end
24 | end
25 |
26 | # calculates the merkle root of a given proof
27 | func calc_merkle_root{
28 | pedersen_ptr: HashBuiltin*,
29 | range_check_ptr
30 | }(
31 | curr: felt,
32 | proof_len: felt,
33 | proof: felt*
34 | ) -> (res: felt):
35 | alloc_locals
36 |
37 | if proof_len == 0:
38 | return (curr)
39 | end
40 |
41 | local node
42 | local proof_elem = [proof]
43 | let (le) = is_le_felt(curr, proof_elem)
44 |
45 | if le == 1:
46 | let (n) = hash2{hash_ptr=pedersen_ptr}(curr, proof_elem)
47 | node = n
48 | else:
49 | let (n) = hash2{hash_ptr=pedersen_ptr}(proof_elem, curr)
50 | node = n
51 | end
52 |
53 | let (res) = calc_merkle_root(node, proof_len-1, proof+1)
54 | return (res)
55 | end
56 |
--------------------------------------------------------------------------------
/src/codefordao/core/Governor.cairo:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 |
3 | %lang starknet
4 |
5 | from starkware.cairo.common.cairo_builtins import HashBuiltin
6 | from openzeppelin.introspection.ERC165 import ERC165
7 |
8 | #
9 | # Initializer
10 | #
11 | @constructor
12 | func constructor{
13 | syscall_ptr: felt*,
14 | pedersen_ptr: HashBuiltin*,
15 | range_check_ptr
16 | }(
17 | name: felt,
18 | token_addr: felt,
19 | treasury_addr: felt
20 | settings: felt
21 | ):
22 | return ()
23 | end
24 |
25 | #
26 | # Getters
27 | #
28 |
29 | @view
30 | func quorum{
31 | syscall_ptr: felt*,
32 | pedersen_ptr: HashBuiltin*,
33 | range_check_ptr
34 | }(block_number: felt):
35 | return ()
36 | end
37 |
38 | @view
39 | func getVotes{
40 | syscall_ptr: felt*,
41 | pedersen_ptr: HashBuiltin*,
42 | range_check_ptr
43 | }(addr: felt, block_number: felt):
44 | return ()
45 | end
46 |
47 | @view
48 | func state{
49 | syscall_ptr: felt*,
50 | pedersen_ptr: HashBuiltin*,
51 | range_check_ptr
52 | }(proposal_id: felt):
53 | return ()
54 | end
55 |
56 | @view
57 | func proposalThreshold{
58 | syscall_ptr: felt*,
59 | pedersen_ptr: HashBuiltin*,
60 | range_check_ptr
61 | }():
62 | return ()
63 | end
64 |
65 | @view
66 | func supportsInterface{
67 | syscall_ptr: felt*,
68 | pedersen_ptr: HashBuiltin*,
69 | range_check_ptr
70 | }(interfaceId: felt) -> (success: felt):
71 | let (success) = ERC165.supports_interface(interfaceId)
72 | return (success)
73 | end
74 |
75 | #
76 | # Externals
77 | #
78 | @external
79 | func propose{
80 | syscall_ptr: felt*,
81 | pedersen_ptr: HashBuiltin*,
82 | range_check_ptr
83 | }(
84 | ):
85 | return ()
86 | end
--------------------------------------------------------------------------------
/src/codefordao/core/Treasury.cairo:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 |
3 | %lang starknet
4 |
5 | from starkware.cairo.common.cairo_builtins import HashBuiltin
6 |
7 | #
8 | # Storage
9 | #
10 | @storage_var
11 | func contracts_addresses(contract_type: ContractType) -> (addr: felt):
12 | end
13 |
14 | #
15 | # Initializer
16 | #
17 | @constructor
18 | func constructor{
19 | syscall_ptr: felt*,
20 | pedersen_ptr: HashBuiltin*,
21 | range_check_ptr
22 | }(
23 | timelock_delay: felt,
24 | membership_address: felt,
25 | share_address: felt
26 | ):
27 | return ()
28 | end
29 |
30 | #
31 | # Externals
32 | #
33 |
34 | @external
35 | func vestingShare{
36 | syscall_ptr: felt*,
37 | pedersen_ptr: HashBuiltin*,
38 | range_check_ptr
39 | }(uri: felt, shareRatio: felt):
40 | Ownable.assert_only_owner()
41 | return ()
42 | end
43 |
44 | @external
45 | func updateInvestmentSettings{
46 | syscall_ptr: felt*,
47 | pedersen_ptr: HashBuiltin*,
48 | range_check_ptr
49 | }(settings: felt):
50 | Ownable.assert_only_owner()
51 | return ()
52 | end
53 |
54 | @external
55 | func updateShareSplit{
56 | syscall_ptr: felt*,
57 | pedersen_ptr: HashBuiltin*,
58 | range_check_ptr
59 | }(share_split: felt):
60 | Ownable.assert_only_owner()
61 | return ()
62 | end
63 |
64 | @external
65 | func invest{
66 | syscall_ptr: felt*,
67 | pedersen_ptr: HashBuiltin*,
68 | range_check_ptr
69 | }(amount: felt):
70 | check_investment_enabled()
71 | Ownable.assert_only_owner()
72 | return ()
73 | end
74 |
75 | @external
76 | func investInERC20{
77 | syscall_ptr: felt*,
78 | pedersen_ptr: HashBuiltin*,
79 | range_check_ptr
80 | }(amount: felt):
81 | check_investment_enabled()
82 | Ownable.assert_only_owner()
83 | return ()
84 | end
85 |
86 | @external
87 | func pullModulePayment{
88 | syscall_ptr: felt*,
89 | pedersen_ptr: HashBuiltin*,
90 | range_check_ptr
91 | }(amount: felt):
92 | Ownable.assert_only_owner()
93 | return ()
94 | end
95 |
96 | @external
97 | func approveModulePayment{
98 | syscall_ptr: felt*,
99 | pedersen_ptr: HashBuiltin*,
100 | range_check_ptr
101 | }(amount: felt):
102 | Ownable.assert_only_owner()
103 | return ()
104 | end
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | artifacts/
2 | *DS_STORE
3 | # Byte-compiled / optimized / DLL files
4 | __pycache__/
5 | *.py[cod]
6 | *$py.class
7 |
8 | # C extensions
9 | *.so
10 |
11 | # Env
12 | *.env
13 | *.accounts.json
14 | accounts.json
15 |
16 | # Distribution / packaging
17 | .Python
18 | build/
19 | develop-eggs/
20 | dist/
21 | downloads/
22 | eggs/
23 | .eggs/
24 | lib/
25 | lib64/
26 | parts/
27 | sdist/
28 | var/
29 | wheels/
30 | pip-wheel-metadata/
31 | share/python-wheels/
32 | *.egg-info/
33 | .installed.cfg
34 | *.egg
35 | MANIFEST
36 |
37 | # PyInstaller
38 | # Usually these files are written by a python script from a template
39 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
40 | *.manifest
41 | *.spec
42 |
43 | # Installer logs
44 | pip-log.txt
45 | pip-delete-this-directory.txt
46 |
47 | # Unit test / coverage reports
48 | htmlcov/
49 | .tox/
50 | .nox/
51 | .coverage
52 | .coverage.*
53 | .cache
54 | nosetests.xml
55 | coverage.xml
56 | *.cover
57 | *.py,cover
58 | .hypothesis/
59 | .pytest_cache/
60 |
61 | # Translations
62 | *.mo
63 | *.pot
64 |
65 | # Django stuff:
66 | *.log
67 | local_settings.py
68 | db.sqlite3
69 | db.sqlite3-journal
70 |
71 | # Flask stuff:
72 | instance/
73 | .webassets-cache
74 |
75 | # Scrapy stuff:
76 | .scrapy
77 |
78 | # Sphinx documentation
79 | docs/_build/
80 |
81 | # PyBuilder
82 | target/
83 |
84 | # Jupyter Notebook
85 | .ipynb_checkpoints
86 |
87 | # IPython
88 | profile_default/
89 | ipython_config.py
90 |
91 | # pyenv
92 | .python-version
93 |
94 | # pipenv
95 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
96 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
97 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
98 | # install all needed dependencies.
99 | #Pipfile.lock
100 |
101 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow
102 | __pypackages__/
103 |
104 | # Celery stuff
105 | celerybeat-schedule
106 | celerybeat.pid
107 |
108 | # SageMath parsed files
109 | *.sage.py
110 |
111 | # Environments
112 | .env
113 | .venv
114 | env/
115 | venv/
116 | ENV/
117 | env.bak/
118 | venv.bak/
119 |
120 | # Spyder project settings
121 | .spyderproject
122 | .spyproject
123 |
124 | # Rope project settings
125 | .ropeproject
126 |
127 | # mkdocs documentation
128 | /site
129 |
130 | # mypy
131 | .mypy_cache/
132 | .dmypy.json
133 | dmypy.json
134 |
135 | # Pyre type checker
136 | .pyre/
137 |
138 |
139 | node.json
140 | *.deployments.txt
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CodeforDAO Contracts in Cairo (StarkNet)
6 |
7 |
8 | Base on, build upon and code for DAOs.
9 |
10 |
11 | Make DAO the next generation of productivity tools for global collaboration.
12 |
13 |
14 | Follow us on Twitter @codefordao.
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | > **This project is a work in progress, it has not been audited for code security and is being deployed in local development and test networks at this time. Please use with caution.**
24 |
25 | The CodeforDAO contract is a set of DAO infrastructure and efficiency tools with member NFT at its core.
26 |
27 | It is centered on a set of membership contracts for the `ERC721` protocol, the creation of its counterpart share contracts, two parallel governance frameworks and a timelock vault contract.
28 |
29 | It introduces some basic features to DAO, including vault contracts for self-service participation in investments, a set of modular frameworks to support aggressive governance.
30 |
31 | Read the full documents in this [Solidity Repo](https://github.com/CodeforDAO/contracts) of CodeforDAO contracts
32 |
33 | ## Set up the project
34 |
35 | Before creating virtual environment, please **make sure** to install Python `3.7.12` using the Python version management tool and activate that version.
36 |
37 | ### Create a Python virtual environment
38 |
39 | ```bash
40 | python -m venv env
41 | source env/bin/activate
42 | ```
43 |
44 | ### Install the requirements
45 |
46 | ```bash
47 | pip install -r requirements.txt
48 | ```
49 |
50 | **Notice**: this project use the latest version of OpenZeppelin contract for Cairo instead of the stable release of it.
51 |
52 | ## Compile
53 |
54 | ```bash
55 | nile compile --directory src
56 | ```
57 |
58 | ## Running tests
59 |
60 | Running spec tests where you can find them in `./test` folder
61 |
62 | ```bash
63 | $ pytest tests
64 | ```
65 |
66 | ## Use this module in your project
67 |
68 | **Note:** these smart contracts are not designed to be library contracts(except `Module.cairo`), and you can fork these contracts locally to modify them yourself, rather than importing them directly by a git link.
69 |
70 | ```bash
71 | pip install git+https://github.com/CodeforDAO/cairo-contracts.git
72 | ```
73 |
74 | ## License
75 |
76 | This project is released under the [MIT](LICENSE).
77 |
--------------------------------------------------------------------------------
/src/codefordao/libraries/utils.cairo:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 |
3 | %lang starknet
4 |
5 | from starkware.cairo.common.alloc import alloc
6 | from starkware.cairo.common.cairo_builtins import HashBuiltin
7 |
8 | struct ArrayInfo:
9 | member key : felt
10 | member len : felt
11 | end
12 |
13 | @storage_var
14 | func _array_key_index() -> (res: felt):
15 | end
16 |
17 | @storage_var
18 | func _arrays(key: felt, index: felt) -> (res: felt):
19 | end
20 |
21 | @storage_var
22 | func _array_info(key: felt) -> (res: ArrayInfo):
23 | end
24 |
25 | namespace Array:
26 | # Save array to storage with increasing key.
27 | func save{
28 | syscall_ptr : felt*,
29 | pedersen_ptr : HashBuiltin*,
30 | range_check_ptr
31 | }(
32 | arr_len: felt,
33 | arr: felt*
34 | ) -> (key: felt):
35 | alloc_locals
36 |
37 | with_attr error_message("Arrays.push: invalid length of giving array"):
38 | assert arr_len = 0
39 | end
40 |
41 | let (local k) = _array_key_index.read()
42 | let info = ArrayInfo(key=k, len=arr_len)
43 |
44 | _array_info.write(key=k, value=info)
45 | _write_array(key=k, arr_index=0, arr_len=arr_len, arr=arr)
46 | _array_key_index.write(k + 1)
47 |
48 | return (k)
49 | end
50 |
51 | # Fetch array item by key and index
52 | func get_item{
53 | syscall_ptr : felt*,
54 | pedersen_ptr : HashBuiltin*,
55 | range_check_ptr
56 | }(
57 | key: felt,
58 | index: felt
59 | ) -> (res: felt):
60 | let (res) = _arrays.read(key=key, index=index)
61 | return (res)
62 | end
63 |
64 | func get_array{
65 | syscall_ptr : felt*,
66 | pedersen_ptr : HashBuiltin*,
67 | range_check_ptr
68 | }(key: felt) -> (
69 | arr_len: felt,
70 | arr: felt*
71 | ):
72 | alloc_locals
73 |
74 | let (arr) = alloc()
75 | let (local arr_info) = _array_info.read(key)
76 |
77 | if arr_info.len == 0:
78 | return (arr_len=arr_info.len, arr=arr)
79 | end
80 |
81 | _read_array(key=key, arr_index=0, arr_len=arr_info.len, arr=arr)
82 | return (arr_len=arr_info.len, arr=arr)
83 | end
84 |
85 | # Store arrays into multi-dimensional maps by recursion
86 | func _write_array{
87 | syscall_ptr : felt*,
88 | pedersen_ptr : HashBuiltin*,
89 | range_check_ptr
90 | }(
91 | key: felt,
92 | arr_index: felt,
93 | arr_len: felt,
94 | arr: felt*
95 | ):
96 | if arr_index == arr_len:
97 | return ()
98 | end
99 |
100 | _arrays.write(key=key, index=arr_index, value=[arr])
101 | _write_array(key=key, arr_index=arr_index + 1, arr_len=arr_len, arr=arr + 1)
102 |
103 | return ()
104 | end
105 |
106 | func _read_array{
107 | syscall_ptr : felt*,
108 | pedersen_ptr : HashBuiltin*,
109 | range_check_ptr
110 | }(
111 | key: felt,
112 | arr_index: felt,
113 | arr_len: felt,
114 | arr: felt*
115 | ):
116 | if arr_index == arr_len:
117 | return ()
118 | end
119 |
120 | let (item) = _arrays.read(key=key, index=arr_index)
121 | assert arr[arr_index] = item
122 |
123 | _read_array(
124 | key=key,
125 | arr_index=arr_index + 1,
126 | arr_len=arr_len,
127 | arr=arr
128 | )
129 |
130 | return ()
131 | end
132 | end
--------------------------------------------------------------------------------
/src/codefordao/core/Module.cairo:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 |
3 | %lang starknet
4 |
5 | from starkware.cairo.common.alloc import alloc
6 | from starkware.cairo.common.cairo_builtins import HashBuiltin
7 | from starkware.cairo.common.math import assert_le, assert_lt
8 | from starkware.starknet.common.syscalls import call_contract, get_caller_address
9 |
10 | from src.codefordao.libraries.structs import ContractAddressType
11 | from src.codefordao.libraries.utils import Arrays
12 |
13 | #
14 | # Events
15 | #
16 |
17 | @event
18 | func ModuleProposalCreated(
19 | module_addr: felt,
20 | operator_addr : felt,
21 | id : felt,
22 | timestamp : felt
23 | ):
24 | end
25 |
26 | @event
27 | func ModuleProposalConfirmed(
28 | module_addr: felt,
29 | operator_addr : felt,
30 | id : felt,
31 | timestamp : felt
32 | ):
33 | end
34 |
35 | @event
36 | func ModuleProposalScheduled(
37 | module_addr: felt,
38 | operator_addr : felt,
39 | id : felt,
40 | timestamp : felt
41 | ):
42 | end
43 |
44 | @event
45 | func ModuleProposalExecuted(
46 | module_addr: felt,
47 | operator_addr : felt,
48 | id : felt,
49 | timestamp : felt
50 | ):
51 | end
52 |
53 | @event
54 | func ModuleProposalCancelled(
55 | module_addr: felt,
56 | operator_addr : felt,
57 | id : felt,
58 | timestamp : felt
59 | ):
60 | end
61 |
62 | #
63 | # Structs
64 | #
65 |
66 | struct MicroProposal:
67 | member target : felt
68 | member function_selector : felt
69 | member calldata_len : felt
70 | member confirmations : felt
71 | member status: felt
72 | end
73 |
74 | #
75 | # Storage
76 | #
77 |
78 | @storage_var
79 | func _name() -> (uri: felt):
80 | end
81 |
82 | @storage_var
83 | func _description() -> (uri: felt):
84 | end
85 |
86 | @storage_var
87 | func _operators_key() -> (res: felt):
88 | end
89 |
90 | @storage_var
91 | func _addresses(addr_type: ContractAddressType) -> (addr: felt):
92 | end
93 |
94 | namespace CodeforDAO_Module:
95 |
96 | #
97 | # Initializer
98 | #
99 | func initializer{
100 | syscall_ptr: felt*,
101 | pedersen_ptr: HashBuiltin*,
102 | range_check_ptr
103 | }(
104 | name: felt,
105 | description: felt,
106 | membership_addr: felt,
107 | operators_len: felt,
108 | operators: felt*,
109 | timelock_delay: felt
110 | ):
111 | _name.write(name)
112 | _description.write(description)
113 | _addresses.write(addr_type=ContractAddressType.membership, addr=membership_addr)
114 |
115 | let (_key) = Arrays.push(arr_len=operators_len, arr=operators)
116 | _operators_key.write(_key)
117 |
118 | return ()
119 | end
120 |
121 | #
122 | # Public functions
123 | #
124 | func operators{
125 | pedersen_ptr: HashBuiltin*,
126 | syscall_ptr: felt*,
127 | range_check_ptr
128 | }() -> (
129 | operators_len: felt,
130 | operators: felt*
131 | ):
132 |
133 | let (key) = _operators_key.read()
134 | let (arr_len, arr) = Arrays.get_array(key)
135 |
136 | return (operators_len=arr_len, operators=arr)
137 | end
138 |
139 | func getMembershipTokenId{
140 | pedersen_ptr: HashBuiltin*,
141 | syscall_ptr: felt*,
142 | range_check_ptr
143 | }() -> ():
144 | end
145 |
146 | func getAddressByMemberId{
147 | pedersen_ptr: HashBuiltin*,
148 | syscall_ptr: felt*,
149 | range_check_ptr
150 | }() -> ():
151 | end
152 |
153 | func getProposal{
154 | pedersen_ptr: HashBuiltin*,
155 | syscall_ptr: felt*,
156 | range_check_ptr
157 | }(proposal_id: felt) -> ():
158 | end
159 |
160 | func propose{
161 | pedersen_ptr: HashBuiltin*,
162 | syscall_ptr: felt*,
163 | range_check_ptr
164 | }() -> ():
165 | end
166 |
167 | func confirm{
168 | pedersen_ptr: HashBuiltin*,
169 | syscall_ptr: felt*,
170 | range_check_ptr
171 | }(proposal_id: felt) -> ():
172 | end
173 |
174 | func schedule{
175 | pedersen_ptr: HashBuiltin*,
176 | syscall_ptr: felt*,
177 | range_check_ptr
178 | }(proposal_id: felt) -> ():
179 | end
180 |
181 | func execute{
182 | pedersen_ptr: HashBuiltin*,
183 | syscall_ptr: felt*,
184 | range_check_ptr
185 | }(proposal_id: felt) -> ():
186 | end
187 |
188 | func cancel{
189 | pedersen_ptr: HashBuiltin*,
190 | syscall_ptr: felt*,
191 | range_check_ptr
192 | }(proposal_id: felt) -> ():
193 | end
194 |
195 | #
196 | # Internal
197 | #
198 | func pullPayments{
199 | pedersen_ptr: HashBuiltin*,
200 | syscall_ptr: felt*,
201 | range_check_ptr
202 | }() -> ():
203 | end
204 | end
--------------------------------------------------------------------------------
/src/codefordao/core/Share.cairo:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 |
3 | %lang starknet
4 |
5 | from starkware.cairo.common.cairo_builtins import HashBuiltin
6 | from starkware.cairo.common.uint256 import Uint256
7 | from starkware.cairo.common.bool import TRUE
8 | from starkware.starknet.common.syscalls import get_caller_address
9 |
10 | from openzeppelin.token.erc20.library import ERC20
11 | from openzeppelin.security.pausable import Pausable
12 | from openzeppelin.access.ownable import Ownable
13 |
14 | #
15 | # @title Share
16 | # @notice The share contract determines the issuance and suspension of share tokens,
17 | # as well as the administrator role.
18 | # Basically it is a pre-defined contract for erc20 token but support ERC20Votes.
19 | #
20 |
21 | @constructor
22 | func constructor{
23 | syscall_ptr: felt*,
24 | pedersen_ptr: HashBuiltin*,
25 | range_check_ptr
26 | }(
27 | name: felt,
28 | symbol: felt,
29 | owner: felt
30 | ):
31 | ERC20.initializer(name, symbol, 18)
32 | Ownable.initializer(owner)
33 | return ()
34 | end
35 |
36 | #
37 | # Getters
38 | #
39 |
40 | @view
41 | func name{
42 | syscall_ptr: felt*,
43 | pedersen_ptr: HashBuiltin*,
44 | range_check_ptr
45 | }() -> (name: felt):
46 | let (name) = ERC20.name()
47 | return (name)
48 | end
49 |
50 | @view
51 | func symbol{
52 | syscall_ptr: felt*,
53 | pedersen_ptr: HashBuiltin*,
54 | range_check_ptr
55 | }() -> (symbol: felt):
56 | let (symbol) = ERC20.symbol()
57 | return (symbol)
58 | end
59 |
60 | @view
61 | func totalSupply{
62 | syscall_ptr: felt*,
63 | pedersen_ptr: HashBuiltin*,
64 | range_check_ptr
65 | }() -> (totalSupply: Uint256):
66 | let (totalSupply) = ERC20_totalSupply()
67 | return (totalSupply)
68 | end
69 |
70 | @view
71 | func decimals{
72 | syscall_ptr: felt*,
73 | pedersen_ptr: HashBuiltin*,
74 | range_check_ptr
75 | }() -> (decimals: felt):
76 | let (decimals) = ERC20_decimals()
77 | return (decimals)
78 | end
79 |
80 | @view
81 | func balanceOf{
82 | syscall_ptr: felt*,
83 | pedersen_ptr: HashBuiltin*,
84 | range_check_ptr
85 | }(account: felt) -> (balance: Uint256):
86 | let (balance: Uint256) = ERC20.balance_of(account)
87 | return (balance)
88 | end
89 |
90 | @view
91 | func allowance{
92 | syscall_ptr: felt*,
93 | pedersen_ptr: HashBuiltin*,
94 | range_check_ptr
95 | }(owner: felt, spender: felt) -> (remaining: Uint256):
96 | let (remaining: Uint256) = ERC20.allowance(owner, spender)
97 | return (remaining)
98 | end
99 |
100 | @view
101 | func owner{
102 | syscall_ptr : felt*,
103 | pedersen_ptr : HashBuiltin*,
104 | range_check_ptr
105 | }() -> (owner: felt):
106 | let (owner: felt) = Ownable.owner()
107 | return (owner)
108 | end
109 |
110 | @view
111 | func paused{
112 | syscall_ptr: felt*,
113 | pedersen_ptr: HashBuiltin*,
114 | range_check_ptr
115 | }() -> (paused: felt):
116 | let (paused) = Pausable.is_paused()
117 | return (paused)
118 | end
119 |
120 | #
121 | # Externals
122 | #
123 |
124 | @external
125 | func transfer{
126 | syscall_ptr: felt*,
127 | pedersen_ptr: HashBuiltin*,
128 | range_check_ptr
129 | }(recipient: felt, amount: Uint256) -> (success: felt):
130 | Pausable.assert_not_paused()
131 | ERC20.transfer(recipient, amount)
132 | return (TRUE)
133 | end
134 |
135 | @external
136 | func transferFrom{
137 | syscall_ptr: felt*,
138 | pedersen_ptr: HashBuiltin*,
139 | range_check_ptr
140 | }(
141 | sender: felt,
142 | recipient: felt,
143 | amount: Uint256
144 | ) -> (success: felt):
145 | Pausable.assert_not_paused()
146 | ERC20.transfer_from(sender, recipient, amount)
147 | return (TRUE)
148 | end
149 |
150 | @external
151 | func approve{
152 | syscall_ptr: felt*,
153 | pedersen_ptr: HashBuiltin*,
154 | range_check_ptr
155 | }(spender: felt, amount: Uint256) -> (success: felt):
156 | Pausable.assert_not_paused()
157 | ERC20.approve(spender, amount)
158 | return (TRUE)
159 | end
160 |
161 | @external
162 | func increaseAllowance{
163 | syscall_ptr: felt*,
164 | pedersen_ptr: HashBuiltin*,
165 | range_check_ptr
166 | }(spender: felt, added_value: Uint256) -> (success: felt):
167 | Pausable.assert_not_paused()
168 | ERC20.increase_allowance(spender, added_value)
169 | return (TRUE)
170 | end
171 |
172 | @external
173 | func decreaseAllowance{
174 | syscall_ptr: felt*,
175 | pedersen_ptr: HashBuiltin*,
176 | range_check_ptr
177 | }(spender: felt, subtracted_value: Uint256) -> (success: felt):
178 | Pausable.assert_not_paused()
179 | ERC20.decrease_allowance(spender, subtracted_value)
180 | return (TRUE)
181 | end
182 |
183 | @external
184 | func transferOwnership{
185 | syscall_ptr: felt*,
186 | pedersen_ptr: HashBuiltin*,
187 | range_check_ptr
188 | }(newOwner: felt):
189 | Ownable.transfer_ownership(newOwner)
190 | return ()
191 | end
192 |
193 | @external
194 | func renounceOwnership{
195 | syscall_ptr: felt*,
196 | pedersen_ptr: HashBuiltin*,
197 | range_check_ptr
198 | }():
199 | Ownable.renounce_ownership()
200 | return ()
201 | end
202 |
203 | @external
204 | func burn{
205 | syscall_ptr: felt*,
206 | pedersen_ptr: HashBuiltin*,
207 | range_check_ptr
208 | }(amount: Uint256):
209 | Pausable.assert_not_paused()
210 | let (owner) = get_caller_address()
211 | ERC20._burn(owner, amount)
212 | return ()
213 | end
214 |
215 | @external
216 | func pause{
217 | syscall_ptr: felt*,
218 | pedersen_ptr: HashBuiltin*,
219 | range_check_ptr
220 | }():
221 | Ownable.assert_only_owner()
222 | Pausable._pause()
223 | return ()
224 | end
225 |
226 | @external
227 | func unpause{
228 | syscall_ptr: felt*,
229 | pedersen_ptr: HashBuiltin*,
230 | range_check_ptr
231 | }():
232 | Ownable.assert_only_owner()
233 | Pausable._unpause()
234 | return ()
235 | end
236 |
237 | @external
238 | func mint{
239 | syscall_ptr: felt*,
240 | pedersen_ptr: HashBuiltin*,
241 | range_check_ptr
242 | }(to: felt, amount: Uint256):
243 | Ownable.assert_only_owner()
244 | ERC20._mint(to, amount)
245 | return ()
246 | end
247 |
--------------------------------------------------------------------------------
/tests/utils.py:
--------------------------------------------------------------------------------
1 | """Utilities for testing Cairo contracts."""
2 | #Copied from https://github.com/OpenZeppelin/cairo-contracts/blob/main/tests/utils.py
3 | from pathlib import Path
4 | import math
5 | from starkware.cairo.common.hash_state import compute_hash_on_elements
6 | from starkware.crypto.signature.signature import private_to_stark_key, sign
7 | from starkware.starknet.public.abi import get_selector_from_name
8 | from starkware.starknet.compiler.compile import compile_starknet_files
9 | from starkware.starkware_utils.error_handling import StarkException
10 | from starkware.starknet.testing.starknet import StarknetContract
11 | from starkware.starknet.business_logic.execution.objects import Event
12 |
13 |
14 | MAX_UINT256 = (2**128 - 1, 2**128 - 1)
15 | INVALID_UINT256 = (MAX_UINT256[0] + 1, MAX_UINT256[1])
16 | ZERO_ADDRESS = 0
17 | TRUE = 1
18 | FALSE = 0
19 |
20 | TRANSACTION_VERSION = 0
21 |
22 | _root = Path(__file__).parent.parent
23 |
24 |
25 | def contract_path(name):
26 | if name.startswith("tests/"):
27 | return str(_root / name)
28 | else:
29 | return str(_root / "src" / name)
30 |
31 |
32 | def str_to_felt(text):
33 | b_text = bytes(text, "ascii")
34 | return int.from_bytes(b_text, "big")
35 |
36 |
37 | def felt_to_str(felt):
38 | b_felt = felt.to_bytes(31, "big")
39 | return b_felt.decode()
40 |
41 |
42 | def assert_event_emitted(tx_exec_info, from_address, name, data):
43 | assert Event(
44 | from_address=from_address,
45 | keys=[get_selector_from_name(name)],
46 | data=data,
47 | ) in tx_exec_info.raw_events
48 |
49 |
50 | def uint(a):
51 | return(a, 0)
52 |
53 |
54 | def to_uint(a):
55 | """Takes in value, returns uint256-ish tuple."""
56 | return (a & ((1 << 128) - 1), a >> 128)
57 |
58 |
59 | def from_uint(uint):
60 | """Takes in uint256-ish tuple, returns value."""
61 | return uint[0] + (uint[1] << 128)
62 |
63 |
64 | def add_uint(a, b):
65 | """Returns the sum of two uint256-ish tuples."""
66 | a = from_uint(a)
67 | b = from_uint(b)
68 | c = a + b
69 | return to_uint(c)
70 |
71 |
72 | def sub_uint(a, b):
73 | """Returns the difference of two uint256-ish tuples."""
74 | a = from_uint(a)
75 | b = from_uint(b)
76 | c = a - b
77 | return to_uint(c)
78 |
79 |
80 | def mul_uint(a, b):
81 | """Returns the product of two uint256-ish tuples."""
82 | a = from_uint(a)
83 | b = from_uint(b)
84 | c = a * b
85 | return to_uint(c)
86 |
87 |
88 | def div_rem_uint(a, b):
89 | """Returns the quotient and remainder of two uint256-ish tuples."""
90 | a = from_uint(a)
91 | b = from_uint(b)
92 | c = math.trunc(a / b)
93 | m = a % b
94 | return (to_uint(c), to_uint(m))
95 |
96 |
97 | async def assert_revert(fun, reverted_with=None):
98 | try:
99 | await fun
100 | assert False
101 | except StarkException as err:
102 | _, error = err.args
103 | if reverted_with is not None:
104 | assert reverted_with in error['message']
105 |
106 |
107 | def assert_event_emitted(tx_exec_info, from_address, name, data):
108 | assert Event(
109 | from_address=from_address,
110 | keys=[get_selector_from_name(name)],
111 | data=data,
112 | ) in tx_exec_info.raw_events
113 |
114 |
115 | def get_contract_def(path):
116 | """Returns the contract definition from the contract path"""
117 | path = contract_path(path)
118 | contract_def = compile_starknet_files(
119 | files=[path],
120 | debug_info=True
121 | )
122 | return contract_def
123 |
124 |
125 | def cached_contract(state, definition, deployed):
126 | """Returns the cached contract"""
127 | contract = StarknetContract(
128 | state=state,
129 | abi=definition.abi,
130 | contract_address=deployed.contract_address,
131 | deploy_execution_info=deployed.deploy_execution_info
132 | )
133 | return contract
134 |
135 |
136 | class Signer():
137 | """
138 | Utility for sending signed transactions to an Account on Starknet.
139 |
140 | Parameters
141 | ----------
142 |
143 | private_key : int
144 |
145 | Examples
146 | ---------
147 | Constructing a Signer object
148 |
149 | >>> signer = Signer(1234)
150 |
151 | Sending a transaction
152 |
153 | >>> await signer.send_transaction(account,
154 | account.contract_address,
155 | 'set_public_key',
156 | [other.public_key]
157 | )
158 |
159 | """
160 |
161 | def __init__(self, private_key):
162 | self.private_key = private_key
163 | self.public_key = private_to_stark_key(private_key)
164 |
165 | def sign(self, message_hash):
166 | return sign(msg_hash=message_hash, priv_key=self.private_key)
167 |
168 | async def send_transaction(self, account, to, selector_name, calldata, nonce=None, max_fee=0):
169 | return await self.send_transactions(account, [(to, selector_name, calldata)], nonce, max_fee)
170 |
171 | async def send_transactions(self, account, calls, nonce=None, max_fee=0):
172 | if nonce is None:
173 | execution_info = await account.get_nonce().call()
174 | nonce, = execution_info.result
175 |
176 | calls_with_selector = [
177 | (call[0], get_selector_from_name(call[1]), call[2]) for call in calls]
178 | (call_array, calldata) = from_call_to_call_array(calls)
179 |
180 | message_hash = hash_multicall(
181 | account.contract_address, calls_with_selector, nonce, max_fee)
182 | sig_r, sig_s = self.sign(message_hash)
183 |
184 | return await account.__execute__(call_array, calldata, nonce).invoke(signature=[sig_r, sig_s])
185 |
186 |
187 | def from_call_to_call_array(calls):
188 | call_array = []
189 | calldata = []
190 | for i, call in enumerate(calls):
191 | assert len(call) == 3, "Invalid call parameters"
192 | entry = (call[0], get_selector_from_name(
193 | call[1]), len(calldata), len(call[2]))
194 | call_array.append(entry)
195 | calldata.extend(call[2])
196 | return (call_array, calldata)
197 |
198 |
199 | def hash_multicall(sender, calls, nonce, max_fee):
200 | hash_array = []
201 | for call in calls:
202 | call_elements = [call[0], call[1], compute_hash_on_elements(call[2])]
203 | hash_array.append(compute_hash_on_elements(call_elements))
204 |
205 | message = [
206 | str_to_felt('StarkNet Transaction'),
207 | sender,
208 | compute_hash_on_elements(hash_array),
209 | nonce,
210 | max_fee,
211 | TRANSACTION_VERSION
212 | ]
213 | return compute_hash_on_elements(message)
--------------------------------------------------------------------------------
/src/codefordao/core/Membership.cairo:
--------------------------------------------------------------------------------
1 | # SPDX-License-Identifier: MIT
2 |
3 | %lang starknet
4 |
5 | from starkware.cairo.common.cairo_builtins import HashBuiltin
6 | from starkware.cairo.common.hash import hash2
7 | from starkware.cairo.common.uint256 import Uint256
8 | from starkware.starknet.common.syscalls import get_caller_address
9 |
10 | from openzeppelin.token.erc721.library import (
11 | ERC721_name,
12 | ERC721_symbol,
13 | ERC721_balanceOf,
14 | ERC721_ownerOf,
15 | ERC721_getApproved,
16 | ERC721_isApprovedForAll,
17 | ERC721_tokenURI,
18 | ERC721_approve,
19 | ERC721_setApprovalForAll,
20 | ERC721_transferFrom,
21 | ERC721_safeTransferFrom,
22 | ERC721_burn,
23 | ERC721_safeMint,
24 | ERC721_initializer,
25 | ERC721_only_token_owner,
26 | ERC721_setTokenURI,
27 | )
28 |
29 | from openzeppelin.token.erc721_enumerable.library import (
30 | ERC721_Enumerable_initializer,
31 | ERC721_Enumerable_totalSupply,
32 | ERC721_Enumerable_tokenByIndex,
33 | ERC721_Enumerable_tokenOfOwnerByIndex,
34 | ERC721_Enumerable_mint,
35 | ERC721_Enumerable_burn,
36 | ERC721_Enumerable_transferFrom,
37 | ERC721_Enumerable_safeTransferFrom
38 | )
39 |
40 | from openzeppelin.introspection.ERC165 import ERC165
41 | from openzeppelin.security.pausable import Pausable
42 | from immutablex.starknet.access.AccessControl import AccessControl, DEFAULT_ADMIN_ROLE
43 |
44 | from src.codefordao.libraries.structs import ContractAddressType
45 | from src.codefordao.libraries.merkle import merkle_verify
46 |
47 | #
48 | # Constants
49 | #
50 |
51 | const MINTER_ROLE = 'MINTER_ROLE'
52 | const INVITER_ROLE = 'INVITER_ROLE'
53 |
54 | #
55 | # Storage
56 | #
57 | @storage_var
58 | func contract_uri() -> (uri: felt):
59 | end
60 |
61 | @storage_var
62 | func investor(token_id: Uint256) -> (res: felt):
63 | end
64 |
65 | @storage_var
66 | func contracts_addresses(contract_type: ContractAddressType) -> (addr: felt):
67 | end
68 |
69 | @storage_var
70 | func merkle_root() -> (root: felt):
71 | end
72 |
73 | #
74 | # Initializer
75 | #
76 | @constructor
77 | func constructor{
78 | syscall_ptr: felt*,
79 | pedersen_ptr: HashBuiltin*,
80 | range_check_ptr
81 | }(
82 | name: felt,
83 | symbol: felt,
84 | default_admin: felt
85 | ):
86 | ERC721_initializer(name, symbol)
87 | ERC721_Enumerable_initializer()
88 | AccessControl.initializer(default_admin)
89 | return ()
90 | end
91 |
92 | #
93 | # Getters
94 | #
95 |
96 | @view
97 | func totalSupply{
98 | pedersen_ptr: HashBuiltin*,
99 | syscall_ptr: felt*,
100 | range_check_ptr
101 | }() -> (totalSupply: Uint256):
102 | let (totalSupply: Uint256) = ERC721_Enumerable_totalSupply()
103 | return (totalSupply)
104 | end
105 |
106 | @view
107 | func tokenByIndex{
108 | pedersen_ptr: HashBuiltin*,
109 | syscall_ptr: felt*,
110 | range_check_ptr
111 | }(index: Uint256) -> (tokenId: Uint256):
112 | let (tokenId: Uint256) = ERC721_Enumerable_tokenByIndex(index)
113 | return (tokenId)
114 | end
115 |
116 | @view
117 | func tokenOfOwnerByIndex{
118 | pedersen_ptr: HashBuiltin*,
119 | syscall_ptr: felt*,
120 | range_check_ptr
121 | }(owner: felt, index: Uint256) -> (tokenId: Uint256):
122 | let (tokenId: Uint256) = ERC721_Enumerable_tokenOfOwnerByIndex(owner, index)
123 | return (tokenId)
124 | end
125 |
126 | @view
127 | func supportsInterface{
128 | syscall_ptr: felt*,
129 | pedersen_ptr: HashBuiltin*,
130 | range_check_ptr
131 | }(interfaceId: felt) -> (success: felt):
132 | let (success) = ERC165.supports_interface(interfaceId)
133 | return (success)
134 | end
135 |
136 | @view
137 | func name{
138 | syscall_ptr: felt*,
139 | pedersen_ptr: HashBuiltin*,
140 | range_check_ptr
141 | }() -> (name: felt):
142 | let (name) = ERC721_name()
143 | return (name)
144 | end
145 |
146 | @view
147 | func symbol{
148 | syscall_ptr: felt*,
149 | pedersen_ptr: HashBuiltin*,
150 | range_check_ptr
151 | }() -> (symbol: felt):
152 | let (symbol) = ERC721_symbol()
153 | return (symbol)
154 | end
155 |
156 | @view
157 | func balanceOf{
158 | syscall_ptr: felt*,
159 | pedersen_ptr: HashBuiltin*,
160 | range_check_ptr
161 | }(owner: felt) -> (balance: Uint256):
162 | let (balance) = ERC721_balanceOf(owner)
163 | return (balance)
164 | end
165 |
166 | @view
167 | func ownerOf{
168 | syscall_ptr: felt*,
169 | pedersen_ptr: HashBuiltin*,
170 | range_check_ptr
171 | }(token_id: Uint256) -> (owner: felt):
172 | let (owner) = ERC721_ownerOf(token_id)
173 | return (owner)
174 | end
175 |
176 | @view
177 | func getApproved{
178 | syscall_ptr: felt*,
179 | pedersen_ptr: HashBuiltin*,
180 | range_check_ptr
181 | }(token_id: Uint256) -> (approved: felt):
182 | let (approved) = ERC721_getApproved(token_id)
183 | return (approved)
184 | end
185 |
186 | @view
187 | func isApprovedForAll{
188 | syscall_ptr: felt*,
189 | pedersen_ptr: HashBuiltin*,
190 | range_check_ptr
191 | }(owner: felt, operator: felt) -> (isApproved: felt):
192 | let (isApproved) = ERC721_isApprovedForAll(owner, operator)
193 | return (isApproved)
194 | end
195 |
196 | @view
197 | func tokenURI{
198 | syscall_ptr: felt*,
199 | pedersen_ptr: HashBuiltin*,
200 | range_check_ptr
201 | }(tokenId: Uint256) -> (tokenURI: felt):
202 | let (tokenURI) = ERC721_tokenURI(tokenId)
203 | return (tokenURI)
204 | end
205 |
206 | @view
207 | func contractURI{
208 | syscall_ptr: felt*,
209 | pedersen_ptr: HashBuiltin*,
210 | range_check_ptr
211 | }() -> (owner: felt):
212 | let (uri) = contract_uri()
213 | return (uri)
214 | end
215 |
216 | @view
217 | func isInvestor{
218 | syscall_ptr: felt*,
219 | pedersen_ptr: HashBuiltin*,
220 | range_check_ptr
221 | }(token_id: Uint256) -> (res: felt):
222 | let (res) = investor.read(token_id)
223 | return (res)
224 | end
225 |
226 | @view
227 | func paused{
228 | syscall_ptr: felt*,
229 | pedersen_ptr: HashBuiltin*,
230 | range_check_ptr
231 | }() -> (paused: felt):
232 | let (paused) = Pausable.is_paused()
233 | return (paused)
234 | end
235 |
236 | @view
237 | func hasRole{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}(
238 | role : felt, account : felt
239 | ) -> (res : felt):
240 | let (res) = AccessControl.has_role(role, account)
241 | return (res)
242 | end
243 |
244 | @view
245 | func getRoleAdmin{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}(
246 | role : felt
247 | ) -> (role_admin : felt):
248 | let (role_admin) = AccessControl.get_role_admin(role)
249 | return (role_admin)
250 | end
251 |
252 | #
253 | # Externals
254 | #
255 |
256 | @external
257 | func setContractURI{
258 | syscall_ptr: felt*,
259 | pedersen_ptr: HashBuiltin*,
260 | range_check_ptr
261 | }(uri: felt):
262 | AccessControl.only_role(DEFAULT_ADMIN_ROLE)
263 | contract_uri.write(uri)
264 | return ()
265 | end
266 |
267 | @external
268 | func setMerkleRoot{
269 | syscall_ptr: felt*,
270 | pedersen_ptr: HashBuiltin*,
271 | range_check_ptr
272 | }(root: felt):
273 | AccessControl.only_role(INVITER_ROLE)
274 | merkle_root.write(root)
275 | return ()
276 | end
277 |
278 | @external
279 | func setupGovernor{
280 | syscall_ptr: felt*,
281 | pedersen_ptr: HashBuiltin*,
282 | range_check_ptr
283 | }(
284 | governor_addr: felt,
285 | treasury_addr: felt,
286 | share_token_addr: felt,
287 | share_governor_addr: felt
288 | ):
289 | AccessControl.only_role(DEFAULT_ADMIN_ROLE)
290 | contracts_addresses.write(ContractAddressType.treasury, treasury_addr)
291 | contracts_addresses.write(ContractAddressType.governor, governor_addr)
292 | contracts_addresses.write(ContractAddressType.share_token, share_token_addr)
293 | contracts_addresses.write(ContractAddressType.share_governor, share_governor_addr)
294 | return ()
295 | end
296 |
297 | @external
298 | func approve{
299 | syscall_ptr: felt*,
300 | pedersen_ptr: HashBuiltin*,
301 | range_check_ptr
302 | }(to: felt, tokenId: Uint256):
303 | Pausable.assert_not_paused()
304 | ERC721_approve(to, tokenId)
305 | return ()
306 | end
307 |
308 | @external
309 | func setApprovalForAll{
310 | syscall_ptr: felt*,
311 | pedersen_ptr: HashBuiltin*,
312 | range_check_ptr
313 | }(operator: felt, approved: felt):
314 | Pausable.assert_not_paused()
315 | ERC721_setApprovalForAll(operator, approved)
316 | return ()
317 | end
318 |
319 | @external
320 | func transferFrom{
321 | syscall_ptr: felt*,
322 | pedersen_ptr: HashBuiltin*,
323 | range_check_ptr
324 | }(from_: felt, to: felt, tokenId: Uint256):
325 | Pausable.assert_not_paused()
326 | ERC721_Enumerable_transferFrom(from_, to, tokenId)
327 | return ()
328 | end
329 |
330 | @external
331 | func safeTransferFrom{
332 | syscall_ptr: felt*,
333 | pedersen_ptr: HashBuiltin*,
334 | range_check_ptr
335 | }(from_: felt, to: felt, tokenId: Uint256, data_len: felt, data: felt*):
336 | Pausable.assert_not_paused()
337 | ERC721_Enumerable_safeTransferFrom(from_, to, tokenId, data_len, data)
338 | return ()
339 | end
340 |
341 | @external
342 | func pause{
343 | syscall_ptr: felt*,
344 | pedersen_ptr: HashBuiltin*,
345 | range_check_ptr
346 | }():
347 | AccessControl.only_role(DEFAULT_ADMIN_ROLE)
348 | Pausable._pause()
349 | return ()
350 | end
351 |
352 | @external
353 | func unpause{
354 | syscall_ptr: felt*,
355 | pedersen_ptr: HashBuiltin*,
356 | range_check_ptr
357 | }():
358 | AccessControl.only_role(DEFAULT_ADMIN_ROLE)
359 | Pausable._unpause()
360 | return ()
361 | end
362 |
363 | @external
364 | func burn{
365 | syscall_ptr: felt*,
366 | pedersen_ptr: HashBuiltin*,
367 | range_check_ptr
368 | }(tokenId: Uint256):
369 | Pausable.assert_not_paused()
370 | ERC721_only_token_owner(tokenId)
371 | ERC721_Enumerable_burn(tokenId)
372 | return ()
373 | end
374 |
375 | @external
376 | func mint{
377 | pedersen_ptr: HashBuiltin*,
378 | syscall_ptr: felt*,
379 | range_check_ptr
380 | }(
381 | proof_len: felt,
382 | proof: felt*
383 | token_id: Uint256
384 | ):
385 | alloc_locals
386 |
387 | Pausable.assert_not_paused()
388 |
389 | let (sender) = get_caller_address()
390 | let local amount = Uint256(0, 1)
391 | let (amount_hash) = hash2{hash_ptr=pedersen_ptr}(amount.low, amount.high)
392 | let (leaf) = hash2{hash_ptr=pedersen_ptr}(sender, amount_hash)
393 |
394 | let (local root) = merkle_root.read()
395 | let (proof_valid) = merkle_verify(leaf, root, proof_len, proof)
396 |
397 | assert proof_valid = 1
398 |
399 | ERC721_Enumerable_mint(sender, tokenId)
400 | return ()
401 | end
402 |
403 | @external
404 | func setTokenURI{
405 | pedersen_ptr: HashBuiltin*,
406 | syscall_ptr: felt*,
407 | range_check_ptr
408 | }(tokenId: Uint256, tokenURI: felt):
409 | AccessControl.only_role(DEFAULT_ADMIN_ROLE)
410 | ERC721_setTokenURI(tokenId, tokenURI)
411 | return ()
412 | end
413 |
414 | #
415 | # Access control related functions
416 | #
417 |
418 | @external
419 | func grantRole{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}(
420 | role : felt,
421 | account : felt
422 | ):
423 | AccessControl.grant_role(role, account)
424 | return ()
425 | end
426 |
427 | @external
428 | func revokeRole{syscall_ptr : felt*, pedersen_ptr : HashBuiltin*, range_check_ptr}(
429 | role : felt,
430 | account : felt
431 | ):
432 | AccessControl.revoke_role(role, account)
433 | return ()
434 | end
435 |
--------------------------------------------------------------------------------