Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixup of escrow clearing after withdrawing, added tests to check #246

Merged
merged 7 commits into from
Oct 14, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
152 changes: 74 additions & 78 deletions apps/blockchain/starknet/src/bridge.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,12 @@ mod bridge {
use starknet::eth_address::EthAddressZeroable;

use openzeppelin::access::ownable::OwnableComponent;
use openzeppelin::access::ownable::interface::{
IOwnableDispatcher, IOwnableDispatcherTrait
};
use openzeppelin::access::ownable::interface::{IOwnableDispatcher, IOwnableDispatcherTrait};

use starklane::interfaces::{IStarklane,
IUpgradeable, IUpgradeableDispatcher, IUpgradeableDispatcherTrait,
IStarklaneCollectionAdmin};
use starklane::interfaces::{
IStarklane, IUpgradeable, IUpgradeableDispatcher, IUpgradeableDispatcherTrait,
IStarklaneCollectionAdmin
};
// events
use starklane::interfaces::{
DepositRequestInitiated, WithdrawRequestCompleted, CollectionDeployedFromL1,
Expand All @@ -30,19 +29,15 @@ mod bridge {
};

use starklane::request::{
Request,
compute_request_header_v1,
compute_request_hash,
collection_type_from_header,
Request, compute_request_header_v1, compute_request_hash, collection_type_from_header,
};
use starklane::token::{
interfaces::{
IERC721Dispatcher, IERC721DispatcherTrait,
IERC721BridgeableDispatcher, IERC721BridgeableDispatcherTrait,
IERC721Dispatcher, IERC721DispatcherTrait, IERC721BridgeableDispatcher,
IERC721BridgeableDispatcherTrait,
},
collection_manager::{
CollectionType,
deploy_erc721_bridgeable, verify_collection_address, erc721_metadata,
CollectionType, deploy_erc721_bridgeable, verify_collection_address, erc721_metadata,
},
};

Expand All @@ -51,7 +46,8 @@ mod bridge {
component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);

#[abi(embed_v0)]
impl OwnableTwoStepMixinImpl = OwnableComponent::OwnableTwoStepMixinImpl<ContractState>;
impl OwnableTwoStepMixinImpl =
OwnableComponent::OwnableTwoStepMixinImpl<ContractState>;

impl OwnableInternalImpl = OwnableComponent::InternalImpl<ContractState>;

Expand All @@ -68,17 +64,13 @@ mod bridge {
// Registry of escrowed token for collections.
// <(collection_l2_address, token_id), original_depositor_l2_address>
escrow: LegacyMap::<(ContractAddress, u256), ContractAddress>,

// White list enabled flag
white_list_enabled: bool,

// Registry of whitelisted collections
white_listed_list: LegacyMap::<ContractAddress, (bool, ContractAddress)>,
white_listed_head: ContractAddress,

// Bridge enabled flag
enabled: bool,

#[substorage(v0)]
ownable: OwnableComponent::Storage,
}
Expand Down Expand Up @@ -127,14 +119,9 @@ mod bridge {
/// to be more flexible? And the first felt25 being the header
/// defines how the deserialization takes place?
#[l1_handler]
fn withdraw_auto_from_l1(
ref self: ContractState,
from_address: felt252,
req: Request
) {
fn withdraw_auto_from_l1(ref self: ContractState, from_address: felt252, req: Request) {
ensure_is_enabled(@self);
assert(self.bridge_l1_address.read().into() == from_address,
'Invalid L1 msg sender');
assert(self.bridge_l1_address.read().into() == from_address, 'Invalid L1 msg sender');

// TODO: recompute HASH to ensure data are not altered.
// TODO: Validate all fields the request (cf. FSM).
Expand All @@ -159,26 +146,32 @@ mod bridge {

if is_escrowed {
IERC721Dispatcher { contract_address: collection_l2 }
.transfer_from(from, to, token_id);
.transfer_from(from, to, token_id);

let null_value = starknet::contract_address_const::<0>();
self.escrow.write((collection_l2, token_id), null_value);
} else {
if (req.uris.len() != 0) {
let token_uri = req.uris[i];
IERC721BridgeableDispatcher { contract_address: collection_l2 }
.mint_from_bridge_uri(to, token_id, token_uri.clone());
.mint_from_bridge_uri(to, token_id, token_uri.clone());
} else {
IERC721BridgeableDispatcher { contract_address: collection_l2 }
.mint_from_bridge(to, token_id);
.mint_from_bridge(to, token_id);
}
}

i += 1;
};

self.emit(WithdrawRequestCompleted {
hash: req.hash,
block_timestamp: starknet::info::get_block_timestamp(),
req_content: req
});
self
.emit(
WithdrawRequestCompleted {
hash: req.hash,
block_timestamp: starknet::info::get_block_timestamp(),
req_content: req
}
);
}

#[abi(embed_v0)]
Expand All @@ -188,10 +181,12 @@ mod bridge {

match starknet::replace_class_syscall(class_hash) {
Result::Ok(_) => {
self.emit(ReplacedClassHash {
contract: starknet::get_contract_address(),
class: class_hash,
})
self
.emit(
ReplacedClassHash {
contract: starknet::get_contract_address(), class: class_hash,
}
)
},
Result::Err(revert_reason) => panic(revert_reason),
};
Expand All @@ -200,7 +195,6 @@ mod bridge {

#[abi(embed_v0)]
impl BridgeImpl of IStarklane<ContractState> {

fn get_l1_collection_address(self: @ContractState, address: ContractAddress) -> EthAddress {
self.l2_to_l1_addresses.read(address)
}
Expand Down Expand Up @@ -237,8 +231,10 @@ mod bridge {
/// * `collection_l2` - Address of the collection on L2.
/// * `owner_l1` - Address of the owner on L1.
/// * `tokens_ids` - Tokens to be bridged on L1.
/// * `use_withdraw_auto` - Tokens are automatically withdrawn on L1 using Starklane indexer.
/// * `use_deposit_burn_auto` - Tokens are automatically burnt on L2 once transferred using Starklane indexer.
/// * `use_withdraw_auto` - Tokens are automatically withdrawn on L1 using Starklane
/// indexer.
/// * `use_deposit_burn_auto` - Tokens are automatically burnt on L2 once transferred using
/// Starklane indexer.
///
/// TODO: add new_owners, values and uris.
/// TODO: better to use a struct than too much arguments? (DepositParams/DepositInputs/???)
Expand Down Expand Up @@ -295,17 +291,17 @@ mod bridge {
let mut buf: Array<felt252> = array![];
req.serialize(ref buf);

starknet::send_message_to_l1_syscall(
self.bridge_l1_address.read().into(),
buf.span(),
)
starknet::send_message_to_l1_syscall(self.bridge_l1_address.read().into(), buf.span(),)
.unwrap_syscall();

self.emit(DepositRequestInitiated {
hash: req.hash,
block_timestamp: starknet::info::get_block_timestamp(),
req_content: req
});

self
.emit(
DepositRequestInitiated {
hash: req.hash,
block_timestamp: starknet::info::get_block_timestamp(),
req_content: req
}
);
}

fn enable_white_list(ref self: ContractState, enable: bool) {
Expand All @@ -318,13 +314,12 @@ mod bridge {
self.white_list_enabled.read()
}

fn white_list_collection(ref self: ContractState, collection: ContractAddress, enabled: bool) {
fn white_list_collection(
ref self: ContractState, collection: ContractAddress, enabled: bool
) {
ensure_is_admin(@self);
_white_list_collection(ref self, collection, enabled);
self.emit(CollectionWhiteListUpdated {
collection,
enabled,
});
self.emit(CollectionWhiteListUpdated { collection, enabled, });
}

fn is_white_listed(self: @ContractState, collection: ContractAddress) -> bool {
Expand Down Expand Up @@ -352,16 +347,16 @@ mod bridge {
fn enable(ref self: ContractState, enable: bool) {
ensure_is_admin(@self);
self.enabled.write(enable);
self.emit(BridgeEnabled {
enable: enable
});
self.emit(BridgeEnabled { enable: enable });
}

fn is_enabled(self: @ContractState) -> bool {
self.enabled.read()
}

fn set_l1_l2_collection_mapping(ref self: ContractState, collection_l1: EthAddress, collection_l2: ContractAddress) {
fn set_l1_l2_collection_mapping(
ref self: ContractState, collection_l1: EthAddress, collection_l2: ContractAddress
) {
ensure_is_admin(@self);
self.l1_to_l2_addresses.write(collection_l1, collection_l2);
self.l2_to_l1_addresses.write(collection_l2, collection_l1);
Expand All @@ -371,17 +366,19 @@ mod bridge {

#[abi(embed_v0)]
impl BridgeCollectionAdminImpl of IStarklaneCollectionAdmin<ContractState> {
fn collection_upgrade(ref self: ContractState, collection: ContractAddress, class_hash: ClassHash) {
fn collection_upgrade(
ref self: ContractState, collection: ContractAddress, class_hash: ClassHash
) {
ensure_is_admin(@self);
IUpgradeableDispatcher { contract_address: collection }
.upgrade(class_hash);
IUpgradeableDispatcher { contract_address: collection }.upgrade(class_hash);
}

// transfer owner of the given collection to the given address
fn collection_transfer_ownership(ref self: ContractState, collection: ContractAddress, new_owner: ContractAddress) {
fn collection_transfer_ownership(
ref self: ContractState, collection: ContractAddress, new_owner: ContractAddress
) {
ensure_is_admin(@self);
IOwnableDispatcher { contract_address: collection }
.transfer_ownership(new_owner);
IOwnableDispatcher { contract_address: collection }.transfer_ownership(new_owner);
}
}

Expand Down Expand Up @@ -431,7 +428,6 @@ mod bridge {
///
/// * `req` - Request for bridging assets.
fn ensure_erc721_deployment(ref self: ContractState, req: @Request) -> ContractAddress {

let l1_req: EthAddress = *req.collection_l1;
let l2_req: ContractAddress = *req.collection_l2;

Expand Down Expand Up @@ -476,21 +472,21 @@ mod bridge {
let (already_white_listed, _) = self.white_listed_list.read(l2_addr_from_deploy);
if already_white_listed != true {
_white_list_collection(ref self, l2_addr_from_deploy, true);
self.emit(CollectionWhiteListUpdated {
collection: l2_addr_from_deploy,
enabled: true,
});
self
.emit(
CollectionWhiteListUpdated { collection: l2_addr_from_deploy, enabled: true, }
);
}
l2_addr_from_deploy
}

fn _is_white_listed(self: @ContractState, collection: ContractAddress) -> bool {
let enabled = self.white_list_enabled.read();
if (enabled) {
let (ret, _) = self.white_listed_list.read(collection);
return ret;
}
true
let enabled = self.white_list_enabled.read();
if (enabled) {
let (ret, _) = self.white_listed_list.read(collection);
return ret;
}
true
}

fn _white_list_collection(ref self: ContractState, collection: ContractAddress, enabled: bool) {
Expand All @@ -517,7 +513,7 @@ mod bridge {
prev = next;
};
self.white_listed_list.write(prev, (true, collection));
} else {
} else {
// change head
if prev == collection {
let (_, next) = self.white_listed_list.read(prev);
Expand Down
9 changes: 6 additions & 3 deletions apps/blockchain/starknet/src/interfaces.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ use starklane::request::Request;

#[starknet::interface]
trait IStarklane<T> {

fn deposit_tokens(
ref self: T,
salt: felt252,
Expand Down Expand Up @@ -33,7 +32,9 @@ trait IStarklane<T> {
fn enable(ref self: T, enable: bool);
fn is_enabled(self: @T) -> bool;

fn set_l1_l2_collection_mapping(ref self: T , collection_l1: EthAddress, collection_l2: ContractAddress);
fn set_l1_l2_collection_mapping(
ref self: T, collection_l1: EthAddress, collection_l2: ContractAddress
);
}

/// Upgradeable contract.
Expand All @@ -48,7 +49,9 @@ trait IStarklaneCollectionAdmin<T> {
fn collection_upgrade(ref self: T, collection: ContractAddress, class_hash: ClassHash);

// transfer owner of the given collection to the given address
fn collection_transfer_ownership(ref self: T, collection: ContractAddress, new_owner: ContractAddress);
fn collection_transfer_ownership(
ref self: T, collection: ContractAddress, new_owner: ContractAddress
);
}

//////////////////////////
Expand Down
Loading
Loading