Ejara smart contract implementation for tokenized bonds using the ERC-1155 standard, built with Cairo 1.0.
Ejara tokenized bonds aim to fractionalize bonds into the smallest units for enhanced accessibility. This smart contract provides a secure and efficient way to manage tokenized bonds on StarkNet.
- Multiple token types in a single contract
- Batch operations support
Span<felt252>
data argument for transfers- Interface ID validation
Although Starknet is not EVM compatible, this implementation aims to be as close as possible to the ERC1155 standard but some differences can still be found, such as:
- The optional
data
argument in bothsafe_transfer_from
andsafe_batch_transfer_from
is implemented asSpan<felt252>
. IERC1155Receiver
compliant contracts must implementSRC5
and register theIERC1155Receiver
interface ID.IERC1155Receiver::on_erc1155_received
must return that interface ID on success.
- Owner-based administration
- Minter management
- Pause/unpause control
- URI and upgrade management
- Multi-minter system
- Dynamic minter addition/removal
- Zero-address validation
- Pausable operations
- Emergency pause mechanism
- Owner-restricted controls
- Upgradeable architecture
- Bug fixes and feature additions
- Owner-controlled upgrades
- Minting
- Single and batch minting
- Authorized minter restrictions
- URI Management
- Configurable base URI
- snake_case and camelCase support
- Event System
- Minter management events
- Token operation tracking
- Administrative action logging
Built with OpenZeppelin components:
- ERC1155 implementation
- Ownable access control
- Pausable functionality
- SRC5 introspection
- Upgradeable pattern
is_contract_paused
: Global pause statetoken_metadata
: Token ID to metadata mappingminter_tokens_metadata
: Minter token trackingminter_exist
: Minter registry
- Contract Management
pause()
: Halt operationsresume()
: Resume operations
- Token Operations
mint(account, token_id, value, data)
: Token creationburn(account, token_id, value)
: Token destruction
- Transfer Controls
resume_inter_transfer(uint token_id)
: Enable transferspause_inter_transfer(uint token_id)
: Disable transfers
- Minter Administration
add_minter(address minter)
: Register minterremove_minter(address minter)
: Deregister minterreplace_minter(address old_minter, address new_minter)
: Update minter
Storage Vector Clearing
The contract uses a storage mapping of vectors (Map<ContractAddress, Vec<u256>>
) to track minter tokens:
In Cairo, there is currently no way to completely clear or remove a Vec within a Map in storage. This affects the replace_minter
function in the following ways:
- When a minter is replaced, their old token vector remains in storage
- This is not a security concern because:
- The old minter's status is set to 0 (
self.minters.entry(old_minter).write(0)
) - All access to minter functions requires the minter status to be 1
- The tokens themselves are properly transferred to the new minter
- The old minter's status is set to 0 (
While the old vectors remain in storage, this doesn't affect the contract's functionality. However, it does mean that over time, "orphaned" vectors might be in storage. This is an accepted limitation of the current Cairo storage model.
-
Install asdf
brew install asdf
-
Verify that asdf is installed
asdf --version
-
Install the asdf Scarb plugin
asdf plugin add scarb
-
Install the latest version of Scarb
asdf install scarb 2.9.2
-
Set a global version for Scarb (need for using scarb init)
asdf global scarb 2.9.2
-
Restart the terminal and verify that Scarb is installed correctly
scarb --version
- Clone the repo
git clone https://github.com/keep-starknet-strange/tokenized-bond.git
- Install dependencies
cd tokenized-bond scarb build
- Run tests
scarb test
-
Set environment variables in .env file
-
Use Starkli to deploy the contract
-
In scripts folder, run the bash script to deploy the contract
For more detailed documentation, please visit our Documentation.
The source code is available on GitHub.