From 3d9f1fa2d83889fd14037b7a2b569a1ee8e52dd0 Mon Sep 17 00:00:00 2001 From: Lana Ivina Date: Thu, 5 Dec 2024 18:06:30 +0100 Subject: [PATCH 1/4] fix working directory --- .github/workflows/contracts.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/contracts.yml b/.github/workflows/contracts.yml index 1e1253d..a46b65e 100644 --- a/.github/workflows/contracts.yml +++ b/.github/workflows/contracts.yml @@ -18,11 +18,11 @@ jobs: - name: Check cairo format run: scarb fmt --check - working-directory: onchain + working-directory: packages/onchain - name: Build cairo onchain run: scarb build - working-directory: onchain + working-directory: packages/onchain test: runs-on: ubuntu-latest @@ -42,4 +42,4 @@ jobs: - name: Run tests and generate report run: snforge test - working-directory: onchain \ No newline at end of file + working-directory: packages/onchain \ No newline at end of file From fcce1f0fc750ba84e410f4c9f4caf5eae78a944a Mon Sep 17 00:00:00 2001 From: Lana Ivina Date: Thu, 5 Dec 2024 18:28:46 +0100 Subject: [PATCH 2/4] scarb fmt --- .../onchain/src/orderbook/interface.cairo | 29 +++-- .../onchain/src/orderbook/orderbook.cairo | 115 +++++++----------- .../src/orderbook/test_orderbook.cairo | 71 +++++------ packages/onchain/src/utils/constants.cairo | 2 +- packages/onchain/src/utils/erc20_utils.cairo | 2 +- packages/onchain/src/utils/utils.cairo | 1 + 6 files changed, 93 insertions(+), 127 deletions(-) diff --git a/packages/onchain/src/orderbook/interface.cairo b/packages/onchain/src/orderbook/interface.cairo index 18cdce5..43f720d 100644 --- a/packages/onchain/src/orderbook/interface.cairo +++ b/packages/onchain/src/orderbook/interface.cairo @@ -3,8 +3,8 @@ use core::starknet::contract_address::ContractAddress; #[derive(Default, Drop, PartialEq, starknet::Store)] pub enum Status { Open, - Locked, - Canceled, + Locked, + Canceled, Closed, #[default] Undefined, @@ -13,12 +13,12 @@ pub enum Status { #[starknet::interface] pub trait IOrderbook { fn request_inscription( - ref self: TContractState, + ref self: TContractState, inscription_data: ByteArray, receiving_address: ByteArray, - satoshi: felt252, - currency_fee: felt252, - submitter_fee: u256 + satoshi: felt252, + currency_fee: felt252, + submitter_fee: u256, ) -> u32; fn cancel_inscription(ref self: TContractState, inscription_id: u32, currency_fee: felt252); fn lock_inscription(ref self: TContractState, inscription_id: u32, tx_hash: ByteArray); @@ -31,12 +31,12 @@ pub trait IOrderbook { #[starknet::interface] pub trait OrderbookABI { fn request_inscription( - ref self: TContractState, + ref self: TContractState, inscription_data: ByteArray, receiving_address: ByteArray, - satoshi: felt252, - currency_fee: felt252, - submitter_fee: u256 + satoshi: felt252, + currency_fee: felt252, + submitter_fee: u256, ) -> u32; fn cancel_inscription(ref self: TContractState, inscription_id: u32, currency_fee: felt252); fn lock_inscription(ref self: TContractState, inscription_id: u32, tx_hash: ByteArray); @@ -49,11 +49,14 @@ pub trait OrderbookABI { fn balance_of(self: @TContractState, account: ContractAddress) -> felt252; fn transfer(ref self: TContractState, recipient: ContractAddress, amount: felt252); fn transfer_from( - ref self: TContractState, sender: ContractAddress, recipient: ContractAddress, amount: felt252 + ref self: TContractState, + sender: ContractAddress, + recipient: ContractAddress, + amount: felt252, ); fn approve(ref self: TContractState, spender: ContractAddress, amount: felt252); fn increase_allowance(ref self: TContractState, spender: ContractAddress, added_value: felt252); fn decrease_allowance( - ref self: TContractState, spender: ContractAddress, subtracted_value: felt252 + ref self: TContractState, spender: ContractAddress, subtracted_value: felt252, ); -} \ No newline at end of file +} diff --git a/packages/onchain/src/orderbook/orderbook.cairo b/packages/onchain/src/orderbook/orderbook.cairo index 17d71de..4bcedaf 100644 --- a/packages/onchain/src/orderbook/orderbook.cairo +++ b/packages/onchain/src/orderbook/orderbook.cairo @@ -5,9 +5,9 @@ mod Orderbook { use core::byte_array::ByteArray; use onchain::orderbook::interface::Status; use openzeppelin_token::erc20::{ERC20ABIDispatcher, ERC20ABIDispatcherTrait}; - use starknet::storage::{ - Map, StorageMapReadAccess, StorageMapWriteAccess, StoragePathEntry, - StoragePointerReadAccess, StoragePointerWriteAccess, + use starknet::storage::{ + Map, StorageMapReadAccess, StorageMapWriteAccess, StoragePathEntry, + StoragePointerReadAccess, StoragePointerWriteAccess, }; use starknet::{ContractAddress, get_caller_address, get_contract_address, get_block_number}; @@ -15,7 +15,7 @@ mod Orderbook { struct Storage { // ID of the next inscription. new_inscription_id: u32, - // A map from the inscription ID to a tuple with the inscribed + // A map from the inscription ID to a tuple with the inscribed // data and submitter fee. inscriptions: Map, // A map from the inscription ID to status. Possible values: @@ -26,22 +26,20 @@ mod Orderbook { // Locks on inscriptions. Maps the inscription ID to a tuple of // submitter address, precomputed transaction hash, and block number. inscription_locks: Map, - // STRK fee token. + // STRK fee token. strk_token: ERC20ABIDispatcher, } #[constructor] - fn constructor( - ref self: ContractState, strk_token: ContractAddress - ) { + fn constructor(ref self: ContractState, strk_token: ContractAddress) { // initialize contract self.initializer(:strk_token); } #[abi(embed_v0)] impl OrderbookImpl of super::IOrderbook { - /// Called by a user. - /// Inputs: + /// Called by a user. + /// Inputs: /// - `inscription_data: ByteArray`, the data to be inscribed on Bitcoin. /// - `receiving_address: ByteArray`, the taproot address that will own the inscription. /// - `satoshi: felt252`, the Sat where the user wants to inscribe data. @@ -50,27 +48,27 @@ mod Orderbook { /// Returns: /// - `id: felt252`, the ID of the created inscription. fn request_inscription( - ref self: ContractState, + ref self: ContractState, inscription_data: ByteArray, receiving_address: ByteArray, - satoshi: felt252, - currency_fee: felt252, + satoshi: felt252, + currency_fee: felt252, submitter_fee: u256, ) -> u32 { assert( - self.is_valid_bitcoin_address(receiving_address) == true, - 'Not a valid bitcoin address' - ); - assert( - currency_fee == 'STRK'.into(), - 'The currency is not supported' + self.is_valid_bitcoin_address(receiving_address) == true, + 'Not a valid bitcoin address', ); + assert(currency_fee == 'STRK'.into(), 'The currency is not supported'); let caller = get_caller_address(); let escrow_address = get_contract_address(); if (currency_fee == 'STRK'.into()) { let strk_token = self.strk_token.read(); // TODO: change the transfer to the escrow contract once it's implemented. - strk_token.transfer_from(sender: caller, recipient: escrow_address, amount: submitter_fee); + strk_token + .transfer_from( + sender: caller, recipient: escrow_address, amount: submitter_fee, + ); } let id = self.new_inscription_id.read(); self.inscriptions.write(id, (inscription_data, submitter_fee)); @@ -79,7 +77,7 @@ mod Orderbook { } /// Helper function that checks the format of the taproot address. - /// Inputs: + /// Inputs: /// - `receiving_address: ByteArray`, the ID of the inscription. /// Returns: /// - `bool` @@ -88,7 +86,7 @@ mod Orderbook { true } - /// Inputs: + /// Inputs: /// - `inscription_id: felt252`, the ID of the inscription. /// Returns: /// - `(ByteArray, felt252)`, the tuple with the inscribed data and the fee. @@ -96,29 +94,17 @@ mod Orderbook { self.inscriptions.read(inscription_id) } - /// Called by a user. - /// Inputs: - /// - `inscription_id: felt252`, the ID of the inscription the user wants to - /// cancel. + /// Called by a user. + /// Inputs: + /// - `inscription_id: felt252`, the ID of the inscription the user wants to + /// cancel. /// - `currency_fee: felt252`, the token that the user paid the submitter fee in. fn cancel_inscription(ref self: ContractState, inscription_id: u32, currency_fee: felt252) { let status = self.inscription_statuses.read(inscription_id); - assert( - status != Status::Undefined, - 'Inscription does not exist' - ); - assert( - status != Status::Locked, - 'The inscription is locked' - ); - assert( - status != Status::Canceled, - 'The inscription is canceled' - ); - assert( - status != Status::Closed, - 'The inscription has been closed' - ); + assert(status != Status::Undefined, 'Inscription does not exist'); + assert(status != Status::Locked, 'The inscription is locked'); + assert(status != Status::Canceled, 'The inscription is canceled'); + assert(status != Status::Closed, 'The inscription has been closed'); let caller = get_caller_address(); // TODO: change the address to the actual escrow contract once it's implemented. @@ -133,35 +119,26 @@ mod Orderbook { self.inscription_statuses.write(inscription_id, Status::Canceled); } - /// Called by a submitter. Multiple submitters are allowed to lock the - /// inscription simultaneously. The fee will be received only by the - /// submitter that will actually create the inscription on Bitcoin. - /// Assert that the inscription has not been closed yet. If there is a + /// Called by a submitter. Multiple submitters are allowed to lock the + /// inscription simultaneously. The fee will be received only by the + /// submitter that will actually create the inscription on Bitcoin. + /// Assert that the inscription has not been closed yet. If there is a /// prior lock on the inscription, X blocks have to pass before a new /// lock can be created. - /// Inputs: - /// - `inscription_id: u32`, the ID of the inscription being locked. + /// Inputs: + /// - `inscription_id: u32`, the ID of the inscription being locked. /// - `tx_hash: ByteArray`, the precomputed bitcoin transaction hash that will be - /// submitted onchain by the submitter. + /// submitted onchain by the submitter. fn lock_inscription(ref self: ContractState, inscription_id: u32, tx_hash: ByteArray) { let status = self.inscription_statuses.read(inscription_id); - assert( - status != Status::Undefined, - 'Inscription does not exist' - ); - assert( - status != Status::Canceled, - 'The inscription is canceled' - ); - assert( - status != Status::Closed, - 'The inscription has been closed' - ); + assert(status != Status::Undefined, 'Inscription does not exist'); + assert(status != Status::Canceled, 'The inscription is canceled'); + assert(status != Status::Closed, 'The inscription has been closed'); if (status == Status::Locked) { let (_, _, blocknumber) = self.inscription_locks.read(inscription_id); // TODO: replace block time delta - assert(get_block_number() - blocknumber < 100, 'Prior lock has not expired'); + assert(get_block_number() - blocknumber < 100, 'Prior lock has not expired'); } let submitter = get_caller_address(); @@ -171,11 +148,11 @@ mod Orderbook { self.inscription_statuses.write(inscription_id, Status::Locked); } - /// Called by a submitter. The fee is transferred to the submitter if - /// the inscription on Bitcoin has been made. The submitted hash must - /// match the precomputed transaction hash in storage. If successful, + /// Called by a submitter. The fee is transferred to the submitter if + /// the inscription on Bitcoin has been made. The submitted hash must + /// match the precomputed transaction hash in storage. If successful, /// the status of the inscription changes from 'Locked' to 'Closed'. - /// Inputs: + /// Inputs: /// - `inscription_id: felt252`, the ID of the inscription being locked. /// - `tx_hash: ByteArray`, the hash of the transaction submitted to Bitcoin. fn submit_inscription(ref self: ContractState, inscription_id: u32, tx_hash: ByteArray) { @@ -188,8 +165,8 @@ mod Orderbook { } /// Helper function that checks if the inscription has already been locked. - /// Inputs: - /// - `tx_hash: ByteArray`, the precomputed transaction hash for the inscription + /// Inputs: + /// - `tx_hash: ByteArray`, the precomputed transaction hash for the inscription /// being locked. /// Returns: /// - `(bool, ContractAddress)` @@ -203,7 +180,7 @@ mod Orderbook { #[generate_trait] pub impl InternalImpl of InternalTrait { - /// Executed once when the Orderbook contract is deployed. Used to set + /// Executed once when the Orderbook contract is deployed. Used to set /// initial values for contract storage variables for the fee tokens. fn initializer(ref self: ContractState, strk_token: ContractAddress) { self.strk_token.write(ERC20ABIDispatcher { contract_address: strk_token }); diff --git a/packages/onchain/src/orderbook/test_orderbook.cairo b/packages/onchain/src/orderbook/test_orderbook.cairo index ac27d17..ec1391e 100644 --- a/packages/onchain/src/orderbook/test_orderbook.cairo +++ b/packages/onchain/src/orderbook/test_orderbook.cairo @@ -2,15 +2,19 @@ use starknet::{ContractAddress}; use snforge_std::{ declare, ContractClassTrait, DeclareResultTrait, start_cheat_caller_address_global, stop_cheat_caller_address_global, test_address, start_cheat_block_number_global, - stop_cheat_block_number_global + stop_cheat_block_number_global, +}; +use openzeppelin::presets::interfaces::{ + ERC20UpgradeableABIDispatcher, ERC20UpgradeableABIDispatcherTrait, }; -use openzeppelin::presets::interfaces::{ERC20UpgradeableABIDispatcher, ERC20UpgradeableABIDispatcherTrait}; use openzeppelin::utils::serde::SerializedAppend; use onchain::orderbook::interface::{OrderbookABIDispatcher, OrderbookABIDispatcherTrait}; use onchain::utils::{constants, erc20_utils}; -fn setup_orderbook(erc20_contract_address: ContractAddress) -> (OrderbookABIDispatcher, ContractAddress) { +fn setup_orderbook( + erc20_contract_address: ContractAddress, +) -> (OrderbookABIDispatcher, ContractAddress) { // declare Orderbook contract let contract_class = declare("Orderbook").unwrap().contract_class(); @@ -23,7 +27,9 @@ fn setup_orderbook(erc20_contract_address: ContractAddress) -> (OrderbookABIDisp (OrderbookABIDispatcher { contract_address }, contract_address) } -fn setup() -> (OrderbookABIDispatcher, ContractAddress, ERC20UpgradeableABIDispatcher, ContractAddress) { +fn setup() -> ( + OrderbookABIDispatcher, ContractAddress, ERC20UpgradeableABIDispatcher, ContractAddress, +) { // deploy an ERC20 let (erc20_strk, erc20_address) = test_utils::setup_erc20(test_address()); @@ -37,15 +43,13 @@ fn setup() -> (OrderbookABIDispatcher, ContractAddress, ERC20UpgradeableABIDispa fn test_request_inscription_stored_and_retrieved() { let (orderbook_dispatcher, contract_address, token_dispatcher, _) = setup(); - let test_taproot_address: ByteArray = "bc1p5d7rjq7g6r4jdyhzks9smlaqtedr4dekq08ge8ztwac72sfr9rusxg3297"; + let test_taproot_address: ByteArray = + "bc1p5d7rjq7g6r4jdyhzks9smlaqtedr4dekq08ge8ztwac72sfr9rusxg3297"; let test_data: ByteArray = "data"; token_dispatcher.approve(contract_address, 100); - orderbook_dispatcher - .request_inscription( - test_data, test_taproot_address, 1, 'STRK'.into(), 10 - ); + orderbook_dispatcher.request_inscription(test_data, test_taproot_address, 1, 'STRK'.into(), 10); let expected = ("data", 10); // the inscription data and the submitter fee let actual = orderbook_dispatcher.query_inscription(0); @@ -70,10 +74,7 @@ fn test_request_inscription_fails_wrong_currency() { token_dispatcher.approve(contract_address, 100); - orderbook_dispatcher - .request_inscription( - test_data, test_taproot_address, 1, 'BTC'.into(), 10 - ); + orderbook_dispatcher.request_inscription(test_data, test_taproot_address, 1, 'BTC'.into(), 10); } #[test] @@ -87,9 +88,7 @@ fn test_request_inscription_fails_insufficient_balance() { token_dispatcher.approve(contract_address, 2000); orderbook_dispatcher - .request_inscription( - test_data, test_taproot_address, 1, 'STRK'.into(), 2000 - ); + .request_inscription(test_data, test_taproot_address, 1, 'STRK'.into(), 2000); } #[test] @@ -102,9 +101,7 @@ fn test_lock_inscription_works() { token_dispatcher.approve(contract_address, 100); let id = orderbook_dispatcher - .request_inscription( - test_data, test_taproot_address, 1, 'STRK'.into(), 10 - ); + .request_inscription(test_data, test_taproot_address, 1, 'STRK'.into(), 10); start_cheat_block_number_global(1000); orderbook_dispatcher.lock_inscription(id, "hash"); @@ -122,9 +119,7 @@ fn test_lock_inscription_fails_prior_lock_not_expired() { token_dispatcher.approve(contract_address, 100); let id = orderbook_dispatcher - .request_inscription( - test_data, test_taproot_address, 1, 'STRK'.into(), 10 - ); + .request_inscription(test_data, test_taproot_address, 1, 'STRK'.into(), 10); orderbook_dispatcher.lock_inscription(id, "hash"); orderbook_dispatcher.lock_inscription(id, "other_hash"); @@ -141,16 +136,13 @@ fn test_lock_inscription_fails_inscription_not_found() { token_dispatcher.approve(contract_address, 100); let _ = orderbook_dispatcher - .request_inscription( - test_data, test_taproot_address, 1, 'STRK'.into(), 10 - ); + .request_inscription(test_data, test_taproot_address, 1, 'STRK'.into(), 10); orderbook_dispatcher.lock_inscription(42, "hash"); } #[test] -fn test_lock_inscription_fails_status_closed() { - // TODO: when `submit_inscription` is implemented +fn test_lock_inscription_fails_status_closed() {// TODO: when `submit_inscription` is implemented } #[test] @@ -163,11 +155,9 @@ fn test_cancel_inscription_works() { token_dispatcher.approve(contract_address, 100); let id = orderbook_dispatcher - .request_inscription( - test_data, test_taproot_address, 1, 'STRK'.into(), 10 - ); - - start_cheat_caller_address_global(contract_address); + .request_inscription(test_data, test_taproot_address, 1, 'STRK'.into(), 10); + + start_cheat_caller_address_global(contract_address); // TODO: is this the correct way to set permissions? token_dispatcher.approve(contract_address, 100); stop_cheat_caller_address_global(); @@ -186,17 +176,14 @@ fn test_cancel_inscription_fails_locked() { token_dispatcher.approve(contract_address, 100); let id = orderbook_dispatcher - .request_inscription( - test_data, test_taproot_address, 1, 'STRK'.into(), 10 - ); + .request_inscription(test_data, test_taproot_address, 1, 'STRK'.into(), 10); orderbook_dispatcher.lock_inscription(id, "hash"); orderbook_dispatcher.cancel_inscription(id, 'STRK'.into()) } #[test] -fn test_cancel_inscription_fails_closed() { - // TODO: when `submit_inscription` is implemented +fn test_cancel_inscription_fails_closed() {// TODO: when `submit_inscription` is implemented } #[test] @@ -210,14 +197,12 @@ fn test_cancel_inscription_fails_canceled() { token_dispatcher.approve(contract_address, 100); let id = orderbook_dispatcher - .request_inscription( - test_data, test_taproot_address, 1, 'STRK'.into(), 10 - ); - - start_cheat_caller_address_global(contract_address); + .request_inscription(test_data, test_taproot_address, 1, 'STRK'.into(), 10); + + start_cheat_caller_address_global(contract_address); token_dispatcher.approve(contract_address, 100); stop_cheat_caller_address_global(); orderbook_dispatcher.cancel_inscription(id, 'STRK'.into()); orderbook_dispatcher.cancel_inscription(id, 'STRK'.into()); -} \ No newline at end of file +} diff --git a/packages/onchain/src/utils/constants.cairo b/packages/onchain/src/utils/constants.cairo index f56d759..b586186 100644 --- a/packages/onchain/src/utils/constants.cairo +++ b/packages/onchain/src/utils/constants.cairo @@ -12,4 +12,4 @@ pub fn SYMBOL() -> ByteArray { pub fn OWNER() -> ContractAddress { contract_address_const::<'owner'>() -} \ No newline at end of file +} diff --git a/packages/onchain/src/utils/erc20_utils.cairo b/packages/onchain/src/utils/erc20_utils.cairo index 5581e38..edc4a99 100644 --- a/packages/onchain/src/utils/erc20_utils.cairo +++ b/packages/onchain/src/utils/erc20_utils.cairo @@ -17,4 +17,4 @@ pub fn setup_erc20(recipient: ContractAddress) -> (ERC20UpgradeableABIDispatcher let (contract_address, _) = contract.deploy(@calldata).unwrap(); (ERC20UpgradeableABIDispatcher { contract_address: contract_address }, contract_address) -} \ No newline at end of file +} diff --git a/packages/onchain/src/utils/utils.cairo b/packages/onchain/src/utils/utils.cairo index e69de29..8b13789 100644 --- a/packages/onchain/src/utils/utils.cairo +++ b/packages/onchain/src/utils/utils.cairo @@ -0,0 +1 @@ + From ac86eb03746aa7adc4ff849b8414959f3770ed52 Mon Sep 17 00:00:00 2001 From: Lana Ivina Date: Thu, 5 Dec 2024 18:30:38 +0100 Subject: [PATCH 3/4] minor fmt --- packages/onchain/src/orderbook/test_orderbook.cairo | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/onchain/src/orderbook/test_orderbook.cairo b/packages/onchain/src/orderbook/test_orderbook.cairo index ec1391e..a94f247 100644 --- a/packages/onchain/src/orderbook/test_orderbook.cairo +++ b/packages/onchain/src/orderbook/test_orderbook.cairo @@ -142,7 +142,7 @@ fn test_lock_inscription_fails_inscription_not_found() { } #[test] -fn test_lock_inscription_fails_status_closed() {// TODO: when `submit_inscription` is implemented +fn test_lock_inscription_fails_status_closed() { // TODO: when `submit_inscription` is implemented } #[test] @@ -183,7 +183,7 @@ fn test_cancel_inscription_fails_locked() { } #[test] -fn test_cancel_inscription_fails_closed() {// TODO: when `submit_inscription` is implemented +fn test_cancel_inscription_fails_closed() { // TODO: when `submit_inscription` is implemented } #[test] From fff15e8ef66c8d93e8f71354b81585310c2622a7 Mon Sep 17 00:00:00 2001 From: Lana Ivina Date: Thu, 5 Dec 2024 18:39:33 +0100 Subject: [PATCH 4/4] fix test setup --- packages/onchain/src/orderbook/test_orderbook.cairo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/onchain/src/orderbook/test_orderbook.cairo b/packages/onchain/src/orderbook/test_orderbook.cairo index a94f247..050bd78 100644 --- a/packages/onchain/src/orderbook/test_orderbook.cairo +++ b/packages/onchain/src/orderbook/test_orderbook.cairo @@ -31,7 +31,7 @@ fn setup() -> ( OrderbookABIDispatcher, ContractAddress, ERC20UpgradeableABIDispatcher, ContractAddress, ) { // deploy an ERC20 - let (erc20_strk, erc20_address) = test_utils::setup_erc20(test_address()); + let (erc20_strk, erc20_address) = erc20_utils::setup_erc20(test_address()); // deploy Orderbook contract let (orderbook, contract_address) = setup_orderbook(erc20_strk.contract_address);