#[cfg(feature = "rust")]
use bon::Builder;
#[cfg(feature = "node")]
use napi_derive::napi;
#[cfg(feature = "python")]
use pyo3::{pyclass, pymethods};
#[cfg(feature = "python")]
use pyo3_stub_gen::derive::{gen_stub_pyclass, gen_stub_pymethods};
use serde::{Deserialize, Deserializer, Serialize};
fn deserialize_as_optional_json_string<'de, D>(deserializer: D) -> Result<Option<String>, D::Error>
where
D: Deserializer<'de>,
{
let value = Option::<serde_json::Value>::deserialize(deserializer)?;
match value {
None => Ok(None),
Some(v) => serde_json::to_string(&v)
.map(Some)
.map_err(serde::de::Error::custom),
}
}
#[cfg_attr(feature = "node", napi(string_enum))]
#[cfg_attr(not(feature = "node"), derive(Clone))]
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum WebhookTemplateId {
EvmWalletFilter,
EvmContractEvents,
EvmAbiFilter,
SolanaWalletFilter,
BitcoinWalletFilter,
XrplWalletFilter,
HyperliquidWalletEventsFilter,
StellarWalletTransactionsSourceAccountFilter,
}
impl WebhookTemplateId {
pub fn as_str(&self) -> &'static str {
match self {
WebhookTemplateId::EvmWalletFilter => "evmWalletFilter",
WebhookTemplateId::EvmContractEvents => "evmContractEvents",
WebhookTemplateId::EvmAbiFilter => "evmAbiFilter",
WebhookTemplateId::SolanaWalletFilter => "solanaWalletFilter",
WebhookTemplateId::BitcoinWalletFilter => "bitcoinWalletFilter",
WebhookTemplateId::XrplWalletFilter => "xrplWalletFilter",
WebhookTemplateId::HyperliquidWalletEventsFilter => "hyperliquidWalletEventsFilter",
WebhookTemplateId::StellarWalletTransactionsSourceAccountFilter => {
"stellarWalletTransactionsSourceAccountFilter"
}
}
}
}
#[cfg_attr(feature = "node", napi(string_enum))]
#[cfg_attr(not(feature = "node"), derive(Clone))]
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum WebhookStartFrom {
Last,
Latest,
}
#[cfg_attr(feature = "rust", derive(Builder))]
#[cfg_attr(feature = "python", gen_stub_pyclass)]
#[cfg_attr(feature = "python", pyclass(get_all, set_all))]
#[cfg_attr(feature = "node", napi(object))]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EvmWalletFilterTemplate {
pub wallets: Vec<String>,
}
#[cfg(feature = "python")]
#[gen_stub_pymethods]
#[pymethods]
impl EvmWalletFilterTemplate {
#[new]
pub fn new(wallets: Vec<String>) -> Self {
Self { wallets }
}
}
#[cfg_attr(feature = "rust", derive(Builder))]
#[cfg_attr(feature = "python", gen_stub_pyclass)]
#[cfg_attr(feature = "python", pyclass(get_all, set_all))]
#[cfg_attr(feature = "node", napi(object))]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct EvmContractEventsTemplate {
pub contracts: Vec<String>,
pub event_hashes: Vec<String>,
}
#[cfg(feature = "python")]
#[gen_stub_pymethods]
#[pymethods]
impl EvmContractEventsTemplate {
#[new]
pub fn new(contracts: Vec<String>, event_hashes: Vec<String>) -> Self {
Self {
contracts,
event_hashes,
}
}
}
#[cfg_attr(feature = "rust", derive(Builder))]
#[cfg_attr(feature = "python", gen_stub_pyclass)]
#[cfg_attr(feature = "python", pyclass(get_all, set_all))]
#[cfg_attr(feature = "node", napi(object))]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EvmAbiFilterTemplate {
pub abi: String,
pub contracts: Vec<String>,
}
#[cfg(feature = "python")]
#[gen_stub_pymethods]
#[pymethods]
impl EvmAbiFilterTemplate {
#[new]
pub fn new(abi: String, contracts: Vec<String>) -> Self {
Self { abi, contracts }
}
}
#[cfg_attr(feature = "rust", derive(Builder))]
#[cfg_attr(feature = "python", gen_stub_pyclass)]
#[cfg_attr(feature = "python", pyclass(get_all, set_all))]
#[cfg_attr(feature = "node", napi(object))]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SolanaWalletFilterTemplate {
pub accounts: Vec<String>,
}
#[cfg(feature = "python")]
#[gen_stub_pymethods]
#[pymethods]
impl SolanaWalletFilterTemplate {
#[new]
pub fn new(accounts: Vec<String>) -> Self {
Self { accounts }
}
}
#[cfg_attr(feature = "rust", derive(Builder))]
#[cfg_attr(feature = "python", gen_stub_pyclass)]
#[cfg_attr(feature = "python", pyclass(get_all, set_all))]
#[cfg_attr(feature = "node", napi(object))]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BitcoinWalletFilterTemplate {
pub wallets: Vec<String>,
}
#[cfg(feature = "python")]
#[gen_stub_pymethods]
#[pymethods]
impl BitcoinWalletFilterTemplate {
#[new]
pub fn new(wallets: Vec<String>) -> Self {
Self { wallets }
}
}
#[cfg_attr(feature = "rust", derive(Builder))]
#[cfg_attr(feature = "python", gen_stub_pyclass)]
#[cfg_attr(feature = "python", pyclass(get_all, set_all))]
#[cfg_attr(feature = "node", napi(object))]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct XrplWalletFilterTemplate {
pub wallets: Vec<String>,
}
#[cfg(feature = "python")]
#[gen_stub_pymethods]
#[pymethods]
impl XrplWalletFilterTemplate {
#[new]
pub fn new(wallets: Vec<String>) -> Self {
Self { wallets }
}
}
#[cfg_attr(feature = "rust", derive(Builder))]
#[cfg_attr(feature = "python", gen_stub_pyclass)]
#[cfg_attr(feature = "python", pyclass(get_all, set_all))]
#[cfg_attr(feature = "node", napi(object))]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HyperliquidWalletEventsFilterTemplate {
pub wallets: Vec<String>,
}
#[cfg(feature = "python")]
#[gen_stub_pymethods]
#[pymethods]
impl HyperliquidWalletEventsFilterTemplate {
#[new]
pub fn new(wallets: Vec<String>) -> Self {
Self { wallets }
}
}
#[cfg_attr(feature = "rust", derive(Builder))]
#[cfg_attr(feature = "python", gen_stub_pyclass)]
#[cfg_attr(feature = "python", pyclass(get_all, set_all))]
#[cfg_attr(feature = "node", napi(object))]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StellarWalletTransactionsFilterTemplate {
pub wallets: Vec<String>,
}
#[cfg(feature = "python")]
#[gen_stub_pymethods]
#[pymethods]
impl StellarWalletTransactionsFilterTemplate {
#[new]
pub fn new(wallets: Vec<String>) -> Self {
Self { wallets }
}
}
#[cfg_attr(feature = "rust", derive(Builder))]
#[cfg_attr(feature = "python", gen_stub_pyclass)]
#[cfg_attr(feature = "python", pyclass(get_all, set_all))]
#[cfg_attr(feature = "node", napi(object))]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct EvmWalletFilterByListTemplate {
pub wallets_list_name: String,
}
#[cfg(feature = "python")]
#[gen_stub_pymethods]
#[pymethods]
impl EvmWalletFilterByListTemplate {
#[new]
pub fn new(wallets_list_name: String) -> Self {
Self { wallets_list_name }
}
}
#[cfg_attr(feature = "rust", derive(Builder))]
#[cfg_attr(feature = "python", gen_stub_pyclass)]
#[cfg_attr(feature = "python", pyclass(get_all, set_all))]
#[cfg_attr(feature = "node", napi(object))]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct EvmContractEventsByListTemplate {
pub contracts_list_name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub event_hashes_list_name: Option<String>,
}
#[cfg(feature = "python")]
#[gen_stub_pymethods]
#[pymethods]
impl EvmContractEventsByListTemplate {
#[new]
#[pyo3(signature = (contracts_list_name, event_hashes_list_name=None))]
pub fn new(contracts_list_name: String, event_hashes_list_name: Option<String>) -> Self {
Self {
contracts_list_name,
event_hashes_list_name,
}
}
}
#[cfg_attr(feature = "rust", derive(Builder))]
#[cfg_attr(feature = "python", gen_stub_pyclass)]
#[cfg_attr(feature = "python", pyclass(get_all, set_all))]
#[cfg_attr(feature = "node", napi(object))]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct EvmAbiFilterByListTemplate {
pub abi_json: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub contracts_list_name: Option<String>,
}
#[cfg(feature = "python")]
#[gen_stub_pymethods]
#[pymethods]
impl EvmAbiFilterByListTemplate {
#[new]
#[pyo3(signature = (abi_json, contracts_list_name=None))]
pub fn new(abi_json: String, contracts_list_name: Option<String>) -> Self {
Self {
abi_json,
contracts_list_name,
}
}
}
#[cfg_attr(feature = "rust", derive(Builder))]
#[cfg_attr(feature = "python", gen_stub_pyclass)]
#[cfg_attr(feature = "python", pyclass(get_all, set_all))]
#[cfg_attr(feature = "node", napi(object))]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SolanaWalletFilterByListTemplate {
pub accounts_list_name: String,
}
#[cfg(feature = "python")]
#[gen_stub_pymethods]
#[pymethods]
impl SolanaWalletFilterByListTemplate {
#[new]
pub fn new(accounts_list_name: String) -> Self {
Self { accounts_list_name }
}
}
#[cfg_attr(feature = "rust", derive(Builder))]
#[cfg_attr(feature = "python", gen_stub_pyclass)]
#[cfg_attr(feature = "python", pyclass(get_all, set_all))]
#[cfg_attr(feature = "node", napi(object))]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct BitcoinWalletFilterByListTemplate {
pub wallets_list_name: String,
}
#[cfg(feature = "python")]
#[gen_stub_pymethods]
#[pymethods]
impl BitcoinWalletFilterByListTemplate {
#[new]
pub fn new(wallets_list_name: String) -> Self {
Self { wallets_list_name }
}
}
#[cfg_attr(feature = "rust", derive(Builder))]
#[cfg_attr(feature = "python", gen_stub_pyclass)]
#[cfg_attr(feature = "python", pyclass(get_all, set_all))]
#[cfg_attr(feature = "node", napi(object))]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct XrplWalletFilterByListTemplate {
pub wallets_list_name: String,
}
#[cfg(feature = "python")]
#[gen_stub_pymethods]
#[pymethods]
impl XrplWalletFilterByListTemplate {
#[new]
pub fn new(wallets_list_name: String) -> Self {
Self { wallets_list_name }
}
}
#[cfg_attr(feature = "rust", derive(Builder))]
#[cfg_attr(feature = "python", gen_stub_pyclass)]
#[cfg_attr(feature = "python", pyclass(get_all, set_all))]
#[cfg_attr(feature = "node", napi(object))]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct HyperliquidWalletEventsFilterByListTemplate {
pub wallets_list_name: String,
}
#[cfg(feature = "python")]
#[gen_stub_pymethods]
#[pymethods]
impl HyperliquidWalletEventsFilterByListTemplate {
#[new]
pub fn new(wallets_list_name: String) -> Self {
Self { wallets_list_name }
}
}
#[cfg_attr(feature = "rust", derive(Builder))]
#[cfg_attr(feature = "python", gen_stub_pyclass)]
#[cfg_attr(feature = "python", pyclass(get_all, set_all))]
#[cfg_attr(feature = "node", napi(object))]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct StellarWalletTransactionsFilterByListTemplate {
pub wallets_list_name: String,
}
#[cfg(feature = "python")]
#[gen_stub_pymethods]
#[pymethods]
impl StellarWalletTransactionsFilterByListTemplate {
#[new]
pub fn new(wallets_list_name: String) -> Self {
Self { wallets_list_name }
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum EvmWalletFilterInput {
Inline(EvmWalletFilterTemplate),
ByList(EvmWalletFilterByListTemplate),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum EvmContractEventsInput {
Inline(EvmContractEventsTemplate),
ByList(EvmContractEventsByListTemplate),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum EvmAbiFilterInput {
Inline(EvmAbiFilterTemplate),
ByList(EvmAbiFilterByListTemplate),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum SolanaWalletFilterInput {
Inline(SolanaWalletFilterTemplate),
ByList(SolanaWalletFilterByListTemplate),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum BitcoinWalletFilterInput {
Inline(BitcoinWalletFilterTemplate),
ByList(BitcoinWalletFilterByListTemplate),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum XrplWalletFilterInput {
Inline(XrplWalletFilterTemplate),
ByList(XrplWalletFilterByListTemplate),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum HyperliquidWalletEventsFilterInput {
Inline(HyperliquidWalletEventsFilterTemplate),
ByList(HyperliquidWalletEventsFilterByListTemplate),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum StellarWalletTransactionsFilterInput {
Inline(StellarWalletTransactionsFilterTemplate),
ByList(StellarWalletTransactionsFilterByListTemplate),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "templateId", content = "templateArgs", rename_all = "camelCase")]
pub enum TemplateArgs {
EvmWalletFilter(EvmWalletFilterInput),
EvmContractEvents(EvmContractEventsInput),
EvmAbiFilter(EvmAbiFilterInput),
SolanaWalletFilter(SolanaWalletFilterInput),
BitcoinWalletFilter(BitcoinWalletFilterInput),
XrplWalletFilter(XrplWalletFilterInput),
HyperliquidWalletEventsFilter(HyperliquidWalletEventsFilterInput),
StellarWalletTransactionsSourceAccountFilter(StellarWalletTransactionsFilterInput),
}
impl TemplateArgs {
pub fn tag(&self) -> WebhookTemplateId {
match self {
Self::EvmWalletFilter(_) => WebhookTemplateId::EvmWalletFilter,
Self::EvmContractEvents(_) => WebhookTemplateId::EvmContractEvents,
Self::EvmAbiFilter(_) => WebhookTemplateId::EvmAbiFilter,
Self::SolanaWalletFilter(_) => WebhookTemplateId::SolanaWalletFilter,
Self::BitcoinWalletFilter(_) => WebhookTemplateId::BitcoinWalletFilter,
Self::XrplWalletFilter(_) => WebhookTemplateId::XrplWalletFilter,
Self::HyperliquidWalletEventsFilter(_) => {
WebhookTemplateId::HyperliquidWalletEventsFilter
}
Self::StellarWalletTransactionsSourceAccountFilter(_) => {
WebhookTemplateId::StellarWalletTransactionsSourceAccountFilter
}
}
}
}
#[cfg_attr(feature = "python", gen_stub_pyclass)]
#[cfg_attr(feature = "python", pyclass(get_all, set_all))]
#[cfg_attr(feature = "node", napi(object))]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WebhookDestinationAttributes {
pub url: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub security_token: Option<String>,
pub compression: String,
}
#[cfg(feature = "python")]
#[gen_stub_pymethods]
#[pymethods]
impl WebhookDestinationAttributes {
#[new]
#[pyo3(signature = (url, compression, security_token=None))]
pub fn new(url: String, compression: String, security_token: Option<String>) -> Self {
Self {
url,
security_token,
compression,
}
}
}
#[cfg_attr(feature = "python", gen_stub_pyclass)]
#[cfg_attr(feature = "python", pyclass(get_all, set_all))]
#[cfg_attr(feature = "node", napi(object))]
#[cfg_attr(not(feature = "node"), derive(Clone))]
#[derive(Debug, Default, Serialize, Deserialize)]
pub struct GetWebhooksParams {
#[serde(skip_serializing_if = "Option::is_none")]
pub limit: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub offset: Option<i64>,
}
#[cfg(feature = "python")]
#[gen_stub_pymethods]
#[pymethods]
impl GetWebhooksParams {
#[new]
#[pyo3(signature = (limit=None, offset=None))]
pub fn new(limit: Option<i64>, offset: Option<i64>) -> Self {
Self { limit, offset }
}
}
#[cfg_attr(feature = "python", gen_stub_pyclass)]
#[cfg_attr(feature = "python", pyclass(get_all, set_all))]
#[cfg_attr(feature = "node", napi(object))]
#[cfg_attr(not(feature = "node"), derive(Clone))]
#[derive(Debug, Default, Serialize, Deserialize)]
pub struct UpdateWebhookParams {
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub notification_email: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub destination_attributes: Option<WebhookDestinationAttributes>,
}
#[cfg(feature = "python")]
#[gen_stub_pymethods]
#[pymethods]
impl UpdateWebhookParams {
#[new]
#[pyo3(signature = (name=None, notification_email=None, destination_attributes=None))]
pub fn new(
name: Option<String>,
notification_email: Option<String>,
destination_attributes: Option<WebhookDestinationAttributes>,
) -> Self {
Self {
name,
notification_email,
destination_attributes,
}
}
}
#[cfg_attr(feature = "node", napi(object))]
#[cfg_attr(not(feature = "node"), derive(Clone))]
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ActivateWebhookParams {
pub start_from: WebhookStartFrom,
}
#[cfg_attr(feature = "rust", derive(Builder))]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CreateWebhookFromTemplateParams {
pub name: String,
pub network: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub notification_email: Option<String>,
pub destination_attributes: WebhookDestinationAttributes,
#[serde(flatten)]
pub template_args: TemplateArgs,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UpdateWebhookTemplateParams {
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub notification_email: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub destination_attributes: Option<WebhookDestinationAttributes>,
#[serde(flatten)]
pub template_args: TemplateArgs,
}
#[cfg_attr(feature = "python", gen_stub_pyclass)]
#[cfg_attr(feature = "python", pyclass(get_all, set_all))]
#[cfg_attr(feature = "node", napi(object))]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Webhook {
pub id: String,
pub name: String,
pub status: String,
pub network: String,
pub created_at: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub updated_at: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub template_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub notification_email: Option<String>,
#[serde(
default,
skip_serializing_if = "Option::is_none",
deserialize_with = "deserialize_as_optional_json_string"
)]
pub destination_attributes: Option<String>,
}
#[cfg_attr(feature = "python", gen_stub_pyclass)]
#[cfg_attr(feature = "python", pyclass(get_all, set_all))]
#[cfg_attr(feature = "node", napi(object))]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WebhookPageInfo {
pub limit: i64,
pub offset: i64,
pub total: i64,
}
#[cfg_attr(feature = "python", gen_stub_pyclass)]
#[cfg_attr(feature = "python", pyclass(get_all, set_all))]
#[cfg_attr(feature = "node", napi(object))]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ListWebhooksResponse {
pub data: Vec<Webhook>,
#[serde(rename = "pageInfo")]
pub page_info: WebhookPageInfo,
}
#[cfg_attr(feature = "python", gen_stub_pyclass)]
#[cfg_attr(feature = "python", pyclass(get_all, set_all))]
#[cfg_attr(feature = "node", napi(object))]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WebhookEnabledCountResponse {
pub total: i64,
}
#[cfg(test)]
#[allow(clippy::unwrap_used)]
mod template_args_tests {
use super::*;
#[test]
fn evm_wallet_filter_roundtrip() {
let args =
TemplateArgs::EvmWalletFilter(EvmWalletFilterInput::Inline(EvmWalletFilterTemplate {
wallets: vec!["0xabc".to_string()],
}));
let json = serde_json::to_string(&args).unwrap();
assert!(json.contains(r#""templateId":"evmWalletFilter""#));
assert!(json.contains(r#""wallets":["0xabc"]"#));
let parsed: TemplateArgs = serde_json::from_str(&json).unwrap();
assert!(matches!(
parsed,
TemplateArgs::EvmWalletFilter(EvmWalletFilterInput::Inline(_))
));
assert!(matches!(parsed.tag(), WebhookTemplateId::EvmWalletFilter));
}
#[test]
fn evm_wallet_filter_by_list_roundtrip() {
let args = TemplateArgs::EvmWalletFilter(EvmWalletFilterInput::ByList(
EvmWalletFilterByListTemplate {
wallets_list_name: "my_list".to_string(),
},
));
let json = serde_json::to_string(&args).unwrap();
assert!(json.contains(r#""templateId":"evmWalletFilter""#));
assert!(json.contains(r#""walletsListName":"my_list""#));
assert!(!json.contains(r#""wallets":"#));
let parsed: TemplateArgs = serde_json::from_str(&json).unwrap();
assert!(matches!(
parsed,
TemplateArgs::EvmWalletFilter(EvmWalletFilterInput::ByList(_))
));
}
#[test]
fn evm_contract_events_roundtrip() {
let args = TemplateArgs::EvmContractEvents(EvmContractEventsInput::Inline(
EvmContractEventsTemplate {
contracts: vec!["0xdef".to_string()],
event_hashes: vec!["0x1234".to_string()],
},
));
let json = serde_json::to_string(&args).unwrap();
assert!(json.contains(r#""templateId":"evmContractEvents""#));
assert!(json.contains(r#""eventHashes":["0x1234"]"#));
assert!(!json.contains("event_hashes"));
let parsed: TemplateArgs = serde_json::from_str(&json).unwrap();
assert!(matches!(
parsed,
TemplateArgs::EvmContractEvents(EvmContractEventsInput::Inline(_))
));
}
#[test]
fn evm_contract_events_by_list_roundtrip() {
let args = TemplateArgs::EvmContractEvents(EvmContractEventsInput::ByList(
EvmContractEventsByListTemplate {
contracts_list_name: "my_contracts".to_string(),
event_hashes_list_name: None,
},
));
let json = serde_json::to_string(&args).unwrap();
assert!(json.contains(r#""contractsListName":"my_contracts""#));
assert!(!json.contains("eventHashesListName"));
let parsed: TemplateArgs = serde_json::from_str(&json).unwrap();
assert!(matches!(
parsed,
TemplateArgs::EvmContractEvents(EvmContractEventsInput::ByList(_))
));
}
#[test]
fn evm_abi_filter_roundtrip() {
let args = TemplateArgs::EvmAbiFilter(EvmAbiFilterInput::Inline(EvmAbiFilterTemplate {
abi: "[]".to_string(),
contracts: vec!["0xdef".to_string()],
}));
let json = serde_json::to_string(&args).unwrap();
assert!(json.contains(r#""templateId":"evmAbiFilter""#));
let parsed: TemplateArgs = serde_json::from_str(&json).unwrap();
assert!(matches!(parsed, TemplateArgs::EvmAbiFilter(_)));
}
#[test]
fn evm_abi_filter_by_list_roundtrip() {
let args =
TemplateArgs::EvmAbiFilter(EvmAbiFilterInput::ByList(EvmAbiFilterByListTemplate {
abi_json: "[]".to_string(),
contracts_list_name: Some("my_contracts".to_string()),
}));
let json = serde_json::to_string(&args).unwrap();
assert!(json.contains(r#""abiJson":"[]""#));
assert!(json.contains(r#""contractsListName":"my_contracts""#));
assert!(!json.contains(r#""abi":"#));
let parsed: TemplateArgs = serde_json::from_str(&json).unwrap();
assert!(matches!(
parsed,
TemplateArgs::EvmAbiFilter(EvmAbiFilterInput::ByList(_))
));
}
#[test]
fn solana_wallet_filter_roundtrip() {
let args = TemplateArgs::SolanaWalletFilter(SolanaWalletFilterInput::Inline(
SolanaWalletFilterTemplate {
accounts: vec!["acc".to_string()],
},
));
let json = serde_json::to_string(&args).unwrap();
assert!(json.contains(r#""templateId":"solanaWalletFilter""#));
let parsed: TemplateArgs = serde_json::from_str(&json).unwrap();
assert!(matches!(parsed, TemplateArgs::SolanaWalletFilter(_)));
}
#[test]
fn solana_wallet_filter_by_list_roundtrip() {
let args = TemplateArgs::SolanaWalletFilter(SolanaWalletFilterInput::ByList(
SolanaWalletFilterByListTemplate {
accounts_list_name: "my_accounts".to_string(),
},
));
let json = serde_json::to_string(&args).unwrap();
assert!(json.contains(r#""accountsListName":"my_accounts""#));
assert!(!json.contains(r#""accounts":"#));
}
#[test]
fn bitcoin_wallet_filter_roundtrip() {
let args = TemplateArgs::BitcoinWalletFilter(BitcoinWalletFilterInput::Inline(
BitcoinWalletFilterTemplate {
wallets: vec!["bc1".to_string()],
},
));
let json = serde_json::to_string(&args).unwrap();
assert!(json.contains(r#""templateId":"bitcoinWalletFilter""#));
let parsed: TemplateArgs = serde_json::from_str(&json).unwrap();
assert!(matches!(parsed, TemplateArgs::BitcoinWalletFilter(_)));
}
#[test]
fn bitcoin_wallet_filter_by_list_roundtrip() {
let args = TemplateArgs::BitcoinWalletFilter(BitcoinWalletFilterInput::ByList(
BitcoinWalletFilterByListTemplate {
wallets_list_name: "my_btc_list".to_string(),
},
));
let json = serde_json::to_string(&args).unwrap();
assert!(json.contains(r#""walletsListName":"my_btc_list""#));
}
#[test]
fn xrpl_wallet_filter_roundtrip() {
let args = TemplateArgs::XrplWalletFilter(XrplWalletFilterInput::Inline(
XrplWalletFilterTemplate {
wallets: vec!["r1".to_string()],
},
));
let json = serde_json::to_string(&args).unwrap();
assert!(json.contains(r#""templateId":"xrplWalletFilter""#));
let parsed: TemplateArgs = serde_json::from_str(&json).unwrap();
assert!(matches!(parsed, TemplateArgs::XrplWalletFilter(_)));
}
#[test]
fn xrpl_wallet_filter_by_list_roundtrip() {
let args = TemplateArgs::XrplWalletFilter(XrplWalletFilterInput::ByList(
XrplWalletFilterByListTemplate {
wallets_list_name: "my_xrpl_list".to_string(),
},
));
let json = serde_json::to_string(&args).unwrap();
assert!(json.contains(r#""walletsListName":"my_xrpl_list""#));
}
#[test]
fn hyperliquid_wallet_events_filter_roundtrip() {
let args = TemplateArgs::HyperliquidWalletEventsFilter(
HyperliquidWalletEventsFilterInput::Inline(HyperliquidWalletEventsFilterTemplate {
wallets: vec!["0xhl".to_string()],
}),
);
let json = serde_json::to_string(&args).unwrap();
assert!(json.contains(r#""templateId":"hyperliquidWalletEventsFilter""#));
let parsed: TemplateArgs = serde_json::from_str(&json).unwrap();
assert!(matches!(
parsed,
TemplateArgs::HyperliquidWalletEventsFilter(_)
));
}
#[test]
fn hyperliquid_wallet_events_filter_by_list_roundtrip() {
let args = TemplateArgs::HyperliquidWalletEventsFilter(
HyperliquidWalletEventsFilterInput::ByList(
HyperliquidWalletEventsFilterByListTemplate {
wallets_list_name: "my_hl_list".to_string(),
},
),
);
let json = serde_json::to_string(&args).unwrap();
assert!(json.contains(r#""walletsListName":"my_hl_list""#));
}
#[test]
fn stellar_wallet_transactions_filter_roundtrip() {
let args = TemplateArgs::StellarWalletTransactionsSourceAccountFilter(
StellarWalletTransactionsFilterInput::Inline(StellarWalletTransactionsFilterTemplate {
wallets: vec!["G...".to_string()],
}),
);
let json = serde_json::to_string(&args).unwrap();
assert!(json.contains(r#""templateId":"stellarWalletTransactionsSourceAccountFilter""#));
let parsed: TemplateArgs = serde_json::from_str(&json).unwrap();
assert!(matches!(
parsed,
TemplateArgs::StellarWalletTransactionsSourceAccountFilter(_)
));
}
#[test]
fn stellar_wallet_transactions_filter_by_list_roundtrip() {
let args = TemplateArgs::StellarWalletTransactionsSourceAccountFilter(
StellarWalletTransactionsFilterInput::ByList(
StellarWalletTransactionsFilterByListTemplate {
wallets_list_name: "my_stellar_list".to_string(),
},
),
);
let json = serde_json::to_string(&args).unwrap();
assert!(json.contains(r#""walletsListName":"my_stellar_list""#));
}
#[test]
fn create_params_flattens_template_args() {
let params = CreateWebhookFromTemplateParams {
name: "n".to_string(),
network: "ethereum-mainnet".to_string(),
notification_email: None,
destination_attributes: WebhookDestinationAttributes {
url: "https://x".to_string(),
security_token: None,
compression: "none".to_string(),
},
template_args: TemplateArgs::EvmWalletFilter(EvmWalletFilterInput::Inline(
EvmWalletFilterTemplate {
wallets: vec!["0xabc".to_string()],
},
)),
};
let json = serde_json::to_value(¶ms).unwrap();
let obj = json.as_object().unwrap();
assert_eq!(
obj.get("templateId").and_then(|v| v.as_str()),
Some("evmWalletFilter")
);
assert!(obj.get("templateArgs").unwrap().is_object());
assert_eq!(obj["templateArgs"]["wallets"][0].as_str(), Some("0xabc"));
}
}