From 63899ade54b32ce74532c132550e0a29b00b7020 Mon Sep 17 00:00:00 2001
From: Patrice Tisserand
Date: Wed, 23 Oct 2024 10:22:48 +0200
Subject: [PATCH 1/3] fix(contracts): emit OrderCancelled event when an order
is cancelled by a new one
---
.../src/orderbook/orderbook.cairo | 24 +++
.../tests/integration/create_order.cairo | 194 +++++++++++++++++-
2 files changed, 217 insertions(+), 1 deletion(-)
diff --git a/contracts/ark_component/src/orderbook/orderbook.cairo b/contracts/ark_component/src/orderbook/orderbook.cairo
index 0ed79981..29504133 100644
--- a/contracts/ark_component/src/orderbook/orderbook.cairo
+++ b/contracts/ark_component/src/orderbook/orderbook.cairo
@@ -666,6 +666,18 @@ pub mod OrderbookComponent {
let cancelled_order_hash = self._process_previous_order(token_hash, order.offerer);
order_write(order_hash, order_type, order);
self.token_listings.write(token_hash, order_hash);
+ if (cancelled_order_hash.is_some()) {
+ let cancelled_order_hash = cancelled_order_hash.unwrap();
+ self
+ .emit(
+ OrderCancelled {
+ order_hash: cancelled_order_hash,
+ reason: OrderStatus::CancelledByNewOrder.into(),
+ order_type,
+ version: ORDER_CANCELLED_EVENT_VERSION,
+ }
+ )
+ }
self
.emit(
OrderPlaced {
@@ -710,6 +722,18 @@ pub mod OrderbookComponent {
let cancelled_order_hash = self._process_previous_order(token_hash, order.offerer);
order_write(order_hash, order_type, order);
self.auctions.write(token_hash, (order_hash, order.end_date, 0));
+ if (cancelled_order_hash.is_some()) {
+ let cancelled_order_hash = cancelled_order_hash.unwrap();
+ self
+ .emit(
+ OrderCancelled {
+ order_hash: cancelled_order_hash,
+ reason: OrderStatus::CancelledByNewOrder.into(),
+ order_type,
+ version: ORDER_CANCELLED_EVENT_VERSION,
+ }
+ )
+ }
self
.emit(
OrderPlaced {
diff --git a/contracts/ark_starknet/tests/integration/create_order.cairo b/contracts/ark_starknet/tests/integration/create_order.cairo
index 1ae60481..1c8a470f 100644
--- a/contracts/ark_starknet/tests/integration/create_order.cairo
+++ b/contracts/ark_starknet/tests/integration/create_order.cairo
@@ -18,6 +18,8 @@ use ark_tokens::erc20::IFreeMintDispatcherTrait as Erc20DispatcherTrait;
use ark_tokens::erc721::IFreeMintDispatcher as Erc721Dispatcher;
use ark_tokens::erc721::IFreeMintDispatcherTrait as Erc721DispatcherTrait;
+use openzeppelin::token::erc721::interface::{IERC721Dispatcher, IERC721DispatcherTrait};
+
use snforge_std::{
cheat_caller_address, CheatSpan, spy_events, EventSpyAssertionsTrait,
start_cheat_block_timestamp_global, stop_cheat_block_timestamp_global
@@ -523,7 +525,6 @@ fn test_create_order_erc1155_to_erc20_ok() {
fn test_create_order_offerer_not_own_enough_erc1155_token() {
let (executor_address, erc20_address, erc1155_address) = setup_erc1155();
let offerer = erc1155_address;
- let other = contract_address_const::<'other'>();
let quantity = 50_u256;
let token_id = Erc1155Dispatcher { contract_address: erc1155_address }.mint(offerer, 2_u256);
@@ -582,3 +583,194 @@ fn test_create_order_erc1155_to_erc20_disabled() {
IExecutorDispatcher { contract_address: executor_address }.create_order(order);
}
+
+#[test]
+fn test_create_listing_order_transfer_token_to_other_user() {
+ let (executor_address, erc20_address, nft_address) = setup();
+ let offerer = contract_address_const::<'offerer'>();
+ let other_offerer = contract_address_const::<'other_offerer'>();
+
+ let start_amount = 10_000_000;
+ let other_start_amount = 20_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);
+ let order_hash = order.compute_order_hash();
+
+ cheat_caller_address(executor_address, offerer, CheatSpan::TargetCalls(1));
+ IExecutorDispatcher { contract_address: executor_address }.create_order(order);
+
+ cheat_caller_address(nft_address, offerer, CheatSpan::TargetCalls(1));
+ IERC721Dispatcher { contract_address: nft_address }
+ .transfer_from(offerer, other_offerer, token_id);
+
+ let other_order = setup_listing_order(
+ erc20_address, nft_address, other_offerer, token_id, other_start_amount
+ );
+ let other_order_hash = other_order.compute_order_hash();
+ let order_version = other_order.get_version();
+
+ let mut spy = spy_events();
+ cheat_caller_address(executor_address, other_offerer, CheatSpan::TargetCalls(1));
+ IExecutorDispatcher { contract_address: executor_address }.create_order(other_order);
+
+ spy
+ .assert_emitted(
+ @array![
+ (
+ executor_address,
+ executor::Event::OrderbookEvent(
+ OrderbookComponent::Event::OrderCancelled(
+ OrderbookComponent::OrderCancelled {
+ order_hash,
+ reason: OrderStatus::CancelledByNewOrder.into(),
+ order_type: OrderType::Listing,
+ version: OrderbookComponent::ORDER_CANCELLED_EVENT_VERSION,
+ }
+ )
+ )
+ ),
+ (
+ executor_address,
+ executor::Event::OrderbookEvent(
+ OrderbookComponent::Event::OrderPlaced(
+ OrderbookComponent::OrderPlaced {
+ order_hash: other_order_hash,
+ order_version,
+ order_type: OrderType::Listing,
+ version: OrderbookComponent::ORDER_PLACED_EVENT_VERSION,
+ cancelled_order_hash: Option::Some(order_hash),
+ order: other_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_type(other_order_hash),
+ OrderType::Listing,
+ "Wrong other order type"
+ );
+
+ assert_eq!(
+ IOrderbookDispatcher { contract_address: executor_address }.get_order_status(order_hash),
+ OrderStatus::CancelledByNewOrder,
+ "Wrong order status"
+ );
+
+ assert_eq!(
+ IOrderbookDispatcher { contract_address: executor_address }
+ .get_order_status(other_order_hash),
+ OrderStatus::Open,
+ "Wrong other order status"
+ );
+}
+
+#[test]
+fn test_create_auction_order_transfer_token_to_other_user() {
+ let (executor_address, erc20_address, nft_address) = setup();
+ let offerer = contract_address_const::<'offerer'>();
+ let other_offerer = contract_address_const::<'other_offerer'>();
+
+ let start_amount = 10_000_000;
+ let other_start_amount = 15_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();
+
+ cheat_caller_address(executor_address, offerer, CheatSpan::TargetCalls(1));
+ IExecutorDispatcher { contract_address: executor_address }.create_order(order);
+
+ cheat_caller_address(nft_address, offerer, CheatSpan::TargetCalls(1));
+ IERC721Dispatcher { contract_address: nft_address }
+ .transfer_from(offerer, other_offerer, token_id);
+
+ let other_order = setup_auction_order(
+ erc20_address, nft_address, other_offerer, token_id, other_start_amount, end_amount
+ );
+ let other_order_hash = other_order.compute_order_hash();
+ let order_version = other_order.get_version();
+
+ let mut spy = spy_events();
+ cheat_caller_address(executor_address, other_offerer, CheatSpan::TargetCalls(1));
+ IExecutorDispatcher { contract_address: executor_address }.create_order(other_order);
+
+ spy
+ .assert_emitted(
+ @array![
+ (
+ executor_address,
+ executor::Event::OrderbookEvent(
+ OrderbookComponent::Event::OrderCancelled(
+ OrderbookComponent::OrderCancelled {
+ order_hash,
+ reason: OrderStatus::CancelledByNewOrder.into(),
+ order_type: OrderType::Auction,
+ version: OrderbookComponent::ORDER_CANCELLED_EVENT_VERSION,
+ }
+ )
+ )
+ ),
+ (
+ executor_address,
+ executor::Event::OrderbookEvent(
+ OrderbookComponent::Event::OrderPlaced(
+ OrderbookComponent::OrderPlaced {
+ order_hash: other_order_hash,
+ order_version,
+ order_type: OrderType::Auction,
+ version: OrderbookComponent::ORDER_PLACED_EVENT_VERSION,
+ cancelled_order_hash: Option::Some(order_hash),
+ order: other_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_type(other_order_hash),
+ OrderType::Auction,
+ "Wrong other order type"
+ );
+
+ assert_eq!(
+ IOrderbookDispatcher { contract_address: executor_address }.get_order_status(order_hash),
+ OrderStatus::CancelledByNewOrder,
+ "Wrong order status"
+ );
+
+ assert_eq!(
+ IOrderbookDispatcher { contract_address: executor_address }
+ .get_order_status(other_order_hash),
+ OrderStatus::Open,
+ "Wrong other order status"
+ );
+}
From 11a83abdc819dc1f5e15698255853218479def4a Mon Sep 17 00:00:00 2001
From: Patrice Tisserand
Date: Wed, 23 Oct 2024 11:18:32 +0200
Subject: [PATCH 2/3] fix: add missing await
---
packages/deployer/src/contracts/erc721royalties.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/deployer/src/contracts/erc721royalties.ts b/packages/deployer/src/contracts/erc721royalties.ts
index 00a48c5a..a124e51e 100644
--- a/packages/deployer/src/contracts/erc721royalties.ts
+++ b/packages/deployer/src/contracts/erc721royalties.ts
@@ -48,7 +48,7 @@ export async function deployERC721Royalties(
constructorCalldata: contractConstructor
});
- setDefaultFees(
+ await setDefaultFees(
provider,
deployerAccount,
deployR.deploy.contract_address,
From 232f337b2e09eb888ce4be3866ba113cfaad209b Mon Sep 17 00:00:00 2001
From: Patrice Tisserand
Date: Wed, 23 Oct 2024 12:54:13 +0200
Subject: [PATCH 3/3] fix: SDK add missing quantity field in FulfillInfo
---
packages/core/src/actions/order/fulfillAuction.ts | 3 +++
packages/core/src/actions/order/fulfillListing.ts | 3 +++
packages/core/src/actions/order/fulfillOffer.ts | 3 +++
packages/core/src/types/index.ts | 1 +
packages/core/tests/fulfillAuction.test.ts | 3 ++-
packages/core/tests/fulfillListing.test.ts | 1 +
packages/core/tests/fulfillOffer.test.ts | 4 +++-
7 files changed, 16 insertions(+), 2 deletions(-)
diff --git a/packages/core/src/actions/order/fulfillAuction.ts b/packages/core/src/actions/order/fulfillAuction.ts
index 3ea4f2a0..3c5abb29 100644
--- a/packages/core/src/actions/order/fulfillAuction.ts
+++ b/packages/core/src/actions/order/fulfillAuction.ts
@@ -17,6 +17,7 @@ export interface FulfillAuctionParameters {
relatedOrderHash: bigint;
tokenAddress: string;
tokenId: bigint;
+ quantity: bigint;
currencyAddress?: string;
waitForTransaction?: boolean;
}
@@ -44,6 +45,7 @@ export async function fulfillAuction(
relatedOrderHash,
tokenAddress,
tokenId,
+ quantity,
waitForTransaction = true
} = parameters;
const chainId = await config.starknetProvider.getChainId();
@@ -61,6 +63,7 @@ export async function fulfillAuction(
CairoOptionVariant.Some,
cairo.uint256(tokenId)
),
+ quantity: cairo.uint256(quantity),
fulfillBrokerAddress: brokerAddress
};
diff --git a/packages/core/src/actions/order/fulfillListing.ts b/packages/core/src/actions/order/fulfillListing.ts
index cb270f30..f3a7b221 100644
--- a/packages/core/src/actions/order/fulfillListing.ts
+++ b/packages/core/src/actions/order/fulfillListing.ts
@@ -18,6 +18,7 @@ export interface FulfillListingParameters {
orderHash: bigint;
tokenAddress: string;
tokenId: bigint;
+ quantity: bigint;
amount: bigint;
waitForTransaction?: boolean;
}
@@ -45,6 +46,7 @@ export async function fulfillListing(
orderHash,
tokenAddress,
tokenId,
+ quantity,
amount,
waitForTransaction = true
} = parameters;
@@ -66,6 +68,7 @@ export async function fulfillListing(
CairoOptionVariant.Some,
cairo.uint256(tokenId)
),
+ quantity: cairo.uint256(quantity),
fulfillBrokerAddress: brokerAddress
};
diff --git a/packages/core/src/actions/order/fulfillOffer.ts b/packages/core/src/actions/order/fulfillOffer.ts
index 157cb2cd..96937c68 100644
--- a/packages/core/src/actions/order/fulfillOffer.ts
+++ b/packages/core/src/actions/order/fulfillOffer.ts
@@ -16,6 +16,7 @@ export interface FulfillOfferParameters {
orderHash: bigint;
tokenAddress: string;
tokenId: bigint;
+ quantity: bigint;
waitForTransaction?: boolean;
}
@@ -41,6 +42,7 @@ export async function fulfillOffer(
orderHash,
tokenAddress,
tokenId,
+ quantity,
waitForTransaction = true
} = parameters;
const chainId = await config.starknetProvider.getChainId();
@@ -55,6 +57,7 @@ export async function fulfillOffer(
CairoOptionVariant.Some,
cairo.uint256(tokenId)
),
+ quantity: cairo.uint256(quantity),
fulfillBrokerAddress: brokerAddress
};
diff --git a/packages/core/src/types/index.ts b/packages/core/src/types/index.ts
index 3d73c91c..0ca2c4c7 100644
--- a/packages/core/src/types/index.ts
+++ b/packages/core/src/types/index.ts
@@ -91,6 +91,7 @@ export type FulfillInfo = {
tokenChainId: constants.StarknetChainId;
tokenAddress: string;
tokenId: CairoOption;
+ quantity: Uint256;
fulfillBrokerAddress: string;
};
diff --git a/packages/core/tests/fulfillAuction.test.ts b/packages/core/tests/fulfillAuction.test.ts
index 9b5e0078..d62643e5 100644
--- a/packages/core/tests/fulfillAuction.test.ts
+++ b/packages/core/tests/fulfillAuction.test.ts
@@ -42,7 +42,8 @@ describe("fulfillAuction", () => {
orderHash,
relatedOrderHash: offerOrderHash,
tokenAddress,
- tokenId
+ tokenId,
+ quantity: BigInt(1),
});
const { orderStatus } = await getOrderStatus(config, {
diff --git a/packages/core/tests/fulfillListing.test.ts b/packages/core/tests/fulfillListing.test.ts
index ffad8748..d142e338 100644
--- a/packages/core/tests/fulfillListing.test.ts
+++ b/packages/core/tests/fulfillListing.test.ts
@@ -25,6 +25,7 @@ describe("fulfillOffer", () => {
orderHash,
tokenAddress,
tokenId,
+ quantity: BigInt(1),
amount: startAmount
});
diff --git a/packages/core/tests/fulfillOffer.test.ts b/packages/core/tests/fulfillOffer.test.ts
index c07ad7d0..570b779b 100644
--- a/packages/core/tests/fulfillOffer.test.ts
+++ b/packages/core/tests/fulfillOffer.test.ts
@@ -31,7 +31,8 @@ describe("fulfillOffer", () => {
brokerAddress: saleBroker.address,
orderHash,
tokenAddress,
- tokenId
+ tokenId,
+ quantity: BigInt(1),
});
const { orderStatus: orderStatusFulfilled } = await getOrderStatus(config, {
@@ -66,6 +67,7 @@ describe("fulfillOffer", () => {
orderHash,
tokenAddress,
tokenId,
+ quantity: BigInt(1),
brokerAddress: saleBroker.address
});