From 72530220581a9effd118369542ce7b42302bfc1f Mon Sep 17 00:00:00 2001 From: Tarrence van As Date: Wed, 9 Aug 2023 11:03:26 -0400 Subject: [PATCH] Update syntax --- crates/dojo-erc/src/erc721/components.cairo | 36 +++++-- crates/dojo-erc/src/erc721/erc721.cairo | 86 +++++---------- crates/dojo-erc/src/erc721/systems.cairo | 109 +++++++++++--------- 3 files changed, 112 insertions(+), 119 deletions(-) diff --git a/crates/dojo-erc/src/erc721/components.cairo b/crates/dojo-erc/src/erc721/components.cairo index 9bc29628a0..6330d4f26b 100644 --- a/crates/dojo-erc/src/erc721/components.cairo +++ b/crates/dojo-erc/src/erc721/components.cairo @@ -1,26 +1,46 @@ use starknet::ContractAddress; #[derive(Component, Copy, Drop, Serde, SerdeLen)] -struct Balances { - amount: felt252, +struct Balance { + #[key] + token: ContractAddress, + #[key] + account: ContractAddress, + amount: felt252, } #[derive(Component, Copy, Drop, Serde, SerdeLen)] -struct Owners { - address: felt252 +struct Owner { + #[key] + token: ContractAddress, + #[key] + token_id: felt252, + address: ContractAddress } #[derive(Component, Copy, Drop, Serde, SerdeLen)] -struct TokenApprovals { - address: felt252, +struct TokenApproval { + #[key] + token: ContractAddress, + #[key] + token_id: felt252, + address: ContractAddress, } #[derive(Component, Copy, Drop, Serde, SerdeLen)] -struct OperatorApprovals { - approved: felt252 +struct OperatorApproval { + #[key] + token: ContractAddress, + #[key] + owner: ContractAddress, + #[key] + operator: ContractAddress, + approved: bool } #[derive(Component, Copy, Drop, Serde, SerdeLen)] struct TokenUri { + #[key] + token_id: felt252, uri: felt252 } diff --git a/crates/dojo-erc/src/erc721/erc721.cairo b/crates/dojo-erc/src/erc721/erc721.cairo index c3bfe4b871..2a72897184 100644 --- a/crates/dojo-erc/src/erc721/erc721.cairo +++ b/crates/dojo-erc/src/erc721/erc721.cairo @@ -6,25 +6,18 @@ mod ERC721 { use traits::{Into, TryInto}; use zeroable::Zeroable; - use dojo::database::query::{ - Query, LiteralIntoQuery, TupleSize1IntoQuery, TupleSize2IntoQuery, IntoPartitioned, - IntoPartitionedQuery - }; - use dojo::world::{IWorldDispatcher, IWorldDispatcherTrait}; - use dojo_erc::erc721::components::{ - Balances, OperatorApprovals, Owners, TokenApprovals, TokenUri - }; + use dojo_erc::erc721::components::{Balance, OperatorApproval, Owner, TokenApproval, TokenUri}; use dojo_erc::erc721::systems::{ erc721_approve, erc721_set_approval_for_all, erc721_transfer_from }; #[storage] struct Storage { - world_address: ContractAddress, - _name: felt252, - _symbol: felt252, - _uri: felt252, + world: IWorldDispatcher, + token_name: felt252, + token_symbol: felt252, + token_uri: felt252, } #[event] @@ -58,53 +51,49 @@ mod ERC721 { #[constructor] fn constructor( - ref self: ContractState, world: ContractAddress, name: felt252, symbol: felt252 + ref self: ContractState, world: IWorldDispatcher, name: felt252, symbol: felt252 ) { - self.world_address.write(world); - self._name.write(name); - self._symbol.write(symbol); + self.world.write(world); + self.token_name.write(name); + self.token_symbol.write(symbol); } #[external(v0)] fn name(self: @ContractState) -> felt252 { - self._name.read() + self.token_name.read() } #[external(v0)] fn symbol(self: @ContractState) -> felt252 { - self._symbol.read() + self.token_symbol.read() } #[external(v0)] fn uri(self: @ContractState) -> felt252 { - self._uri.read() + self.token_uri.read() } #[external(v0)] fn balance_of(self: @ContractState, account: ContractAddress) -> u256 { let token = get_contract_address(); - let query: Query = (token, (account, )).into_partitioned(); - let mut balance_raw = world(self).entity('Balances'.into(), query, 0, 0); - let balance = serde::Serde::::deserialize(ref balance_raw).unwrap(); + let balance = get !(self.world.read(), (token, account), Balance); balance.amount.into() } #[external(v0)] fn owner_of(self: @ContractState, token_id: u256) -> ContractAddress { let token = get_contract_address(); - let query: Query = (token, (u256_into_felt252(token_id), )).into_partitioned(); - let mut owner_raw = world(self).entity('Owners'.into(), query, 0, 0); - let owner = serde::Serde::::deserialize(ref owner_raw).unwrap(); - owner.address.try_into().unwrap() + let owner = get !(self.world.read(), (token, u256_into_felt252(token_id)), Owner); + owner.address } #[external(v0)] fn get_approved(self: @ContractState, token_id: u256) -> ContractAddress { let token = get_contract_address(); - let query: Query = (token, (u256_into_felt252(token_id), )).into_partitioned(); - let mut approved_raw = world(self).entity('TokenApprovals'.into(), query, 0, 0); - let approved = serde::Serde::::deserialize(ref approved_raw).unwrap(); - approved.address.try_into().unwrap() + let approved = get !( + self.world.read(), (token, u256_into_felt252(token_id)), TokenApproval + ); + approved.address } #[external(v0)] @@ -112,10 +101,8 @@ mod ERC721 { self: @ContractState, owner: ContractAddress, operator: ContractAddress ) -> bool { let token = get_contract_address(); - let query: Query = (token, (owner, operator)).into_partitioned(); - let mut result_raw = world(self).entity('OperatorApprovals'.into(), query, 0, 0); - let result = serde::Serde::::deserialize(ref result_raw).unwrap(); - felt252_into_bool(result.approved) + let result = get !(self.world.read(), (token, owner, operator), OperatorApproval); + result.approved } #[external(v0)] @@ -124,7 +111,7 @@ mod ERC721 { let owner = owner_of(@self, token_id); calldata.append(u256_into_felt252(token_id)); calldata.append(to.into()); - world(@self).execute('erc721_approve'.into(), calldata.span()); + self.world.read().execute('erc721_approve'.into(), calldata.span()); let owner = owner_of(@self, token_id); self.emit(Approval { owner, to, token_id }); } @@ -136,8 +123,8 @@ mod ERC721 { assert(owner != operator, 'ERC721: approval to owner'); calldata.append(owner.into()); calldata.append(operator.into()); - calldata.append(bool_into_felt252(approved)); - world(@self).execute('erc721_set_approval_for_all'.into(), calldata.span()); + calldata.append(approved.into()); + self.world.read().execute('erc721_set_approval_for_all'.into(), calldata.span()); self.emit(ApprovalForAll { owner, operator, approved }); } @@ -150,35 +137,12 @@ mod ERC721 { calldata.append(from.into()); calldata.append(to.into()); calldata.append(u256_into_felt252(token_id)); - world(@self).execute('erc721_transfer_from'.into(), calldata.span()); + self.world.read().execute('erc721_transfer_from'.into(), calldata.span()); self.emit(Transfer { from, to, token_id }); } - // NOTE: temporary, until we have inline commands outside of systems - fn world(self: @ContractState) -> IWorldDispatcher { - IWorldDispatcher { contract_address: self.world_address.read() } - } - fn u256_into_felt252(val: u256) -> felt252 { // temporary, until TryInto of this is in corelib val.low.into() + val.high.into() * 0x100000000000000000000000000000000 } - - - fn bool_into_felt252(_bool: bool) -> felt252 { - if _bool == true { - return 1; - } else { - return 0; - } - } - - fn felt252_into_bool(bool_felt252: felt252) -> bool { - if bool_felt252 == 1 { - true - } else { - false - } - } } - diff --git a/crates/dojo-erc/src/erc721/systems.cairo b/crates/dojo-erc/src/erc721/systems.cairo index 870f063af7..04366d2e80 100644 --- a/crates/dojo-erc/src/erc721/systems.cairo +++ b/crates/dojo-erc/src/erc721/systems.cairo @@ -1,25 +1,18 @@ #[system] mod erc721_approve { - use starknet::{ContractAddress, get_caller_address}; + use starknet::ContractAddress; use traits::Into; + use dojo::world::Context; - use dojo_erc::erc721::components::{Owners, TokenApprovals, OperatorApprovals}; + use dojo_erc::erc721::components::{Owner, TokenApproval, OperatorApproval}; use dojo_erc::erc721::erc721::ERC721; - fn execute(ctx: Context, token_id: felt252, operator: felt252) { - let owner = get!(ctx.world, token_id.into(), Owners); - let is_approved_for_all = get!( - ctx.world, (owner.address, operator).into_partitioned(), OperatorApprovals - ); - assert( - owner.address == operator || ERC721::felt252_into_bool(is_approved_for_all.approved), - 'ERC721: unauthorized caller' - ); - set!( - ctx.world, - (token_id, operator).into_partitioned(), - (TokenApprovals { address: operator }) - ) + fn execute(ctx: Context, token: ContractAddress, token_id: felt252, operator: ContractAddress) { + // TODO: operator + token can not be used defined + let owner = get !(ctx.world, (token, token_id), Owner); + let approval = get !(ctx.world, (token, owner.address, operator), OperatorApproval); + assert(owner.address == operator || approval.approved, 'ERC721: unauthorized caller'); + set !(ctx.world, TokenApproval { token, token_id, address: operator }); } } @@ -29,75 +22,91 @@ mod erc721_set_approval_for_all { use traits::Into; use dojo::world::Context; - use dojo_erc::erc721::components::OperatorApprovals; + use dojo_erc::erc721::components::OperatorApproval; - fn execute(ctx: Context, owner: felt252, operator: felt252, _approved: felt252) { + fn execute( + ctx: Context, + token: ContractAddress, + owner: ContractAddress, + operator: ContractAddress, + approved: bool + ) { assert(owner != operator, 'ERC721: self approval'); - set!( - ctx.world, - (owner, operator).into_partitioned(), - (OperatorApprovals { approved: _approved }) - ) + set !(ctx.world, OperatorApproval { token, owner, operator, approved }); } } #[system] mod erc721_transfer_from { + use starknet::ContractAddress; use traits::Into; use zeroable::Zeroable; use dojo::world::Context; - use dojo_erc::erc721::components::{Balances, TokenApprovals, OperatorApprovals, Owners}; + use dojo_erc::erc721::components::{Balance, TokenApproval, OperatorApproval, Owner}; use dojo_erc::erc721::erc721::ERC721; - fn execute(ctx: Context, from: felt252, to: felt252, token_id: felt252) { - let owner = get!(ctx.world, token_id.into(), Owners); - let is_approved_for_all = get!( - ctx.world, (owner.address, from).into_partitioned(), OperatorApprovals - ); - assert( - owner.address == from || ERC721::felt252_into_bool(is_approved_for_all.approved), - 'ERC721: unauthorized caller' - ); + fn execute( + ctx: Context, + token: ContractAddress, + from: ContractAddress, + to: ContractAddress, + token_id: felt252 + ) { + let owner = get !(ctx.world, (token, token_id), Owner); + let is_approved = get !(ctx.world, (token, owner.address, from), OperatorApproval); + assert(owner.address == from || is_approved.approved, 'ERC721: unauthorized caller'); assert(!to.is_zero(), 'ERC721: invalid receiver'); assert(from == owner.address, 'ERC721: wrong sender'); - set!(ctx.world, (token_id).into(), (TokenApprovals { address: Zeroable::zero() })) - let from_balance = get!(ctx.world, from.into(), Balances); - let to_balance = get!(ctx.world, to.into(), Balances); - set!(ctx.world, (from).into(), (Balances { amount: from_balance.amount - 1 })) - set!(ctx.world, (to).into(), (Balances { amount: to_balance.amount + 1 })) + + set !(ctx.world, TokenApproval { token, token_id, address: Zeroable::zero() }); + + let mut from_balance = get !(ctx.world, (token, from), Balance); + from_balance.amount -= 1; + set !(ctx.world, (from_balance)); + + let mut to_balance = get !(ctx.world, (token, to), Balance); + to_balance.amount += 1; + set !(ctx.world, (to_balance)); } } #[system] mod erc721_mint { + use starknet::ContractAddress; use traits::Into; use zeroable::Zeroable; + use dojo::world::Context; - use dojo_erc::erc721::components::{Balances, Owners}; + use dojo_erc::erc721::components::{Balance, Owner}; - fn execute(ctx: Context, token_id: felt252, recipient: felt252) { + fn execute( + ctx: Context, token: ContractAddress, token_id: felt252, recipient: ContractAddress + ) { assert(recipient.is_non_zero(), 'ERC721: mint to 0'); // increase token supply - let balance = get!(ctx.world, recipient.into(), Balances); - set!(ctx.world, recipient.into(), (Balances { amount: balance.amount + 1 })); - - set!(ctx.world, token_id.into(), (Owners { address: recipient })); + let mut balance = get !(ctx.world, (token, recipient), Balance); + balance.amount += 1; + set !(ctx.world, (balance)); + set !(ctx.world, Owner { token, token_id, address: recipient }); } } #[system] mod erc721_burn { + use starknet::ContractAddress; use traits::Into; use zeroable::Zeroable; + use dojo::world::Context; - use dojo_erc::erc721::components::{Balances, Owners}; + use dojo_erc::erc721::components::{Balance, Owner}; - fn execute(ctx: Context, token_id: felt252) { - let owner = get!(ctx.world, token_id.into(), Owners); - let balance = get!(ctx.world, owner.address.into(), Balances); - set!(ctx.world, owner.address.into(), (Balances { amount: balance.amount - 1 })); - set!(ctx.world, token_id.into(), (Owners { address: Zeroable::zero() })); + fn execute(ctx: Context, token: ContractAddress, token_id: felt252) { + let owner = get !(ctx.world, (token, token_id), Owner); + let mut balance = get !(ctx.world, (token, owner.address), Balance); + balance.amount -= 1; + set !(ctx.world, (balance)); + set !(ctx.world, Owner { token, token_id, address: Zeroable::zero() }); } }