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

Introduce predicate_id() to the std-lib #5425

Merged
merged 11 commits into from
Jan 3, 2024
31 changes: 31 additions & 0 deletions sway-lib-std/src/auth.sw
Original file line number Diff line number Diff line change
Expand Up @@ -177,3 +177,34 @@ pub fn caller_address() -> Result<Address, AuthError> {
None => Err(AuthError::CallerIsInternal),
}
}

/// Get the current predicate's id when called in an internal context.
///
/// # Returns
///
/// * [Address] - The address of this predicate.
///
/// # Reverts
///
/// * When called not in a predicate context.
bitzoic marked this conversation as resolved.
Show resolved Hide resolved
///
/// # Examples
///
/// ```sway
/// use std::{auth::predicate_id};
bitzoic marked this conversation as resolved.
Show resolved Hide resolved
///
/// fn main() {
/// let this_predicate = predicate_id();
/// log(this_predicate);
/// }
/// ```
pub fn predicate_id() -> Address {
// Get index of current predicate.
// i3 = GM_GET_VERIFYING_PREDICATE
let predicate_index = asm(r1) {
gm r1 i3;
r1: u64
};

input_coin_owner(predicate_index).unwrap()
}
5 changes: 5 additions & 0 deletions test/src/sdk-harness/Forc.lock
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ dependencies = [
"std",
]

[[package]]
name = "auth_predicate"
source = "member"
dependencies = ["std"]

[[package]]
name = "auth_testing_abi"
source = "member"
Expand Down
1 change: 1 addition & 0 deletions test/src/sdk-harness/Forc.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ members = [
"test_projects/vec_in_abi",
"test_artifacts/auth_caller_contract",
"test_artifacts/auth_caller_script",
"test_artifacts/auth_predicate",
"test_artifacts/auth_testing_abi",
"test_artifacts/auth_testing_contract",
"test_artifacts/balance_contract",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
out
target
13 changes: 13 additions & 0 deletions test/src/sdk-harness/test_artifacts/auth_predicate/Forc.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[[package]]
name = "auth_predicate"
source = "member"
dependencies = ["std"]

[[package]]
name = "core"
source = "path+from-root-7FCE6F17DDEC6CE9"

[[package]]
name = "std"
source = "path+from-root-7FCE6F17DDEC6CE9"
dependencies = ["core"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[project]
authors = ["Fuel Labs <[email protected]>"]
entry = "main.sw"
license = "Apache-2.0"
name = "auth_predicate"

[dependencies]
std = { path = "../../../../../sway-lib-std" }
11 changes: 11 additions & 0 deletions test/src/sdk-harness/test_artifacts/auth_predicate/src/main.sw
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
predicate;

use std::auth::predicate_id;

fn main(predicate_address: Address) -> bool {
let address = predicate_id();
assert(predicate_address == address);

true
bitzoic marked this conversation as resolved.
Show resolved Hide resolved
}

115 changes: 113 additions & 2 deletions test/src/sdk-harness/test_projects/auth/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use fuels::{
accounts::wallet::{Wallet, WalletUnlocked},
accounts::{wallet::{Wallet, WalletUnlocked}, predicate::Predicate},
prelude::*,
types::ContractId,
};
use std::str::FromStr;

abigen!(
Contract(
Expand All @@ -12,7 +13,11 @@ abigen!(
Contract(
name = "AuthCallerContract",
abi = "test_artifacts/auth_caller_contract/out/debug/auth_caller_contract-abi.json"
)
),
Predicate(
name = "AuthPredicate",
abi = "test_artifacts/auth_predicate/out/debug/auth_predicate-abi.json"
),
);

#[tokio::test]
Expand Down Expand Up @@ -94,3 +99,109 @@ async fn get_contracts() -> (
wallet.lock(),
)
}

#[tokio::test]
async fn can_get_predicate_id() {
// Setup Wallets
let asset_id = AssetId::default();
let wallets_config = WalletsConfig::new_multiple_assets(
2,
vec![AssetConfig {
id: asset_id,
num_coins: 1,
coin_amount: 1_000,
}],
);
let wallets = &launch_custom_provider_and_get_wallets(wallets_config, None, None).await.unwrap();
let first_wallet = &wallets[0];
let second_wallet = &wallets[1];

// Setup Predciate
let hex_predicate_address: &str = "0x935a191561e0e9388c1b5dfc4626f6ecd98b2b3dd416a9a9e9ce2f0bb214f4b8";
bitzoic marked this conversation as resolved.
Show resolved Hide resolved
bitzoic marked this conversation as resolved.
Show resolved Hide resolved
let predicate_address = Address::from_str(hex_predicate_address).expect("failed to create Address from string");
let predicate_bech32_address = Bech32Address::from(predicate_address);
let predicate_data = AuthPredicateEncoder::encode_data(predicate_bech32_address);
let predicate: Predicate = Predicate::load_from("test_artifacts/auth_predicate/out/debug/auth_predicate.bin").unwrap()
.with_provider(first_wallet.try_provider().unwrap().clone())
.with_data(predicate_data);

// Next, we lock some assets in this predicate using the first wallet:
bitzoic marked this conversation as resolved.
Show resolved Hide resolved
// First wallet transfers amount to predicate.
first_wallet
.transfer(predicate.address(), 500, asset_id, TxPolicies::default())
.await.unwrap();

// Check predicate balance.
let balance = predicate.get_asset_balance(&AssetId::default()).await.unwrap();
assert_eq!(balance, 500);

// Then we can transfer assets owned by the predicate via the Account trait:
let amount_to_unlock = 500;

// Will transfer if the correct predicate address is passed as an argument to the predicate
predicate
.transfer(
second_wallet.address(),
amount_to_unlock,
asset_id,
TxPolicies::default(),
)
.await.unwrap();

// Predicate balance is zero.
let balance = predicate.get_asset_balance(&AssetId::default()).await.unwrap();
assert_eq!(balance, 0);

// Second wallet balance is updated.
let balance = second_wallet.get_asset_balance(&AssetId::default()).await.unwrap();
assert_eq!(balance, 1500);
}

#[tokio::test]
#[should_panic]
async fn when_incorrect_predicate_address_passed() {
// Setup Wallets
let asset_id = AssetId::default();
let wallets_config = WalletsConfig::new_multiple_assets(
2,
vec![AssetConfig {
id: asset_id,
num_coins: 1,
coin_amount: 1_000,
}],
);
let wallets = &launch_custom_provider_and_get_wallets(wallets_config, None, None).await.unwrap();
let first_wallet = &wallets[0];
let second_wallet = &wallets[1];

// Setup Predciate with incorrect address
let hex_predicate_address: &str = "0x36bf4bd40f2a3b3db595ef8fd8b21dbe9e6c0dd7b419b4413ff6b584ce7da5d7";
let predicate_address = Address::from_str(hex_predicate_address).expect("failed to create Address from string");
let predicate_data = AuthPredicateEncoder::encode_data(Bech32Address::from(predicate_address));
let predicate: Predicate = Predicate::load_from("test_artifacts/auth_predicate/out/debug/auth_predicate.bin").unwrap()
.with_provider(first_wallet.try_provider().unwrap().clone())
.with_data(predicate_data);

// Next, we lock some assets in this predicate using the first wallet:
// First wallet transfers amount to predicate.
first_wallet
.transfer(predicate.address(), 500, asset_id, TxPolicies::default())
.await.unwrap();

// Check predicate balance.
let balance = predicate.get_asset_balance(&AssetId::default()).await.unwrap();
assert_eq!(balance, 500);

// Then we can transfer assets owned by the predicate via the Account trait:
let amount_to_unlock = 500;

// Will should fail to transfer
predicate
.transfer(
second_wallet.address(),
amount_to_unlock,
asset_id,
TxPolicies::default(),
)
.await.unwrap();
}
Loading