Skip to content
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
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ stateDiagram-v2

| Function | Description |
|---|---|
| `__constructor` | Open a channel with an initial deposit. Callable by the funder, or anyone if amount is zero. |
| `__constructor` | Open a channel with an initial deposit. Callable by the deployer, authorized by the funder. |
| `top_up` | Deposit additional tokens into the channel. |
| `settle` | Withdraw funds using a signed commitment without closing the channel. |
| `close` | Close the channel using a signed commitment, withdrawing funds to the recipient. Automatically attempts to refund the funder. |
Expand Down
12 changes: 5 additions & 7 deletions contracts/channel-factory/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,16 +80,14 @@ impl FactoryContract {

/// Deploy a new channel.
///
/// Callable by anyone.
/// Callable by anyone, authorized by the funder (from).
///
/// # Auth
/// - `from`: required if amount > 0.
/// - `from`: required.
pub fn open(env: &Env, salt: BytesN<32>, token: Address, from: Address, commitment_key: BytesN<32>, to: Address, amount: i128, refund_waiting_period: u32) -> Address {
if amount > 0 {
// Authorize the funder at the factory level so that the channel
// constructor's top_up does not require non-root authorization.
from.require_auth();
}
// Authorize the funder at the factory level so that the channel
// constructor's top_up does not require non-root authorization.
from.require_auth();

// Deploy the channel contract using the stored wasm hash.
let wasm_hash = Self::wasm_hash(env);
Expand Down
56 changes: 54 additions & 2 deletions contracts/channel-factory/src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

use ed25519_dalek::SigningKey;
use soroban_sdk::{
testutils::Address as _,
testutils::{Address as _, AuthorizedFunction, AuthorizedInvocation},
token::{StellarAssetClient, TokenClient},
xdr::ToXdr,
Address, BytesN, Env,
Address, BytesN, Env, IntoVal, Symbol,
};

use crate::{DeploymentSaltPreimage, FactoryContract, FactoryContractClient};
Expand Down Expand Up @@ -59,3 +59,55 @@ fn test_open() {
assert_eq!(token.balance(&channel_id), 500);
assert_eq!(token.balance(&funder), 500);
}

/// Opening a channel with amount 0 still requires the funder's auth.
#[test]
fn test_open_zero_amount() {
let env = Env::default();
env.mock_all_auths();

let admin = Address::generate(&env);
let wasm_hash = env.deployer().upload_contract_wasm(channel_contract::WASM);

// Deploy the factory.
let factory_id = env.register(FactoryContract, (&admin, &wasm_hash));
let factory_client = FactoryContractClient::new(&env, &factory_id);

// Set up a channel.
let auth_key = SigningKey::from_bytes(&[2u8; 32]);
let auth_pubkey = BytesN::from_array(&env, &auth_key.verifying_key().to_bytes());
let funder = Address::generate(&env);
let to = Address::generate(&env);

let (token_addr, token, asset_admin) = create_token(&env);
asset_admin.mint(&funder, &1000);

// Deploy a channel via the factory with no initial deposit.
let salt = BytesN::from_array(&env, &[0u8; 32]);
let channel_id = factory_client.open(&salt, &token_addr, &funder, &auth_pubkey, &to, &0i128, &100u32);

assert_eq!(
env.auths(),
[(
funder.clone(),
AuthorizedInvocation {
function: AuthorizedFunction::Contract((
factory_id.clone(),
Symbol::new(&env, "open"),
(salt.clone(), token_addr.clone(), funder.clone(), auth_pubkey.clone(), to.clone(), 0i128, 100u32).into_val(&env),
)),
sub_invocations: [AuthorizedInvocation {
function: AuthorizedFunction::Contract((
channel_id.clone(),
Symbol::new(&env, "__constructor"),
(token_addr.clone(), funder.clone(), auth_pubkey.clone(), to.clone(), 0i128, 100u32).into_val(&env),
)),
sub_invocations: [].into(),
}]
.into(),
}
)]
);
assert_eq!(token.balance(&channel_id), 0);
assert_eq!(token.balance(&funder), 1000);
}
20 changes: 10 additions & 10 deletions contracts/channel-factory/test_snapshots/test/test_open.1.json

Large diffs are not rendered by default.

Loading
Loading