Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
spending limits added to wit
  • Loading branch information
Hallmane committed Aug 9, 2025
commit eaa9799bd9bed2de4dc49fe6188cb2f2e12dde3d
15 changes: 15 additions & 0 deletions hyperware-wit/hyperwallet:sys-v0.wit
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ interface hyperwallet {
export-wallet(export-wallet-request),
list-wallets,
get-wallet-info(get-wallet-info-request),
set-wallet-limits(set-wallet-limits-request),

// Ethereum Operations
send-eth(send-eth-request),
Expand Down Expand Up @@ -256,6 +257,7 @@ interface hyperwallet {
get-wallet-info(get-wallet-info-response),
get-balance(get-balance-response),
get-token-balance(get-token-balance-response),
set-wallet-limits(set-wallet-limits-response),

// Transactions
send-eth(send-eth-response),
Expand Down Expand Up @@ -311,6 +313,12 @@ interface hyperwallet {
wallet-id: string,
}

/// Set wallet-level spending limits
record set-wallet-limits-request {
wallet-id: string,
limits: wallet-spending-limits,
}

record get-balance-request {
wallet-id: string,
}
Expand Down Expand Up @@ -541,6 +549,13 @@ interface hyperwallet {
total: u64,
}

/// Response for setting wallet limits
record set-wallet-limits-response {
success: bool,
wallet-id: string,
message: string,
}

record wallet {
address: wallet-address,
name: option<string>,
Expand Down
26 changes: 24 additions & 2 deletions src/hyperwallet_client/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ use super::types::{
self, Balance, BuildAndSignUserOperationForPaymentRequest, BuildAndSignUserOperationResponse,
CreateWalletRequest, ExportWalletResponse, GetTokenBalanceResponse, HyperwalletMessage,
HyperwalletRequest, ImportWalletRequest, ListWalletsResponse, PaymasterConfig,
RenameWalletRequest, SendEthRequest, SendTokenRequest, SessionId, TxReceipt,
UnlockWalletRequest, UserOperationReceiptResponse, Wallet,
RenameWalletRequest, SendEthRequest, SendTokenRequest, SessionId, SetWalletLimitsRequest,
SetWalletLimitsResponse, TxReceipt, UnlockWalletRequest, UserOperationReceiptResponse, Wallet,
};
use super::HyperwalletClientError;
use crate::wallet;
Expand Down Expand Up @@ -206,6 +206,28 @@ pub fn rename_wallet(
}
}

pub fn set_wallet_limits(
session_id: &SessionId,
wallet_id: &str,
limits: types::WalletSpendingLimits,
) -> Result<SetWalletLimitsResponse, HyperwalletClientError> {
let message = build_message(
session_id,
HyperwalletRequest::SetWalletLimits(SetWalletLimitsRequest {
wallet_id: wallet_id.to_string(),
limits,
}),
);

let response = super::send_message(message)?;
match response.data {
Some(types::HyperwalletResponseData::SetWalletLimits(resp)) => Ok(resp),
_ => Err(HyperwalletClientError::ServerError(
types::OperationError::internal_error("Missing SetWalletLimits response data"),
)),
}
}

// === TRANSACTIONS ===

pub fn send_eth(
Expand Down
127 changes: 127 additions & 0 deletions src/hyperwallet_client/serde_request_response_impls.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
use crate::hyperware::process::hyperwallet as wit;
use serde::de::{self};
use serde::ser::Serialize;
use serde::Deserialize;

// Create a macro to generate stub implementations for request/response types
macro_rules! impl_stub_serde {
($type:ty, $name:literal) => {
impl Serialize for $type {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::ser::Serializer,
{
// For now, serialize as debug representation
let json_val = serde_json::json!({
"type": $name,
"data": format!("{:?}", self)
});
json_val.serialize(serializer)
}
}

impl<'a> Deserialize<'a> for $type {
fn deserialize<D>(deserializer: D) -> Result<$type, D::Error>
where
D: serde::de::Deserializer<'a>,
{
// The hyperwallet service is sending the response wrapped in a debug format
// We need to deserialize the actual JSON payload
let val = serde_json::Value::deserialize(deserializer)?;

// Try normal JSON deserialization first
match serde_json::from_value(val.clone()) {
Ok(result) => Ok(result),
Err(_) => {
// If that fails, it might be wrapped in the debug format
// For now, we can't parse debug format strings back to structs
// This is a fundamental issue with the hyperwallet service
Err(de::Error::custom(format!(
"{} cannot be deserialized from debug format. The hyperwallet service needs to be fixed to return proper JSON.",
$name
)))
}
}
}
}
};
}

// Request types
impl_stub_serde!(
wit::UpdateSpendingLimitsRequest,
"UpdateSpendingLimitsRequest"
);
impl_stub_serde!(wit::ImportWalletRequest, "ImportWalletRequest");
impl_stub_serde!(wit::DeleteWalletRequest, "DeleteWalletRequest");
impl_stub_serde!(wit::RenameWalletRequest, "RenameWalletRequest");
impl_stub_serde!(wit::ExportWalletRequest, "ExportWalletRequest");
impl_stub_serde!(wit::GetWalletInfoRequest, "GetWalletInfoRequest");
impl_stub_serde!(wit::SendEthRequest, "SendEthRequest");
impl_stub_serde!(wit::SendTokenRequest, "SendTokenRequest");
impl_stub_serde!(wit::ApproveTokenRequest, "ApproveTokenRequest");
impl_stub_serde!(wit::GetBalanceRequest, "GetBalanceRequest");
impl_stub_serde!(wit::GetTokenBalanceRequest, "GetTokenBalanceRequest");
impl_stub_serde!(wit::CallContractRequest, "CallContractRequest");
impl_stub_serde!(wit::SignTransactionRequest, "SignTransactionRequest");
impl_stub_serde!(wit::SignMessageRequest, "SignMessageRequest");
impl_stub_serde!(
wit::BuildAndSignUserOperationForPaymentRequest,
"BuildAndSignUserOperationForPaymentRequest"
);
impl_stub_serde!(
wit::SubmitUserOperationRequest,
"SubmitUserOperationRequest"
);
impl_stub_serde!(
wit::GetUserOperationReceiptRequest,
"GetUserOperationReceiptRequest"
);
impl_stub_serde!(
wit::GetTransactionHistoryRequest,
"GetTransactionHistoryRequest"
);
impl_stub_serde!(wit::EstimateGasRequest, "EstimateGasRequest");

// Response types
impl_stub_serde!(wit::UnlockWalletResponse, "UnlockWalletResponse");
impl_stub_serde!(wit::CreateWalletResponse, "CreateWalletResponse");
impl_stub_serde!(wit::ImportWalletResponse, "ImportWalletResponse");
impl_stub_serde!(wit::DeleteWalletResponse, "DeleteWalletResponse");
impl_stub_serde!(wit::ExportWalletResponse, "ExportWalletResponse");
impl_stub_serde!(wit::ListWalletsResponse, "ListWalletsResponse");
impl_stub_serde!(wit::GetWalletInfoResponse, "GetWalletInfoResponse");
impl_stub_serde!(wit::GetBalanceResponse, "GetBalanceResponse");
impl_stub_serde!(wit::GetTokenBalanceResponse, "GetTokenBalanceResponse");
impl_stub_serde!(wit::SendEthResponse, "SendEthResponse");
impl_stub_serde!(wit::SendTokenResponse, "SendTokenResponse");
impl_stub_serde!(wit::BuildAndSignUserOperationResponse,"BuildAndSignUserOperationResponse");
impl_stub_serde!(wit::SubmitUserOperationResponse,"SubmitUserOperationResponse");
impl_stub_serde!(wit::UserOperationReceiptResponse,"UserOperationReceiptResponse");

// Other request types
impl_stub_serde!(wit::GetTransactionReceiptRequest,"GetTransactionReceiptRequest");
impl_stub_serde!(wit::BuildUserOperationRequest, "BuildUserOperationRequest");
impl_stub_serde!(wit::SignUserOperationRequest, "SignUserOperationRequest");
impl_stub_serde!(wit::BuildAndSignUserOperationRequest,"BuildAndSignUserOperationRequest");
impl_stub_serde!(wit::EstimateUserOperationGasRequest,"EstimateUserOperationGasRequest");
impl_stub_serde!(wit::ConfigurePaymasterRequest, "ConfigurePaymasterRequest");
impl_stub_serde!(wit::ExecuteViaTbaRequest, "ExecuteViaTbaRequest");
impl_stub_serde!(wit::CheckTbaOwnershipRequest, "CheckTbaOwnershipRequest");
impl_stub_serde!(wit::SetupTbaDelegationRequest, "SetupTbaDelegationRequest");
impl_stub_serde!(wit::CreateNoteRequest, "CreateNoteRequest");
impl_stub_serde!(wit::ReadNoteRequest, "ReadNoteRequest");
impl_stub_serde!(wit::ResolveIdentityRequest, "ResolveIdentityRequest");
impl_stub_serde!(wit::SetupDelegationRequest, "SetupDelegationRequest");
impl_stub_serde!(wit::VerifyDelegationRequest, "VerifyDelegationRequest");
impl_stub_serde!(wit::MintEntryRequest, "MintEntryRequest");

// Other response types
impl_stub_serde!(wit::CreateNoteResponse, "CreateNoteResponse");
impl_stub_serde!(wit::ExecuteViaTbaResponse, "ExecuteViaTbaResponse");
impl_stub_serde!(wit::CheckTbaOwnershipResponse, "CheckTbaOwnershipResponse");

// Other types that may need serde
impl_stub_serde!(wit::Balance, "Balance");
impl_stub_serde!(wit::Wallet, "Wallet");
impl_stub_serde!(wit::WalletSpendingLimits, "WalletSpendingLimits");
63 changes: 63 additions & 0 deletions src/hyperwallet_client/serde_response_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,36 @@ use serde::ser::SerializeStruct;
use serde::{Deserialize, Serialize};

// ============== REQUEST TYPES ==============
// SetWalletLimitsRequest
impl Serialize for wit::SetWalletLimitsRequest {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut state = serializer.serialize_struct("SetWalletLimitsRequest", 2)?;
state.serialize_field("wallet_id", &self.wallet_id)?;
state.serialize_field("limits", &self.limits)?;
state.end()
}
}

impl<'de> Deserialize<'de> for wit::SetWalletLimitsRequest {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
#[derive(Deserialize)]
struct Helper {
wallet_id: String,
limits: wit::WalletSpendingLimits,
}
let h = Helper::deserialize(deserializer)?;
Ok(wit::SetWalletLimitsRequest {
wallet_id: h.wallet_id,
limits: h.limits,
})
}
}

// ImportWalletRequest
impl Serialize for wit::ImportWalletRequest {
Expand Down Expand Up @@ -405,6 +435,39 @@ impl<'de> Deserialize<'de> for wit::GetUserOperationReceiptRequest {
}

// ============== RESPONSE TYPES ==============
// SetWalletLimitsResponse
impl Serialize for wit::SetWalletLimitsResponse {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut state = serializer.serialize_struct("SetWalletLimitsResponse", 3)?;
state.serialize_field("success", &self.success)?;
state.serialize_field("wallet_id", &self.wallet_id)?;
state.serialize_field("message", &self.message)?;
state.end()
}
}

impl<'de> Deserialize<'de> for wit::SetWalletLimitsResponse {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
#[derive(Deserialize)]
struct Helper {
success: bool,
wallet_id: String,
message: String,
}
let h = Helper::deserialize(deserializer)?;
Ok(wit::SetWalletLimitsResponse {
success: h.success,
wallet_id: h.wallet_id,
message: h.message,
})
}
}

// CreateWalletResponse
impl Serialize for wit::CreateWalletResponse {
Expand Down
28 changes: 28 additions & 0 deletions src/hyperwallet_client/serde_variant_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,10 @@ impl Serialize for wit::HyperwalletRequest {
state.serialize_field("type", "MintEntry")?;
state.serialize_field("data", data)?;
}
SetWalletLimits(data) => {
state.serialize_field("type", "SetWalletLimits")?;
state.serialize_field("data", data)?;
}
}

state.end()
Expand Down Expand Up @@ -443,6 +447,16 @@ impl<'a> Deserialize<'a> for wit::HyperwalletRequest {
})?;
Ok(GetUserOperationReceipt(req))
}
"SetWalletLimits" => {
let data = data.ok_or_else(|| de::Error::missing_field("data"))?;
let req = serde_json::from_value(data).map_err(|e| {
de::Error::custom(format!(
"Failed to deserialize SetWalletLimitsRequest: {}",
e
))
})?;
Ok(SetWalletLimits(req))
}
"BuildUserOperation" => {
let data = data.ok_or_else(|| de::Error::missing_field("data"))?;
let req = serde_json::from_value(data).map_err(|e| {
Expand Down Expand Up @@ -724,6 +738,10 @@ impl Serialize for wit::HyperwalletResponseData {
state.serialize_field("type", "CheckTbaOwnership")?;
state.serialize_field("data", data)?;
}
SetWalletLimits(data) => {
state.serialize_field("type", "SetWalletLimits")?;
state.serialize_field("data", data)?;
}
}

state.end()
Expand Down Expand Up @@ -922,6 +940,16 @@ impl<'a> Deserialize<'a> for wit::HyperwalletResponseData {
})?;
Ok(GetTokenBalance(response))
}
"SetWalletLimits" => {
let data = data.ok_or_else(|| de::Error::missing_field("data"))?;
let response = serde_json::from_value(data).map_err(|e| {
de::Error::custom(format!(
"Failed to deserialize SetWalletLimitsResponse: {}",
e
))
})?;
Ok(SetWalletLimits(response))
}
"CreateNote" => {
let data = data.ok_or_else(|| de::Error::missing_field("data"))?;
let response = serde_json::from_value(data).map_err(|e| {
Expand Down
14 changes: 10 additions & 4 deletions src/hyperwallet_client/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,19 @@ pub use wit::{
CheckTbaOwnershipRequest, ConfigurePaymasterRequest, CreateNoteRequest, EstimateGasRequest,
EstimateUserOperationGasRequest, ExecuteViaTbaRequest, GetTransactionHistoryRequest,
GetTransactionReceiptRequest, GetUserOperationReceiptRequest, MintEntryRequest,
ReadNoteRequest, ResolveIdentityRequest, SetupDelegationRequest, SetupTbaDelegationRequest,
SignMessageRequest, SignTransactionRequest, SignUserOperationRequest,
SubmitUserOperationRequest, UpdateSpendingLimitsRequest, VerifyDelegationRequest,
ReadNoteRequest, ResolveIdentityRequest, SetWalletLimitsRequest, SetupDelegationRequest,
SetupTbaDelegationRequest, SignMessageRequest, SignTransactionRequest,
SignUserOperationRequest, SubmitUserOperationRequest, UpdateSpendingLimitsRequest,
VerifyDelegationRequest,
};

// SetWalletLimits request/response types (wallet-level limits)
// Not available in current WIT; requires WIT update to add request/response and variants.

// Re-export response types
pub use wit::{
BuildAndSignUserOperationResponse, CheckTbaOwnershipResponse, SubmitUserOperationResponse,
BuildAndSignUserOperationResponse, CheckTbaOwnershipResponse, SetWalletLimitsResponse,
SubmitUserOperationResponse,
};

// Type aliases for compatibility
Expand Down Expand Up @@ -305,6 +310,7 @@ pub fn operation_type(request: &HyperwalletRequest) -> Operation {
HyperwalletRequest::BuildAndSignUserOperation(_) => Operation::BuildAndSignUserOperation,
HyperwalletRequest::EstimateUserOperationGas(_) => Operation::EstimateUserOperationGas,
HyperwalletRequest::ConfigurePaymaster(_) => Operation::ConfigurePaymaster,
HyperwalletRequest::SetWalletLimits(_) => Operation::SetWalletLimits,

// Hypermap Operations
HyperwalletRequest::ResolveIdentity(_) => Operation::ResolveIdentity,
Expand Down