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

Remove channelID array #14

Open
wants to merge 1 commit into
base: adapt-to-ethereum
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
139 changes: 32 additions & 107 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ mod ethsig;
mod multi;
mod sol;
use crate::multi::CrossAsset;
use crate::sol::SubAllocSol;
use alloy_primitives::{address, keccak256, Address as EthAddress, Bytes as PrimBytes, FixedBytes, U256, U64, U16};
use crate::sol::{get_channel_id_cross, SubAllocSol};
use alloy_primitives::{address, keccak256, Address as EthAddress, Bytes as PrimBytes, FixedBytes, U256, U64, U16, Uint};
use soroban_sdk::xdr::WriteXdr;

#[contracterror]
Expand Down Expand Up @@ -100,7 +100,7 @@ pub struct Participant {
pub struct State {
/// channel_id is always a hash of the channel Params to which this
/// state belongs.
pub channel_id: Vec<BytesN<32>>,
pub channel_id: BytesN<32>,
/// balances is the balance distribution between the channel's participants
/// in this state.
pub balances: Balances,
Expand Down Expand Up @@ -182,9 +182,9 @@ impl Adjudicator {
// checks
// We verify that the sha_256 hash of the params matches the channel id
// in the state.
let cid = get_channel_id(&env, &params);
let cid = get_channel_id_cross(&env, &params);

if !channel_id_matches(&state, &cid)? {
if !cid.eq(&state.channel_id) {
return Err(Error::ChannelIDMismatch);
}
if state.version != 0 {
Expand Down Expand Up @@ -216,7 +216,7 @@ impl Adjudicator {
// Assemble the channel.
let channel = make_channel(&params, &state, &control);
// Write the new channel to storage.
set_channel(&env, &channel, &cid);
set_channel(&env, &channel);
// Emit open event.
env.events().publish(
(symbol_short!("perun"), symbol_short!("open")),
Expand Down Expand Up @@ -280,7 +280,7 @@ impl Adjudicator {
actor.require_auth();

// Write the updated channel to storage.
set_channel(&env, &channel, &channel_id);
set_channel(&env, &channel);
// Emit fund event.
env.events().publish(
(symbol_short!("perun"), symbol_short!("fund")),
Expand Down Expand Up @@ -323,7 +323,7 @@ impl Adjudicator {
if !state.finalized {
return Err(Error::CloseOnNonFinalState);
}
let mut channel = find_valid_channel(&env, &state)?;
let mut channel = get_channel(&env, &state.channel_id).ok_or(Error::ChannelNotFound)?;
// If the channel was not funded, we prohibit closing.
// If we would not do this, one could drain the contract's balance
// by opening a channel, closing without funding and subsequently withdrawing.
Expand All @@ -332,7 +332,6 @@ impl Adjudicator {
}

// We verify both parties' signatures on the submitted final state.
let message = state.clone().to_xdr(&env);
let state_sol_prefix_hash =
hash_state_eth_prefixed(&env, &state)?;

Expand Down Expand Up @@ -369,10 +368,10 @@ impl Adjudicator {
(symbol_short!("perun"), symbol_short!("pay_c")),
channel.clone(),
);
iter_delete_channel(&env, &channel)?;
delete_channel(&env, &channel.state.channel_id);
} else {
// Write the updated channel to contract storage.
iter_set_channel(&env, &channel)?;
set_channel(&env, &channel);
}

Ok(())
Expand Down Expand Up @@ -413,9 +412,9 @@ impl Adjudicator {
(symbol_short!("perun"), symbol_short!("pay_c")),
channel.clone(),
);
iter_delete_channel(&env, &channel)?;
delete_channel(&env, &channel.state.channel_id)
} else {
set_channel(&env, &channel, &channel_id);
set_channel(&env, &channel);
}

Ok(())
Expand All @@ -430,7 +429,7 @@ impl Adjudicator {
sig_b_stellar: BytesN<65>,
) -> Result<(), Error> {
// checks
let mut channel = find_valid_channel(&env, &new_state)?;
let mut channel = get_channel(&env, &new_state.channel_id).ok_or(Error::ChannelNotFound)?;
// We only allow dispute on funded channels.
if !is_funded(&channel) {
return Err(Error::OperationOnUnfundedChannel);
Expand All @@ -445,8 +444,6 @@ impl Adjudicator {
}

// We verify that the new state is signed by both parties.
let message = new_state.clone().to_xdr(&env);

let state_sol_prefix_hash =
hash_state_eth_prefixed(&env, &new_state).expect("hashing state eth style failed");

Expand All @@ -472,7 +469,7 @@ impl Adjudicator {
channel.control.timestamp = env.ledger().timestamp();
// Set the new state and save the updated channel in the contract storage.
channel.state = new_state;
iter_set_channel(&env, &channel)?;
set_channel(&env, &channel);

// Emit a dispute event.
env.events().publish(
Expand Down Expand Up @@ -574,7 +571,7 @@ impl Adjudicator {
);
delete_channel(&env, &channel_id);
} else {
set_channel(&env, &channel, &channel_id);
set_channel(&env, &channel);
}

Ok(())
Expand Down Expand Up @@ -656,10 +653,10 @@ pub fn get_channel(env: &Env, id: &BytesN<32>) -> Option<Channel> {

/// set_channel writes the given channel to persistent storage.
/// The key is the channel id in the channel's state.
pub fn set_channel(env: &Env, channel: &Channel, chan_id: &BytesN<32>) {
pub fn set_channel(env: &Env, channel: &Channel) {
env.storage()
.persistent()
.set(&ChannelID::ID(chan_id.clone()), channel);
.set(&ChannelID::ID(channel.state.channel_id.clone()), channel);
}

/// delete_channel deletes the channel with the given id from persistent storage.
Expand All @@ -669,38 +666,6 @@ pub fn delete_channel(env: &Env, channel_id: &BytesN<32>) {
.remove(&ChannelID::ID(channel_id.clone()));
}

fn iter_delete_channel(env: &Env, channel: &Channel) -> Result<(), Error> {
let mut deletion_successful = false;

for channel_id in channel.state.channel_id.iter() {
delete_channel(env, &channel_id);

deletion_successful = true;
}

if deletion_successful {
Ok(())
} else {
Err(Error::ChannelIDMismatch)
}
}

fn iter_set_channel(env: &Env, channel: &Channel) -> Result<(), Error> {
let mut setting_successful = false;

for channel_id in channel.state.channel_id.iter() {
set_channel(env, channel, &channel_id);

setting_successful = true;
}

if setting_successful {
Ok(())
} else {
Err(Error::ChannelNotFound)
}
}

/// get_channel_id returns the channel id for the given channel parameters.
pub fn get_channel_id(env: &Env, params: &Params) -> BytesN<32> {
let data = params.clone().to_xdr(env);
Expand Down Expand Up @@ -752,24 +717,6 @@ pub fn is_valid_state_transition(old: &State, new: &State) -> bool {
return true;
}

pub fn channel_id_matches(state: &State, chan_id: &BytesN<32>) -> Result<bool, Error> {
for state_channel_id in state.channel_id.iter() {
if state_channel_id == *chan_id {
return Ok(true);
}
}
Ok(false)
}

fn find_valid_channel(env: &Env, state: &State) -> Result<Channel, Error> {
for state_channel_id in state.channel_id.iter() {
if let Some(channel) = get_channel(env, &state_channel_id) {
return Ok(channel);
}
}
Err(Error::ChannelNotFound)
}

/// A channel is considered funded, iff both funded bits are true.
pub fn is_funded(channel: &Channel) -> bool {
return channel.control.funded_a && channel.control.funded_b;
Expand Down Expand Up @@ -804,18 +751,18 @@ pub fn convert_cross_assets(
}

let convert_asset = |cross_asset: &CrossAsset| -> Result<sol::AssetSol, Error> {
let chain_id = U256::from(cross_asset.chain.as_u8());
let chain_id = U256::from(cross_asset.chain.as_u64());

// Define zero addresses
let zero_eth_address = EthAddress::from_slice(&[0u8; 20]);
let zero_stellar_address = PrimBytes::copy_from_slice(&[0u8; 40]);
let zero_stellar_address = PrimBytes::copy_from_slice(&[0u8; 32]);

// Extract addresses from the CrossAsset
let eth_address = &cross_asset.eth_address;
let stellar_address = &cross_asset.stellar_address;

// Create the holders based on the presence of addresses
let (eth_holder, cc_holder) = if stellar_address.to_xdr(e).iter().all(|byte| byte == 0u8) {
let (eth_holder, cc_holder) = if chain_id != Uint::try_from(2).unwrap() {
// If there's a valid Ethereum address, use it
let mut eth_addr_slice = [0u8; 20];
eth_address.copy_into_slice(&mut eth_addr_slice);
Expand Down Expand Up @@ -852,36 +799,19 @@ pub fn convert_allocation(e: &Env, state: &State) -> Result<sol::AllocationSol,
// Determine backends based on the address types in cross_assets
let backends: [U256; 2] = [
{
let mut eth_addr_slice = [0u8; 20];
cross_assets.get_unchecked(0).eth_address.copy_into_slice(&mut eth_addr_slice);

// Check if the Ethereum address is non-zero
if eth_addr_slice != [0u8; 20] {
// Check if the chain is 2
if cross_assets.get_unchecked(0).chain != multi::Chain::new(2) {
U256::from(1) // Ethereum
} else {
// Check if Stellar address is non-zero
let stellar_addr_xdr = cross_assets.get_unchecked(0).stellar_address.to_xdr(&e);
if stellar_addr_xdr.iter().all(|byte| byte == 0u8) {
U256::from(1)
} else {
U256::from(2)
}
U256::from(2) // Stellar
}
},
{
let mut eth_addr_slice = [0u8; 20];
cross_assets.get_unchecked(1).eth_address.copy_into_slice(&mut eth_addr_slice);

if eth_addr_slice != [0u8; 20] {
// Check if the chain is 2
if cross_assets.get_unchecked(1).chain != multi::Chain::new(2) {
U256::from(1) // Ethereum
} else {
// Check Stellar address
let stellar_addr_xdr = cross_assets.get_unchecked(1).stellar_address.to_xdr(&e);
if stellar_addr_xdr.iter().all(|byte| byte == 0u8) {
U256::from(1)
} else {
U256::from(2)
}
U256::from(2) // Stellar
}
},
];
Expand Down Expand Up @@ -910,34 +840,29 @@ pub fn convert_allocation(e: &Env, state: &State) -> Result<sol::AllocationSol,
pub fn convert_state(e: &Env, state: &State) -> Result<sol::StateSol, Error> {
// let channel_id_xdr = state.channel_id.clone().to_xdr(e);

let channel_id_0 = state.channel_id.get_unchecked(0);
let channel_id_1 = state.channel_id.get_unchecked(1);
let channel_id = state.channel_id.clone();

// Define the expected length
let chanid_len = 32;

// Check if the length of channel_id_xdr matches the expected length
if channel_id_0.len() != chanid_len {
if channel_id.len() != chanid_len {
return Err(Error::InvalidChanIdSize); // Ensure this error variant is defined
}

let mut channel_id_slice_0 = [0u8; 32];
let mut channel_id_slice_1 = [0u8; 32];
let mut channel_id_slice = [0u8; 32];

channel_id_0.copy_into_slice(&mut channel_id_slice_0);
channel_id_1.copy_into_slice(&mut channel_id_slice_1);
channel_id.copy_into_slice(&mut channel_id_slice);

let channel_id_alloy_0 = FixedBytes::from_slice(&channel_id_slice_0);
let channel_id_alloy_1 = FixedBytes::from_slice(&channel_id_slice_1);
let channel_id_vec = [channel_id_alloy_0, channel_id_alloy_1].to_vec();
let channel_id_alloy = FixedBytes::from_slice(&channel_id_slice);
let app_data_alloy = PrimBytes::copy_from_slice(&[]);
let is_final_alloy = state.finalized;

let outcome = convert_allocation(e, state)?;

// 1 for Ethereum, 2 for Stellar
Ok(sol::StateSol {
channelID: channel_id_vec,
channelID: channel_id_alloy,
version: state.version,
outcome,
appData: app_data_alloy,
Expand Down
Loading