Skip to main content

Address Events

Monitor all on-chain activity for specific Sui addresses in real-time. Track wallet movements, protocol treasuries, or key actors in your ecosystem without polling.

Overview​

Address Events let you subscribe to all on-chain changes affecting a specific Sui address. Every time an object is created, modified, transferred, or deleted at that address, you receive an instant notification via Server-Sent Events (SSE).

Surflux enriches these events with decoded object data, giving you complete visibility into what's happening at any address — including the full object state before and after each change.

Use Cases​

Wallet Monitoring

  • Track incoming and outgoing transactions for user wallets
  • Build real-time balance updates for your app
  • Monitor specific whale wallets for trading signals

Protocol Treasury Tracking

  • Watch your protocol's treasury address for deposits and withdrawals
  • Build alerts for significant treasury movements
  • Track liquidity pool balance changes

User Activity Feeds

  • Create live activity feeds showing user actions
  • Monitor key actors in your dApp ecosystem
  • Build reputation systems based on on-chain behavior

Security & Compliance

  • Monitor addresses flagged for suspicious activity
  • Track compliance-related wallet movements
  • Build real-time alert systems for address activity

DeFi & Trading Bots

  • Follow smart money wallets
  • React instantly to large position changes
  • Build copy-trading or mirror-trading systems

How to Subscribe​

Endpoint​

GET /events?api-key={your_api_key}&last-id={resumption_id}

Base URL (Mainnet): https://flux.surflux.dev

Base URL (Testnet): https://testnet-flux.surflux.dev

Parameters​

ParameterRequiredDescription
api-keyYesYour Surflux API key for authentication
last-idNoResume stream from a specific event ID

Stream Resumption with last-id​

ValueBehavior
0 (default)Start from the beginning (server buffer limits apply)
$Only receive new events from now onwards
{event-id}Resume from after this specific event ID

Tip: Persist the event ID from each received event. If your connection drops, use the last ID to resume without missing any address updates.

Connection Limits​

Only one client per API key can be connected at a time. Contact support if you need multiple simultaneous connections.

Event Structure​

Address Update Format​

{
"type": "address_update",
"timestamp_ms": 1730565189365,
"checkpoint_id": 75542359,
"tx_hash": "Fw7Hk5bjtiYLVeZc6N5ZAeHur9tvfgNN6KQThD2AwFUg",
"data": {
"address": "0x1148207ed0d1b54bd24172fe0a49092c858e363e702cc32c56bd9bf50afeb952",
"new_object": {
"object_type": "0x2::coin::Coin<0x2::sui::SUI>",
"contents": {
"id": {
"id": "0xffd4afc3063c8b06ac07c2c645d65845ca0ebf4f379794cc01195db85de045e7"
},
"balance": "2997435468"
}
},
"old_object": null
}
}

Field Descriptions​

FieldTypeDescription
typestringAlways "address_update" for address events
timestamp_msnumberUnix timestamp in milliseconds when the change occurred
checkpoint_idnumberSui checkpoint number
tx_hashstringTransaction digest that caused this update
data.addressstringThe address being monitored
data.new_objectobject | nullThe new state of the object (null if deleted)
data.old_objectobject | nullThe previous state of the object (null if newly created)

Object Structure​

When an object is created or modified, the new_object and old_object fields contain:

FieldTypeDescription
object_typestringFull type path of the object
contentsobjectDecoded object fields and values

Understanding Object Changes​

Address events track three types of changes:

Object Created (old_object: null) A new object was created at this address (e.g., receiving a coin or NFT).

Object Modified (both objects present) An existing object's state changed (e.g., balance update, metadata change).

Object Deleted (new_object: null) An object was removed from this address (e.g., coin spent, NFT transferred out).

Code Examples​

JavaScript / TypeScript​

const apiKey = "your_api_key_here";
const monitoredAddress = "0x1148207ed0d1b54bd24172fe0a49092c858e363e702cc32c56bd9bf50afeb952";

const eventSource = new EventSource(
`https://flux.surflux.dev/events?api-key=${apiKey}&last-id=$`
);

eventSource.onmessage = (event) => {
const data = JSON.parse(event.data);

if (data.type === "address_update" && data.data.address === monitoredAddress) {
const { address, new_object, old_object } = data.data;

if (old_object === null && new_object !== null) {
console.log("Object created:", new_object.object_type);
console.log("Contents:", new_object.contents);
} else if (old_object !== null && new_object !== null) {
console.log("Object modified:", new_object.object_type);
console.log("Old:", old_object.contents);
console.log("New:", new_object.contents);
} else if (new_object === null) {
console.log("Object deleted:", old_object.object_type);
}

// Persist event ID for resumption
localStorage.setItem("lastEventId", event.lastEventId);
}
};

eventSource.onerror = (error) => {
console.error("Connection error:", error);
eventSource.close();
};

Track Balance Changes​

eventSource.onmessage = (event) => {
const data = JSON.parse(event.data);

if (data.type === "address_update") {
const { new_object, old_object } = data.data;

// Check if it's a SUI coin update
if (new_object?.object_type?.includes("::coin::Coin<") &&
new_object?.object_type?.includes("::sui::SUI>")) {

const oldBalance = old_object?.contents?.balance || "0";
const newBalance = new_object?.contents?.balance || "0";

const balanceChange = BigInt(newBalance) - BigInt(oldBalance);

if (balanceChange > 0) {
console.log(`Received ${balanceChange} MIST`);
} else if (balanceChange < 0) {
console.log(`Spent ${Math.abs(Number(balanceChange))} MIST`);
}
}
}
};

Best Practices​

  • Filter by Address — The SSE stream includes events for all addresses. Always filter by your target address(es) on the client side.
  • Track Multiple Addresses — To monitor multiple addresses, filter for them in your event handler. Each address will have its own stream of address_update events.
  • Handle Large Objects — Some objects have large contents fields. Consider implementing pagination or selective field extraction if processing many events.
  • Persist Last Event ID — Always save the event ID to resume streams after disconnections without missing updates.
  • Detect Balance Changes — Compare old_object and new_object to calculate balance changes, track NFT transfers, or detect state mutations.
  • Build Caches — Use address events to maintain a local cache of an address's current objects, updated in real-time as events arrive.