From 6b727be298d32f2299f66e57ac73825890b48616 Mon Sep 17 00:00:00 2001 From: Charlotte Date: Fri, 30 Aug 2024 20:41:30 +0800 Subject: [PATCH 1/3] feat : escrow component --- contracts/src/components.cairo | 1 + contracts/src/components/escrow.cairo | 4 + contracts/src/components/escrow/escrow.cairo | 80 +++++++++++++++++++ .../src/components/escrow/interface.cairo | 15 ++++ 4 files changed, 100 insertions(+) create mode 100644 contracts/src/components/escrow.cairo create mode 100644 contracts/src/components/escrow/escrow.cairo create mode 100644 contracts/src/components/escrow/interface.cairo diff --git a/contracts/src/components.cairo b/contracts/src/components.cairo index d633012..791afd3 100644 --- a/contracts/src/components.cairo +++ b/contracts/src/components.cairo @@ -1,2 +1,3 @@ +pub mod escrow; pub mod processors; pub mod registry; diff --git a/contracts/src/components/escrow.cairo b/contracts/src/components/escrow.cairo new file mode 100644 index 0000000..66137bd --- /dev/null +++ b/contracts/src/components/escrow.cairo @@ -0,0 +1,4 @@ +pub mod escrow; +pub mod interface; + + diff --git a/contracts/src/components/escrow/escrow.cairo b/contracts/src/components/escrow/escrow.cairo new file mode 100644 index 0000000..d4ef1ac --- /dev/null +++ b/contracts/src/components/escrow/escrow.cairo @@ -0,0 +1,80 @@ +#[starknet::component] +pub mod EscrowComponent { + use openzeppelin_token::erc20::interface::{IERC20Dispatcher, IERC20DispatcherTrait}; + use starknet::ContractAddress; + use starknet::storage::Map; + use zkramp::components::escrow::interface; + + // + // Storage + // + + #[storage] + struct Storage { + // (owner, token) -> amount + deposits: Map::<(ContractAddress, ContractAddress), u256>, + } + + // + // Errors + // + + pub mod Errors { + pub const PROOF_OF_DEPOSIT_FAILED: felt252 = 'Proof of deposit failed'; + pub const INSUFFICIENT_BALANCE: felt252 = 'Insufficient deposit balance'; + } + + // + // Escrow impl + // + + #[embeddable_as(RegistryImpl)] + impl Escrow< + TContractState, +HasComponent, +Drop, + > of interface::IEscrow> { + fn lock_from( + ref self: ComponentState, + from: ContractAddress, + token: ContractAddress, + amount: u256 + ) { + let locked_amount = self.deposits.read((from, token)); + + self.deposits.write((from, token), amount + locked_amount); + } + + fn unlock_to( + ref self: ComponentState, + from: ContractAddress, + to: ContractAddress, + token: ContractAddress, + amount: u256 + ) { + let locked_amount = self.deposits.read((from, token)); + + // TODO + // check for proof of deposit + assert(true, Errors::PROOF_OF_DEPOSIT_FAILED); + + assert(locked_amount >= amount, Errors::INSUFFICIENT_BALANCE); + + // transfert of the amount `amount` from `from` to `to` + transfer_erc20(from, to, token, amount); + + // update locked amount + self.deposits.write((from, token), locked_amount - amount); + } + } + + // + // Internals + // + + fn transfer_erc20( + from: ContractAddress, token: ContractAddress, to: ContractAddress, amount: u256 + ) { + let erc20_dispatcher = IERC20Dispatcher { contract_address: token }; + + erc20_dispatcher.transfer_from(from, to, amount); + } +} diff --git a/contracts/src/components/escrow/interface.cairo b/contracts/src/components/escrow/interface.cairo new file mode 100644 index 0000000..c8f1079 --- /dev/null +++ b/contracts/src/components/escrow/interface.cairo @@ -0,0 +1,15 @@ +use core::hash::HashStateExTrait; +use starknet::ContractAddress; + +#[starknet::interface] +pub trait IEscrow { + fn lock_from(ref self: TState, from: ContractAddress, token: ContractAddress, amount: u256); + fn unlock_to( + ref self: TState, + from: ContractAddress, + to: ContractAddress, + token: ContractAddress, + amount: u256 + ); +} + From a24404707cbcacc1a7b2d7c3f3c5b87d9f7c2039 Mon Sep 17 00:00:00 2001 From: Charlotte Date: Wed, 4 Sep 2024 13:09:40 +0800 Subject: [PATCH 2/3] review fix : lock_from --- contracts/src/components/escrow.cairo | 1 - contracts/src/components/escrow/escrow.cairo | 21 ++++++++++++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/contracts/src/components/escrow.cairo b/contracts/src/components/escrow.cairo index 66137bd..fc733ae 100644 --- a/contracts/src/components/escrow.cairo +++ b/contracts/src/components/escrow.cairo @@ -1,4 +1,3 @@ pub mod escrow; pub mod interface; - diff --git a/contracts/src/components/escrow/escrow.cairo b/contracts/src/components/escrow/escrow.cairo index d4ef1ac..4a1d8a4 100644 --- a/contracts/src/components/escrow/escrow.cairo +++ b/contracts/src/components/escrow/escrow.cairo @@ -13,6 +13,8 @@ pub mod EscrowComponent { struct Storage { // (owner, token) -> amount deposits: Map::<(ContractAddress, ContractAddress), u256>, + // token -> escrow address + escrow_contract_addresses: Map::, } // @@ -38,8 +40,20 @@ pub mod EscrowComponent { token: ContractAddress, amount: u256 ) { + let erc20_dispatcher = IERC20Dispatcher { contract_address: token }; + + let balance = erc20_dispatcher.balance_of(from); + + assert(balance >= amount, Errors::INSUFFICIENT_BALANCE); + let locked_amount = self.deposits.read((from, token)); + // Retreives escrow address for the token `token`` + let escrow_contract_address = self.escrow_contract_addresses.read(token); + + // Transfers funds to escrow + transfer_erc20(from, escrow_contract_address, token, amount); + self.deposits.write((from, token), amount + locked_amount); } @@ -50,18 +64,21 @@ pub mod EscrowComponent { token: ContractAddress, amount: u256 ) { + let escrow_contract_address = self.escrow_contract_addresses.read(token); + let locked_amount = self.deposits.read((from, token)); // TODO // check for proof of deposit assert(true, Errors::PROOF_OF_DEPOSIT_FAILED); + // check deposit balance assert(locked_amount >= amount, Errors::INSUFFICIENT_BALANCE); // transfert of the amount `amount` from `from` to `to` - transfer_erc20(from, to, token, amount); + transfer_erc20(escrow_contract_address, to, token, amount); - // update locked amount + // update locked amount self.deposits.write((from, token), locked_amount - amount); } } From c254aa5509389e922bcb2db3306075573d9aca06 Mon Sep 17 00:00:00 2001 From: Charlotte Date: Wed, 4 Sep 2024 16:56:56 +0800 Subject: [PATCH 3/3] review changes --- contracts/src/components/escrow/escrow.cairo | 37 +++++--------------- 1 file changed, 8 insertions(+), 29 deletions(-) diff --git a/contracts/src/components/escrow/escrow.cairo b/contracts/src/components/escrow/escrow.cairo index 4a1d8a4..0393f50 100644 --- a/contracts/src/components/escrow/escrow.cairo +++ b/contracts/src/components/escrow/escrow.cairo @@ -1,8 +1,8 @@ #[starknet::component] pub mod EscrowComponent { use openzeppelin_token::erc20::interface::{IERC20Dispatcher, IERC20DispatcherTrait}; - use starknet::ContractAddress; use starknet::storage::Map; + use starknet::{ContractAddress, get_contract_address}; use zkramp::components::escrow::interface; // @@ -13,8 +13,6 @@ pub mod EscrowComponent { struct Storage { // (owner, token) -> amount deposits: Map::<(ContractAddress, ContractAddress), u256>, - // token -> escrow address - escrow_contract_addresses: Map::, } // @@ -40,19 +38,12 @@ pub mod EscrowComponent { token: ContractAddress, amount: u256 ) { - let erc20_dispatcher = IERC20Dispatcher { contract_address: token }; - - let balance = erc20_dispatcher.balance_of(from); - - assert(balance >= amount, Errors::INSUFFICIENT_BALANCE); - let locked_amount = self.deposits.read((from, token)); - // Retreives escrow address for the token `token`` - let escrow_contract_address = self.escrow_contract_addresses.read(token); + // transfers funds to escrow + let erc20_dispatcher = IERC20Dispatcher { contract_address: token }; - // Transfers funds to escrow - transfer_erc20(from, escrow_contract_address, token, amount); + erc20_dispatcher.transfer_from(from, get_contract_address(), amount); self.deposits.write((from, token), amount + locked_amount); } @@ -64,8 +55,6 @@ pub mod EscrowComponent { token: ContractAddress, amount: u256 ) { - let escrow_contract_address = self.escrow_contract_addresses.read(token); - let locked_amount = self.deposits.read((from, token)); // TODO @@ -75,23 +64,13 @@ pub mod EscrowComponent { // check deposit balance assert(locked_amount >= amount, Errors::INSUFFICIENT_BALANCE); - // transfert of the amount `amount` from `from` to `to` - transfer_erc20(escrow_contract_address, to, token, amount); + // transfert of the amount to `to` + let erc20_dispatcher = IERC20Dispatcher { contract_address: token }; + + erc20_dispatcher.transfer_from(get_contract_address(), to, amount); // update locked amount self.deposits.write((from, token), locked_amount - amount); } } - - // - // Internals - // - - fn transfer_erc20( - from: ContractAddress, token: ContractAddress, to: ContractAddress, amount: u256 - ) { - let erc20_dispatcher = IERC20Dispatcher { contract_address: token }; - - erc20_dispatcher.transfer_from(from, to, amount); - } }