Skip to content

Commit

Permalink
add tests for reward deposits
Browse files Browse the repository at this point in the history
  • Loading branch information
TAdev0 committed Apr 14, 2024
1 parent b784dca commit fdceb3f
Show file tree
Hide file tree
Showing 7 changed files with 140 additions and 21 deletions.
5 changes: 5 additions & 0 deletions onchain/src/lib.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,12 @@ mod nfts {
};
}

mod mocks {
pub mod erc20_mock;
}

#[cfg(test)]
mod tests {
mod art_peace;
mod utils;
}
1 change: 1 addition & 0 deletions onchain/src/mocks.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod erc20_mock;
42 changes: 42 additions & 0 deletions onchain/src/mocks/erc20_mock.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//
// https://github.com/OpenZeppelin/cairo-contracts/blob/main/src/tests/mocks/erc20_mocks.cairo
//

#[starknet::contract]
pub mod SnakeERC20Mock {
use openzeppelin::token::erc20::ERC20Component;
use starknet::ContractAddress;

component!(path: ERC20Component, storage: erc20, event: ERC20Event);

#[abi(embed_v0)]
impl ERC20Impl = ERC20Component::ERC20Impl<ContractState>;
#[abi(embed_v0)]
impl ERC20MetadataImpl = ERC20Component::ERC20MetadataImpl<ContractState>;
impl InternalImpl = ERC20Component::InternalImpl<ContractState>;

#[storage]
struct Storage {
#[substorage(v0)]
erc20: ERC20Component::Storage
}

#[event]
#[derive(Drop, starknet::Event)]
enum Event {
#[flat]
ERC20Event: ERC20Component::Event
}

#[constructor]
fn constructor(
ref self: ContractState,
name: ByteArray,
symbol: ByteArray,
initial_supply: u256,
recipient: ContractAddress
) {
self.erc20.initializer(name, symbol);
self.erc20._mint(recipient, initial_supply);
}
}
16 changes: 11 additions & 5 deletions onchain/src/templates/component.cairo
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
#[starknet::component]
pub mod TemplateStoreComponent {
use core::num::traits::Zero;
use starknet::ContractAddress;

use art_peace::templates::interfaces::{ITemplateStore, TemplateMetadata};
use openzeppelin::token::erc20::interface::{IERC20Dispatcher, IERC20DispatcherTrait};

#[storage]
struct Storage {
Expand Down Expand Up @@ -54,15 +58,17 @@ pub mod TemplateStoreComponent {

// TODO: Return idx of the template?
fn add_template(
ref self: ComponentState<TContractState>,
template_metadata: TemplateMetadata,
reward_token: ContractAddress,
reward_amount: u256
ref self: ComponentState<TContractState>, template_metadata: TemplateMetadata,
) {
let template_id = self.templates_count.read();
self.templates.write(template_id, template_metadata);
self.templates_count.write(template_id + 1);
self._deposit(starknet::get_caller_address(), reward_token, reward_amount);
self
._deposit(
starknet::get_caller_address(),
template_metadata.reward_token,
template_metadata.reward
);
self.emit(TemplateAdded { id: template_id, metadata: template_metadata });
}

Expand Down
7 changes: 1 addition & 6 deletions onchain/src/templates/interfaces.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,7 @@ pub trait ITemplateStore<TContractState> {
fn get_template_hash(self: @TContractState, template_id: u32) -> felt252;
// Stores a new template image into the contract state w/ metadata.
// If the reward/token are set, then the contract escrows the reward for the template.
fn add_template(
ref self: TContractState,
template_metadata: TemplateMetadata,
reward_token: ContractAddress,
reward_amount: u256
);
fn add_template(ref self: TContractState, template_metadata: TemplateMetadata);
// Returns whether the template is complete.
fn is_template_complete(self: @TContractState, template_id: u32) -> bool;
}
Expand Down
67 changes: 57 additions & 10 deletions onchain/src/tests/art_peace.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,18 @@ use art_peace::templates::interfaces::{
ITemplateStoreDispatcher, ITemplateStoreDispatcherTrait, ITemplateVerifierDispatcher,
ITemplateVerifierDispatcherTrait, TemplateMetadata
};
use art_peace::mocks::erc20_mock::SnakeERC20Mock;
use art_peace::tests::utils;

use core::poseidon::PoseidonTrait;
use core::hash::{HashStateTrait, HashStateExTrait};

use openzeppelin::token::erc20::interface::{IERC20, IERC20Dispatcher, IERC20DispatcherTrait};
use openzeppelin::token::erc721::interface::{IERC721Dispatcher, IERC721DispatcherTrait};

use snforge_std as snf;
use snforge_std::{CheatTarget, ContractClassTrait};
use starknet::{ContractAddress, contract_address_const};
use starknet::{ContractAddress, contract_address_const, get_contract_address};

const DAY_IN_SECONDS: u64 = consteval_int!(60 * 60 * 24);
const WIDTH: u128 = 100;
Expand All @@ -27,6 +31,10 @@ fn ART_PEACE_CONTRACT() -> ContractAddress {
contract_address_const::<'ArtPeace'>()
}

fn ERC20_MOCK_CONTRACT() -> ContractAddress {
contract_address_const::<'erc20mock'>()
}

fn EMPTY_CALLDATA() -> Span<felt252> {
array![].span()
}
Expand Down Expand Up @@ -82,6 +90,24 @@ fn deploy_contract() -> ContractAddress {
contract_addr
}

fn deploy_erc20_mock() -> ContractAddress {
let contract = snf::declare("SnakeERC20Mock");
let name: ByteArray = "erc20 mock";
let symbol: ByteArray = "ERC20MOCK";
let initial_supply: u256 = 10 * utils::pow_256(10, 18);
let recipient: ContractAddress = get_contract_address();

let mut calldata: Array<felt252> = array![];
Serde::serialize(@name, ref calldata);
Serde::serialize(@symbol, ref calldata);
Serde::serialize(@initial_supply, ref calldata);
Serde::serialize(@recipient, ref calldata);

let contract_addr = contract.deploy_at(@calldata, ERC20_MOCK_CONTRACT()).unwrap();

contract_addr
}

fn deploy_with_quests_contract(
daily_quests: Span<ContractAddress>, main_quests: Span<ContractAddress>
) -> ContractAddress {
Expand Down Expand Up @@ -368,21 +394,16 @@ fn template_full_basic_test() {

assert!(template_store.get_templates_count() == 0, "Templates count is not 0");

let erc20_mock: ContractAddress = deploy_erc20_mock();

// 2x2 template image
let template_image = array![1, 2, 3, 4];
let template_hash = compute_template_hash(template_image.span());
let template_metadata = TemplateMetadata {
hash: template_hash,
position: 0,
width: 2,
height: 2,
reward: 0,
reward_token: contract_address_const::<0>(),
hash: template_hash, position: 0, width: 2, height: 2, reward: 0, reward_token: erc20_mock,
};

let reward_token: ContractAddress = contract_address_const::<0x0>();

template_store.add_template(template_metadata, reward_token, 0);
template_store.add_template(template_metadata);

assert!(template_store.get_templates_count() == 1, "Templates count is not 1");
assert!(template_store.get_template_hash(0) == template_hash, "Template hash is not correct");
Expand Down Expand Up @@ -467,6 +488,32 @@ fn increase_day_panic_test() {
snf::start_warp(CheatTarget::One(art_peace_address), DAY_IN_SECONDS - 1);
art_peace.increase_day_index();
}

#[test]
fn deposit_reward_test() {
let art_peace_address = deploy_contract();
let art_peace = IArtPeaceDispatcher { contract_address: art_peace_address };
let template_store = ITemplateStoreDispatcher { contract_address: art_peace.contract_address };

let erc20_mock: ContractAddress = deploy_erc20_mock();
let reward_amount: u256 = 1 * utils::pow_256(10, 18);

// 2x2 template image
let template_image = array![1, 2, 3, 4];
let template_hash = compute_template_hash(template_image.span());
let template_metadata = TemplateMetadata {
hash: template_hash,
position: 0,
width: 2,
height: 2,
reward: reward_amount,
reward_token: erc20_mock,
};

IERC20Dispatcher { contract_address: erc20_mock }.approve(art_peace_address, reward_amount);

template_store.add_template(template_metadata);
}
// TODO: test invalid template inputs

// TODO: Deploy test for nft that checks name, symbol, uri, etc.
Expand Down
23 changes: 23 additions & 0 deletions onchain/src/tests/utils.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
use core::num::traits::Zero;

// Math
pub(crate) fn pow_256(self: u256, mut exponent: u8) -> u256 {
if self.is_zero() {
return 0;
}
let mut result = 1;
let mut base = self;

loop {
if exponent & 1 == 1 {
result = result * base;
}

exponent = exponent / 2;
if exponent == 0 {
break result;
}

base = base * base;
}
}

0 comments on commit fdceb3f

Please sign in to comment.