diff --git a/contracts/Scarb.lock b/contracts/Scarb.lock index c8865abf6..4b6ca9bb9 100644 --- a/contracts/Scarb.lock +++ b/contracts/Scarb.lock @@ -21,7 +21,6 @@ name = "ark_oz" version = "0.1.0" dependencies = [ "openzeppelin", - "snforge_std", ] [[package]] diff --git a/contracts/Scarb.toml b/contracts/Scarb.toml index 132ebcb44..ef3a145b8 100644 --- a/contracts/Scarb.toml +++ b/contracts/Scarb.toml @@ -1,3 +1,6 @@ [workspace] members = ["ark_common", "ark_orderbook", "ark_starknet", "ark_tokens", "solis"] + +[workspace.dependencies] +snforge_std = { git = "https://github.com/foundry-rs/starknet-foundry.git", tag = "v0.18.0" } diff --git a/contracts/ark_common/Scarb.toml b/contracts/ark_common/Scarb.toml index 3dca0b95c..3f3334b18 100644 --- a/contracts/ark_common/Scarb.toml +++ b/contracts/ark_common/Scarb.toml @@ -6,7 +6,9 @@ version = "0.1.0" [dependencies] starknet = "2.5.4" -snforge_std = { git = "https://github.com/foundry-rs/starknet-foundry.git", tag = "v0.18.0" } + +[dev-dependencies] +snforge_std.workspace = true [lib] diff --git a/contracts/ark_orderbook/Scarb.toml b/contracts/ark_orderbook/Scarb.toml index c712c590a..806b190ee 100644 --- a/contracts/ark_orderbook/Scarb.toml +++ b/contracts/ark_orderbook/Scarb.toml @@ -5,7 +5,9 @@ version = "0.1.0" [dependencies] ark_common = { path = "../ark_common" } starknet = "2.5.4" -snforge_std = { git = "https://github.com/foundry-rs/starknet-foundry.git", tag = "v0.18.0" } + +[dev-dependencies] +snforge_std.workspace = true [[target.starknet-contract]] sierra = true diff --git a/contracts/ark_oz/Scarb.toml b/contracts/ark_oz/Scarb.toml index ffa101978..c654dc1e0 100644 --- a/contracts/ark_oz/Scarb.toml +++ b/contracts/ark_oz/Scarb.toml @@ -7,6 +7,8 @@ version = "0.1.0" [dependencies] starknet = "2.5.4" openzeppelin = { git = "https://github.com/OpenZeppelin/cairo-contracts.git", tag = "v0.10.0" } + +[dev-dependencies] snforge_std = { git = "https://github.com/foundry-rs/starknet-foundry.git", tag = "v0.18.0" } [lib] diff --git a/contracts/ark_starknet/Scarb.toml b/contracts/ark_starknet/Scarb.toml index 2d28cb5dd..969fd0ca0 100644 --- a/contracts/ark_starknet/Scarb.toml +++ b/contracts/ark_starknet/Scarb.toml @@ -5,11 +5,13 @@ version = "0.1.0" [dependencies] starknet = "2.5.4" openzeppelin = { git = "https://github.com/OpenZeppelin/cairo-contracts.git", tag = "v0.10.0" } -snforge_std = { git = "https://github.com/foundry-rs/starknet-foundry.git", tag = "v0.18.0" } ark_common = { path = "../ark_common" } ark_tokens = { path = "../ark_tokens" } ark_oz = { path = "../ark_oz" } +[dev-dependencies] +snforge_std.workspace = true + [[target.starknet-contract]] sierra = true casm = true diff --git a/contracts/ark_starknet/src/executor.cairo b/contracts/ark_starknet/src/executor.cairo index 54656b57c..8146b8ec9 100644 --- a/contracts/ark_starknet/src/executor.cairo +++ b/contracts/ark_starknet/src/executor.cairo @@ -100,6 +100,7 @@ mod executor { ark_fees: FeesRatio, // order hash -> OrderInfo orders: LegacyMap, + fulfilled_orders: LegacyMap, // fallback when collection doesn't implement ERC2981 default_receiver: ContractAddress, default_fees: FeesRatio, @@ -322,10 +323,12 @@ mod executor { let messaging = IAppchainMessagingDispatcher { contract_address: self.messaging_address.read() }; + assert!(!self.fulfilled_orders.read(fulfillInfo.order_hash), "Order already fulfilled"); let vinfo = FulfillOrderInfo { fulfillInfo: fulfillInfo.clone() }; _verify_fulfill_order(@self, @vinfo); + self.fulfilled_orders.write(fulfillInfo.order_hash, true); let mut vinfo_buf = array![]; Serde::serialize(@vinfo, ref vinfo_buf); diff --git a/contracts/ark_starknet/tests/integration/fulfill_order.cairo b/contracts/ark_starknet/tests/integration/fulfill_order.cairo index 42e146dbb..02207089b 100644 --- a/contracts/ark_starknet/tests/integration/fulfill_order.cairo +++ b/contracts/ark_starknet/tests/integration/fulfill_order.cairo @@ -503,3 +503,43 @@ fn test_fulfill_auction_order_fulfiller_same_as_offerer() { IExecutorDispatcher { contract_address: executor_address }.fulfill_order(fulfill_info); snf::stop_prank(CheatTarget::One(executor_address)); } + +#[test] +#[should_panic(expected: ("Order already fulfilled",))] +fn test_fulfill_offer_order_already_fulfilled_order() { + let (executor_address, erc20_address, nft_address) = setup(); + let fulfillerA = contract_address_const::<'fulfillerA'>(); + let fulfillerB = contract_address_const::<'fulfillerB'>(); + let start_amount = 10_000_000; + + let (order_hash, offerer, token_id) = create_listing_order( + executor_address, erc20_address, nft_address, start_amount + ); + + IFreeMintDispatcher { contract_address: erc20_address }.mint(fulfillerA, start_amount); + IFreeMintDispatcher { contract_address: erc20_address }.mint(fulfillerB, start_amount); + + snf::start_prank(CheatTarget::One(nft_address), offerer); + IERC721Dispatcher { contract_address: nft_address } + .set_approval_for_all(executor_address, true); + snf::stop_prank(CheatTarget::One(nft_address)); + + let fulfill_infoA = create_fulfill_info(order_hash, fulfillerA, nft_address, token_id); + let fulfill_infoB = create_fulfill_info(order_hash, fulfillerB, nft_address, token_id); + + snf::start_prank(CheatTarget::One(erc20_address), fulfillerA); + IERC20Dispatcher { contract_address: erc20_address }.approve(executor_address, start_amount); + snf::stop_prank(CheatTarget::One(erc20_address)); + + snf::start_prank(CheatTarget::One(erc20_address), fulfillerB); + IERC20Dispatcher { contract_address: erc20_address }.approve(executor_address, start_amount); + snf::stop_prank(CheatTarget::One(erc20_address)); + + snf::start_prank(CheatTarget::One(executor_address), fulfillerA); + IExecutorDispatcher { contract_address: executor_address }.fulfill_order(fulfill_infoA); + snf::stop_prank(CheatTarget::One(executor_address)); + + snf::start_prank(CheatTarget::One(executor_address), fulfillerB); + IExecutorDispatcher { contract_address: executor_address }.fulfill_order(fulfill_infoB); + snf::stop_prank(CheatTarget::One(executor_address)); +} diff --git a/contracts/ark_tokens/Scarb.toml b/contracts/ark_tokens/Scarb.toml index 862324da4..b8f2b5d48 100644 --- a/contracts/ark_tokens/Scarb.toml +++ b/contracts/ark_tokens/Scarb.toml @@ -5,10 +5,12 @@ version = "0.1.0" [dependencies] starknet = "2.5.4" -snforge_std = { git = "https://github.com/foundry-rs/starknet-foundry.git", tag = "v0.18.0" } openzeppelin = { git = "https://github.com/OpenZeppelin/cairo-contracts.git", tag = "v0.10.0" } ark_oz = { path = "../ark_oz" } +[dev-dependencies] +snforge_std.workspace = true + [lib] [[target.starknet-contract]]