Vizium State Monitor API
State Monitor (SM) API Documentation and guide
Introduction
The SM API primarily provides the current on-chain state of an arbitrary smart contract and efficient updates when the smart contract state is updated or changed. Further, the SM also supports complex modeling and analysis that require large amounts of on-chain data calls or data access and as such are not trivial experiments or research to conduct (e.g. trying to monitor a UniswapV3 Order Book in realtime or deep historical analysis).
The SM also provides a standard way to ingest information about common groups of smart contracts, such as dexes or liquidity pools.
Additionally, the SM uses many of the same core infrastructure pieces as the Realtime Chain Monitor (RTCM) with very similar messaging patterns and server/API behavior. Please take a look at the RTCM page for more information and examples.
API Definitions
Client
Enums
Network (Enum)
+-------+----------------------------------+
| Val | Def |
|-------+----------------------------------|
| eth | ethereum, chainId=1 |
| arb | arbitrum, chainId=42161 |
| opt | optimism, chainId=10 |
| bsc | binanceSC, chainId=56 |
| rop | ropsten, chainId=3 |
| ply | polygon, chainId=137 |
| gno | gnosis, chainId=100 |
| arbn | arbitrum_nova, chainId=42170 |
| sep | sepolia, chainId=11155111 |
| bp0 | BP_ARB_TESTNET, chainId=601574 |
| ava | avalanche_c_chain, chainId=43114 |
+-------+----------------------------------+
Messages
Position
+---------+------------+------------+
| field | type | required |
|---------+------------+------------|
| nwk | Network | True |
| posAddr | string | True |
| addr | hex string | False |
| vzLabel | string | False |
| opts | dict | False |
+---------+------------+------------+
Additional Constraints:
both `addr` or `vzLabel` cannot be defined`
either `addr` or `vzLabel` required`
ServerGet
Get service data based on key
+---------+--------+------------+
| field | type | required |
|---------+--------+------------|
| dKey | string | True |
+---------+--------+------------+
State
+---------+------------+------------+
| field | type | required |
|---------+------------+------------|
| nwk | Network | True |
| addr | hex string | False |
| vzLabel | string | False |
| opts | dict | False |
+---------+------------+------------+
Additional Constraints:
both `addr` or `vzLabel` cannot be defined`
either `addr` or `vzLabel` required`
Sub
New Subscription Request
+---------+-------------------+------------+
| field | type | required |
|---------+-------------------+------------|
| clSubId | integer | True |
| data | [Position, State] | True |
+---------+-------------------+------------+
USub
Unsubscribe from a specific subscription id
+---------+--------+------------+
| field | type | required |
|---------+--------+------------|
| subId | string | True |
+---------+--------+------------+
Server
Enums
ErrorCodes (Enum)
+----+---------------------------+
| -1 | "UNKNOWN" |
| 0 | "SERVER_NOT_READY" |
| 1 | "INTERNAL_SERVER_ERROR" |
| 2 | "INVALID_MSG_SPEC" |
| 3 | "INVALID_SUB_REQ" |
| 4 | "DUPLICATE_SUB" |
| 5 | "UNKNOWN_CLIENT_SUB" |
| 6 | "INVALID_AUTH" |
| 7 | "INVALID_SERVER_DATA_KEY" |
+----+---------------------------+
Network (Enum)
+-------+----------------------------------+
| Val | Def |
|-------+----------------------------------|
| eth | ethereum, chainId=1 |
| arb | arbitrum, chainId=42161 |
| opt | optimism, chainId=10 |
| bsc | binanceSC, chainId=56 |
| rop | ropsten, chainId=3 |
| ply | polygon, chainId=137 |
| gno | gnosis, chainId=100 |
| arbn | arbitrum_nova, chainId=42170 |
| sep | sepolia, chainId=11155111 |
| bp0 | BP_ARB_TESTNET, chainId=601574 |
| ava | avalanche_c_chain, chainId=43114 |
+-------+----------------------------------+
ShutdownCodes (Enum)
+----+---------------+
| -1 | "UNKNOWN" |
| 0 | "UNSCHEDULED" |
| 1 | "RESTARTING" |
| 2 | "SCHEDULED" |
+----+---------------+
Messages
Authenticated
Server response indicating connection has authenticated successfully as user
+---------+--------+------------+
| field | type | required |
|---------+--------+------------|
| user | string | True |
| exp | string | True |
+---------+--------+------------+
Error
Server response indicating some sort of error state
+---------+------------+------------+
| field | type | required |
|---------+------------+------------|
| code | ErrorCodes | True |
| rMsg | dict | True |
| eMsg | string | True |
+---------+------------+------------+
Init
Initial server response providing server's internal client id
+-----------+--------+------------+
| field | type | required |
|-----------+--------+------------|
| cid | string | True |
| deployVer | string | True |
| msgDefVer | string | True |
+-----------+--------+------------+
Notify
Notify message for a given subscription id, provided in the Subscription confirmation message and actual subscription event data
+--------------+--------------+------------+
| field | type | required |
|--------------+--------------+------------|
| subId | string | True |
| ts | datetime | True |
| bn | integer | True |
| nwk | Network | True |
| txHash | hex string | True |
| data | [list, dict] | True |
| nInfo | dict | False |
| extraCntInfo | dict | False |
+--------------+--------------+------------+
ServerData
Respond to a service data get message with requested data
+---------+--------+------------+
| field | type | required |
|---------+--------+------------|
| dKey | string | True |
| data | list | True |
+---------+--------+------------+
ShutdownNotice
Alert message indicating the server will be disconnecting
+---------+---------------+------------+
| field | type | required |
|---------+---------------+------------|
| ts | d | True |
| reason | ShutdownCodes | True |
| sMsg | string | True |
+---------+---------------+------------+
SubConfirm
Subscription confirmation with unique subscription id which maps to Subscription Notify messages as well as the confirmed subscription settings
+---------+---------+------------+
| field | type | required |
|---------+---------+------------|
| subId | string | True |
| clSubId | integer | True |
| data | list | True |
| info | dict | False |
+---------+---------+------------+
SubInitState
Special notify message for a given subscription id containing initial state of the subscription
+--------------+--------------+------------+
| field | type | required |
|--------------+--------------+------------|
| subId | string | True |
| ts | string | True |
| bn | integer | True |
| nwk | Network | True |
| txHash | string | True |
| data | [list, dict] | True |
| extraCntInfo | dict | False |
+--------------+--------------+------------+
SubPendingState
Special notify message for a given subscription id is still itializing
+---------+--------+------------+
| field | type | required |
|---------+--------+------------|
| subId | string | True |
+---------+--------+------------+
USubConfirm
Unsubscribe confirmation message for supplied subscription id and subscription settings
+---------+--------+------------+
| field | type | required |
|---------+--------+------------|
| subId | string | True |
| data | list | True |
+---------+--------+------------+
Setting up Access
The SM instance is deployed at 162.243.162.191 on port 4322. It requires both SSL and Vizium credentials (please ask Stephen to generate new credentials).
Interacting with the Server
On client connection, the server sends an initial message informing the client of its client id (cid) as well as some other helpful metadata about the current server and messaging langauge deployment:
{
"type": "init",
"cid": "f1563914-2c61-11ef-8e7c-f634f1e942cc",
"deployVer": "e0fed2271e7",
"msgDefVer": "edb1b03d20f"
}
Very similar to the RTCM, The client can request a list of supported contracts: {'type': 'serverget', 'dKey': 'supportedContracts'}
The server provides a list of defined contracts and supported notification types, where a unique definition is Vizium label, network, and address combination ([VZ_LABEL, network, address]):
{
"type": "serverdata",
"dKey": "supportedContracts",
"data": [
{
"vzLabel": "RadiantPoolV1",
"nwk": "bp0",
"addr": "0x2032b9A8e9F7e76768CA9271003d3e43E1616B1F",
"supportedNotifications": [
"state",
"position"
]
},
{
"vzLabel": "RadiantPoolV1",
"nwk": "arb",
"addr": "0x2032b9A8e9F7e76768CA9271003d3e43E1616B1F",
"supportedNotifications": [
"state",
"position"
]
},
{
"vzLabel": "RadiantPoolV2",
"nwk": "bp0",
"addr": "0xF4B1486DD74D07706052A33d31d7c0AAFD0659E1",
"supportedNotifications": [
"state",
"position"
]
},
{
"vzLabel": "RadiantPoolV2",
"nwk": "eth",
"addr": "0xA950974f64aA33f27F6C5e017eEE93BF7588ED07",
"supportedNotifications": [
"state",
"position"
]
},
{
"vzLabel": "RadiantPoolV2",
"nwk": "arb",
"addr": "0xF4B1486DD74D07706052A33d31d7c0AAFD0659E1",
"supportedNotifications": [
"state",
"position"
]
},
{
"vzLabel": "AavePoolV3",
"nwk": "bp0",
"addr": "0x794a61358D6845594F94dc1DB02A252b5b4814aD",
"supportedNotifications": [
"state",
"position"
]
},
{
"vzLabel": "AavePoolV3",
"nwk": "sep",
"addr": "0x6Ae43d3271ff6888e7Fc43Fd7321a503ff738951",
"supportedNotifications": [
"state",
"position"
]
},
{
"vzLabel": "AavePoolV3",
"nwk": "arb",
"addr": "0x794a61358D6845594F94dc1DB02A252b5b4814aD",
"supportedNotifications": [
"state",
"position"
]
},
{
"vzLabel": "AavePoolV3",
"nwk": "eth",
"addr": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
"supportedNotifications": [
"state",
"position"
]
},
{
"vzLabel": "CompoundPoolV3-USDC",
"nwk": "bp0",
"addr": "0x9c4ec768c28520B50860ea7a15bd7213a9fF58bf",
"supportedNotifications": [
"state",
"position"
]
},
{
"vzLabel": "CompoundPoolV3-USDC",
"nwk": "eth",
"addr": "0xc3d688B66703497DAA19211EEdff47f25384cdc3",
"supportedNotifications": [
"state",
"position"
]
},
{
"vzLabel": "CompoundPoolV3-USDC",
"nwk": "arb",
"addr": "0x9c4ec768c28520B50860ea7a15bd7213a9fF58bf",
"supportedNotifications": [
"state",
"position"
]
},
{
"vzLabel": "CompoundPoolV3-USDC.e",
"nwk": "bp0",
"addr": "0xA5EDBDD9646f8dFF606d7448e414884C7d905dCA",
"supportedNotifications": [
"state",
"position"
]
},
{
"vzLabel": "CompoundPoolV3-USDC.e",
"nwk": "arb",
"addr": "0xA5EDBDD9646f8dFF606d7448e414884C7d905dCA",
"supportedNotifications": [
"state",
"position"
]
},
{
"vzLabel": "CompoundPoolV3-WETH",
"nwk": "eth",
"addr": "0xA17581A9E3356d9A858b789D68B4d866e593aE94",
"supportedNotifications": [
"state",
"position"
]
},
{
"vzLabel": "SiloPool",
"nwk": "eth",
"addr": "0xd998C35B7900b344bbBe6555cc11576942Cf309d",
"supportedNotifications": [
"state",
"position"
]
},
{
"vzLabel": "SiloPool",
"nwk": "arb",
"addr": "0x8658047e48CC09161f4152c79155Dac1d710Ff0a",
"supportedNotifications": [
"state",
"position"
]
},
{
"vzLabel": "SiloPool",
"nwk": "bp0",
"addr": "0x8658047e48CC09161f4152c79155Dac1d710Ff0a",
"supportedNotifications": [
"state",
"position"
]
}
]
}
The state notification refers to monitoring of a contract for state changes, like liquidations or deposits/borrows, while the position notification is to use to track and monitor behavior on a contract for a specific address. This could be an LP position on a dex or a borrowed position on a lending protocol.
The client can subscribe to a notification on a given contract by providing the defined vz label or the address directly.
{
"type": "sub",
"clSubId": 0,
"data": {
"sType": "state",
"nwk": "arb",
"vzLabel": "AavePoolV3"
}
}
The server will confirm a successful subscription by sending a confirm message:
{
"type": "subconfirm",
"subId": "89ab1013-2c63-11ef-8e7c-f634f1e942cc",
"clSubId": 0,
"sType": "State",
"data": [
"arb",
"AavePoolV3"
],
"info": {
"vzLabel": "AavePoolV3"
}
}
This subscription and notification methodology is identical to the RTCM structure. For more information about this messaging structure, check out the RTCM API guide.
However, one important distinction is that the SM is multi-chain within one instance as opposed to the RTCM which has a separate deployment per chain.
Lending Pools Data Format
The SM API tries to standardize data delivery for Lending Pools such that the end user can expect to receive the same highly templated information regardless of the underlying smart contract implementation. The following is an example of the initial confirmation response for AavePoolV3:
{
"type": "subinitstate",
"subId": "89ab1013-2c63-11ef-8e7c-f634f1e942cc",
"sType": "State",
"ts": "2024-06-17T04:38:38.546195",
"bn": 222690261,
"vzLabel": "AavePoolV3",
"nwk": "arb",
"data": {
"pools": [
{
"assetsInfo": {
"AAVE": {
"supplyYield": 0.0,
"vBorrowRate": 0.0,
"sBorrowRate": 0.09000000000000001,
"maxLTV": 0.5,
"liqTh": 0.65,
"liqB": 0.1,
"supplyEnabled": true,
"borrowedEnabled": true,
"incentives": {}
},
"ARB": {
"supplyYield": 0.006687801939058784,
"vBorrowRate": 0.03606114158751444,
"sBorrowRate": 0.11606114158751445,
"maxLTV": 0.58,
"liqTh": 0.63,
"liqB": 0.1,
"supplyEnabled": true,
"borrowedEnabled": true,
"incentives": {}
},
"DAI": {
"supplyYield": 0.06497189588922261,
"vBorrowRate": 0.09843789285863301,
"sBorrowRate": 0.11343789285863301,
"maxLTV": 0.63,
"liqTh": 0.77,
"liqB": 0.05,
"supplyEnabled": true,
"borrowedEnabled": true,
"incentives": {}
},
"EURS": {
"supplyYield": 0.04896119009293672,
"vBorrowRate": 0.08468836886690109,
"sBorrowRate": 0.10470490938149452,
"maxLTV": 0.0,
"liqTh": 0.67,
"liqB": 0.075,
"supplyEnabled": true,
"borrowedEnabled": true,
"incentives": {}
},
"FRAX": {
"supplyYield": 0.10099985815077932,
"vBorrowRate": 0.13926125712139992,
"sBorrowRate": 0.15426125712139993,
"maxLTV": 0.0,
"liqTh": 0.72,
"liqB": 0.06,
"supplyEnabled": true,
"borrowedEnabled": true,
"incentives": {}
},
"LINK": {
"supplyYield": 6.03907166863197e-05,
"vBorrowRate": 0.003426753471680342,
"sBorrowRate": 0.09000000000000001,
"maxLTV": 0.7,
"liqTh": 0.775,
"liqB": 0.1,
"supplyEnabled": true,
"borrowedEnabled": true,
"incentives": {}
},
"LUSD": {
"supplyYield": 0.05595821957213496,
"vBorrowRate": 0.08870808659491804,
"sBorrowRate": 0.13942581626440803,
"maxLTV": 0.0,
"liqTh": 0.0,
"liqB": 0,
"supplyEnabled": true,
"borrowedEnabled": true,
"incentives": {}
},
"MAI": {
"supplyYield": 6.753178077826602e-05,
"vBorrowRate": 0.01643554450309037,
"sBorrowRate": 0.10730468644581795,
"maxLTV": 0.0,
"liqTh": 0.01,
"liqB": 0.05,
"supplyEnabled": true,
"borrowedEnabled": true,
"incentives": {}
},
"USDC": {
"supplyYield": 0.07107260029342513,
"vBorrowRate": 0.088864816368225,
"sBorrowRate": 0.14936934242679167,
"maxLTV": 0.75,
"liqTh": 0.78,
"liqB": 0.05,
"supplyEnabled": true,
"borrowedEnabled": true,
"incentives": {
"supply": [
{
"apy": 0.006024346254890677,
"asset": "ARB",
"assetAddr": "0x912ce59144191c1204e64559fe8253a0e49e6548"
}
]
}
},
"USDC.e": {
"supplyYield": 0.04926669763678241,
"vBorrowRate": 0.09279780895685362,
"sBorrowRate": 0.1398535372851494,
"maxLTV": 0.75,
"liqTh": 0.78,
"liqB": 0.05,
"supplyEnabled": true,
"borrowedEnabled": true,
"incentives": {}
},
"USDT": {
"supplyYield": 0.06715765509607705,
"vBorrowRate": 0.08691504476932128,
"sBorrowRate": 0.10482861359829562,
"maxLTV": 0.75,
"liqTh": 0.78,
"liqB": 0.05,
"supplyEnabled": true,
"borrowedEnabled": true,
"incentives": {}
},
"WBTC": {
"supplyYield": 0.00018851858872117903,
"vBorrowRate": 0.004576735720784934,
"sBorrowRate": 0.06,
"maxLTV": 0.73,
"liqTh": 0.78,
"liqB": 0.07,
"supplyEnabled": true,
"borrowedEnabled": true,
"incentives": {}
},
"WETH": {
"supplyYield": 0.02044190295063068,
"vBorrowRate": 0.028313305228565407,
"sBorrowRate": 0.0977510736380872,
"maxLTV": 0.825,
"liqTh": 0.85,
"liqB": 0.05,
"supplyEnabled": true,
"borrowedEnabled": true,
"incentives": {}
},
"rETH": {
"supplyYield": 0.0002674534033826067,
"vBorrowRate": 0.006996121845742614,
"sBorrowRate": 0.112992797713522,
"maxLTV": 0.67,
"liqTh": 0.74,
"liqB": 0.075,
"supplyEnabled": true,
"borrowedEnabled": true,
"incentives": {}
},
"weETH": {
"supplyYield": 0.003927030796549692,
"vBorrowRate": 0.03778903543020572,
"sBorrowRate": 0.12778903543020573,
"maxLTV": 0.725,
"liqTh": 0.75,
"liqB": 0.075,
"supplyEnabled": true,
"borrowedEnabled": true,
"incentives": {}
},
"wstETH": {
"supplyYield": 0.0004912164575015056,
"vBorrowRate": 0.008954068501172958,
"sBorrowRate": 0.055,
"maxLTV": 0.7,
"liqTh": 0.79,
"liqB": 0.072,
"supplyEnabled": true,
"borrowedEnabled": true,
"incentives": {}
}
},
"poolAddr": "0x794a61358D6845594F94dc1DB02A252b5b4814aD",
"poolLabel": "AavePoolV3"
}
],
"prices": {
"AAVE": "84.00",
"ARB": "0.95067948791353928670",
"DAI": "0.9999",
"FRAX": "0.99389737237141616796",
"LINK": "798494.990174058767196",
"LUSD": "0.999209477328542",
"USDC": "1",
"USDC.e": "1",
"USDT": "0.99938",
"WBTC": "67879.0429783349967456",
"WETH": "3520.2",
"rETH": "3901.30459831461069792",
"weETH": "3659.07617953852193250",
"wstETH": "4116.6051626310575472"
}
},
"extraCntInfo": null
}
In this model, a "pool" is defined to be a series of borrowing and lending markets which may or may not have their own individual characteristics but all share risk together in that, if one of the markets suffered from bad debt, the other markets within the pool are not guaranteed to be safe. In AavePoolV3's case, they functionally only have one pool (per network/deployment!). On the other side, Silo Finance has numerous indepedent "pools" that are each isolated from one another in terms of bad debt:
{
"type": "subinitstate",
"subId": "b3ea2b5f-2c65-11ef-8e7c-f634f1e942cc",
"sType": "State",
"ts": "2024-06-17T03:21:08.474843",
"bn": 222671662,
"vzLabel": "SiloPool",
"nwk": "arb",
"data": {
"pools": [
{
"assetsInfo": {
"WBTC": {
"supplyYield": 0.000672653798847281,
"vBorrowRate": 0.005022391161744,
"maxLTV": 0.8,
"liqTh": 0.85,
"liqB": 0.15
},
"WETH": {
"supplyYield": 0.028700750464035887,
"vBorrowRate": 0.036222009264144,
"maxLTV": 0.8,
"liqTh": 0.9,
"liqB": 0.1
},
"USDC.e": {
"supplyYield": 0.09801839098859123,
"vBorrowRate": 0.130968911625984,
"maxLTV": 0.8,
"liqTh": 0.9,
"liqB": 0.1
}
},
"poolAddr": "0x69eC552BE56E6505703f0C861c40039e5702037A",
"poolLabel": "Silo-WBTC/WETH/USDC.e",
"supplyEnabled": true,
"borrowedEnabled": true
},
{
"assetsInfo": {
"ARB": {
"supplyYield": 6.9304468486952e-05,
"vBorrowRate": 0.002385972889344,
"maxLTV": 0.7,
"liqTh": 0.8,
"liqB": 0.2
},
"WETH": {
"supplyYield": 0.024784559050267493,
"vBorrowRate": 0.033660184984704,
"maxLTV": 0.75,
"liqTh": 0.85,
"liqB": 0.15
},
"USDC.e": {
"supplyYield": 0.10296711054779904,
"vBorrowRate": 0.134235432518112,
"maxLTV": 0.8,
"liqTh": 0.9,
"liqB": 0.1
}
},
"poolAddr": "0x0696E6808EE11a5750733a3d821F9bB847E584FB",
"poolLabel": "Silo-ARB/WETH/USDC.e",
"supplyEnabled": true,
"borrowedEnabled": true
},
{
"assetsInfo": {
"rETH": {
"supplyYield": 1.802295468315e-05,
"vBorrowRate": 0.001216736269344,
"maxLTV": 0.7,
"liqTh": 0.8,
"liqB": 0.2
},
"WETH": {
"supplyYield": 0.007635636146550249,
"vBorrowRate": 0.018683074058112,
"maxLTV": 0.75,
"liqTh": 0.85,
"liqB": 0.15
},
"USDC.e": {
"supplyYield": 0.07811127603999544,
"vBorrowRate": 0.116916462678096,
"maxLTV": 0.8,
"liqTh": 0.9,
"liqB": 0.1
}
},
"poolAddr": "0x170A90981843461295a6CE0e0a631eE440222E29",
"poolLabel": "Silo-rETH/WETH/USDC.e",
"supplyEnabled": true,
"borrowedEnabled": true
},
{
"assetsInfo": {
"wstETH": {
"supplyYield": 0.001623426153932774,
"vBorrowRate": 0.011547802873872,
"maxLTV": 0.8,
"liqTh": 0.9,
"liqB": 0.1
},
"WETH": {
"supplyYield": 0.011641525058562458,
"vBorrowRate": 0.023069112196464,
"maxLTV": 0.85,
"liqTh": 0.9,
"liqB": 0.1
},
"USDC.e": {
"supplyYield": 0.07367861225021179,
"vBorrowRate": 0.113550674215824,
"maxLTV": 0.8,
"liqTh": 0.9,
"liqB": 0.1
}
},
"poolAddr": "0xA8897b4552c075e884BDB8e7b704eB10DB29BF0D",
"poolLabel": "Silo-wstETH/WETH/USDC.e",
"supplyEnabled": true,
"borrowedEnabled": true
},
{
"assetsInfo": {
"weETH": {
"supplyYield": 0.026331980954251755,
"vBorrowRate": 0.07649526197592,
"maxLTV": 0.75,
"liqTh": 0.85,
"liqB": 0.15
},
"WETH": {
"supplyYield": 0.07854891292113673,
"vBorrowRate": 0.132118341651216,
"maxLTV": 0.75,
"liqTh": 0.85,
"liqB": 0.15
},
"USDC.e": {
"supplyYield": 0.09908953100335095,
"vBorrowRate": 0.115984413233712,
"maxLTV": 0.4,
"liqTh": 0.85,
"liqB": 0.15
}
},
"poolAddr": "0x7bec832FF8060cD396645Ccd51E9E9B0E5d8c6e4",
"poolLabel": "Silo-weETH/WETH/USDC.e",
"supplyEnabled": true,
"borrowedEnabled": true
},
{
"assetsInfo": {
"WBTC": {
"supplyYield": 0.000672653798847281,
"vBorrowRate": 0.005022391161744,
"maxLTV": 0.8,
"liqTh": 0.85,
"liqB": 0.15
},
"WETH": {
"supplyYield": 0.028700750464035887,
"vBorrowRate": 0.036222009264144,
"maxLTV": 0.8,
"liqTh": 0.9,
"liqB": 0.1
},
"USDC.e": {
"supplyYield": 0.09801839098859123,
"vBorrowRate": 0.130968911625984,
"maxLTV": 0.8,
"liqTh": 0.9,
"liqB": 0.1
}
},
"poolAddr": "0x69eC552BE56E6505703f0C861c40039e5702037A",
"poolLabel": "Silo-WBTC/WETH/USDC.e",
"supplyEnabled": true,
"borrowedEnabled": true
},
{
"assetsInfo": {
"ARB": {
"supplyYield": 6.9304468486952e-05,
"vBorrowRate": 0.002385972889344,
"maxLTV": 0.7,
"liqTh": 0.8,
"liqB": 0.2
},
"WETH": {
"supplyYield": 0.024784559050267493,
"vBorrowRate": 0.033660184984704,
"maxLTV": 0.75,
"liqTh": 0.85,
"liqB": 0.15
},
"USDC.e": {
"supplyYield": 0.10296711054779904,
"vBorrowRate": 0.134235432518112,
"maxLTV": 0.8,
"liqTh": 0.9,
"liqB": 0.1
}
},
"poolAddr": "0x0696E6808EE11a5750733a3d821F9bB847E584FB",
"poolLabel": "Silo-ARB/WETH/USDC.e",
"supplyEnabled": true,
"borrowedEnabled": true
},
{
"assetsInfo": {
"rETH": {
"supplyYield": 1.802295468315e-05,
"vBorrowRate": 0.001216736269344,
"maxLTV": 0.7,
"liqTh": 0.8,
"liqB": 0.2
},
"WETH": {
"supplyYield": 0.007635636146550249,
"vBorrowRate": 0.018683074058112,
"maxLTV": 0.75,
"liqTh": 0.85,
"liqB": 0.15
},
"USDC.e": {
"supplyYield": 0.07811127603999544,
"vBorrowRate": 0.116916462678096,
"maxLTV": 0.8,
"liqTh": 0.9,
"liqB": 0.1
}
},
"poolAddr": "0x170A90981843461295a6CE0e0a631eE440222E29",
"poolLabel": "Silo-rETH/WETH/USDC.e",
"supplyEnabled": true,
"borrowedEnabled": true
},
{
"assetsInfo": {
"wstETH": {
"supplyYield": 0.001623426153932774,
"vBorrowRate": 0.011547802873872,
"maxLTV": 0.8,
"liqTh": 0.9,
"liqB": 0.1
},
"WETH": {
"supplyYield": 0.011641525058562458,
"vBorrowRate": 0.023069112196464,
"maxLTV": 0.85,
"liqTh": 0.9,
"liqB": 0.1
},
"USDC.e": {
"supplyYield": 0.07367861225021179,
"vBorrowRate": 0.113550674215824,
"maxLTV": 0.8,
"liqTh": 0.9,
"liqB": 0.1
}
},
"poolAddr": "0xA8897b4552c075e884BDB8e7b704eB10DB29BF0D",
"poolLabel": "Silo-wstETH/WETH/USDC.e",
"supplyEnabled": true,
"borrowedEnabled": true
},
{
"assetsInfo": {
"weETH": {
"supplyYield": 0.026331980954251755,
"vBorrowRate": 0.07649526197592,
"maxLTV": 0.75,
"liqTh": 0.85,
"liqB": 0.15
},
"WETH": {
"supplyYield": 0.07854891292113673,
"vBorrowRate": 0.132118341651216,
"maxLTV": 0.75,
"liqTh": 0.85,
"liqB": 0.15
},
"USDC.e": {
"supplyYield": 0.09908953100335095,
"vBorrowRate": 0.115984413233712,
"maxLTV": 0.4,
"liqTh": 0.85,
"liqB": 0.15
}
},
"poolAddr": "0x7bec832FF8060cD396645Ccd51E9E9B0E5d8c6e4",
"poolLabel": "Silo-weETH/WETH/USDC.e",
"supplyEnabled": true,
"borrowedEnabled": true
},
{
"assetsInfo": {
"WBTC": {
"supplyYield": 0.000672653798847281,
"vBorrowRate": 0.005022391161744,
"maxLTV": 0.8,
"liqTh": 0.85,
"liqB": 0.15
},
"WETH": {
"supplyYield": 0.028700750464035887,
"vBorrowRate": 0.036222009264144,
"maxLTV": 0.8,
"liqTh": 0.9,
"liqB": 0.1
},
"USDC.e": {
"supplyYield": 0.09801839098859123,
"vBorrowRate": 0.130968911625984,
"maxLTV": 0.8,
"liqTh": 0.9,
"liqB": 0.1
}
},
"poolAddr": "0x69eC552BE56E6505703f0C861c40039e5702037A",
"poolLabel": "Silo-WBTC/WETH/USDC.e",
"supplyEnabled": true,
"borrowedEnabled": true
},
{
"assetsInfo": {
"ARB": {
"supplyYield": 6.9304468486952e-05,
"vBorrowRate": 0.002385972889344,
"maxLTV": 0.7,
"liqTh": 0.8,
"liqB": 0.2
},
"WETH": {
"supplyYield": 0.024784559050267493,
"vBorrowRate": 0.033660184984704,
"maxLTV": 0.75,
"liqTh": 0.85,
"liqB": 0.15
},
"USDC.e": {
"supplyYield": 0.10296711054779904,
"vBorrowRate": 0.134235432518112,
"maxLTV": 0.8,
"liqTh": 0.9,
"liqB": 0.1
}
},
"poolAddr": "0x0696E6808EE11a5750733a3d821F9bB847E584FB",
"poolLabel": "Silo-ARB/WETH/USDC.e",
"supplyEnabled": true,
"borrowedEnabled": true
},
{
"assetsInfo": {
"rETH": {
"supplyYield": 1.802295468315e-05,
"vBorrowRate": 0.001216736269344,
"maxLTV": 0.7,
"liqTh": 0.8,
"liqB": 0.2
},
"WETH": {
"supplyYield": 0.007635636146550249,
"vBorrowRate": 0.018683074058112,
"maxLTV": 0.75,
"liqTh": 0.85,
"liqB": 0.15
},
"USDC.e": {
"supplyYield": 0.07811127603999544,
"vBorrowRate": 0.116916462678096,
"maxLTV": 0.8,
"liqTh": 0.9,
"liqB": 0.1
}
},
"poolAddr": "0x170A90981843461295a6CE0e0a631eE440222E29",
"poolLabel": "Silo-rETH/WETH/USDC.e",
"supplyEnabled": true,
"borrowedEnabled": true
},
{
"assetsInfo": {
"wstETH": {
"supplyYield": 0.001623426153932774,
"vBorrowRate": 0.011547802873872,
"maxLTV": 0.8,
"liqTh": 0.9,
"liqB": 0.1
},
"WETH": {
"supplyYield": 0.011641525058562458,
"vBorrowRate": 0.023069112196464,
"maxLTV": 0.85,
"liqTh": 0.9,
"liqB": 0.1
},
"USDC.e": {
"supplyYield": 0.07367861225021179,
"vBorrowRate": 0.113550674215824,
"maxLTV": 0.8,
"liqTh": 0.9,
"liqB": 0.1
}
},
"poolAddr": "0xA8897b4552c075e884BDB8e7b704eB10DB29BF0D",
"poolLabel": "Silo-wstETH/WETH/USDC.e",
"supplyEnabled": true,
"borrowedEnabled": true
}
],
"prices": {
"ARB": "0.95067948791353928670",
"USDC.e": "1",
"WBTC": "67879.0429783349967456",
"WETH": "3520.2",
"rETH": "3901.30459831461069792",
"weETH": "3659.07617953852193250",
"wstETH": "4116.6051626310575472"
}
},
"extraCntInfo": null
}
The SM also includes market data to ensure that any asset in the state response can be properly priced. However, these are not high frequency prices and should be used for active trading- they are higher latency "mark prices" helpful for monitoring a financial portfolio rather than truly marketable prices. However, where possible, Vizium does source these prices from the most liquid on chain venues.
For positions, the information is also returned in a similarly structured pooled way. However, rather than protocol level data, the subscription provides the requested addresses's balances in all of a given protocol deployment's pools:
{
"type": "subinitstate",
"subId": "4771b127-2c66-11ef-8e7c-f634f1e942cc",
"sType": "Position",
"ts": "2024-06-17T04:57:40.242071",
"bn": 222671571,
"vzLabel": "AavePoolV3",
"nwk": "arb",
"data": {
"pos": [
{
"cBal_USD": 359.30678767,
"dBal_USD": 120.78445576,
"aBal_USD": 175.64364407,
"liqTh": 85.0,
"hf": 2.5285602157851703,
"ltv": 0.3361596827692904,
"poolAddr": "0x794a61358D6845594F94dc1DB02A252b5b4814aD",
"poolLabel": "AavePoolV3",
"bals": {
"AAVE": {
"sBorrow": "0",
"sBorrow_USD": "0",
"supply": "0",
"supply_USD": "0",
"vBorrow": "0",
"vBorrow_USD": "0"
},
"ARB": {
"sBorrow": "0",
"sBorrow_USD": "0",
"supply": "0",
"supply_USD": "0",
"vBorrow": "0",
"vBorrow_USD": "0"
},
"DAI": {
"sBorrow": "0",
"sBorrow_USD": "0",
"supply": "0",
"supply_USD": "0",
"vBorrow": "0",
"vBorrow_USD": "0"
},
"EURS": {
"sBorrow": "0",
"sBorrow_USD": "0",
"supply": "0",
"supply_USD": "0",
"vBorrow": "0",
"vBorrow_USD": "0"
},
"FRAX": {
"sBorrow": "0",
"sBorrow_USD": "0",
"supply": "0",
"supply_USD": "0",
"vBorrow": "0",
"vBorrow_USD": "0"
},
"LINK": {
"sBorrow": "0",
"sBorrow_USD": "0",
"supply": "0",
"supply_USD": "0",
"vBorrow": "0",
"vBorrow_USD": "0"
},
"LUSD": {
"sBorrow": "0",
"sBorrow_USD": "0",
"supply": "0",
"supply_USD": "0",
"vBorrow": "0",
"vBorrow_USD": "0"
},
"MAI": {
"sBorrow": "0",
"sBorrow_USD": "0",
"supply": "0",
"supply_USD": "0",
"vBorrow": "0",
"vBorrow_USD": "0"
},
"USDC": {
"sBorrow": "0",
"sBorrow_USD": "0",
"supply": "0",
"supply_USD": "0",
"vBorrow": "120.785753",
"vBorrow_USD": "120.785753"
},
"USDC.e": {
"sBorrow": "0",
"sBorrow_USD": "0",
"supply": "0",
"supply_USD": "0",
"vBorrow": "0",
"vBorrow_USD": "0"
},
"USDT": {
"sBorrow": "0",
"sBorrow_USD": "0",
"supply": "0",
"supply_USD": "0",
"vBorrow": "0",
"vBorrow_USD": "0"
},
"WBTC": {
"sBorrow": "0",
"sBorrow_USD": "0",
"supply": "0",
"supply_USD": "0",
"vBorrow": "0",
"vBorrow_USD": "0"
},
"WETH": {
"sBorrow": "0",
"sBorrow_USD": "0",
"supply": "0.00002845667497331804613374240100",
"supply_USD": "0.100173187241074186",
"vBorrow": "0",
"vBorrow_USD": "0"
},
"rETH": {
"sBorrow": "0",
"sBorrow_USD": "0",
"supply": "0",
"supply_USD": "0",
"vBorrow": "0",
"vBorrow_USD": "0"
},
"weETH": {
"sBorrow": "0",
"sBorrow_USD": "0",
"supply": "0",
"supply_USD": "0",
"vBorrow": "0",
"vBorrow_USD": "0"
},
"wstETH": {
"sBorrow": "0",
"sBorrow_USD": "0",
"supply": "0",
"supply_USD": "0",
"vBorrow": "0",
"vBorrow_USD": "0"
}
}
}
]
},
"extraCntInfo": null
}
Sequence Diagram
The below Sequence Diagram, identical to that of the RTCM, is reproduced here to show more information about the messaging structure and expected server/clinet/connection lifecycle.
Sample Code
The following python code demonstrates how to connect to the server and do basic operations. It works for both the RTCM and SM.
You could use the example as follows, assuming you have proper credentials:
python3 ws_client.py -m sm --host wss://api.vizium.xyz --port 4322 --authHost https://api.vizium.xyz -a --authCreds demo tt <VIZIUM_AUTH_PASSWORD>
import aiohttp
import argparse
import asyncio
import enum
import importlib
import json
import logging
import ssl
import traceback as tb
import uuid
import msgspec
import pandas as pd
import websockets
from websockets import exceptions as W_E
class Custom_JSON_Encoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, msgspec.Struct):
return json.loads(msgspec.json.encode(obj))
if isinstance(obj, enum.Enum):
return str(obj)
logging.basicConfig(format='%(asctime)s %(levelname)-8s %(message)s', level=logging.INFO, datefmt='%Y-%m-%d %H:%M:%S')
def pprint(m=None, jm=None):
if jm is None:
pOut = m
else:
pOut = f'{m}\n{json.dumps(jm, indent=4, cls=Custom_JSON_Encoder)}'
logging.info(f'{pOut}')
class BaseWebSocketClient:
def __init__(self, enc, dec, url, logRM=False, logSM=False, authInfo=None):
self._encoder = enc
self._decoder = dec
self._ready = asyncio.Future()
self._wsUrl = url
self._ws = None
self._subIds = {}
self._subReqCnt = 0
self._connectSleepSecs = 3
self._firstConnectFinished = asyncio.Future()
self._connectFinished = asyncio.Future()
self._lRMsgs = logRM
self._lSMsgs = logSM
self._auth, self._authHost, self._authPort, self._authCreds = (False, '', '', {}) if authInfo is None else authInfo
self._shouldRun = False
self.running = None
@property
def connected(self):
return not self._ws is None
async def _recv(self, msg):
raise NotImplementedError()
async def start(self):
asyncio.ensure_future(self._connect())
await self.wait_first_connection()
async def wait_first_connection(self):
await self._firstConnectFinished
async def _wait_ready(self):
return await self._ready
async def _connect(self):
self._shouldRun = True
self.running = asyncio.Future()
async def _conn_loop():
try:
actualUrl = self._wsUrl
sslContext = None
if actualUrl.startswith('wss'):
sslContext = ssl.create_default_context(ssl.Purpose.SERVER_AUTH)
if self._auth:
authUrl = f'{self._authHost}:{self._authPort}/authTkn'
pprint(f'{self} auth required, trying @ {authUrl}')
async with aiohttp.ClientSession() as session:
# sslCtx = None
authResp = await session.request('POST', authUrl, json=self._authCreds, ssl=sslContext)
authD = await authResp.json()
authErr = authD.get('error')
if authErr:
raise RuntimeError(f'{self} auth error {authErr}')
else:
tkn, exp = authD['token'], authD['exp']
pprint(m=f'{self} got auth tkn successfully, expires @ {exp}')
actualUrl = f'{actualUrl}/?token={tkn}'
pprint(f'{self} connecting to {actualUrl}')
async with websockets.connect(actualUrl, ssl=sslContext) as ws:
self._ws = ws
self._ready.set_result(True)
if not self._firstConnectFinished.done():
self._firstConnectFinished.set_result(True)
pprint(m=f'{self} first connection complete!')
while True:
msg = await ws.recv()
try:
await self._recv(self._decoder.decode(msg))
except:
tb.print_exc()
pprint(m=f'{self} error with msg', jm=json.loads(msg))
except ConnectionRefusedError as e:
pprint(m=f'{self} connection refused!')
self._ready.set_result(False)
except (W_E.InvalidMessage, W_E.ConnectionClosedError) as we:
pprint(m=f'{self} websocket protocol exception {we}')
except (W_E.InvalidStatusCode, ) as we:
pprint(m=f'{self} server responded with Invalid Status Code: {we}')
self._ready.set_result(False)
except Exception as e:
tb.print_exc()
self._shouldRun = False
pprint(m=f'{self} {e}')
if not self._firstConnectFinished.done():
self._firstConnectFinished.set_result(True)
self._connectFinished.set_result(True)
isReconnect = False
while self._shouldRun:
asyncio.ensure_future(_conn_loop())
if isReconnect:
readySuccess = await self._wait_ready()
if readySuccess:
asyncio.ensure_future(self._on_reconnect())
await self._connectFinished
if self._shouldRun:
pprint(f'{self} connect loop finished, sleeping {self._connectSleepSecs} seconds and reconnecting')
await asyncio.sleep(self._connectSleepSecs)
isReconnect = True
self._ready = asyncio.Future()
self._connectFinished = asyncio.Future()
self.running.set_result(False)
async def _on_reconnect():
pass
async def _send(self, msg):
if self._lSMsgs:
pprint(m=f'{self} sending msg: ', jm=msg)
await self._ws.send(self._encoder.encode(msg))
class TestWebSocketClient(BaseWebSocketClient):
_serverdata_get_fut = None
_pending_sub_futs = {}
def __init__(self, mode, network, *args, **kwargs):
self._mode = mode
self._network = network
encoder = msgspec.json.Encoder()
msgspec_defs = importlib.import_module(f'msgspec_defs_{self._mode.upper()}.server')
decoder = msgspec.json.Decoder(msgspec_defs.Messages)
super().__init__(encoder, decoder, *args, **kwargs)
self._subscribed_contract_events = set()
self._notify_cbs = []
def add_notify_cb(self, cb):
self._notify_cbs.append(cb)
async def _on_reconnect(self):
match self._mode:
case 'rtcm':
for x in self._subscribed_contract_events:
await self.subscribe_contract_event(*x)
async def _recv(self, msg):
if self._lRMsgs:
pprint(m=f'{self} recv msg', jm=msg)
mType = type(msg).__name__.lower()
match mType:
case 'init':
pprint(m=f'{self} init from server {msg}')
case 'error':
oMsg = msg.rMsg
oMsgType = oMsg['type']
match oMsgType:
case 'serverget':
self._serverdata_get_fut.set_result((False, msg.eMsg))
case 'sub':
clSubId = oMsg['clSubId']
pSubFut = self._pending_sub_futs[clSubId]
pSubFut.set_result((False, msg))
case _:
pprint(m=f'{self} unhandled error from original client msg type {oMsgType}', jm=msg)
case 'subpendingstate':
subId = msg.subId
pprint(m=f'{self} requested subId={subId} is still intializing and pending')
case 'subinitstate':
clSubId, subData = self._subIds[msg.subId]
pSubFut = self._pending_sub_futs[clSubId]
pSubFut.set_result((True, msg))
case 'subconfirm':
clSubId = msg.clSubId
pprint(msg)
self._subIds[msg.subId] = (clSubId, msg.data)
case 'usubconfirm':
clSubId, subData = self._subIds[msg.subId]
del self._subIds[msg.subId]
pprint(m=f'{self} confirmed unsubsubscribed clSubId={clSubId} subId={msg.subId} {subData}', jm=msg)
case 'serverdata':
if not self._serverdata_get_fut.done():
self._serverdata_get_fut.set_result((True, msg.data))
case 'notify':
clSubId, subData = self._subIds[msg.subId]
for cb in self._notify_cbs:
cb(msg, clSubId, subData)
case 'shutdownnotice':
sTs = msg.ts
pprint(m=f'{self} received SHUTDOWN notice ts={msg.ts} reason={msg.reason} sMsg={msg.sMsg}')
async def get_supported_rtcm_contracts(self):
self._serverdata_get_fut = asyncio.Future()
msg = {'type': 'serverget', 'dKey': 'availableContracts'}
await self._send(msg)
await self._serverdata_get_fut
success, res = self._serverdata_get_fut.result()
if success:
pprint(res)
return res
pprint(f'{self} failed to get supported contracts with error: "{res}"')
return None
async def subscribe_contract_event(self, vzLabel, eName):
self._subscribed_contract_events.add((vzLabel, eName))
subRParams = {'sType': 'event', 'eName': eName, 'vzLabel': vzLabel, 'nwk': self._network}
pFut = await self._send_sub_msg_single(subRParams)
await pFut
success, resMsg = pFut.result()
if success:
pprint(m=f'{self} successfully subscribed and init state received for Event vzLabel={vzLabel} eName={eName} from {resMsg.ts} bn={resMsg.bn} txHash={resMsg.txHash} with subId={resMsg.subId} data:', jm=resMsg.data)
else:
pprint(f'{self} failed to subscribe to Event vzLabel={vzLabel} eName={eName} with error: "{resMsg.eMsg}"')
return success
async def get_supported_sm_contracts(self):
self._serverdata_get_fut = asyncio.Future()
msg = {'type': 'serverget', 'dKey': 'supportedContracts'}
await self._send(msg)
await self._serverdata_get_fut
success, res = self._serverdata_get_fut.result()
if success:
pprint(res)
return res
pprint(f'{self} failed to get supported contracts with error: "{res}"')
return None
async def subscribe_sm_state(self, nwk, vzLabel):
subRParams = {'sType': 'state', 'nwk': nwk, 'vzLabel': vzLabel}
pFut = await self._send_sub_msg_single(subRParams)
await pFut
success, resMsg = pFut.result()
if success:
pprint(m=f'{self} successfully subscribed and init state received for State Monitoring nwk={nwk} vzLabel={vzLabel} from {resMsg.ts} bn={resMsg.bn} subId={resMsg.subId} data:', jm=resMsg.data)
else:
pprint(f'{self} failed to subscribe to State nwk={nwk} vzLabel={vzLabel} with error: "{resMsg.eMsg}"')
return success
async def subscribe_sm_position(self, nwk, vzLabel, userAddr):
subRParams = {'sType': 'position', 'nwk': nwk, 'vzLabel': vzLabel, 'posAddr': userAddr}
pFut = await self._send_sub_msg_single(subRParams)
await pFut
success, resMsg = pFut.result()
if success:
pprint(m=f'{self} successfully subscribed and init state received for Position Monitoring nwk={nwk} vzLabel={vzLabel} userAddr={userAddr} from {resMsg.ts} bn={resMsg.bn} subId={resMsg.subId} data:', jm=resMsg.data)
else:
pprint(f'{self} failed to subscribe to Position nwk={nwk} vzLabel={vzLabel} userAddr={userAddr} with error: "{resMsg.eMsg}"')
return success
async def _send_sub_msg_single(self, sData):
sId = self._subReqCnt
self._pending_sub_futs[sId] = asyncio.Future()
msg = {'type': 'sub', 'clSubId': sId, 'data': sData}
self._subReqCnt += 1
await self._send(msg)
return self._pending_sub_futs[sId]
async def _unsub_test(self):
usId = list(self._subIds.keys())[0]
await self._send_usub_msg(usId)
async def _send_usub_msg(self, uSubId):
msg = {'type': 'usub', 'subId': uSubId}
await self._send(msg)
def __str__(self):
return self.__repr__()
def __repr__(self):
return f'TestViziumWebSocketClient-{self._network}'
def log_notify(msg, clSubId, subData):
pprint(m=f'NOTIFICATION {msg.sType} {subData} @ {msg.ts} bn={msg.bn}', jm=msg)
async def gen_client(mode, nwk, host, port, logRMsgs=False, logSMsgs=False, authInfo=None, sslCreds=None):
if authInfo is None:
authInfo = (False, '', '', {})
client = TestWebSocketClient(mode, nwk, f'{host}:{port}', logRM=logRMsgs, logSM=logSMsgs, authInfo=authInfo, sslCreds=sslCreds)
await client.start()
return client
async def main():
parser = argparse.ArgumentParser(description="Sample Vizium API Client")
parser.add_argument('--host', help='vizium server host', default='ws://localhost')
parser.add_argument('-m', '--mode', help='connect to either realtime chain monitor or state monitoring service', default='rtcm', choices=['rtcm', 'sm'])
parser.add_argument('-n', '--network', help='target RTCM EVM network type')
parser.add_argument('--port', help='vizium server port', default=4321)
parser.add_argument('--logRMsgs', help='log received messages', action='store_true', default=False)
parser.add_argument('--logSMsgs', help='log sent messages', action='store_true', default=False)
parser.add_argument('-l', '--listenType', help='selector for RTCM vizium supported contracts', default="USDC", choices=["USDC", "USDT", "Chainlink"])
parser.add_argument('-a', '--authenticated', help='indicates server requires authentication', action='store_true', default=False)
parser.add_argument('--authHost', help='vizium auth server host', default='http://localhost')
parser.add_argument('--authPort', help='vizium auth server port', default=5174)
parser.add_argument('--authCreds', help='vizium auth credentials in form of "username org password"', nargs='+', default=None)
args = parser.parse_args()
if args.mode == 'rtcm' and args.network is None:
parser.error(f'network argument must be provided if running in rtcm mode')
args = parser.parse_args()
fut = asyncio.Future()
if args.authCreds is None:
authCreds = {}
elif len(args.authCreds) != 3:
parser.error(f'authCreds must be in form "username org password"')
else:
username, org, password = args.authCreds
authCreds = {'username': username, 'org': org, 'password': password}
clientAuthInfo = (args.authenticated, args.authHost, args.authPort, authCreds)
async def test_rtcd1():
client = await gen_client(args.mode, args.network, args.host, args.port, logRMsgs=args.logRMsgs, logSMsgs=args.logSMsgs, authInfo=clientAuthInfo)
if client.connected:
client.add_notify_cb(log_notify)
cnts = await client.get_supported_rtcm_contracts()
if not cnts:
fut.set_result(False)
else:
for cnt in cnts:
if args.listenType in cnt['vzLabel']:
await client.subscribe_contract_event(cnt['vzLabel'], cnt['events'][0])
# await asyncio.sleep(20)
# await client._unsub_test()
await client.running
async def test_sm1():
client = await gen_client(args.mode, args.network, args.host, args.port, logRMsgs=args.logRMsgs, logSMsgs=args.logSMsgs, authInfo=clientAuthInfo)
if client.connected:
targets = await client.get_supported_sm_contracts()
testAddr = '0x799fDB02e49c5B77FdDB4B271aDf11bf42DCA586'
for nwk in ['eth', 'arb']:
for p in ['AavePoolV3']:
await client.subscribe_sm_state(nwk, p)
await client.subscribe_sm_position(nwk, p, testAddr)
await client.running
match args.mode:
case 'rtcm':
await test_rtcd1()
case 'sm':
await test_sm1()
if __name__ == '__main__':
asyncio.run(main())
Last updated