use anyhow::{Context, Error};
use serde::{Deserialize, Serialize};
use sui_sdk_types::{Address, MultisigCommittee, SignedTransaction, Transaction, UserSignature};
use crate::Keystore;
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct MultisigIntent {
pub committee: MultisigCommittee,
pub signers: Vec<usize>,
}
pub fn sign_for_address(
transaction: &Transaction,
address: Address,
multisig_intent: Option<MultisigIntent>,
keystore: &Keystore,
) -> Result<UserSignature, Error> {
let signature = if let Some(intent) = multisig_intent {
let msig_address = intent.committee.derive_address();
anyhow::ensure!(
msig_address == address,
"multisig address {msig_address} doesn't match target address {address}"
);
UserSignature::Multisig(keystore.multisign_tx(
transaction,
intent.committee,
&intent.signers,
)?)
} else {
UserSignature::Simple(keystore.sign_tx(transaction, address)?)
};
Ok(signature)
}
pub fn signed_transaction(
transaction: Transaction,
multisig_sender: Option<MultisigIntent>,
multisig_sponsor: Option<MultisigIntent>,
keystore: &Keystore,
) -> Result<SignedTransaction, Error> {
let sigs = signatures(&transaction, multisig_sender, multisig_sponsor, keystore)?;
Ok(SignedTransaction {
transaction,
signatures: sigs,
})
}
pub fn signatures(
transaction: &Transaction,
multisig_sender: Option<MultisigIntent>,
multisig_sponsor: Option<MultisigIntent>,
keystore: &Keystore,
) -> Result<Vec<UserSignature>, Error> {
let sender_signature =
sign_for_address(transaction, transaction.sender, multisig_sender, keystore)
.context("Signing for sender")?;
let mut signatures = vec![sender_signature];
if transaction.sender == transaction.gas_payment.owner {
if multisig_sponsor.is_some() {
log::warn!("Ignoring multisig_sponsor since sender owns the gas inputs");
};
} else {
signatures.push(
sign_for_address(
transaction,
transaction.gas_payment.owner,
multisig_sponsor,
keystore,
)
.context("Signing for sponsor")?,
);
};
Ok(signatures)
}