use alloy::{
hex::encode_prefixed,
primitives::U256,
signers::{SignerSync, local::PrivateKeySigner},
};
use alloy_sol_types::{SolValue, sol};
use anyhow::Result;
use bigdecimal::BigDecimal;
use bon::Builder;
use serde::Deserialize;
use crate::{
actions::{ActionData, ModuleData, utils::to_e18},
models::{Asset, PrivateTransferSpotRequest, SpotAssetEntry},
types::Environment,
};
#[derive(Debug, Clone, Deserialize, Builder)]
pub struct SpotTransferArgs {
#[builder(default = 0)]
pub to_subaccount_id: u64,
pub new_subaccount_manager: u32,
pub asset: String,
pub subaccount_id: u64,
pub amount: BigDecimal,
pub max_fee_usd: BigDecimal,
}
sol! {
#![sol(all_derives)]
struct SpotTransferData {
uint256 toSubaccountId;
uint256 newSubaccountManager;
address protocol_asset_address;
uint256 subId;
uint256 amount;
uint256 max_fee_usd;
}
}
impl ModuleData for SpotTransferData {
fn get_action_data(&self) -> Vec<u8> {
self.abi_encode()
}
}
impl SpotTransferData {
pub fn from_args(
args: SpotTransferArgs,
erc20_details: SpotAssetEntry,
asset: Asset,
) -> Result<Self> {
let scaled_amt = to_e18(&args.amount)?;
let scaled_fee = to_e18(&args.max_fee_usd)?;
Ok(Self {
toSubaccountId: U256::from(args.to_subaccount_id),
newSubaccountManager: U256::from(args.new_subaccount_manager),
protocol_asset_address: erc20_details
.address
.parse()
.expect("Couldnt parse underlying_erc20_address"),
subId: U256::from(
asset
.sub_id
.parse::<u64>()
.expect("Couldnt parse base_asset_sub_id"),
),
amount: scaled_amt,
max_fee_usd: scaled_fee,
})
}
}
impl ActionData {
pub fn populate_transfer_spot_params(
self,
signer: &PrivateKeySigner,
args: SpotTransferArgs,
env: &Environment,
asset: &Asset,
) -> Result<PrivateTransferSpotRequest> {
let encoded_data_hashed = &self.hash(env);
let signature = format!("{}", signer.sign_hash_sync(encoded_data_hashed)?);
let params = PrivateTransferSpotRequest {
to_subaccount_id: args.to_subaccount_id,
new_subaccount_manager: args.new_subaccount_manager,
subaccount_id: args.subaccount_id,
amount: args.amount,
max_fee_usd: args.max_fee_usd,
signature,
asset_name: args.asset,
nonce: self
.nonce
.to_string()
.parse()
.expect("Couldnt parse nonce to u64"),
signature_expiry_sec: u64::try_from(&self.expiry)?,
signer: encode_prefixed(self.signer),
sub_id: asset
.sub_id
.parse::<u64>()
.expect("Couldnt parse asset sub_id"),
};
Ok(params)
}
}