use alloy_primitives::{Address, U256};
use alloy_provider::network::AnyNetwork;
use alloy_provider::{DynProvider, PendingTransactionBuilder};
use alloy_sol_types::SolCall;
use std::marker::PhantomData;
use trident_evm_aa::{MulticallBuilder, MulticallError};
use crate::evm::abi::TridentDelivery;
use crate::evm::abi::TridentDelivery::tridentSpendCall;
use crate::proto::v1;
#[derive(Debug)]
pub struct EvmCallContext {
pub delivery_contract: Address,
pub trident_spend_call: tridentSpendCall,
pub provider: DynProvider<AnyNetwork>,
pub signer_address: Address,
}
#[derive(Debug)]
pub(crate) enum SpendAttestationChainContext {
Evm {
provider: DynProvider<AnyNetwork>,
delivery_contract: Address,
signer_address: Address,
},
}
#[derive(Debug)]
pub struct SpendAttestation<T> {
inner: SpendAttestationChainContext,
attestation: v1::SpendAttestation,
spend_spec_hash: [u8; 32],
_chain_type: PhantomData<T>,
}
impl<T> SpendAttestation<T> {
pub(crate) fn new(
ctx: SpendAttestationChainContext,
attestation: v1::SpendAttestation,
spend_spec_hash: [u8; 32],
) -> Self {
Self {
inner: ctx,
attestation,
spend_spec_hash,
_chain_type: PhantomData,
}
}
pub fn spend_spec_hash(&self) -> [u8; 32] {
self.spend_spec_hash
}
}
impl SpendAttestation<Address> {
pub async fn send(
self,
) -> Result<PendingTransactionBuilder<AnyNetwork>, alloy_contract::Error> {
let SpendAttestationChainContext::Evm {
provider,
delivery_contract,
..
} = self.inner;
let delivery = TridentDelivery::new(delivery_contract, &provider);
delivery
.tridentSpend(
self.attestation.bytes.into(),
self.attestation.signature.into(),
)
.send()
.await
}
pub fn into_call(self) -> EvmCallContext {
let SpendAttestationChainContext::Evm {
provider,
delivery_contract,
signer_address,
} = self.inner;
EvmCallContext {
delivery_contract,
trident_spend_call: tridentSpendCall {
attestation: self.attestation.bytes.into(),
signature: self.attestation.signature.into(),
},
provider,
signer_address,
}
}
pub fn chain<C: SolCall>(self, contract: Address, call: &C) -> SpendMulticall {
let ctx = self.into_call();
let builder = MulticallBuilder::new()
.call(ctx.delivery_contract, &ctx.trident_spend_call)
.call(contract, call);
SpendMulticall {
builder,
provider: ctx.provider,
signer_address: ctx.signer_address,
}
}
pub fn chain_value<C: SolCall>(
self,
contract: Address,
call: &C,
value: U256,
) -> SpendMulticall {
let ctx = self.into_call();
let builder = MulticallBuilder::new()
.call(ctx.delivery_contract, &ctx.trident_spend_call)
.call_with_value(contract, call, value);
SpendMulticall {
builder,
provider: ctx.provider,
signer_address: ctx.signer_address,
}
}
}
pub struct SpendMulticall {
builder: MulticallBuilder,
provider: DynProvider<AnyNetwork>,
signer_address: Address,
}
impl SpendMulticall {
#[must_use]
pub fn call<C: SolCall>(self, contract: Address, call: &C) -> Self {
Self {
builder: self.builder.call(contract, call),
..self
}
}
#[must_use]
pub fn call_with_value<C: SolCall>(self, contract: Address, call: &C, value: U256) -> Self {
Self {
builder: self.builder.call_with_value(contract, call, value),
..self
}
}
#[must_use]
pub fn send_value(self, to: Address, value: U256) -> Self {
Self {
builder: self.builder.send_value(to, value),
..self
}
}
pub async fn send(self) -> Result<PendingTransactionBuilder<AnyNetwork>, MulticallError> {
self.builder.send(self.provider, self.signer_address).await
}
pub fn into_parts(self) -> (MulticallBuilder, DynProvider<AnyNetwork>, Address) {
(self.builder, self.provider, self.signer_address)
}
}