From 7c76862f620287748a89e4dedf8e733bf10c635d Mon Sep 17 00:00:00 2001 From: Patrice Tisserand Date: Tue, 10 Sep 2024 15:05:57 +0200 Subject: [PATCH 01/16] contracts: update starknet-foundry to 0.30.0 --- contracts/.tool-versions | 2 +- contracts/Scarb.lock | 6 +++--- contracts/Scarb.toml | 2 +- contracts/ark_oz/Scarb.toml | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/contracts/.tool-versions b/contracts/.tool-versions index e0955bfc3..27f5ea63a 100644 --- a/contracts/.tool-versions +++ b/contracts/.tool-versions @@ -1,2 +1,2 @@ scarb 2.7.1 -starknet-foundry 0.28.0 \ No newline at end of file +starknet-foundry 0.30.0 \ No newline at end of file diff --git a/contracts/Scarb.lock b/contracts/Scarb.lock index 0c022abc2..afc5d0b48 100644 --- a/contracts/Scarb.lock +++ b/contracts/Scarb.lock @@ -141,12 +141,12 @@ source = "git+https://github.com/OpenZeppelin/cairo-contracts.git?tag=v0.15.1#2f [[package]] name = "snforge_scarb_plugin" version = "0.1.0" -source = "git+https://github.com/foundry-rs/starknet-foundry.git?tag=v0.28.0#4dfe39d96690ed6b3d56971512700de3f58288ea" +source = "git+https://github.com/foundry-rs/starknet-foundry.git?tag=v0.30.0#196f06b251926697c3d66800f2a93ae595e76496" [[package]] name = "snforge_std" -version = "0.28.0" -source = "git+https://github.com/foundry-rs/starknet-foundry.git?tag=v0.28.0#4dfe39d96690ed6b3d56971512700de3f58288ea" +version = "0.30.0" +source = "git+https://github.com/foundry-rs/starknet-foundry.git?tag=v0.30.0#196f06b251926697c3d66800f2a93ae595e76496" dependencies = [ "snforge_scarb_plugin", ] diff --git a/contracts/Scarb.toml b/contracts/Scarb.toml index f9b906048..1808a18b8 100644 --- a/contracts/Scarb.toml +++ b/contracts/Scarb.toml @@ -12,7 +12,7 @@ members = [ [workspace.dependencies] starknet = "2.7.1" openzeppelin = { git = "https://github.com/OpenZeppelin/cairo-contracts.git", tag = "v0.15.1" } -snforge_std = { git = "https://github.com/foundry-rs/starknet-foundry.git", tag = "v0.28.0" } +snforge_std = { git = "https://github.com/foundry-rs/starknet-foundry.git", tag = "v0.30.0" } assert_macros = "0.1.0" [workspace.scripts] diff --git a/contracts/ark_oz/Scarb.toml b/contracts/ark_oz/Scarb.toml index a3c365ee4..9b73c8aef 100644 --- a/contracts/ark_oz/Scarb.toml +++ b/contracts/ark_oz/Scarb.toml @@ -9,7 +9,7 @@ starknet = "2.7.1" openzeppelin = { git = "https://github.com/OpenZeppelin/cairo-contracts.git", tag = "v0.15.1" } [dev-dependencies] -snforge_std = { git = "https://github.com/foundry-rs/starknet-foundry.git", tag = "v0.28.0" } +snforge_std = { git = "https://github.com/foundry-rs/starknet-foundry.git", tag = "v0.30.0" } assert_macros = "0.1.0" [tool.fmt] From 16db98d0698bbe24ebf47ab97a4f3ab6e3c1014e Mon Sep 17 00:00:00 2001 From: Patrice Tisserand Date: Tue, 10 Sep 2024 18:25:03 +0200 Subject: [PATCH 02/16] contracts: add event testing in create_order --- .../src/orderbook/orderbook.cairo | 22 ++--- .../tests/integration/create_order.cairo | 80 ++++++++++++++++++- 2 files changed, 88 insertions(+), 14 deletions(-) diff --git a/contracts/ark_component/src/orderbook/orderbook.cairo b/contracts/ark_component/src/orderbook/orderbook.cairo index c26a133a6..2b23d2604 100644 --- a/contracts/ark_component/src/orderbook/orderbook.cairo +++ b/contracts/ark_component/src/orderbook/orderbook.cairo @@ -42,7 +42,7 @@ pub mod OrderbookComponent { /// Events emitted by the Orderbook contract. #[event] #[derive(Drop, starknet::Event)] - enum Event { + pub enum Event { OrderPlaced: OrderPlaced, OrderExecuted: OrderExecuted, OrderCancelled: OrderCancelled, @@ -51,10 +51,10 @@ pub mod OrderbookComponent { } // must be increased when `OrderPlaced` content change - const ORDER_PLACED_EVENT_VERSION: u8 = 1; + pub const ORDER_PLACED_EVENT_VERSION: u8 = 1; /// Event for when an order is placed. #[derive(Drop, starknet::Event)] - struct OrderPlaced { + pub struct OrderPlaced { #[key] order_hash: felt252, #[key] @@ -70,10 +70,10 @@ pub mod OrderbookComponent { } // must be increased when `OrderExecuted` content change - const ORDER_EXECUTED_EVENT_VERSION: u8 = 2; + pub const ORDER_EXECUTED_EVENT_VERSION: u8 = 2; /// Event for when an order is executed. #[derive(Drop, starknet::Event)] - struct OrderExecuted { + pub struct OrderExecuted { #[key] order_hash: felt252, #[key] @@ -88,10 +88,10 @@ pub mod OrderbookComponent { } // must be increased when `OrderPlaced` content change - const ORDER_CANCELLED_EVENT_VERSION: u8 = 1; + pub const ORDER_CANCELLED_EVENT_VERSION: u8 = 1; /// Event for when an order is cancelled. #[derive(Drop, starknet::Event)] - struct OrderCancelled { + pub struct OrderCancelled { #[key] order_hash: felt252, #[key] @@ -102,10 +102,10 @@ pub mod OrderbookComponent { } // must be increased when `RollbackStatus` content change - const ROLLBACK_STATUS_EVENT_VERSION: u8 = 1; + pub const ROLLBACK_STATUS_EVENT_VERSION: u8 = 1; /// Event for when an order has been rollbacked to placed. #[derive(Drop, starknet::Event)] - struct RollbackStatus { + pub struct RollbackStatus { #[key] order_hash: felt252, #[key] @@ -117,10 +117,10 @@ pub mod OrderbookComponent { } // must be increased when `OrderFulfilled` content change - const ORDER_FULFILLED_EVENT_VERSION: u8 = 1; + pub const ORDER_FULFILLED_EVENT_VERSION: u8 = 1; /// Event for when an order is fulfilled. #[derive(Drop, starknet::Event)] - struct OrderFulfilled { + pub struct OrderFulfilled { #[key] order_hash: felt252, #[key] diff --git a/contracts/ark_starknet/tests/integration/create_order.cairo b/contracts/ark_starknet/tests/integration/create_order.cairo index 7c7626cfa..9ef5336fa 100644 --- a/contracts/ark_starknet/tests/integration/create_order.cairo +++ b/contracts/ark_starknet/tests/integration/create_order.cairo @@ -1,7 +1,10 @@ -use ark_common::protocol::order_types::RouteType; - +use ark_common::protocol::order_types::{OrderStatus, OrderTrait, OrderType, RouteType}; use ark_common::protocol::order_v1::OrderV1; +use ark_component::orderbook::OrderbookComponent; +use ark_component::orderbook::interface::{IOrderbookDispatcher, IOrderbookDispatcherTrait,}; + +use ark_starknet::executor::executor; use ark_starknet::interfaces::{ IExecutorDispatcher, IExecutorDispatcherTrait, IMaintenanceDispatcher, @@ -13,7 +16,7 @@ use ark_tokens::erc20::IFreeMintDispatcherTrait as Erc20DispatcherTrait; use ark_tokens::erc721::IFreeMintDispatcher as Erc721Dispatcher; use ark_tokens::erc721::IFreeMintDispatcherTrait as Erc721DispatcherTrait; -use snforge_std::{cheat_caller_address, CheatSpan}; +use snforge_std::{cheat_caller_address, CheatSpan, spy_events, EventSpyAssertionsTrait,}; use starknet::{ContractAddress, contract_address_const}; use super::super::common::setup::{setup, setup_order}; @@ -28,11 +31,47 @@ fn test_create_order_erc20_to_erc721_ok() { Erc20Dispatcher { contract_address: erc20_address }.mint(offerer, start_amount); let mut order = setup_order(erc20_address, nft_address); + order.offerer = offerer; order.start_amount = start_amount; + let order_hash = order.compute_order_hash(); + let order_version = order.get_version(); + let mut spy = spy_events(); cheat_caller_address(executor_address, offerer, CheatSpan::TargetCalls(1)); IExecutorDispatcher { contract_address: executor_address }.create_order(order); + + spy + .assert_emitted( + @array![ + ( + executor_address, + executor::Event::OrderbookEvent( + OrderbookComponent::Event::OrderPlaced( + OrderbookComponent::OrderPlaced { + order_hash, + order_version, + order_type: OrderType::Offer, + version: OrderbookComponent::ORDER_PLACED_EVENT_VERSION, + cancelled_order_hash: Option::None, + order, + } + ) + ) + ) + ] + ); + + assert_eq!( + IOrderbookDispatcher { contract_address: executor_address }.get_order_type(order_hash), + OrderType::Offer, + "Wrong order type" + ); + assert_eq!( + IOrderbookDispatcher { contract_address: executor_address }.get_order_status(order_hash), + OrderStatus::Open, + "Wrong order status" + ); } #[test] @@ -49,9 +88,44 @@ fn test_create_order_erc721_to_erc20_ok() { order.route = RouteType::Erc721ToErc20.into(); order.offerer = offerer; order.token_id = Option::Some(token_id); + let order_hash = order.compute_order_hash(); + let order_version = order.get_version(); + let mut spy = spy_events(); cheat_caller_address(executor_address, offerer, CheatSpan::TargetCalls(1)); IExecutorDispatcher { contract_address: executor_address }.create_order(order); + + spy + .assert_emitted( + @array![ + ( + executor_address, + executor::Event::OrderbookEvent( + OrderbookComponent::Event::OrderPlaced( + OrderbookComponent::OrderPlaced { + order_hash, + order_version, + order_type: OrderType::Listing, + version: OrderbookComponent::ORDER_PLACED_EVENT_VERSION, + cancelled_order_hash: Option::None, + order, + } + ) + ) + ) + ] + ); + + assert_eq!( + IOrderbookDispatcher { contract_address: executor_address }.get_order_type(order_hash), + OrderType::Listing, + "Wrong order type" + ); + assert_eq!( + IOrderbookDispatcher { contract_address: executor_address }.get_order_status(order_hash), + OrderStatus::Open, + "Wrong order status" + ); } From 957ce8b597779b57cd739a084109331eb953beae Mon Sep 17 00:00:00 2001 From: Patrice Tisserand Date: Tue, 10 Sep 2024 18:38:07 +0200 Subject: [PATCH 03/16] contracts: don't emit anymore `OrderExecuted` directly from starknet contract --- contracts/ark_starknet/src/executor.cairo | 7 ------- 1 file changed, 7 deletions(-) diff --git a/contracts/ark_starknet/src/executor.cairo b/contracts/ark_starknet/src/executor.cairo index 9c06fec98..0dbb41f61 100644 --- a/contracts/ark_starknet/src/executor.cairo +++ b/contracts/ark_starknet/src/executor.cairo @@ -681,13 +681,6 @@ mod executor { let transaction_hash = tx_info.transaction_hash; let block_timestamp = starknet::info::get_block_timestamp(); - self - .emit( - OrderExecuted { - order_hash: execution_info.order_hash, transaction_hash, block_timestamp, - } - ); - let vinfo = ExecutionValidationInfo { order_hash: execution_info.order_hash, transaction_hash, From 4f9b7c8aaca20203583dddc413109c17026c67ab Mon Sep 17 00:00:00 2001 From: Patrice Tisserand Date: Wed, 11 Sep 2024 11:26:35 +0200 Subject: [PATCH 04/16] conntracts: remove OrderExecuted event in executor and use #[flat] for OrderBookComponent events --- contracts/ark_starknet/src/executor.cairo | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/contracts/ark_starknet/src/executor.cairo b/contracts/ark_starknet/src/executor.cairo index 0dbb41f61..a40072e97 100644 --- a/contracts/ark_starknet/src/executor.cairo +++ b/contracts/ark_starknet/src/executor.cairo @@ -116,22 +116,12 @@ mod executor { #[event] #[derive(Drop, starknet::Event)] enum Event { - OrderExecuted: OrderExecuted, CollectionFallbackFees: CollectionFallbackFees, ExecutorInMaintenance: ExecutorInMaintenance, - // #[flat] // OrderExecuted conflict + #[flat] OrderbookEvent: OrderbookComponent::Event, } - #[derive(Drop, starknet::Event)] - struct OrderExecuted { - #[key] - order_hash: felt252, - #[key] - transaction_hash: felt252, - block_timestamp: u64 - } - #[derive(Drop, starknet::Event)] struct CollectionFallbackFees { #[key] From de9a0385b5257c687d38558d6d3c67fd120bc4fa Mon Sep 17 00:00:00 2001 From: Patrice Tisserand Date: Wed, 11 Sep 2024 15:23:31 +0200 Subject: [PATCH 05/16] contracts: add test cases for create auction & collection offer orders --- .../ark_starknet/tests/common/setup.cairo | 107 +++++++++++- .../tests/integration/create_order.cairo | 164 ++++++++++++++---- .../tests/integration/fulfill_order.cairo | 40 ++--- 3 files changed, 247 insertions(+), 64 deletions(-) diff --git a/contracts/ark_starknet/tests/common/setup.cairo b/contracts/ark_starknet/tests/common/setup.cairo index 93772a860..2227a786b 100644 --- a/contracts/ark_starknet/tests/common/setup.cairo +++ b/contracts/ark_starknet/tests/common/setup.cairo @@ -68,7 +68,112 @@ fn setup_royalty() -> (ContractAddress, ContractAddress, ContractAddress) { (executor_address, erc20_address, nft_address) } -fn setup_order(erc20_address: ContractAddress, nft_address: ContractAddress) -> OrderV1 { +fn setup_order( + currency_address: ContractAddress, + nft_address: ContractAddress, + route: RouteType, + offerer: ContractAddress, + token_id: Option, + start_amount: u256, + end_amount: u256, +) -> OrderV1 { + let chain_id = 'SN_MAIN'; + let block_timestamp = starknet::get_block_timestamp(); + let end_date = block_timestamp + (30 * 24 * 60 * 60); + let data = array![]; + + OrderV1 { + route, + currency_address, + currency_chain_id: chain_id, + salt: 1, + offerer, + token_chain_id: chain_id, + token_address: nft_address, + token_id, + quantity: 1, + start_amount, + end_amount, + start_date: block_timestamp, + end_date: end_date, + broker_id: contract_address_const::<'broker_id'>(), + additional_data: data.span() + } +} + +fn setup_offer_order( + currency_address: ContractAddress, + nft_address: ContractAddress, + offerer: ContractAddress, + token_id: u256, + start_amount: u256, +) -> OrderV1 { + setup_order( + currency_address, + nft_address, + RouteType::Erc20ToErc721, + offerer, + Option::Some(token_id), + start_amount, + 0 + ) +} + +fn setup_listing_order( + currency_address: ContractAddress, + nft_address: ContractAddress, + offerer: ContractAddress, + token_id: u256, + start_amount: u256, +) -> OrderV1 { + setup_order( + currency_address, + nft_address, + RouteType::Erc721ToErc20, + offerer, + Option::Some(token_id), + start_amount, + 0 + ) +} + +fn setup_auction_order( + currency_address: ContractAddress, + nft_address: ContractAddress, + offerer: ContractAddress, + token_id: u256, + start_amount: u256, + end_amount: u256, +) -> OrderV1 { + setup_order( + currency_address, + nft_address, + RouteType::Erc721ToErc20, + offerer, + Option::Some(token_id), + start_amount, + end_amount + ) +} + +fn setup_collection_offer_order( + currency_address: ContractAddress, + nft_address: ContractAddress, + offerer: ContractAddress, + start_amount: u256, +) -> OrderV1 { + setup_order( + currency_address, + nft_address, + RouteType::Erc20ToErc721, + offerer, + Option::None, + start_amount, + 0 + ) +} + +fn setup_default_order(erc20_address: ContractAddress, nft_address: ContractAddress) -> OrderV1 { let chain_id = 'SN_MAIN'; let block_timestamp = starknet::get_block_timestamp(); let end_date = block_timestamp + (30 * 24 * 60 * 60); diff --git a/contracts/ark_starknet/tests/integration/create_order.cairo b/contracts/ark_starknet/tests/integration/create_order.cairo index 9ef5336fa..75c408ae0 100644 --- a/contracts/ark_starknet/tests/integration/create_order.cairo +++ b/contracts/ark_starknet/tests/integration/create_order.cairo @@ -19,21 +19,20 @@ use ark_tokens::erc721::IFreeMintDispatcherTrait as Erc721DispatcherTrait; use snforge_std::{cheat_caller_address, CheatSpan, spy_events, EventSpyAssertionsTrait,}; use starknet::{ContractAddress, contract_address_const}; -use super::super::common::setup::{setup, setup_order}; +use super::super::common::setup::{ + setup, setup_auction_order, setup_collection_offer_order, setup_listing_order, setup_offer_order +}; #[test] -fn test_create_order_erc20_to_erc721_ok() { +fn test_create_offer_order_ok() { let (executor_address, erc20_address, nft_address) = setup(); let offerer = contract_address_const::<'offerer'>(); let start_amount = 10_000_000; - + let token_id = 10_u256; Erc20Dispatcher { contract_address: erc20_address }.mint(offerer, start_amount); - let mut order = setup_order(erc20_address, nft_address); - - order.offerer = offerer; - order.start_amount = start_amount; + let order = setup_offer_order(erc20_address, nft_address, offerer, token_id, start_amount); let order_hash = order.compute_order_hash(); let order_version = order.get_version(); @@ -75,19 +74,16 @@ fn test_create_order_erc20_to_erc721_ok() { } #[test] -fn test_create_order_erc721_to_erc20_ok() { +fn test_create_listing_order_ok() { let (executor_address, erc20_address, nft_address) = setup(); let offerer = contract_address_const::<'offerer'>(); - + let start_amount = 10_000_000; let token_id: u256 = Erc721Dispatcher { contract_address: nft_address } .get_current_token_id() .into(); Erc721Dispatcher { contract_address: nft_address }.mint(offerer, 'base_uri'); - let mut order = setup_order(erc20_address, nft_address); - order.route = RouteType::Erc721ToErc20.into(); - order.offerer = offerer; - order.token_id = Option::Some(token_id); + let order = setup_listing_order(erc20_address, nft_address, offerer, token_id, start_amount); let order_hash = order.compute_order_hash(); let order_version = order.get_version(); @@ -128,16 +124,121 @@ fn test_create_order_erc721_to_erc20_ok() { ); } +#[test] +fn test_create_auction_order_ok() { + let (executor_address, erc20_address, nft_address) = setup(); + let offerer = contract_address_const::<'offerer'>(); + let start_amount = 10_000_000; + let end_amount = start_amount * 2; + let token_id: u256 = Erc721Dispatcher { contract_address: nft_address } + .get_current_token_id() + .into(); + Erc721Dispatcher { contract_address: nft_address }.mint(offerer, 'base_uri'); + + let order = setup_auction_order( + erc20_address, nft_address, offerer, token_id, start_amount, end_amount + ); + let order_hash = order.compute_order_hash(); + let order_version = order.get_version(); + + let mut spy = spy_events(); + cheat_caller_address(executor_address, offerer, CheatSpan::TargetCalls(1)); + IExecutorDispatcher { contract_address: executor_address }.create_order(order); + + spy + .assert_emitted( + @array![ + ( + executor_address, + executor::Event::OrderbookEvent( + OrderbookComponent::Event::OrderPlaced( + OrderbookComponent::OrderPlaced { + order_hash, + order_version, + order_type: OrderType::Auction, + version: OrderbookComponent::ORDER_PLACED_EVENT_VERSION, + cancelled_order_hash: Option::None, + order, + } + ) + ) + ) + ] + ); + + assert_eq!( + IOrderbookDispatcher { contract_address: executor_address }.get_order_type(order_hash), + OrderType::Auction, + "Wrong order type" + ); + assert_eq!( + IOrderbookDispatcher { contract_address: executor_address }.get_order_status(order_hash), + OrderStatus::Open, + "Wrong order status" + ); +} + +#[test] +fn test_create_collection_offer_order_ok() { + let (executor_address, erc20_address, nft_address) = setup(); + let offerer = contract_address_const::<'offerer'>(); + let start_amount = 10_000_000; + let token_id = 10_u256; + Erc20Dispatcher { contract_address: erc20_address }.mint(offerer, start_amount); + + let order = setup_collection_offer_order(erc20_address, nft_address, offerer, start_amount); + let order_hash = order.compute_order_hash(); + let order_version = order.get_version(); + + let mut spy = spy_events(); + cheat_caller_address(executor_address, offerer, CheatSpan::TargetCalls(1)); + IExecutorDispatcher { contract_address: executor_address }.create_order(order); + + spy + .assert_emitted( + @array![ + ( + executor_address, + executor::Event::OrderbookEvent( + OrderbookComponent::Event::OrderPlaced( + OrderbookComponent::OrderPlaced { + order_hash, + order_version, + order_type: OrderType::CollectionOffer, + version: OrderbookComponent::ORDER_PLACED_EVENT_VERSION, + cancelled_order_hash: Option::None, + order, + } + ) + ) + ) + ] + ); + + assert_eq!( + IOrderbookDispatcher { contract_address: executor_address }.get_order_type(order_hash), + OrderType::CollectionOffer, + "Wrong order type" + ); + assert_eq!( + IOrderbookDispatcher { contract_address: executor_address }.get_order_status(order_hash), + OrderStatus::Open, + "Wrong order status" + ); +} #[test] #[should_panic(expected: "Caller is not the offerer")] -fn test_create_order_offerer_shall_be_caller() { +fn test_create_offer_order_offerer_shall_be_caller() { let (executor_address, erc20_address, nft_address) = setup(); let offerer = contract_address_const::<'offerer'>(); let caller = contract_address_const::<'caller'>(); + let start_amount = 10_000_000; + let token_id = 10_u256; + + Erc20Dispatcher { contract_address: erc20_address }.mint(offerer, start_amount); - let mut order = setup_order(erc20_address, nft_address); - order.offerer = offerer; + let order = setup_offer_order(erc20_address, nft_address, offerer, token_id, start_amount); cheat_caller_address(executor_address, caller, CheatSpan::TargetCalls(1)); IExecutorDispatcher { contract_address: executor_address }.create_order(order); @@ -145,17 +246,16 @@ fn test_create_order_offerer_shall_be_caller() { #[test] #[should_panic(expected: "Offerer does not own enough ERC20 tokens")] -fn test_create_order_offerer_not_enough_erc20_tokens() { +fn test_create_offer_order_offerer_not_enough_erc20_tokens() { let (executor_address, erc20_address, nft_address) = setup(); let offerer = contract_address_const::<'offerer'>(); let start_amount = 10_000_000; let minted = 10_000; + let token_id = 10_u256; Erc20Dispatcher { contract_address: erc20_address }.mint(offerer, minted); - let mut order = setup_order(erc20_address, nft_address); - order.offerer = offerer; - order.start_amount = start_amount; + let order = setup_offer_order(erc20_address, nft_address, offerer, token_id, start_amount); cheat_caller_address(executor_address, offerer, CheatSpan::TargetCalls(1)); IExecutorDispatcher { contract_address: executor_address }.create_order(order); @@ -163,20 +263,18 @@ fn test_create_order_offerer_not_enough_erc20_tokens() { #[test] #[should_panic(expected: "Offerer does not own the specified ERC721 token")] -fn test_create_order_offerer_not_own_ec721_token() { +fn test_create_listing_order_offerer_not_own_ec721_token() { let (executor_address, erc20_address, nft_address) = setup(); let offerer = contract_address_const::<'offerer'>(); let other = contract_address_const::<'other'>(); + let start_amount = 10_000_000; let token_id: u256 = Erc721Dispatcher { contract_address: nft_address } .get_current_token_id() .into(); Erc721Dispatcher { contract_address: nft_address }.mint(other, 'base_uri'); - let mut order = setup_order(erc20_address, nft_address); - order.route = RouteType::Erc721ToErc20.into(); - order.offerer = offerer; - order.token_id = Option::Some(token_id); + let order = setup_listing_order(erc20_address, nft_address, offerer, token_id, start_amount); cheat_caller_address(executor_address, offerer, CheatSpan::TargetCalls(1)); IExecutorDispatcher { contract_address: executor_address }.create_order(order); @@ -184,17 +282,16 @@ fn test_create_order_offerer_not_own_ec721_token() { #[test] #[should_panic(expected: 'Executor not enabled')] -fn test_create_order_erc20_to_erc721_disabled() { +fn test_create_offer_order_disabled() { let (executor_address, erc20_address, nft_address) = setup(); let admin = contract_address_const::<'admin'>(); let offerer = contract_address_const::<'offerer'>(); let start_amount = 10_000_000; + let token_id = 10_u256; Erc20Dispatcher { contract_address: erc20_address }.mint(offerer, start_amount); - let mut order = setup_order(erc20_address, nft_address); - order.offerer = offerer; - order.start_amount = start_amount; + let order = setup_offer_order(erc20_address, nft_address, offerer, token_id, start_amount); cheat_caller_address(executor_address, admin, CheatSpan::TargetCalls(1)); IMaintenanceDispatcher { contract_address: executor_address }.set_maintenance_mode(true); @@ -205,20 +302,17 @@ fn test_create_order_erc20_to_erc721_disabled() { #[test] #[should_panic(expected: 'Executor not enabled')] -fn test_create_order_erc721_to_erc20_disabled() { +fn test_create_listing_order_disabled() { let (executor_address, erc20_address, nft_address) = setup(); let admin = contract_address_const::<'admin'>(); let offerer = contract_address_const::<'offerer'>(); - + let start_amount = 10_000_000; let token_id: u256 = Erc721Dispatcher { contract_address: nft_address } .get_current_token_id() .into(); Erc721Dispatcher { contract_address: nft_address }.mint(offerer, 'base_uri'); - let mut order = setup_order(erc20_address, nft_address); - order.route = RouteType::Erc721ToErc20.into(); - order.offerer = offerer; - order.token_id = Option::Some(token_id); + let order = setup_listing_order(erc20_address, nft_address, offerer, token_id, start_amount); cheat_caller_address(executor_address, admin, CheatSpan::TargetCalls(1)); IMaintenanceDispatcher { contract_address: executor_address }.set_maintenance_mode(true); diff --git a/contracts/ark_starknet/tests/integration/fulfill_order.cairo b/contracts/ark_starknet/tests/integration/fulfill_order.cairo index 72ec091d8..43b29a5c9 100644 --- a/contracts/ark_starknet/tests/integration/fulfill_order.cairo +++ b/contracts/ark_starknet/tests/integration/fulfill_order.cairo @@ -17,7 +17,10 @@ use openzeppelin::token::erc721::interface::{IERC721Dispatcher, IERC721Dispatche use snforge_std::{cheat_caller_address, CheatSpan}; use starknet::{ContractAddress, contract_address_const}; -use super::super::common::setup::{setup, setup_order}; +use super::super::common::setup::{ + setup, setup_default_order, setup_auction_order, setup_collection_offer_order, + setup_listing_order, setup_offer_order +}; fn create_offer_order( executor_address: ContractAddress, @@ -30,10 +33,7 @@ fn create_offer_order( IFreeMintDispatcher { contract_address: erc20_address }.mint(offerer, start_amount); - let mut order = setup_order(erc20_address, nft_address); - order.offerer = offerer; - order.start_amount = start_amount; - order.token_id = Option::Some(token_id); + let order = setup_offer_order(erc20_address, nft_address, offerer, token_id, start_amount); cheat_caller_address(executor_address, offerer, CheatSpan::TargetCalls(1)); IExecutorDispatcher { contract_address: executor_address }.create_order(order); @@ -49,10 +49,7 @@ fn create_collection_offer_order( IFreeMintDispatcher { contract_address: erc20_address }.mint(offerer, start_amount); - let mut order = setup_order(erc20_address, nft_address); - order.offerer = offerer; - order.start_amount = start_amount; - order.token_id = Option::None; + let order = setup_collection_offer_order(erc20_address, nft_address, offerer, start_amount); cheat_caller_address(executor_address, offerer, CheatSpan::TargetCalls(1)); IExecutorDispatcher { contract_address: executor_address }.create_order(order); @@ -73,11 +70,7 @@ fn create_listing_order( .into(); Erc721Dispatcher { contract_address: nft_address }.mint(offerer, 'base_uri'); - let mut order = setup_order(erc20_address, nft_address); - order.route = RouteType::Erc721ToErc20.into(); - order.offerer = offerer; - order.token_id = Option::Some(token_id); - order.start_amount = start_amount; + let order = setup_listing_order(erc20_address, nft_address, offerer, token_id, start_amount); cheat_caller_address(executor_address, offerer, CheatSpan::TargetCalls(1)); IExecutorDispatcher { contract_address: executor_address }.create_order(order); @@ -99,12 +92,9 @@ fn create_auction_order( .into(); Erc721Dispatcher { contract_address: nft_address }.mint(offerer, 'base_uri'); - let mut order = setup_order(erc20_address, nft_address); - order.route = RouteType::Erc721ToErc20.into(); - order.offerer = offerer; - order.token_id = Option::Some(token_id); - order.start_amount = start_amount; - order.end_amount = end_amount; + let order = setup_auction_order( + erc20_address, nft_address, offerer, token_id, start_amount, end_amount + ); cheat_caller_address(executor_address, offerer, CheatSpan::TargetCalls(1)); IExecutorDispatcher { contract_address: executor_address }.create_order(order); @@ -410,10 +400,7 @@ fn test_fulfill_auction_order_ok() { IFreeMintDispatcher { contract_address: erc20_address }.mint(buyer, start_amount); - let mut buyer_order = setup_order(erc20_address, nft_address); - buyer_order.offerer = buyer; - buyer_order.start_amount = start_amount; - buyer_order.token_id = Option::Some(token_id); + let buyer_order = setup_offer_order(erc20_address, nft_address, buyer, token_id, start_amount); cheat_caller_address(executor_address, buyer, CheatSpan::TargetCalls(1)); IExecutorDispatcher { contract_address: executor_address }.create_order(buyer_order); @@ -446,10 +433,7 @@ fn test_fulfill_auction_order_fulfiller_same_as_offerer() { IFreeMintDispatcher { contract_address: erc20_address }.mint(buyer, start_amount); - let mut buyer_order = setup_order(erc20_address, nft_address); - buyer_order.offerer = buyer; - buyer_order.start_amount = start_amount; - buyer_order.token_id = Option::Some(token_id); + let buyer_order = setup_offer_order(erc20_address, nft_address, buyer, token_id, start_amount); cheat_caller_address(executor_address, buyer, CheatSpan::TargetCalls(1)); IExecutorDispatcher { contract_address: executor_address }.create_order(buyer_order); From 8c0f17cf9d9b5f808c2251f353de07ae779f3046 Mon Sep 17 00:00:00 2001 From: Patrice Tisserand Date: Wed, 11 Sep 2024 15:42:41 +0200 Subject: [PATCH 06/16] contracts: move create_* to setup.cairo --- .../ark_starknet/tests/common/setup.cairo | 94 ++++++++++++++++++- .../tests/integration/fulfill_order.cairo | 80 +--------------- 2 files changed, 92 insertions(+), 82 deletions(-) diff --git a/contracts/ark_starknet/tests/common/setup.cairo b/contracts/ark_starknet/tests/common/setup.cairo index 2227a786b..bab0b3281 100644 --- a/contracts/ark_starknet/tests/common/setup.cairo +++ b/contracts/ark_starknet/tests/common/setup.cairo @@ -1,8 +1,16 @@ -use ark_common::protocol::order_types::RouteType; - +use ark_common::protocol::order_types::{OrderTrait, RouteType}; use ark_common::protocol::order_v1::OrderV1; + +use ark_starknet::interfaces::{IExecutorDispatcher, IExecutorDispatcherTrait,}; + +use ark_tokens::erc20::{IFreeMintDispatcher, IFreeMintDispatcherTrait}; +use ark_tokens::erc721::IFreeMintDispatcher as Erc721Dispatcher; +use ark_tokens::erc721::IFreeMintDispatcherTrait as Erc721DispatcherTrait; + use serde::Serde; -use snforge_std::{ContractClass, ContractClassTrait, declare, DeclareResultTrait}; +use snforge_std::{ + cheat_caller_address, CheatSpan, ContractClass, ContractClassTrait, declare, DeclareResultTrait +}; use starknet::{ContractAddress, contract_address_const}; @@ -197,3 +205,83 @@ fn setup_default_order(erc20_address: ContractAddress, nft_address: ContractAddr additional_data: data.span() } } + +fn create_offer_order( + executor_address: ContractAddress, + erc20_address: ContractAddress, + nft_address: ContractAddress, + token_id: u256 +) -> (felt252, ContractAddress, u256) { + let offerer = contract_address_const::<'offerer'>(); + let start_amount = 10_000_000; + + IFreeMintDispatcher { contract_address: erc20_address }.mint(offerer, start_amount); + + let order = setup_offer_order(erc20_address, nft_address, offerer, token_id, start_amount); + + cheat_caller_address(executor_address, offerer, CheatSpan::TargetCalls(1)); + IExecutorDispatcher { contract_address: executor_address }.create_order(order); + + (order.compute_order_hash(), offerer, start_amount) +} + +fn create_listing_order( + executor_address: ContractAddress, + erc20_address: ContractAddress, + nft_address: ContractAddress, + start_amount: u256 +) -> (felt252, ContractAddress, u256) { + let offerer = contract_address_const::<'offerer'>(); + + let token_id: u256 = Erc721Dispatcher { contract_address: nft_address } + .get_current_token_id() + .into(); + Erc721Dispatcher { contract_address: nft_address }.mint(offerer, 'base_uri'); + + let order = setup_listing_order(erc20_address, nft_address, offerer, token_id, start_amount); + + cheat_caller_address(executor_address, offerer, CheatSpan::TargetCalls(1)); + IExecutorDispatcher { contract_address: executor_address }.create_order(order); + + (order.compute_order_hash(), offerer, token_id) +} + +fn create_auction_order( + executor_address: ContractAddress, + erc20_address: ContractAddress, + nft_address: ContractAddress, + start_amount: u256, + end_amount: u256 +) -> (felt252, ContractAddress, u256) { + let offerer = contract_address_const::<'offerer'>(); + + let token_id: u256 = Erc721Dispatcher { contract_address: nft_address } + .get_current_token_id() + .into(); + Erc721Dispatcher { contract_address: nft_address }.mint(offerer, 'base_uri'); + + let order = setup_auction_order( + erc20_address, nft_address, offerer, token_id, start_amount, end_amount + ); + + cheat_caller_address(executor_address, offerer, CheatSpan::TargetCalls(1)); + IExecutorDispatcher { contract_address: executor_address }.create_order(order); + + (order.compute_order_hash(), offerer, token_id) +} + +fn create_collection_offer_order( + executor_address: ContractAddress, erc20_address: ContractAddress, nft_address: ContractAddress, +) -> (felt252, ContractAddress, u256) { + let offerer = contract_address_const::<'offerer'>(); + let start_amount = 10_000_000; + + IFreeMintDispatcher { contract_address: erc20_address }.mint(offerer, start_amount); + + let order = setup_collection_offer_order(erc20_address, nft_address, offerer, start_amount); + + cheat_caller_address(executor_address, offerer, CheatSpan::TargetCalls(1)); + IExecutorDispatcher { contract_address: executor_address }.create_order(order); + + (order.compute_order_hash(), offerer, start_amount) +} diff --git a/contracts/ark_starknet/tests/integration/fulfill_order.cairo b/contracts/ark_starknet/tests/integration/fulfill_order.cairo index 43b29a5c9..86baa1b31 100644 --- a/contracts/ark_starknet/tests/integration/fulfill_order.cairo +++ b/contracts/ark_starknet/tests/integration/fulfill_order.cairo @@ -18,89 +18,11 @@ use snforge_std::{cheat_caller_address, CheatSpan}; use starknet::{ContractAddress, contract_address_const}; use super::super::common::setup::{ + create_auction_order, create_collection_offer_order, create_listing_order, create_offer_order, setup, setup_default_order, setup_auction_order, setup_collection_offer_order, setup_listing_order, setup_offer_order }; -fn create_offer_order( - executor_address: ContractAddress, - erc20_address: ContractAddress, - nft_address: ContractAddress, - token_id: u256 -) -> (felt252, ContractAddress, u256) { - let offerer = contract_address_const::<'offerer'>(); - let start_amount = 10_000_000; - - IFreeMintDispatcher { contract_address: erc20_address }.mint(offerer, start_amount); - - let order = setup_offer_order(erc20_address, nft_address, offerer, token_id, start_amount); - - cheat_caller_address(executor_address, offerer, CheatSpan::TargetCalls(1)); - IExecutorDispatcher { contract_address: executor_address }.create_order(order); - - (order.compute_order_hash(), offerer, start_amount) -} - -fn create_collection_offer_order( - executor_address: ContractAddress, erc20_address: ContractAddress, nft_address: ContractAddress, -) -> (felt252, ContractAddress, u256) { - let offerer = contract_address_const::<'offerer'>(); - let start_amount = 10_000_000; - - IFreeMintDispatcher { contract_address: erc20_address }.mint(offerer, start_amount); - - let order = setup_collection_offer_order(erc20_address, nft_address, offerer, start_amount); - - cheat_caller_address(executor_address, offerer, CheatSpan::TargetCalls(1)); - IExecutorDispatcher { contract_address: executor_address }.create_order(order); - - (order.compute_order_hash(), offerer, start_amount) -} - -fn create_listing_order( - executor_address: ContractAddress, - erc20_address: ContractAddress, - nft_address: ContractAddress, - start_amount: u256 -) -> (felt252, ContractAddress, u256) { - let offerer = contract_address_const::<'offerer'>(); - - let token_id: u256 = Erc721Dispatcher { contract_address: nft_address } - .get_current_token_id() - .into(); - Erc721Dispatcher { contract_address: nft_address }.mint(offerer, 'base_uri'); - - let order = setup_listing_order(erc20_address, nft_address, offerer, token_id, start_amount); - - cheat_caller_address(executor_address, offerer, CheatSpan::TargetCalls(1)); - IExecutorDispatcher { contract_address: executor_address }.create_order(order); - - (order.compute_order_hash(), offerer, token_id) -} - -fn create_auction_order( - executor_address: ContractAddress, - erc20_address: ContractAddress, - nft_address: ContractAddress, - start_amount: u256, - end_amount: u256 -) -> (felt252, ContractAddress, u256) { - let offerer = contract_address_const::<'offerer'>(); - - let token_id: u256 = Erc721Dispatcher { contract_address: nft_address } - .get_current_token_id() - .into(); - Erc721Dispatcher { contract_address: nft_address }.mint(offerer, 'base_uri'); - - let order = setup_auction_order( - erc20_address, nft_address, offerer, token_id, start_amount, end_amount - ); - - cheat_caller_address(executor_address, offerer, CheatSpan::TargetCalls(1)); - IExecutorDispatcher { contract_address: executor_address }.create_order(order); - - (order.compute_order_hash(), offerer, token_id) -} fn create_fulfill_info( order_hash: felt252, fulfiller: ContractAddress, token_address: ContractAddress, token_id: u256 From 85a53de72cb8f04e1e2ecf762dcf28d9312aee3e Mon Sep 17 00:00:00 2001 From: Patrice Tisserand Date: Wed, 11 Sep 2024 16:09:06 +0200 Subject: [PATCH 07/16] contracts: WIP cancel_order tests --- .../tests/integration/cancel_order.cairo | 68 +++++++++++++++++++ contracts/ark_starknet/tests/lib.cairo | 1 + 2 files changed, 69 insertions(+) create mode 100644 contracts/ark_starknet/tests/integration/cancel_order.cairo diff --git a/contracts/ark_starknet/tests/integration/cancel_order.cairo b/contracts/ark_starknet/tests/integration/cancel_order.cairo new file mode 100644 index 000000000..fa889f512 --- /dev/null +++ b/contracts/ark_starknet/tests/integration/cancel_order.cairo @@ -0,0 +1,68 @@ +use ark_common::protocol::order_types::CancelInfo; + +use ark_starknet::interfaces::{ + IExecutorDispatcher, IExecutorDispatcherTrait, IMaintenanceDispatcher, + IMaintenanceDispatcherTrait +}; + +use snforge_std::{cheat_caller_address, CheatSpan, spy_events, EventSpyAssertionsTrait,}; + +use starknet::{ContractAddress, contract_address_const}; +use super::super::common::setup::{ + create_auction_order, create_collection_offer_order, create_listing_order, create_offer_order, + setup, setup_default_order, setup_auction_order, setup_collection_offer_order, + setup_listing_order, setup_offer_order +}; + +#[test] +fn test_cancel_offer_order() { + let (executor_address, erc20_address, nft_address) = setup(); + let token_id = 10; + + let (order_hash, offerer, start_amount) = create_offer_order( + executor_address, erc20_address, nft_address, token_id + ); + + let cancel_info = CancelInfo { + order_hash, + canceller: offerer, + token_chain_id: 'SN_MAIN', + token_address: nft_address, + token_id: Option::Some(token_id), + }; + + cheat_caller_address(executor_address, offerer, CheatSpan::TargetCalls(1)); + IExecutorDispatcher { contract_address: executor_address }.cancel_order(cancel_info); +} + +// #[test] +// fn test_cancel_listing_order() {} +// +// #[test] +// fn test_cancel_auction_order() {} +// +// #[test] +// fn test_cancel_collection_offer_order() {} + +#[test] +#[should_panic] +fn test_cancel_offer_order_only_offerer() { + let (executor_address, erc20_address, nft_address) = setup(); + let token_id = 10; + let other = contract_address_const::<'other'>(); + + let (order_hash, offerer, start_amount) = create_offer_order( + executor_address, erc20_address, nft_address, token_id + ); + + let cancel_info = CancelInfo { + order_hash, + canceller: offerer, + token_chain_id: 'SN_MAIN', + token_address: nft_address, + token_id: Option::Some(token_id), + }; + + cheat_caller_address(executor_address, other, CheatSpan::TargetCalls(1)); + IExecutorDispatcher { contract_address: executor_address }.cancel_order(cancel_info); +} diff --git a/contracts/ark_starknet/tests/lib.cairo b/contracts/ark_starknet/tests/lib.cairo index 604ac5ca7..c575397ce 100644 --- a/contracts/ark_starknet/tests/lib.cairo +++ b/contracts/ark_starknet/tests/lib.cairo @@ -6,6 +6,7 @@ mod unit { mod test_fees; } mod integration { + mod cancel_order; mod create_order; // mod execute_order; mod fees_amount; From 72da2207d32acf994078d9bc16916201a28c83cb Mon Sep 17 00:00:00 2001 From: Patrice Tisserand Date: Thu, 12 Sep 2024 00:40:35 +0200 Subject: [PATCH 08/16] fix(contracts): ensure caller is the canceller & canceller is the offerer --- contracts/ark_starknet/src/executor.cairo | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/contracts/ark_starknet/src/executor.cairo b/contracts/ark_starknet/src/executor.cairo index a40072e97..f19719cd3 100644 --- a/contracts/ark_starknet/src/executor.cairo +++ b/contracts/ark_starknet/src/executor.cairo @@ -285,6 +285,10 @@ mod executor { fn cancel_order(ref self: ContractState, cancelInfo: CancelInfo) { _ensure_is_not_in_maintenance(@self); + + let vinfo = CancelOrderInfo { cancelInfo: cancelInfo.clone() }; + _verify_cancel_order(@self, @vinfo); + self.orderbook.cancel_order(cancelInfo); } @@ -368,6 +372,19 @@ mod executor { } } + fn _verify_cancel_order(self: @ContractState, vinfo: @CancelOrderInfo) { + let cancel_info = vinfo.cancelInfo; + let caller = starknet::get_caller_address(); + let canceller = *(cancel_info.canceller); + assert!(caller == canceller, "Caller is not the canceller"); + + let order_info = self.orders.read(*cancel_info.order_hash); + // default value for ContractAddress is zero + // and an order's currency address shall not be zero + assert!(order_info.currency_address.is_non_zero(), "Order not found"); + assert!(order_info.offerer == canceller, "Canceller is not the offerer"); + } + fn _verify_fulfill_order(self: @ContractState, vinfo: @FulfillOrderInfo) { let fulfill_info = vinfo.fulfillInfo; let caller = starknet::get_caller_address(); From 6646313f8397e49f324e27ef2cfedae952a068d3 Mon Sep 17 00:00:00 2001 From: Patrice Tisserand Date: Thu, 12 Sep 2024 00:43:54 +0200 Subject: [PATCH 09/16] contracts: add cancel_order tests --- .../tests/integration/cancel_order.cairo | 283 +++++++++++++++++- 1 file changed, 270 insertions(+), 13 deletions(-) diff --git a/contracts/ark_starknet/tests/integration/cancel_order.cairo b/contracts/ark_starknet/tests/integration/cancel_order.cairo index fa889f512..88933b5e0 100644 --- a/contracts/ark_starknet/tests/integration/cancel_order.cairo +++ b/contracts/ark_starknet/tests/integration/cancel_order.cairo @@ -1,4 +1,9 @@ -use ark_common::protocol::order_types::CancelInfo; +use ark_common::protocol::order_types::{CancelInfo, OrderStatus, OrderType}; + +use ark_component::orderbook::OrderbookComponent; +use ark_component::orderbook::interface::{IOrderbookDispatcher, IOrderbookDispatcherTrait,}; + +use ark_starknet::executor::executor; use ark_starknet::interfaces::{ IExecutorDispatcher, IExecutorDispatcherTrait, IMaintenanceDispatcher, @@ -18,8 +23,214 @@ use super::super::common::setup::{ fn test_cancel_offer_order() { let (executor_address, erc20_address, nft_address) = setup(); let token_id = 10; + let (order_hash, offerer, _) = create_offer_order( + executor_address, erc20_address, nft_address, token_id + ); + + let cancel_info = CancelInfo { + order_hash, + canceller: offerer, + token_chain_id: 'SN_MAIN', + token_address: nft_address, + token_id: Option::Some(token_id), + }; + + let mut spy = spy_events(); + cheat_caller_address(executor_address, offerer, CheatSpan::TargetCalls(1)); + IExecutorDispatcher { contract_address: executor_address }.cancel_order(cancel_info); + + spy + .assert_emitted( + @array![ + ( + executor_address, + executor::Event::OrderbookEvent( + OrderbookComponent::Event::OrderCancelled( + OrderbookComponent::OrderCancelled { + order_hash, + reason: OrderStatus::CancelledUser.into(), + order_type: OrderType::Offer, + version: OrderbookComponent::ORDER_CANCELLED_EVENT_VERSION, + } + ) + ) + ) + ] + ); + + assert_eq!( + IOrderbookDispatcher { contract_address: executor_address }.get_order_type(order_hash), + OrderType::Offer, + "Wrong order type" + ); + assert_eq!( + IOrderbookDispatcher { contract_address: executor_address }.get_order_status(order_hash), + OrderStatus::CancelledUser, + "Wrong order status" + ); +} + +#[test] +fn test_cancel_listing_order() { + let (executor_address, erc20_address, nft_address) = setup(); + let start_amount = 10_000_000; + + let (order_hash, offerer, token_id) = create_listing_order( + executor_address, erc20_address, nft_address, start_amount + ); + + let cancel_info = CancelInfo { + order_hash, + canceller: offerer, + token_chain_id: 'SN_MAIN', + token_address: nft_address, + token_id: Option::Some(token_id), + }; + + let mut spy = spy_events(); + cheat_caller_address(executor_address, offerer, CheatSpan::TargetCalls(1)); + IExecutorDispatcher { contract_address: executor_address }.cancel_order(cancel_info); + + spy + .assert_emitted( + @array![ + ( + executor_address, + executor::Event::OrderbookEvent( + OrderbookComponent::Event::OrderCancelled( + OrderbookComponent::OrderCancelled { + order_hash, + reason: OrderStatus::CancelledUser.into(), + order_type: OrderType::Listing, + version: OrderbookComponent::ORDER_CANCELLED_EVENT_VERSION, + } + ) + ) + ) + ] + ); + + assert_eq!( + IOrderbookDispatcher { contract_address: executor_address }.get_order_type(order_hash), + OrderType::Listing, + "Wrong order type" + ); + assert_eq!( + IOrderbookDispatcher { contract_address: executor_address }.get_order_status(order_hash), + OrderStatus::CancelledUser, + "Wrong order status" + ); +} + +#[test] +fn test_cancel_auction_order() { + let (executor_address, erc20_address, nft_address) = setup(); + let start_amount = 10_000_000; + let end_amount = 20_000_000; + + let (order_hash, offerer, token_id) = create_auction_order( + executor_address, erc20_address, nft_address, start_amount, end_amount + ); + + let cancel_info = CancelInfo { + order_hash, + canceller: offerer, + token_chain_id: 'SN_MAIN', + token_address: nft_address, + token_id: Option::Some(token_id), + }; + + let mut spy = spy_events(); + cheat_caller_address(executor_address, offerer, CheatSpan::TargetCalls(1)); + IExecutorDispatcher { contract_address: executor_address }.cancel_order(cancel_info); + + spy + .assert_emitted( + @array![ + ( + executor_address, + executor::Event::OrderbookEvent( + OrderbookComponent::Event::OrderCancelled( + OrderbookComponent::OrderCancelled { + order_hash, + reason: OrderStatus::CancelledUser.into(), + order_type: OrderType::Auction, + version: OrderbookComponent::ORDER_CANCELLED_EVENT_VERSION, + } + ) + ) + ) + ] + ); + + assert_eq!( + IOrderbookDispatcher { contract_address: executor_address }.get_order_type(order_hash), + OrderType::Auction, + "Wrong order type" + ); + assert_eq!( + IOrderbookDispatcher { contract_address: executor_address }.get_order_status(order_hash), + OrderStatus::CancelledUser, + "Wrong order status" + ); +} + +#[test] +fn test_cancel_collection_offer_order() { + let (executor_address, erc20_address, nft_address) = setup(); + let (order_hash, offerer, _) = create_collection_offer_order( + executor_address, erc20_address, nft_address + ); + + let cancel_info = CancelInfo { + order_hash, + canceller: offerer, + token_chain_id: 'SN_MAIN', + token_address: nft_address, + token_id: Option::None + }; + + let mut spy = spy_events(); + cheat_caller_address(executor_address, offerer, CheatSpan::TargetCalls(1)); + IExecutorDispatcher { contract_address: executor_address }.cancel_order(cancel_info); + + spy + .assert_emitted( + @array![ + ( + executor_address, + executor::Event::OrderbookEvent( + OrderbookComponent::Event::OrderCancelled( + OrderbookComponent::OrderCancelled { + order_hash, + reason: OrderStatus::CancelledUser.into(), + order_type: OrderType::CollectionOffer, + version: OrderbookComponent::ORDER_CANCELLED_EVENT_VERSION, + } + ) + ) + ) + ] + ); + + assert_eq!( + IOrderbookDispatcher { contract_address: executor_address }.get_order_type(order_hash), + OrderType::CollectionOffer, + "Wrong order type" + ); + assert_eq!( + IOrderbookDispatcher { contract_address: executor_address }.get_order_status(order_hash), + OrderStatus::CancelledUser, + "Wrong order status" + ); +} - let (order_hash, offerer, start_amount) = create_offer_order( +#[test] +// #[should_panic] +fn test_cancel_offer_order_already_cancelled() { + let (executor_address, erc20_address, nft_address) = setup(); + let token_id = 10; + let (order_hash, offerer, _) = create_offer_order( executor_address, erc20_address, nft_address, token_id ); @@ -33,25 +244,47 @@ fn test_cancel_offer_order() { cheat_caller_address(executor_address, offerer, CheatSpan::TargetCalls(1)); IExecutorDispatcher { contract_address: executor_address }.cancel_order(cancel_info); + + assert_eq!( + IOrderbookDispatcher { contract_address: executor_address }.get_order_status(order_hash), + OrderStatus::CancelledUser, + "Wrong order status" + ); + + cheat_caller_address(executor_address, offerer, CheatSpan::TargetCalls(1)); + IExecutorDispatcher { contract_address: executor_address }.cancel_order(cancel_info); +} + +#[test] +#[should_panic(expected: "Order not found")] +fn test_cancel_offer_order_bad_order_hash() { + let (executor_address, erc20_address, nft_address) = setup(); + let token_id = 10; + let (order_hash, offerer, _) = create_offer_order( + executor_address, erc20_address, nft_address, token_id + ); + + let cancel_info = CancelInfo { + order_hash: order_hash + 1, + canceller: offerer, + token_chain_id: 'SN_MAIN', + token_address: nft_address, + token_id: Option::Some(token_id), + }; + + cheat_caller_address(executor_address, offerer, CheatSpan::TargetCalls(1)); + IExecutorDispatcher { contract_address: executor_address }.cancel_order(cancel_info); } -// #[test] -// fn test_cancel_listing_order() {} -// -// #[test] -// fn test_cancel_auction_order() {} -// -// #[test] -// fn test_cancel_collection_offer_order() {} #[test] -#[should_panic] -fn test_cancel_offer_order_only_offerer() { +#[should_panic(expected: "Caller is not the canceller")] +fn test_cancel_offer_order_caller_is_not_offerer() { let (executor_address, erc20_address, nft_address) = setup(); let token_id = 10; let other = contract_address_const::<'other'>(); - let (order_hash, offerer, start_amount) = create_offer_order( + let (order_hash, offerer, _) = create_offer_order( executor_address, erc20_address, nft_address, token_id ); @@ -66,3 +299,27 @@ fn test_cancel_offer_order_only_offerer() { cheat_caller_address(executor_address, other, CheatSpan::TargetCalls(1)); IExecutorDispatcher { contract_address: executor_address }.cancel_order(cancel_info); } + + +#[test] +#[should_panic(expected: "Canceller is not the offerer")] +fn test_cancel_offer_order_offerer_is_not_the_canceller() { + let (executor_address, erc20_address, nft_address) = setup(); + let token_id = 10; + let other = contract_address_const::<'other'>(); + + let (order_hash, _offerer, _start_amount) = create_offer_order( + executor_address, erc20_address, nft_address, token_id + ); + + let cancel_info = CancelInfo { + order_hash, + canceller: other, + token_chain_id: 'SN_MAIN', + token_address: nft_address, + token_id: Option::Some(token_id), + }; + + cheat_caller_address(executor_address, other, CheatSpan::TargetCalls(1)); + IExecutorDispatcher { contract_address: executor_address }.cancel_order(cancel_info); +} From d3038bfb9e2b5951802a4ddb2599bc8af6e92a3e Mon Sep 17 00:00:00 2001 From: Patrice Tisserand Date: Thu, 12 Sep 2024 11:56:44 +0200 Subject: [PATCH 10/16] fix(contracts): ensure an order with same hash can't be created twice --- .../src/orderbook/orderbook.cairo | 13 +--- .../tests/integration/create_order.cairo | 71 ++++++++++++++++++- 2 files changed, 72 insertions(+), 12 deletions(-) diff --git a/contracts/ark_component/src/orderbook/orderbook.cairo b/contracts/ark_component/src/orderbook/orderbook.cairo index 2b23d2604..6e265aee2 100644 --- a/contracts/ark_component/src/orderbook/orderbook.cairo +++ b/contracts/ark_component/src/orderbook/orderbook.cairo @@ -265,21 +265,12 @@ pub mod OrderbookComponent { .validate_order_type() .expect(orderbook_errors::ORDER_INVALID_DATA); let order_hash = order.compute_order_hash(); + assert(order_status_read(order_hash).is_none(), orderbook_errors::ORDER_ALREADY_EXISTS); match order_type { OrderType::Listing => { - assert( - order_status_read(order_hash).is_none(), - orderbook_errors::ORDER_ALREADY_EXISTS - ); let _ = self._create_listing_order(order, order_type, order_hash); }, - OrderType::Auction => { - assert( - order_status_read(order_hash).is_none(), - orderbook_errors::ORDER_ALREADY_EXISTS - ); - self._create_auction(order, order_type, order_hash); - }, + OrderType::Auction => { self._create_auction(order, order_type, order_hash); }, OrderType::Offer => { self._create_offer(order, order_type, order_hash); }, OrderType::CollectionOffer => { self._create_collection_offer(order, order_type, order_hash); diff --git a/contracts/ark_starknet/tests/integration/create_order.cairo b/contracts/ark_starknet/tests/integration/create_order.cairo index 75c408ae0..02676d729 100644 --- a/contracts/ark_starknet/tests/integration/create_order.cairo +++ b/contracts/ark_starknet/tests/integration/create_order.cairo @@ -183,7 +183,6 @@ fn test_create_collection_offer_order_ok() { let (executor_address, erc20_address, nft_address) = setup(); let offerer = contract_address_const::<'offerer'>(); let start_amount = 10_000_000; - let token_id = 10_u256; Erc20Dispatcher { contract_address: erc20_address }.mint(offerer, start_amount); let order = setup_collection_offer_order(erc20_address, nft_address, offerer, start_amount); @@ -320,3 +319,73 @@ fn test_create_listing_order_disabled() { cheat_caller_address(executor_address, offerer, CheatSpan::TargetCalls(1)); IExecutorDispatcher { contract_address: executor_address }.create_order(order); } + +#[test] +#[should_panic(expected: 'OB: order already exists')] +fn test_create_offer_order_twice() { + let (executor_address, erc20_address, nft_address) = setup(); + let offerer = contract_address_const::<'offerer'>(); + let start_amount = 10_000_000; + let token_id = 10_u256; + Erc20Dispatcher { contract_address: erc20_address }.mint(offerer, start_amount); + + let order = setup_offer_order(erc20_address, nft_address, offerer, token_id, start_amount); + + cheat_caller_address(executor_address, offerer, CheatSpan::TargetCalls(2)); + IExecutorDispatcher { contract_address: executor_address }.create_order(order); + IExecutorDispatcher { contract_address: executor_address }.create_order(order); +} + +#[test] +#[should_panic(expected: 'OB: order already exists')] +fn test_create_listing_order_twice() { + let (executor_address, erc20_address, nft_address) = setup(); + let offerer = contract_address_const::<'offerer'>(); + let start_amount = 10_000_000; + let token_id: u256 = Erc721Dispatcher { contract_address: nft_address } + .get_current_token_id() + .into(); + Erc721Dispatcher { contract_address: nft_address }.mint(offerer, 'base_uri'); + + let order = setup_listing_order(erc20_address, nft_address, offerer, token_id, start_amount); + + cheat_caller_address(executor_address, offerer, CheatSpan::TargetCalls(2)); + IExecutorDispatcher { contract_address: executor_address }.create_order(order); + IExecutorDispatcher { contract_address: executor_address }.create_order(order); +} + +#[test] +#[should_panic(expected: 'OB: order already exists')] +fn test_create_auction_order_twice() { + let (executor_address, erc20_address, nft_address) = setup(); + let offerer = contract_address_const::<'offerer'>(); + let start_amount = 10_000_000; + let end_amount = start_amount * 2; + let token_id: u256 = Erc721Dispatcher { contract_address: nft_address } + .get_current_token_id() + .into(); + Erc721Dispatcher { contract_address: nft_address }.mint(offerer, 'base_uri'); + + let order = setup_auction_order( + erc20_address, nft_address, offerer, token_id, start_amount, end_amount + ); + + cheat_caller_address(executor_address, offerer, CheatSpan::TargetCalls(2)); + IExecutorDispatcher { contract_address: executor_address }.create_order(order); + IExecutorDispatcher { contract_address: executor_address }.create_order(order); +} + +#[test] +#[should_panic(expected: 'OB: order already exists')] +fn test_create_collection_offer_order_twice() { + let (executor_address, erc20_address, nft_address) = setup(); + let offerer = contract_address_const::<'offerer'>(); + let start_amount = 10_000_000; + Erc20Dispatcher { contract_address: erc20_address }.mint(offerer, start_amount); + + let order = setup_collection_offer_order(erc20_address, nft_address, offerer, start_amount); + + cheat_caller_address(executor_address, offerer, CheatSpan::TargetCalls(2)); + IExecutorDispatcher { contract_address: executor_address }.create_order(order); + IExecutorDispatcher { contract_address: executor_address }.create_order(order); +} From 016129e08b84508d9c68f3eb613ee53750a55a31 Mon Sep 17 00:00:00 2001 From: Patrice Tisserand Date: Thu, 12 Sep 2024 17:08:20 +0200 Subject: [PATCH 11/16] contracts: add test case for expired orders creation --- .../tests/integration/create_order.cairo | 85 ++++++++++++++++++- 1 file changed, 84 insertions(+), 1 deletion(-) diff --git a/contracts/ark_starknet/tests/integration/create_order.cairo b/contracts/ark_starknet/tests/integration/create_order.cairo index 02676d729..d3f421788 100644 --- a/contracts/ark_starknet/tests/integration/create_order.cairo +++ b/contracts/ark_starknet/tests/integration/create_order.cairo @@ -16,7 +16,10 @@ use ark_tokens::erc20::IFreeMintDispatcherTrait as Erc20DispatcherTrait; use ark_tokens::erc721::IFreeMintDispatcher as Erc721Dispatcher; use ark_tokens::erc721::IFreeMintDispatcherTrait as Erc721DispatcherTrait; -use snforge_std::{cheat_caller_address, CheatSpan, spy_events, EventSpyAssertionsTrait,}; +use snforge_std::{ + cheat_caller_address, CheatSpan, spy_events, EventSpyAssertionsTrait, + start_cheat_block_timestamp_global, stop_cheat_block_timestamp_global +}; use starknet::{ContractAddress, contract_address_const}; use super::super::common::setup::{ @@ -389,3 +392,83 @@ fn test_create_collection_offer_order_twice() { IExecutorDispatcher { contract_address: executor_address }.create_order(order); IExecutorDispatcher { contract_address: executor_address }.create_order(order); } + +#[test] +#[should_panic(expected: 'END_DATE_IN_THE_PAST')] +fn test_create_offer_order_expired() { + let (executor_address, erc20_address, nft_address) = setup(); + let offerer = contract_address_const::<'offerer'>(); + let start_amount = 10_000_000; + let token_id = 10_u256; + Erc20Dispatcher { contract_address: erc20_address }.mint(offerer, start_amount); + + let mut order = setup_offer_order(erc20_address, nft_address, offerer, token_id, start_amount); + let current = starknet::get_block_timestamp(); + order.end_date = current + 10; + start_cheat_block_timestamp_global(current + 30); + cheat_caller_address(executor_address, offerer, CheatSpan::TargetCalls(1)); + IExecutorDispatcher { contract_address: executor_address }.create_order(order); + stop_cheat_block_timestamp_global(); +} + +#[test] +#[should_panic(expected: 'END_DATE_IN_THE_PAST')] +fn test_create_listing_order_expired() { + let (executor_address, erc20_address, nft_address) = setup(); + let offerer = contract_address_const::<'offerer'>(); + let start_amount = 10_000_000; + let token_id: u256 = Erc721Dispatcher { contract_address: nft_address } + .get_current_token_id() + .into(); + Erc721Dispatcher { contract_address: nft_address }.mint(offerer, 'base_uri'); + + let mut order = setup_listing_order( + erc20_address, nft_address, offerer, token_id, start_amount + ); + let current = starknet::get_block_timestamp(); + order.end_date = current + 10; + start_cheat_block_timestamp_global(current + 30); + cheat_caller_address(executor_address, offerer, CheatSpan::TargetCalls(1)); + IExecutorDispatcher { contract_address: executor_address }.create_order(order); + stop_cheat_block_timestamp_global(); +} + +#[test] +#[should_panic(expected: 'END_DATE_IN_THE_PAST')] +fn test_create_auction_order_expired() { + let (executor_address, erc20_address, nft_address) = setup(); + let offerer = contract_address_const::<'offerer'>(); + let start_amount = 10_000_000; + let end_amount = start_amount * 2; + let token_id: u256 = Erc721Dispatcher { contract_address: nft_address } + .get_current_token_id() + .into(); + Erc721Dispatcher { contract_address: nft_address }.mint(offerer, 'base_uri'); + + let mut order = setup_auction_order( + erc20_address, nft_address, offerer, token_id, start_amount, end_amount + ); + let current = starknet::get_block_timestamp(); + order.end_date = current + 10; + start_cheat_block_timestamp_global(current + 30); + cheat_caller_address(executor_address, offerer, CheatSpan::TargetCalls(1)); + IExecutorDispatcher { contract_address: executor_address }.create_order(order); + stop_cheat_block_timestamp_global(); +} + +#[test] +#[should_panic(expected: 'END_DATE_IN_THE_PAST')] +fn test_create_collection_offer_order_expired() { + let (executor_address, erc20_address, nft_address) = setup(); + let offerer = contract_address_const::<'offerer'>(); + let start_amount = 10_000_000; + Erc20Dispatcher { contract_address: erc20_address }.mint(offerer, start_amount); + + let mut order = setup_collection_offer_order(erc20_address, nft_address, offerer, start_amount); + let current = starknet::get_block_timestamp(); + order.end_date = current + 10; + start_cheat_block_timestamp_global(current + 30); + cheat_caller_address(executor_address, offerer, CheatSpan::TargetCalls(1)); + IExecutorDispatcher { contract_address: executor_address }.create_order(order); + stop_cheat_block_timestamp_global(); +} From 900e9c2d98452eafe1648d092085e3760924e697 Mon Sep 17 00:00:00 2001 From: Patrice Tisserand Date: Fri, 13 Sep 2024 10:28:25 +0200 Subject: [PATCH 12/16] contracts(starknet): arkchain orderbook is no more used --- contracts/ark_starknet/src/executor.cairo | 19 ------------------- contracts/ark_starknet/src/interfaces.cairo | 3 --- 2 files changed, 22 deletions(-) diff --git a/contracts/ark_starknet/src/executor.cairo b/contracts/ark_starknet/src/executor.cairo index f19719cd3..204bf58d7 100644 --- a/contracts/ark_starknet/src/executor.cairo +++ b/contracts/ark_starknet/src/executor.cairo @@ -96,7 +96,6 @@ mod executor { #[storage] struct Storage { admin_address: ContractAddress, - arkchain_orderbook_address: ContractAddress, eth_contract_address: ContractAddress, chain_id: felt252, broker_fees: Map, @@ -253,30 +252,12 @@ mod executor { } } - fn get_orderbook_address(self: @ContractState) -> ContractAddress { - self.arkchain_orderbook_address.read() - } - - fn update_arkchain_orderbook_address( - ref self: ContractState, orderbook_address: ContractAddress - ) { - _ensure_admin(@self); - - self.arkchain_orderbook_address.write(orderbook_address); - } - fn update_eth_address(ref self: ContractState, eth_address: ContractAddress) { _ensure_admin(@self); self.eth_contract_address.write(eth_address); } - fn update_orderbook_address(ref self: ContractState, orderbook_address: ContractAddress) { - _ensure_admin(@self); - - self.arkchain_orderbook_address.write(orderbook_address); - } - fn update_admin_address(ref self: ContractState, admin_address: ContractAddress) { _ensure_admin(@self); diff --git a/contracts/ark_starknet/src/interfaces.cairo b/contracts/ark_starknet/src/interfaces.cairo index e2b02f514..f283272b5 100644 --- a/contracts/ark_starknet/src/interfaces.cairo +++ b/contracts/ark_starknet/src/interfaces.cairo @@ -20,10 +20,7 @@ trait IExecutor { fn create_order(ref self: T, order: OrderV1); // fn execute_order(ref self: T, execution_info: ExecutionInfo); fn update_admin_address(ref self: T, admin_address: ContractAddress); - fn update_orderbook_address(ref self: T, orderbook_address: ContractAddress); fn update_eth_address(ref self: T, eth_address: ContractAddress); - fn get_orderbook_address(self: @T) -> ContractAddress; - fn update_arkchain_orderbook_address(ref self: T, orderbook_address: ContractAddress); fn set_broker_fees(ref self: T, fees_ratio: FeesRatio); fn get_broker_fees(self: @T, broker_address: ContractAddress) -> FeesRatio; fn set_ark_fees(ref self: T, fees_ratio: FeesRatio); From c45e200779bc8f093d2c63910b334f18724ea22c Mon Sep 17 00:00:00 2001 From: Patrice Tisserand Date: Sat, 14 Sep 2024 21:46:25 +0200 Subject: [PATCH 13/16] CI: run SDK test with devnet --- .env.devnet | 44 +++++ .github/actions/install-snforge/action.yml | 34 ++++ .github/workflows/arkproject-contracts.yml | 75 +++++--- pnpm-lock.yaml | 201 ++++++++++++++++++--- 4 files changed, 306 insertions(+), 48 deletions(-) create mode 100644 .env.devnet create mode 100644 .github/actions/install-snforge/action.yml diff --git a/.env.devnet b/.env.devnet new file mode 100644 index 000000000..e80c1d960 --- /dev/null +++ b/.env.devnet @@ -0,0 +1,44 @@ +# Starknet RPC URL +STARKNET_RPC_URL=http://0.0.0.0:5050 + +## starknet-devnet-rs 0.2.0 account --seed 0 +# Starknet accounts +STARKNET_ADMIN_ADDRESS_DEV=0x64b48806902a367c8598f4f95c305e8c1a1acba5f082d294a43793113115691 +STARKNET_ADMIN_PRIVATE_KEY_DEV=0x0000000000000000000000000000000071d7bb07b9a64f6f78ac4c816aff4da9 + +STARKNET_ACCOUNT1_ADDRESS=0x78662e7352d062084b0010068b99288486c2d8b914f6e2a55ce945f8792c8b1 +STARKNET_ACCOUNT1_PRIVATE_KEY=0x000000000000000000000000000000000e1406455b7d66b1690803be066cbe5e +STARKNET_ACCOUNT1_PUBLIC_KEY=0x007a1bb2744a7dd29bffd44341dbd78008adb4bc11733601e7eddff322ada9cb + +STARKNET_ACCOUNT2_ADDRESS=0x49dfb8ce986e21d354ac93ea65e6a11f639c1934ea253e5ff14ca62eca0f38e +STARKNET_ACCOUNT2_PRIVATE_KEY=0x00000000000000000000000000000000a20a02f0ac53692d144b20cb371a60d7 +STARKNET_ACCOUNT2_PUBLIC_KEY=0x00b8fd4ddd415902d96f61b7ad201022d495997c2dff8eb9e0eb86253e30fabc + +STARKNET_ARK_RECEIVER_ADDRESS=0x4f348398f859a55a0c80b1446c5fdc37edb3a8478a32f10764659fc241027d3 +STARKNET_ARK_RECEIVER_PRIVATE_KEY=0x00000000000000000000000000000000a641611c17d4d92bd0790074e34beeb7 + +STARKNET_ARK_COLLECTION_RECEIVER_ADDRESS=0xd513de92c16aa42418cf7e5b60f8022dbee1b4dfd81bcf03ebee079cfb5cb5 +STARKNET_ARK_COLLECTION_RECEIVER_PRIVATE_KEY=0x000000000000000000000000000000005b4ac23628a5749277bcabbf4726b025 + +STARKNET_ARK_COLLECTION_2981_RECEIVER_ADDRESS=0x1e8c6c17efa3a047506c0b1610bd188aa3e3dd6c5d9227549b65428de24de78 +STARKNET_ARK_COLLECTION_2981_RECEIVER_PRIVATE_KEY=0x00000000000000000000000000000000836203aceb0e9b0066138c321dda5ae6 + +STARKNET_LISTING_BROKER_ACCOUNT_ADDRESS=0x557ba9ef60b52dad611d79b60563901458f2476a5c1002a8b4869fcb6654c7e +STARKNET_LISTING_BROKER_ACCOUNT_PRIVATE_KEY=0x0000000000000000000000000000000015b5e3013d752c909988204714f1ff35 + +STARKNET_SALE_BROKER_ACCOUNT_ADDRESS=0x3736286f1050d4ba816b4d56d15d80ca74c1752c4e847243f1da726c36e06f +STARKNET_SALE_BROKER_ACCOUNT_PRIVATE_KEY=0x00000000000000000000000000000000a56597ba3378fa9e6440ea9ae0cf2865 + +SOLIS_ADMIN_ADDRESS_DEV=0xb3ff441a68610b30fd5e2abbf3a1548eb6ba6f3559f2862bf2dc757e5828ca +SOLIS_ADMIN_PRIVATE_KEY_DEV=0x2bbf4f9fd0bbb2e60b0316c1fe0b76cf7a4d0198bd493ced9b8df2a3a24d68a +SOLIS_ADMIN_PUBLIC_KEY_DEV=0x640466ebd2ce505209d3e5c4494b4276ed8f1cde764d757eb48831961f7cdea + +SOLIS_ADMIN_ADDRESS=0x6b86e40118f29ebe393a75469b4d926c7a44c2e2681b6d319520b7c1156d114 +SOLIS_ADMIN_PRIVATE_KEY=0x1c9053c053edf324aec366a34c6901b1095b07af69495bffec7d7fe21effb1b + +# Starknet network +STARKNET_NETWORK_ID=dev +# Solis network +SOLIS_NETWORK_ID=dev + +BROKER_ID= diff --git a/.github/actions/install-snforge/action.yml b/.github/actions/install-snforge/action.yml new file mode 100644 index 000000000..3de238ac2 --- /dev/null +++ b/.github/actions/install-snforge/action.yml @@ -0,0 +1,34 @@ +name: "Install contract dependencies" +description: "Install dependencies for smart contract" + +env: + SCARB_VERSION: 2.7.1 + STARKNET_FOUNDRY_VERSION: 0.30.0 + +runs: + using: "composite" + steps: + - name: Install universal sierra compiler + run: | + curl -L https://raw.githubusercontent.com/software-mansion/universal-sierra-compiler/master/scripts/install.sh | sh + echo "/root/.local/bin" >> ${GITHUB_PATH} + + - name: Check universal sierra compiler version + run: universal-sierra-compiler --version + + - name: Setup Scarb + uses: software-mansion/setup-scarb@v1 + with: + scarb-version: ${{ env.SCARB_VERSION }} + + - name: Setup Starknet Foundry + uses: foundry-rs/setup-snfoundry@v3 + with: + starknet-foundry-version: ${{ env.STARKNET_FOUNDRY_VERSION }} + + - name: Set Up Stable Rust Toolchain + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + diff --git a/.github/workflows/arkproject-contracts.yml b/.github/workflows/arkproject-contracts.yml index 499894f3c..979857317 100644 --- a/.github/workflows/arkproject-contracts.yml +++ b/.github/workflows/arkproject-contracts.yml @@ -10,47 +10,74 @@ on: paths: - "contracts/**" +env: + SCARB_VERSION: 2.7.1 + STARKNET_DEVNET_VERSION: 0.2.0-rc3 + DEVNET_DUMP_PATH: /devnet-dump.json jobs: fmt: runs-on: ubuntu-latest name: Cairo formatting steps: - name: Checkout Repository - uses: actions/checkout@v3 - - name: Install universal sierra compiler - run: curl -L https://raw.githubusercontent.com/software-mansion/universal-sierra-compiler/master/scripts/install.sh | sh + uses: actions/checkout@v4 + - name: Setup Scarb uses: software-mansion/setup-scarb@v1 with: - scarb-version: 2.7.1 + scarb-version: ${{ env.SCARB_VERSION }} + - name: Check Scarb Formatting run: cd contracts && scarb fmt --check - test: + + forge-test: runs-on: ubuntu-latest name: Cairo starknet foundry tests steps: - name: Checkout Repository - uses: actions/checkout@v3 - - name: Install universal sierra compiler - run: curl -L https://raw.githubusercontent.com/software-mansion/universal-sierra-compiler/master/scripts/install.sh | sh - - name: Setup Scarb - uses: software-mansion/setup-scarb@v1 - with: - scarb-version: 2.7.1 + uses: actions/checkout@v4 - - name: Setup Starknet Foundry - uses: foundry-rs/setup-snfoundry@v2 - with: - starknet-foundry-version: 0.28.0 + - name: Install starknet foundry & dependencies + uses: ./.github/actions/install-snforge + + - name: Test contracts + run: cd contracts && snforge test + + devnet-test: + runs-on: ubuntu-latest + name: Running SDK test with starknet-devnet + # needs: forge-test + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + + - name: Install starknet foundry & dependencies + uses: ./.github/actions/install-snforge + + - name: Build smart contracts + run: cd contracts && scarb build --workspace + + - name: Run starknet-devnet as a background process + run: | + docker run -d --rm --name starknet-devnet \ + -p 5050:5050 \ + ptisserand/starknet-devnet-rs:${STARKNET_DEVNET_VERSION} \ + --seed 0 --dump-path $DEVNET_DUMP_PATH --state-archive-capacity full + sleep 3 # Wait for 3 seconds for the Docker container to initialize - - name: Test ark_common contracts - run: cd contracts/ark_common && snforge test + - name: Install SDK dependencies + uses: ./.github/actions/install-dependencies + + - name: Deploy smart contract + run: pnpm deploy:starknet:local + + - name: Run SDK test + run: | + cp .env.devnet .env + pnpm test - - name: Test ark_orderbook contracts - run: cd contracts/ark_orderbook && snforge test + - name: Stop starknet-devnet container + if: always() + run: docker stop starknet-devnet - - name: Test ark_starknet contracts - run: cd contracts/ark_starknet && snforge test - - name: Test ark_tokens contracts - run: cd contracts/ark_tokens && snforge test diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c95909a53..a0a506cad 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -58,7 +58,7 @@ importers: version: 6.11.0 ts-node: specifier: ^10.9.1 - version: 10.9.2(@types/node@20.16.1)(typescript@5.5.4) + version: 10.9.2(@types/node@22.5.5)(typescript@5.5.4) typescript: specifier: ^5.0.0 version: 5.5.4 @@ -134,8 +134,8 @@ importers: packages/deployer: dependencies: commander: - specifier: ^11.1.0 - version: 11.1.0 + specifier: ^12.1.0 + version: 12.1.0 dotenv: specifier: ^16.3.1 version: 16.4.5 @@ -159,8 +159,8 @@ importers: specifier: workspace:* version: link:../typescript-config '@types/node': - specifier: ^20.10.7 - version: 20.16.1 + specifier: ^22.5.4 + version: 22.5.5 tsx: specifier: ^4.11.0 version: 4.17.0 @@ -252,7 +252,7 @@ importers: version: 16.4.5 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.16.1)(ts-node@10.9.2(@types/node@20.16.1)(typescript@5.5.4)) + version: 29.7.0(@types/node@22.5.5) jest-environment-jsdom: specifier: ^29.7.0 version: 29.7.0 @@ -264,13 +264,13 @@ importers: version: 18.3.1(react@18.3.1) ts-jest: specifier: ^29.1.1 - version: 29.2.5(@babel/core@7.25.2)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.25.2))(esbuild@0.20.2)(jest@29.7.0(@types/node@20.16.1)(ts-node@10.9.2(@types/node@20.16.1)(typescript@5.5.4)))(typescript@5.5.4) + version: 29.2.5(@babel/core@7.25.2)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.25.2))(jest@29.7.0(@types/node@22.5.5))(typescript@5.5.4) typescript: specifier: ^5.3.3 version: 5.5.4 vitest: specifier: ^2.0.5 - version: 2.0.5(@types/node@20.16.1)(jsdom@20.0.3) + version: 2.0.5(@types/node@22.5.5)(jsdom@20.0.3) packages/typescript-config: {} @@ -1433,6 +1433,9 @@ packages: '@types/node@20.16.1': resolution: {integrity: sha512-zJDo7wEadFtSyNz5QITDfRcrhqDvQI1xQNQ0VoizPjM/dVAODqqIUWbJPkvsxmTI0MYRGRikcdjMPhOssnPejQ==} + '@types/node@22.5.5': + resolution: {integrity: sha512-Xjs4y5UPO/CLdzpgR6GirZJx36yScjh73+2NlLlkFRSoQN8B0DpfXPdZGnvVmLRLOsqDpOfTNv7D9trgGhmOIA==} + '@types/normalize-package-data@2.4.4': resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} @@ -1945,9 +1948,9 @@ packages: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} - commander@11.1.0: - resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} - engines: {node: '>=16'} + commander@12.1.0: + resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} + engines: {node: '>=18'} commander@4.1.1: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} @@ -5823,6 +5826,10 @@ snapshots: dependencies: undici-types: 6.19.8 + '@types/node@22.5.5': + dependencies: + undici-types: 6.19.8 + '@types/normalize-package-data@2.4.4': {} '@types/prop-types@15.7.12': {} @@ -5842,7 +5849,7 @@ snapshots: '@types/ws@8.5.12': dependencies: - '@types/node': 20.12.14 + '@types/node': 20.16.1 '@types/yargs-parser@21.0.3': {} @@ -5987,7 +5994,7 @@ snapshots: '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4) '@typescript-eslint/parser': 6.21.0(eslint@8.57.0)(typescript@5.5.4) eslint-config-prettier: 9.1.0(eslint@8.57.0) - eslint-import-resolver-alias: 1.1.2(eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)) + eslint-import-resolver-alias: 1.1.2(eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)) eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.5.4))(eslint-plugin-import@2.29.1)(eslint@8.57.0) eslint-plugin-eslint-comments: 3.2.0(eslint@8.57.0) eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) @@ -6462,7 +6469,7 @@ snapshots: dependencies: delayed-stream: 1.0.0 - commander@11.1.0: {} + commander@12.1.0: {} commander@4.1.1: {} @@ -6487,6 +6494,21 @@ snapshots: - supports-color - ts-node + create-jest@29.7.0(@types/node@22.5.5): + dependencies: + '@jest/types': 29.6.3 + chalk: 4.1.2 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-config: 29.7.0(@types/node@22.5.5) + jest-util: 29.7.0 + prompts: 2.4.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + create-require@1.1.1: {} cross-spawn@5.1.0: @@ -6893,7 +6915,7 @@ snapshots: eslint: 8.57.0 eslint-plugin-turbo: 1.13.4(eslint@8.57.0) - eslint-import-resolver-alias@1.1.2(eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)): + eslint-import-resolver-alias@1.1.2(eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)): dependencies: eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) @@ -6972,7 +6994,7 @@ snapshots: eslint: 8.57.0 optionalDependencies: '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4) - jest: 29.7.0(@types/node@20.16.1)(ts-node@10.9.2(@types/node@20.16.1)(typescript@5.5.4)) + jest: 29.7.0 transitivePeerDependencies: - supports-color - typescript @@ -7789,6 +7811,26 @@ snapshots: - babel-plugin-macros - supports-color + jest-cli@29.7.0: + dependencies: + '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@20.16.1)(typescript@5.5.4)) + '@jest/test-result': 29.7.0 + '@jest/types': 29.6.3 + chalk: 4.1.2 + create-jest: 29.7.0(@types/node@20.16.1)(ts-node@10.9.2(@types/node@20.16.1)(typescript@5.5.4)) + exit: 0.1.2 + import-local: 3.2.0 + jest-config: 29.7.0(@types/node@20.16.1)(ts-node@10.9.2(@types/node@20.16.1)(typescript@5.5.4)) + jest-util: 29.7.0 + jest-validate: 29.7.0 + yargs: 17.7.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + optional: true + jest-cli@29.7.0(@types/node@20.16.1)(ts-node@10.9.2(@types/node@20.16.1)(typescript@5.5.4)): dependencies: '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@20.16.1)(typescript@5.5.4)) @@ -7808,6 +7850,25 @@ snapshots: - supports-color - ts-node + jest-cli@29.7.0(@types/node@22.5.5): + dependencies: + '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@20.16.1)(typescript@5.5.4)) + '@jest/test-result': 29.7.0 + '@jest/types': 29.6.3 + chalk: 4.1.2 + create-jest: 29.7.0(@types/node@22.5.5) + exit: 0.1.2 + import-local: 3.2.0 + jest-config: 29.7.0(@types/node@22.5.5) + jest-util: 29.7.0 + jest-validate: 29.7.0 + yargs: 17.7.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + jest-config@29.7.0(@types/node@20.16.1)(ts-node@10.9.2(@types/node@20.16.1)(typescript@5.5.4)): dependencies: '@babel/core': 7.25.2 @@ -7839,6 +7900,36 @@ snapshots: - babel-plugin-macros - supports-color + jest-config@29.7.0(@types/node@22.5.5): + dependencies: + '@babel/core': 7.25.2 + '@jest/test-sequencer': 29.7.0 + '@jest/types': 29.6.3 + babel-jest: 29.7.0(@babel/core@7.25.2) + chalk: 4.1.2 + ci-info: 3.9.0 + deepmerge: 4.3.1 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-circus: 29.7.0 + jest-environment-node: 29.7.0 + jest-get-type: 29.6.3 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-runner: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + micromatch: 4.0.8 + parse-json: 5.2.0 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-json-comments: 3.1.1 + optionalDependencies: + '@types/node': 22.5.5 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + jest-diff@29.7.0: dependencies: chalk: 4.1.2 @@ -8069,6 +8160,19 @@ snapshots: merge-stream: 2.0.0 supports-color: 8.1.1 + jest@29.7.0: + dependencies: + '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@20.16.1)(typescript@5.5.4)) + '@jest/types': 29.6.3 + import-local: 3.2.0 + jest-cli: 29.7.0 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + optional: true + jest@29.7.0(@types/node@20.16.1)(ts-node@10.9.2(@types/node@20.16.1)(typescript@5.5.4)): dependencies: '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@20.16.1)(typescript@5.5.4)) @@ -8081,6 +8185,18 @@ snapshots: - supports-color - ts-node + jest@29.7.0(@types/node@22.5.5): + dependencies: + '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@20.16.1)(typescript@5.5.4)) + '@jest/types': 29.6.3 + import-local: 3.2.0 + jest-cli: 29.7.0(@types/node@22.5.5) + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + jju@1.4.0: {} joycon@3.1.1: {} @@ -9179,6 +9295,25 @@ snapshots: babel-jest: 29.7.0(@babel/core@7.25.2) esbuild: 0.20.2 + ts-jest@29.2.5(@babel/core@7.25.2)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.25.2))(jest@29.7.0(@types/node@22.5.5))(typescript@5.5.4): + dependencies: + bs-logger: 0.2.6 + ejs: 3.1.10 + fast-json-stable-stringify: 2.1.0 + jest: 29.7.0(@types/node@22.5.5) + jest-util: 29.7.0 + json5: 2.2.3 + lodash.memoize: 4.1.2 + make-error: 1.3.6 + semver: 7.6.3 + typescript: 5.5.4 + yargs-parser: 21.1.1 + optionalDependencies: + '@babel/core': 7.25.2 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + babel-jest: 29.7.0(@babel/core@7.25.2) + ts-mixer@6.0.4: {} ts-node@10.9.2(@types/node@20.16.1)(typescript@5.5.4): @@ -9199,6 +9334,24 @@ snapshots: v8-compile-cache-lib: 3.0.1 yn: 3.1.1 + ts-node@10.9.2(@types/node@22.5.5)(typescript@5.5.4): + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.11 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.4 + '@types/node': 22.5.5 + acorn: 8.12.1 + acorn-walk: 8.3.3 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 5.5.4 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + tsconfig-paths@3.15.0: dependencies: '@types/json5': 0.0.29 @@ -9393,13 +9546,13 @@ snapshots: - utf-8-validate - zod - vite-node@2.0.5(@types/node@20.16.1): + vite-node@2.0.5(@types/node@22.5.5): dependencies: cac: 6.7.14 debug: 4.3.6(supports-color@5.5.0) pathe: 1.1.2 tinyrainbow: 1.2.0 - vite: 5.4.3(@types/node@20.16.1) + vite: 5.4.3(@types/node@22.5.5) transitivePeerDependencies: - '@types/node' - less @@ -9411,16 +9564,16 @@ snapshots: - supports-color - terser - vite@5.4.3(@types/node@20.16.1): + vite@5.4.3(@types/node@22.5.5): dependencies: esbuild: 0.21.5 postcss: 8.4.45 rollup: 4.21.0 optionalDependencies: - '@types/node': 20.16.1 + '@types/node': 22.5.5 fsevents: 2.3.3 - vitest@2.0.5(@types/node@20.16.1)(jsdom@20.0.3): + vitest@2.0.5(@types/node@22.5.5)(jsdom@20.0.3): dependencies: '@ampproject/remapping': 2.3.0 '@vitest/expect': 2.0.5 @@ -9438,11 +9591,11 @@ snapshots: tinybench: 2.9.0 tinypool: 1.0.1 tinyrainbow: 1.2.0 - vite: 5.4.3(@types/node@20.16.1) - vite-node: 2.0.5(@types/node@20.16.1) + vite: 5.4.3(@types/node@22.5.5) + vite-node: 2.0.5(@types/node@22.5.5) why-is-node-running: 2.3.0 optionalDependencies: - '@types/node': 20.16.1 + '@types/node': 22.5.5 jsdom: 20.0.3 transitivePeerDependencies: - less From 9261660b8569b995bf0e2f549b0dcce589a93b74 Mon Sep 17 00:00:00 2001 From: Patrice Tisserand Date: Sat, 14 Sep 2024 21:53:25 +0200 Subject: [PATCH 14/16] fix(CI): add missing shell property for action --- .github/actions/install-snforge/action.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/actions/install-snforge/action.yml b/.github/actions/install-snforge/action.yml index 3de238ac2..eebf800ea 100644 --- a/.github/actions/install-snforge/action.yml +++ b/.github/actions/install-snforge/action.yml @@ -9,11 +9,13 @@ runs: using: "composite" steps: - name: Install universal sierra compiler + shell: bash run: | curl -L https://raw.githubusercontent.com/software-mansion/universal-sierra-compiler/master/scripts/install.sh | sh echo "/root/.local/bin" >> ${GITHUB_PATH} - name: Check universal sierra compiler version + shell: bash run: universal-sierra-compiler --version - name: Setup Scarb From 772d357a94a7d53d8b5500b589ff80c0fca13aa6 Mon Sep 17 00:00:00 2001 From: Patrice Tisserand Date: Sat, 14 Sep 2024 22:01:02 +0200 Subject: [PATCH 15/16] turbo: ARKCHAIN_RPC_URL is no more needed --- turbo.json | 49 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/turbo.json b/turbo.json index 8a94cd071..b85cae98c 100644 --- a/turbo.json +++ b/turbo.json @@ -1,10 +1,16 @@ { "$schema": "https://turbo.build/schema.json", - "globalDependencies": ["**/.env.*local"], - "globalDotEnv": [".env"], + "globalDependencies": [ + "**/.env.*local" + ], + "globalDotEnv": [ + ".env" + ], "pipeline": { "build:packages": { - "dependsOn": ["^build"], + "dependsOn": [ + "^build" + ], "outputs": [ ".next/**", "!.next/cache/**", @@ -14,7 +20,9 @@ }, "build": { "cache": false, - "dependsOn": ["^build"], + "dependsOn": [ + "^build" + ], "outputs": [ ".next/**", "!.next/cache/**", @@ -23,26 +31,42 @@ ] }, "@ark-project/demo#build": { - "dependsOn": ["^build"], + "dependsOn": [ + "^build" + ], "env": [ "NEXT_PUBLIC_NFT_API_KEY", "NEXT_PUBLIC_ORDERBOOK_API_URL", "NEXT_PUBLIC_NFT_API_URL" ], - "outputs": [".next/**", "!.next/cache/**", ".vercel/output/**"] + "outputs": [ + ".next/**", + "!.next/cache/**", + ".vercel/output/**" + ] }, "dev": { - "dependsOn": ["^dev"], - "outputs": [".dist/**"] + "dependsOn": [ + "^dev" + ], + "outputs": [ + ".dist/**" + ] }, "lint": { - "dependsOn": ["^lint"] + "dependsOn": [ + "^lint" + ] }, "test": { - "dependsOn": ["^test"] + "dependsOn": [ + "^test" + ] }, "lint:fix": { - "dependsOn": ["^lint:fix"] + "dependsOn": [ + "^lint:fix" + ] }, "clean": { "cache": false @@ -78,7 +102,6 @@ }, "globalEnv": [ "ACCOUNT_CLASS_HASH", - "ARKCHAIN_RPC_URL", "BROKER_ID", "CI", "NEXT_PUBLIC_BROKER_ID", @@ -114,4 +137,4 @@ "SOLIS_ADMIN_PUBLIC_KEY_MAINNET", "SOLIS_NODE_URL_SEPOLIA" ] -} +} \ No newline at end of file From f9b47e860d5f2ddec536eec7d9173ac02c96ab8f Mon Sep 17 00:00:00 2001 From: Patrice Tisserand Date: Sat, 14 Sep 2024 22:07:10 +0200 Subject: [PATCH 16/16] fix(CI): add missing step for devnet environment --- .github/workflows/arkproject-contracts.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/arkproject-contracts.yml b/.github/workflows/arkproject-contracts.yml index 979857317..77e18a5a9 100644 --- a/.github/workflows/arkproject-contracts.yml +++ b/.github/workflows/arkproject-contracts.yml @@ -68,6 +68,9 @@ jobs: - name: Install SDK dependencies uses: ./.github/actions/install-dependencies + - name: Setup environment for devnet + run: cp .env.devnet .env + - name: Deploy smart contract run: pnpm deploy:starknet:local