Skip to content

Commit

Permalink
Add events based on casper-events-standard crate.
Browse files Browse the repository at this point in the history
  • Loading branch information
zie1ony committed Jan 31, 2023
1 parent 6ead2fe commit 2671e75
Show file tree
Hide file tree
Showing 5 changed files with 255 additions and 12 deletions.
1 change: 1 addition & 0 deletions contract/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ casper-types = "1.4.5"
serde = { version = "1", features = ["derive", "alloc"], default-features = false }
base16 = { version = "0.2", default-features = false, features = ["alloc"] }
casper-serde-json-wasm = { git = "https://github.com/darthsiroftardis/casper-serde-json-wasm", branch = "casper-no-std"}
casper-event-standard = "0.1.0"

[[bin]]
name = "contract"
Expand Down
122 changes: 122 additions & 0 deletions contract/src/events.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
use alloc::{string::String, vec::Vec};
use casper_event_standard::Event;
use casper_types::Key;

use crate::modalities::TokenIdentifier;

#[derive(Event)]
pub struct Mint {
recipient: Key,
token_id: TokenIdentifier,
data: String,
}

impl Mint {
pub fn new(recipient: Key, token_id: TokenIdentifier, data: String) -> Self {
Self {
recipient,
token_id,
data
}
}
}

#[derive(Event)]
pub struct Burn {
owner: Key,
token_id: TokenIdentifier,
}

impl Burn {
pub fn new(owner: Key, token_id: TokenIdentifier) -> Self {
Self { owner, token_id }
}
}

#[derive(Event)]
pub struct Approval {
owner: Key,
operator: Key,
token_id: TokenIdentifier,
}

impl Approval {
pub fn new(owner: Key, operator: Key, token_id: TokenIdentifier) -> Self {
Self {
owner,
operator,
token_id,
}
}
}

#[derive(Event)]
pub struct ApprovalForAll {
owner: Key,
operator: Option<Key>,
token_ids: Vec<TokenIdentifier>,
}

impl ApprovalForAll {
pub fn new(owner: Key, operator: Option<Key>, token_ids: Vec<TokenIdentifier>) -> Self {
Self {
owner,
operator,
token_ids,
}
}
}

#[derive(Event)]
pub struct Transfer {
owner: Key,
operator: Option<Key>,
recipient: Key,
token_id: TokenIdentifier,
}

impl Transfer {
pub fn new(
owner: Key,
operator: Option<Key>,
recipient: Key,
token_id: TokenIdentifier,
) -> Self {
Self {
owner,
operator,
recipient,
token_id,
}
}
}

#[derive(Event)]
pub struct MetadataUpdated {
token_id: TokenIdentifier,
data: String,
}

impl MetadataUpdated {
pub fn new(token_id: TokenIdentifier, data: String) -> Self {
Self { token_id, data }
}
}

#[derive(Event)]
pub struct VariablesSet {}

impl VariablesSet {
pub fn new() -> Self {
Self {}
}
}

#[derive(Event)]
pub struct Migration {}

impl Migration {
pub fn new() -> Self {
Self {}
}
}
56 changes: 51 additions & 5 deletions contract/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ compile_error!("target arch should be wasm32: compile with '--target wasm32-unkn

mod constants;
mod error;
mod events;
mod metadata;
mod modalities;
mod utils;
Expand All @@ -20,6 +21,9 @@ use alloc::{
vec::Vec,
};
use core::convert::TryInto;
use events::{
Approval, ApprovalForAll, Burn, MetadataUpdated, Migration, Mint, Transfer, VariablesSet,
};

use casper_types::{
contracts::NamedKeys, runtime_args, CLType, CLValue, ContractHash, ContractPackageHash,
Expand Down Expand Up @@ -348,6 +352,9 @@ pub extern "C" fn init() {
runtime::put_key(PAGE_LIMIT, storage::new_uref(page_table_width).into());
}
runtime::put_key(MIGRATION_FLAG, storage::new_uref(true).into());

// Initialize events structures.
utils::init_events();
}

// set_variables allows the user to set any variable or any combination of variables simultaneously.
Expand Down Expand Up @@ -402,6 +409,9 @@ pub extern "C" fn set_variables() {
WhitelistMode::Locked => runtime::revert(NFTCoreError::InvalidWhitelistMode),
}
}

// Emit VariablesSet event.
casper_event_standard::emit(VariablesSet::new());
}

// Mints a new token. Minting will fail if allow_minting is set to false.
Expand Down Expand Up @@ -539,7 +549,7 @@ pub extern "C" fn mint() {
utils::upsert_dictionary_value_from_key(
&metadata::get_metadata_dictionary_name(&metadata_kind),
&token_identifier.get_dictionary_item_key(),
metadata,
metadata.clone(),
);

let owned_tokens_item_key = utils::get_owned_tokens_dictionary_item_key(token_owner_key);
Expand Down Expand Up @@ -569,6 +579,9 @@ pub extern "C" fn mint() {
);
storage::write(number_of_minted_tokens_uref, minted_tokens_count + 1u64);

// Emit Mint event.
casper_event_standard::emit(Mint::new(token_owner_key, token_identifier.clone(), metadata));

if let OwnerReverseLookupMode::Complete = utils::get_reporting_mode() {
if (NFTIdentifierMode::Hash == identifier_mode)
&& utils::should_migrate_token_hashes(token_owner_key)
Expand Down Expand Up @@ -696,6 +709,9 @@ pub extern "C" fn burn() {
};

utils::upsert_dictionary_value_from_key(TOKEN_COUNTS, &owned_tokens_item_key, updated_balance);

// Emit Burn event.
casper_event_standard::emit(Burn::new(token_owner, token_identifier));
}

// approve marks a token as approved for transfer by an account
Expand Down Expand Up @@ -778,6 +794,9 @@ pub extern "C" fn approve() {
&token_identifier_dictionary_key,
Some(operator),
);

// Emit Approval event.
casper_event_standard::emit(Approval::new(token_owner_key, operator, token_identifier));
}

// This is an extremely gas intensive operation. DO NOT invoke this
Expand All @@ -801,6 +820,8 @@ pub extern "C" fn set_approval_for_all() {
)
.unwrap_or_revert();

let token_owner: Key = utils::get_verified_caller().unwrap_or_revert();

let operator = utils::get_named_arg_with_user_errors::<Key>(
ARG_OPERATOR,
NFTCoreError::MissingOperator,
Expand All @@ -820,14 +841,17 @@ pub extern "C" fn set_approval_for_all() {
};

// Depending on approve_all we either approve all or disapprove all.
for token_id in owned_tokens {
let operator = if approve_all { Some(operator) } else { None };
for token_id in &owned_tokens {
// We assume a burned token cannot be approved
if utils::is_token_burned(&token_id) {
if utils::is_token_burned(token_id) {
runtime::revert(NFTCoreError::PreviouslyBurntToken)
}
let operator = if approve_all { Some(operator) } else { None };
storage::dictionary_put(operator_uref, &token_id.get_dictionary_item_key(), operator);
}

// Emit ApprovalForAll event.
casper_event_standard::emit(ApprovalForAll::new(token_owner, operator, owned_tokens));
}

// Transfers token from token_owner to specified account. Transfer will go through if caller is
Expand Down Expand Up @@ -976,6 +1000,19 @@ pub extern "C" fn transfer() {
Option::<Key>::None,
);

// Emit Transfer event.
let operator = if caller == token_owner_key {
None
} else {
Some(caller)
};
casper_event_standard::emit(Transfer::new(
token_owner_key,
operator,
target_owner_key,
token_identifier.clone(),
));

if let OwnerReverseLookupMode::Complete = utils::get_reporting_mode() {
// Update to_account owned_tokens. Revert if owned_tokens list is not found
let token_number = utils::get_token_index(&token_identifier);
Expand Down Expand Up @@ -1252,8 +1289,11 @@ pub extern "C" fn set_token_metadata() {
utils::upsert_dictionary_value_from_key(
&metadata::get_metadata_dictionary_name(&metadata_kind),
&token_identifier.get_dictionary_item_key(),
updated_metadata,
updated_metadata.clone(),
);

// Emit MetadataUpdate event.
casper_event_standard::emit(MetadataUpdated::new(token_identifier, updated_metadata));
}

#[no_mangle]
Expand Down Expand Up @@ -1340,6 +1380,12 @@ pub extern "C" fn migrate() {
);
}
}

// Initialize events structures.
utils::init_events();

// Emit Migration event.
casper_event_standard::emit(Migration::new());
}

#[no_mangle]
Expand Down
70 changes: 63 additions & 7 deletions contract/src/modalities.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
use alloc::string::{String, ToString};
use alloc::{
string::{String, ToString},
vec::Vec,
};
use casper_contract::unwrap_or_revert::UnwrapOrRevert;
use casper_types::{
bytesrepr::{self, FromBytes, ToBytes, U64_SERIALIZED_LENGTH, U8_SERIALIZED_LENGTH},
CLTyped,
};

use core::convert::TryFrom;

Expand Down Expand Up @@ -174,42 +182,90 @@ impl TryFrom<u8> for MetadataMutability {
}

#[derive(PartialEq, Eq, Clone)]
pub(crate) enum TokenIdentifier {
pub enum TokenIdentifier {
Index(u64),
Hash(String),
}

impl TokenIdentifier {
pub(crate) fn new_index(index: u64) -> Self {
pub fn new_index(index: u64) -> Self {
TokenIdentifier::Index(index)
}

pub(crate) fn new_hash(hash: String) -> Self {
pub fn new_hash(hash: String) -> Self {
TokenIdentifier::Hash(hash)
}

pub(crate) fn get_index(&self) -> Option<u64> {
pub fn get_index(&self) -> Option<u64> {
if let Self::Index(index) = self {
return Some(*index);
}
None
}

pub(crate) fn get_hash(self) -> Option<String> {
pub fn get_hash(self) -> Option<String> {
if let Self::Hash(hash) = self {
return Some(hash);
}
None
}

pub(crate) fn get_dictionary_item_key(&self) -> String {
pub fn get_dictionary_item_key(&self) -> String {
match self {
TokenIdentifier::Index(token_index) => token_index.to_string(),
TokenIdentifier::Hash(hash) => hash.clone(),
}
}
}

impl ToBytes for TokenIdentifier {
fn to_bytes(&self) -> Result<Vec<u8>, bytesrepr::Error> {
let mut bytes = Vec::new();
match self {
TokenIdentifier::Index(index) => {
bytes.push(NFTIdentifierMode::Ordinal as u8);
bytes.append(&mut index.to_bytes()?);
}
TokenIdentifier::Hash(string) => {
bytes.push(NFTIdentifierMode::Hash as u8);
bytes.append(&mut string.to_bytes()?);
}
};
Ok(bytes)
}

fn serialized_length(&self) -> usize {
U8_SERIALIZED_LENGTH
+ match self {
TokenIdentifier::Index(_) => U64_SERIALIZED_LENGTH,
TokenIdentifier::Hash(string) => string.serialized_length(),
}
}
}

impl FromBytes for TokenIdentifier {
fn from_bytes(bytes: &[u8]) -> Result<(Self, &[u8]), bytesrepr::Error> {
let (identifier_mode, bytes) = u8::from_bytes(bytes)?;
let identifier_mode = NFTIdentifierMode::try_from(identifier_mode).unwrap_or_revert();
match identifier_mode {
NFTIdentifierMode::Ordinal => {
let (index, bytes) = u64::from_bytes(bytes)?;
Ok((TokenIdentifier::Index(index), bytes))
}
NFTIdentifierMode::Hash => {
let (string, bytes) = String::from_bytes(bytes)?;
Ok((TokenIdentifier::Hash(string), bytes))
}
}
}
}

impl CLTyped for TokenIdentifier {
fn cl_type() -> casper_types::CLType {
casper_types::CLType::Any
}
}

#[repr(u8)]
pub enum BurnMode {
Burnable = 0,
Expand Down
Loading

0 comments on commit 2671e75

Please sign in to comment.