Skip to content

Instantly share code, notes, and snippets.

@codeWhizperer
Created June 16, 2023 11:49
Show Gist options
  • Select an option

  • Save codeWhizperer/7f74bd5c08f45920b701ac350ea5b130 to your computer and use it in GitHub Desktop.

Select an option

Save codeWhizperer/7f74bd5c08f45920b701ac350ea5b130 to your computer and use it in GitHub Desktop.
use starknet::ContractAddress;
////////////////////////
// IERC721 interface
///////////////////////
#[abi]
trait IERC721{
fn name() -> felt252;
fn symbol() -> felt252;
fn token_uri(token_id:u256) -> felt252;
fn balance_of(account:ContractAddress) ->u256;
fn owner_of(token_id:u256) -> ContractAddress;
}
// const IERC165_ID: u32 = 0x01ffc9a7_u32;
// const INVALID_ID: u32 = 0xffffffff_u32;
// const IERC721_ID: u32 = 0x80ac58cd_u32;
// const IERC721_METADATA_ID: u32 = 0x5b5e139f_u32;
const IERC165_ID: u32 = 0x01ffc9a7_u32;
const INVALID_ID: u32 = 0xffffffff_u32;
const IERC721_ID: u32 = 0x80ac58cd_u32;
const IERC721_METADATA_ID: u32 = 0x5b5e139f_u32;
// note: contract did not implement some functionalities such as transfer, approve as token is meant to be soulbound.
#[contract]
mod ERC721{
/////////////////////
// Module Imports
///////////////////
// use erc721::interface::IERC721;
////////////////////
// Others
///////////////////
use starknet::ContractAddress;
use starknet::get_caller_address;
use zeroable::Zeroable;
use option::OptionTrait;
use array::SpanTrait;
use traits::Into;
////////////////////
// state variables
//////////////////
struct Storage{
_name:felt252,
_symbol:felt252,
_creator:ContractAddress,
_event_uri: felt252,
_owners: LegacyMap::<u256, ContractAddress>,
_balances: LegacyMap::<ContractAddress, u256>,
_tokenId:u256,
_hasClaimed:LegacyMap::<ContractAddress, bool>,
_token_uri: LegacyMap::<u256, felt252>,
_current_prezent_amount:u256,
_prezent_mint_limit:u256,
_supported_interfaces:LegacyMap<u32,bool>,
}
#[event]
fn Transfer(from: ContractAddress, to: ContractAddress, token_id: u256) {}
/////////////////////
// IERC721 implementation
////////////////////
impl ERC721Impl of super::IERC721{
fn name() -> felt252{
return _name::read();
}
fn symbol() -> felt252{
return _symbol::read();
}
fn token_uri(token_id:u256) -> felt252{
assert(_exists(token_id), 'ERC721:invalid token ID');
return _token_uri::read(token_id);
}
fn balance_of(account:ContractAddress) -> u256{
assert(!account.is_zero(), 'ERC721:invalid account');
return _balances::read(account);
}
fn owner_of(token_id: u256) -> ContractAddress {
return _owner_of(token_id);
}
}
////////////////
// initialize contract state
//////////////
#[constructor]
fn constructor(name: felt252, symbol: felt252, event_uri:felt252, creator:ContractAddress, _prezent_mint_limit:u256) {
initializer(name, symbol, event_uri, creator, _prezent_mint_limit);
}
////////////////////
// view functions
///////////////////
#[view]
fn eventUri() -> felt252{
return _event_uri::read();
}
#[view]
fn creator() -> ContractAddress{
return _creator::read();
}
#[view]
fn get_claimed_status(account: ContractAddress) -> bool{
return _hasClaimed::read(account);
}
#[view]
fn get_prezent_amount() -> u256{
return _current_prezent_amount::read();
}
#[view]
fn get_prezent_limit() -> u256{
return _prezent_mint_limit::read();
}
#[view]
fn supports_interface(interface_id:u32) -> bool{
return _supported_interfaces::read(interface_id);
}
#[view]
fn name() -> felt252 {
return ERC721Impl::name();
}
#[view]
fn symbol() -> felt252 {
return ERC721Impl::symbol();
}
#[view]
fn token_uri(token_id: u256) -> felt252 {
return ERC721Impl::token_uri(token_id);
}
#[view]
fn balance_of(account: ContractAddress) -> u256 {
return ERC721Impl::balance_of(account);
}
#[view]
fn owner_of(token_id: u256) -> ContractAddress {
return ERC721Impl::owner_of(token_id);
}
////////////////////////
//internal function
///////////////////////
#[internal]
fn _exists(token_id: u256) -> bool {
!_owners::read(token_id).is_zero()
}
#[internal]
fn initializer(name_: felt252, symbol_: felt252, event_uri_:felt252,creator_:ContractAddress, prezent_mint_limit:u256) {
// let caller = get_caller_address();
_name::write(name_);
_symbol::write(symbol_);
_event_uri::write(event_uri_);
_creator::write(creator_);
_prezent_mint_limit::write(prezent_mint_limit);
register_interface(super::IERC721_ID);
register_interface(super::IERC721_METADATA_ID);
}
#[internal]
fn _owner_of(token_id: u256) -> ContractAddress {
let owner = _owners::read(token_id);
match owner.is_zero() {
bool::False(()) => owner,
bool::True(()) => panic_with_felt252('ERC721: invalid token ID')
}
}
#[internal]
fn _mint(to: ContractAddress, token_id: u256) {
assert(!to.is_zero(), 'ERC721: invalid receiver');
assert(!_exists(token_id), 'ERC721: token already minted');
// Update balances
_balances::write(to, _balances::read(to) + 1.into());
// Update token_id owner
_owners::write(token_id, to);
// Emit event
Transfer(Zeroable::zero(), to, token_id);
}
#[internal]
fn _safe_mint(to: ContractAddress, token_id:u256) {
_mint(to, token_id);
}
#[internal]
fn _set_token_uri(token_id: u256, token_uri: felt252) {
assert(_exists(token_id), 'ERC721: invalid token ID');
_token_uri::write(token_id, token_uri)
}
#[internal]
fn register_interface(interface_id: u32) {
assert(interface_id != super::INVALID_ID, 'Invalid id');
_supported_interfaces::write(interface_id, true);
}
#[internal]
fn deregister_interface(interface_id: u32) {
assert(interface_id != super::IERC165_ID, 'Invalid id');
_supported_interfaces::write(interface_id, false);
}
#[external]
fn safemint(to: ContractAddress) {
assert(_current_prezent_amount::read() <= _prezent_mint_limit::read(), 'ERC721: Mint limit reached');
let prev_prezent_amount:u256 = _current_prezent_amount::read();
let prevTokenId:u256 = _tokenId::read();
let token_id:u256 = prevTokenId + 1.into();
let token_uri = _token_uri::read(token_id);
let latest_prezent_amount:u256 = prev_prezent_amount + 1.into();
_safe_mint(to, token_id);
_set_token_uri(token_id, token_uri);
_tokenId::write(token_id);
_current_prezent_amount::write(latest_prezent_amount);
}
#[external]
fn claimPrezent(account:ContractAddress){
// let msgSender = get_caller_address();
assert(!account.is_zero(), 'CALLER_ZERO_ADDRESS');
assert(_hasClaimed::read(account) == false, 'ALREADY CLAIM');
safemint(account);
_hasClaimed::write(account, true);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment