Icon LinkSigning

Once you've instantiated your wallet in an unlocked state using one of the previously discussed methods, you can sign a message with wallet.sign_message. Below is a full example of how to sign and recover a message.

let mut rng = StdRng::seed_from_u64(2322u64);
let mut secret_seed = [0u8; 32];
rng.fill_bytes(&mut secret_seed);
 
let secret = secret_seed
    .as_slice()
    .try_into()
    .expect("The seed size is valid");
 
// Create a wallet using the private key created above.
let wallet = WalletUnlocked::new_from_private_key(secret, None);
 
let message = "my message";
 
let signature = wallet.sign_message(message).await?;
 
// Check if signature is what we expect it to be
assert_eq!(signature, Signature::from_str("0x8eeb238db1adea4152644f1cd827b552dfa9ab3f4939718bb45ca476d167c6512a656f4d4c7356bfb9561b14448c230c6e7e4bd781df5ee9e5999faa6495163d")?);
 
// Recover address that signed the message
let message = Message::new(message);
let recovered_address = signature.recover(&message)?;
 
assert_eq!(wallet.address().hash(), recovered_address.hash());
 
// Verify signature
signature.verify(&recovered_address, &message)?;

Icon LinkSigning a transaction

Every signed resource in the inputs needs to have a witness index that points to a valid witness. Changing the witness index inside an input will change the transaction id. This means that we need to set all witness indexes before finally signing the tx. Previously, the user had to make sure that the witness indexes and the order of the witnesses are correct. To automate this process, the SDK will keep track of the signatures in the transaction builder and resolve the final transaction automatically. This is done by storing the secret keys of all signers until the final transaction is built.

To sign a transaction builder use the wallet.sign_transaction. Below is a full example of how to create a transaction and sign it.

Note: When you sign a transaction builder the secret key is stored inside it and will not be resolved until you call build()!

let secret = SecretKey::from_str(
    "5f70feeff1f229e4a95e1056e8b4d80d0b24b565674860cc213bdb07127ce1b1",
)?;
let wallet = WalletUnlocked::new_from_private_key(secret, None);
 
// Set up a transaction
let mut tb = {
    let input_coin = Input::ResourceSigned {
        resource: CoinType::Coin(Coin {
            amount: 10000000,
            owner: wallet.address().clone(),
            ..Default::default()
        }),
    };
 
    let output_coin = Output::coin(
        Address::from_str(
            "0xc7862855b418ba8f58878db434b21053a61a2025209889cc115989e8040ff077",
        )?,
        1,
        Default::default(),
    );
 
    ScriptTransactionBuilder::prepare_transfer(
        vec![input_coin],
        vec![output_coin],
        Default::default(),
    )
};
 
// Sign the transaction
wallet.sign_transaction(&mut tb); // Add the private key to the transaction builder
let tx = tb.build()?; // Resolve signatures and add corresponding witness indexes
 
// Extract the signature from the tx witnesses
let bytes = <[u8; Signature::LEN]>::try_from(tx.witnesses().first().unwrap().as_ref())?;
let tx_signature = Signature::from_bytes(bytes);
 
// Sign the transaction manually
let message = Message::from_bytes(*tx.id(0.into()));
let signature = Signature::sign(&wallet.private_key, &message);
 
// Check if the signatures are the same
assert_eq!(signature, tx_signature);
 
// Check if the signature is what we expect it to be
assert_eq!(signature, Signature::from_str("d7027be16db0aada625ac8cd438f9b6187bd74465495ba39511c1ad72b7bb10af4ef582c94cc33433f7a1eb4f2ad21c471473947f5f645e90924ba273e2cee7f")?);
 
// Recover the address that signed the transaction
let recovered_address = signature.recover(&message)?;
 
assert_eq!(wallet.address().hash(), recovered_address.hash());
 
// Verify the signature
signature.verify(&recovered_address, &message)?;

Was this page helpful?

Icon ListDetailsOn this page