Check Unlock Conditions
Outputs may have multiple UnlockConditions, which may require returning some or all of the transferred amount. The outputs could also expire if not claimed in time, or may not be unlockable for a predefined period.
Code Example
The following example will:
- Create an account manager.
- Get Alice's account which was created in the first guide.
- Check if an output has only an address unlock condition and that the address is from the account.
- Rust
- Nodejs
- Python
- Java
// Copyright 2023 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0
//! cargo run --example check_unlock_conditions --release
// In this example we check if an output has only an address unlock condition and that the address is from the account.
use iota_client::block::output::{unlock_condition::AddressUnlockCondition, BasicOutputBuilder, UnlockCondition};
use iota_wallet::{account::types::AddressWrapper, account_manager::AccountManager, Result};
#[tokio::main]
async fn main() -> Result<()> {
// Create the account manager
let manager = AccountManager::builder().finish().await?;
// Get the account we generated with `01_create_wallet`
let account = manager.get_account("Alice").await?;
let account_addresses: Vec<AddressWrapper> = account
.addresses()
.await?
.into_iter()
.map(|a| a.address().clone())
.collect();
let output = BasicOutputBuilder::new_with_amount(1_000_000)?
.add_unlock_condition(UnlockCondition::Address(AddressUnlockCondition::new(
*account_addresses[0].as_ref(),
)))
.finish_output(account.client().get_token_supply().await?)?;
let controlled_by_account = if let [UnlockCondition::Address(address_unlock_condition)] = output
.unlock_conditions()
.expect("output needs to have unlock conditions")
.as_ref()
{
// Check that address in the unlock condition belongs to the account
account_addresses
.iter()
.any(|a| a.as_ref() == address_unlock_condition.address())
} else {
false
};
println!(
"The output has only an address unlock condition and the address is from the account: {controlled_by_account:?}"
);
Ok(())
}
Run the example by running the following command:
cargo run --example check_unlock_conditions --release
/**
* In this example we check if an output has only an address unlock condition and that the address is from the account.
*/
const getUnlockedManager = require('./account-manager');
async function run() {
try {
let manager = await getUnlockedManager();
const account = await manager.getAccount('Alice');
let accountAddresses = await account.addresses()
const output = await account.prepareOutput({
recipientAddress: accountAddresses[0].address,
amount: "1000000",
});
let hexEncodedAccountAddresses = await Promise.all(accountAddresses.map(async (a) => await manager.bech32ToHex(a.address)));
let controlledByAccount = false
if (output.unlockConditions.length === 1 &&
output.unlockConditions[0].type === 0 &&
hexEncodedAccountAddresses.includes(output.unlockConditions[0].address.pubKeyHash)) {
controlledByAccount = true
}
console.log("The output has only an address unlock condition and the address is from the account: " + controlledByAccount)
} catch (error) {
console.log('Error: ', error);
}
process.exit(0);
}
run();
You can run the example by running the following command from the wallet/bindings/nodejs/examples/
folder:
node 36-check-unlock-conditions.js
from iota_wallet import IotaWallet
# In this example we check if an output has only an address unlock condition and that the address is from the account.
wallet = IotaWallet("./alice-database")
account = wallet.get_account("Alice")
wallet.set_stronghold_password("some_hopefully_secure_password")
accountAddresses = account.addresses()
# using prepare_output
output = account.prepare_output(
{
"amount": "1000000",
"recipientAddress": accountAddresses[0]['address'],
}
)
def hexAddress(address):
return wallet.bech32_to_hex(address['address'])
hexEncodedAccountAddresses = map(hexAddress, accountAddresses)
controlled_by_account = False
if len(output['unlockConditions']) == 1 and output['unlockConditions'][0]['type'] == 0:
if output['unlockConditions'][0]['address']['pubKeyHash'] in hexEncodedAccountAddresses:
controlled_by_account = True
print(
f'The output has only an address unlock condition and the address is from the account: {controlled_by_account}')
You can run the example by running the following command from the binding/python/examples
folder:
python3 13-check-unlock-conditions.py
// Copyright 2023 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0
import org.iota.Wallet;
import org.iota.types.*;
import org.iota.types.account_methods.PrepareOutput;
import org.iota.types.account_methods.SyncAccount;
import org.iota.types.addresses.Ed25519Address;
import org.iota.types.exceptions.InitializeWalletException;
import org.iota.types.exceptions.WalletException;
import org.iota.types.outputs.Output;
import org.iota.types.outputs.BasicOutput;
import org.iota.types.unlock_conditions.AddressUnlockCondition;
import org.iota.types.ids.account.AccountAlias;
import org.iota.types.secret.StrongholdSecretManager;
import java.util.ArrayList;
public class CheckUnlockConditions {
public static void main(String[] args) throws WalletException, InterruptedException, InitializeWalletException {
// This example assumes that a wallet has already been created using the ´SetupWallet.java´ example.
// If you haven't run the ´SetupWallet.java´ example yet, you must run it first to be able to load the wallet as shown below:
Wallet wallet = new Wallet(new WalletConfig()
.withClientOptions(new ClientConfig().withNodes(Env.NODE))
.withSecretManager(new StrongholdSecretManager(Env.STRONGHOLD_PASSWORD, null, Env.STRONGHOLD_VAULT_PATH))
.withCoinType(CoinType.Shimmer)
.withStoragePath(Env.STORAGE_PATH)
);
// Get account.
AccountHandle a = wallet.getAccount(new AccountAlias(Env.ACCOUNT_NAME));
// Convert addresses to hex.
ArrayList<String> hexEncodedAccountAddresses = new ArrayList<String>();
for (AccountAddress address: a.getAddresses())
hexEncodedAccountAddresses.add(wallet.bech32ToHex(address.getAddress()));
// Build an output.
Output output = a.prepareOutput(new PrepareOutput().withOptions(new OutputOptions()
.withAmount("1000000")
.withRecipientAddress(a.getPublicAddresses()[0].getAddress())
));
boolean controlledByAccount = false;
BasicOutput basicOutput = (BasicOutput) output;
AddressUnlockCondition addressUnlockCondition = (AddressUnlockCondition) basicOutput.getUnlockConditions()[0];
Ed25519Address ed25519Address = (Ed25519Address) addressUnlockCondition.getAddress();
if (basicOutput.getUnlockConditions().length == 1 &&
addressUnlockCondition.getType() == 0 &&
hexEncodedAccountAddresses.contains(ed25519Address.getPubKeyHash())) {
controlledByAccount = true;
}
// Print the balance.
System.out.println("The output has only an address unlock condition and the address is from the account: " + controlledByAccount);
// In case you are done and don't need the wallet instance anymore you can destroy the instance to clean up memory.
// For this, check out the ´DestroyWallet.java´ example.
}
}
You can run the example by running the following command from the wallet/bindings/java/
folder:
./gradlew run -Pexample=CheckUnlockConditions
Expected Output
- Rust
- Nodejs
- Python
- Java
The output has only an address unlock condition and the address is from the account: true
The output has only an address unlock condition and the address is from the account: true
The output has only an address unlock condition and the address is from the account: True
The output has only an address unlock condition and the address is from the account: true