Skip to content

Commit eba6ac0

Browse files
Added Indexer Streams for SubscribeReceipts, SubscribeEvents, SubscribeBalanceUpdates (#252)
* Terminal started adding SubscribeEvents, SubscribeReceipts, SubscribeBalanceUpdates to Indexer * added summaries for indexer event functions * added tests for indexer event streams * fixed DownloadHandlerStream, refined test logs * version increment * logic to abort all running streams * added EventDecoded data type * Added end-to-end tests that confirm we receive the events --------- Co-authored-by: Quinn Purdy <[email protected]>
1 parent 958840f commit eba6ac0

35 files changed

+573
-7
lines changed

Assets/SequenceSDK/Indexer/Tests/ChainIndexerTests.cs

Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,14 @@
55
using System.Threading.Tasks;
66
using NUnit.Framework;
77
using Sequence;
8+
using Sequence.Contracts;
9+
using Sequence.EmbeddedWallet;
10+
using Sequence.EmbeddedWallet.Tests;
811
using Sequence.Utils;
912
using UnityEngine;
1013
using UnityEngine.TestTools;
14+
using EOAWallet = Sequence.Wallet.EOAWallet;
15+
using Transaction = System.Transactions.Transaction;
1116

1217
namespace Sequence.Indexer.Tests
1318
{
@@ -299,5 +304,217 @@ public async Task TestRequestDecodingErrorHandling(bool logError)
299304

300305
Assert.IsTrue(errorEventFired);
301306
}
307+
308+
[TestCase]
309+
public void TestSubscribeReceipts()
310+
{
311+
var indexer = new ChainIndexer(Chain.TestnetArbitrumSepolia);
312+
var streamOptions = new WebRPCStreamOptions<SubscribeReceiptsReturn>(
313+
OnSubscribeReceiptsMessageReceived,
314+
OnWebRPCErrorReceived);
315+
316+
var filter = new TransactionFilter
317+
{
318+
contractAddress = "0x4ab3b16e9d3328f6d8025e71cefc64305ae4fe9c"
319+
};
320+
321+
indexer.SubscribeReceipts(new SubscribeReceiptsArgs(filter), streamOptions);
322+
}
323+
324+
[Test]
325+
public async Task TestReceiptSubscriptionReceived()
326+
{
327+
Chain chain = Chain.ArbitrumNova;
328+
bool receiptReceived = false;
329+
IIndexer indexer = new ChainIndexer(chain);
330+
ERC1155 universallyMintable = new ERC1155("0x0ee3af1874789245467e7482f042ced9c5171073");
331+
var streamOptions = new WebRPCStreamOptions<SubscribeReceiptsReturn>(
332+
(@return =>
333+
{
334+
Assert.IsNotNull(@return);
335+
Assert.IsNotNull(@return.receipt);
336+
receiptReceived = true;
337+
}),
338+
OnWebRPCErrorReceived);
339+
340+
341+
var filter = new TransactionFilter()
342+
{
343+
contractAddress = universallyMintable.Contract.GetAddress()
344+
};
345+
indexer.SubscribeReceipts(new SubscribeReceiptsArgs(filter), streamOptions);
346+
347+
await DoMintTransaction(chain);
348+
349+
while (!receiptReceived)
350+
{
351+
await Task.Yield();
352+
}
353+
}
354+
355+
private async Task DoMintTransaction(Chain chain)
356+
{
357+
var tcs = new TaskCompletionSource<bool>();
358+
EndToEndTestHarness testHarness = new EndToEndTestHarness();
359+
EOAWallet toWallet = new EOAWallet();
360+
string toAddress = toWallet.GetAddress().Value;
361+
362+
testHarness.Login(async wallet =>
363+
{
364+
try
365+
{
366+
ERC1155 erc1155 = new ERC1155("0x0ee3af1874789245467e7482f042ced9c5171073");
367+
368+
TransactionReturn transactionReturn = await wallet.SendTransaction(chain,
369+
new EmbeddedWallet.Transaction[]
370+
{
371+
new RawTransaction(erc1155.Mint(toAddress, 1, 1)),
372+
});
373+
Assert.IsNotNull(transactionReturn);
374+
Assert.IsTrue(transactionReturn is SuccessfulTransactionReturn);
375+
376+
tcs.TrySetResult(true);
377+
}
378+
catch (System.Exception e)
379+
{
380+
tcs.TrySetException(e);
381+
}
382+
}, (error, method, email, methods) =>
383+
{
384+
tcs.TrySetException(new Exception(error));
385+
});
386+
387+
await tcs.Task;
388+
}
389+
390+
[TestCase]
391+
public void TestSubscribeEvents()
392+
{
393+
var indexer = new ChainIndexer(Chain.TestnetArbitrumSepolia);
394+
var streamOptions = new WebRPCStreamOptions<SubscribeEventsReturn>(
395+
OnSubscribeEventsMessageReceived,
396+
OnWebRPCErrorReceived);
397+
398+
var eventFilter = new EventFilter
399+
{
400+
accounts = Array.Empty<string>(),
401+
contractAddresses = new[] {"0x4ab3b16e9d3328f6d8025e71cefc64305ae4fe9c"},
402+
tokenIDs = new[] {"0"},
403+
events = new[] {"Transfer(address from, address to, uint256 value)"}
404+
};
405+
406+
indexer.SubscribeEvents(new SubscribeEventsArgs(eventFilter), streamOptions);
407+
}
408+
409+
[Test]
410+
public async Task TestEventSubscriptionReceived()
411+
{
412+
Chain chain = Chain.ArbitrumNova;
413+
bool eventReceived = false;
414+
IIndexer indexer = new ChainIndexer(chain);
415+
ERC1155 universallyMintable = new ERC1155("0x0ee3af1874789245467e7482f042ced9c5171073");
416+
var streamOptions = new WebRPCStreamOptions<SubscribeEventsReturn>(
417+
(@return =>
418+
{
419+
Assert.IsNotNull(@return);
420+
Assert.IsNotNull(@return.log);
421+
Assert.AreEqual(universallyMintable.Contract.GetAddress().Value, @return.log.contractAddress);
422+
eventReceived = true;
423+
}),
424+
OnWebRPCErrorReceived);
425+
426+
427+
var eventFilter = new EventFilter
428+
{
429+
accounts = Array.Empty<string>(),
430+
contractAddresses = new[] {universallyMintable.Contract.GetAddress().Value},
431+
tokenIDs = new[] {"1"},
432+
events = new[] {"TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value)"}
433+
};
434+
435+
indexer.SubscribeEvents(new SubscribeEventsArgs(eventFilter), streamOptions);
436+
437+
await DoMintTransaction(chain);
438+
439+
while (!eventReceived)
440+
{
441+
await Task.Yield();
442+
}
443+
}
444+
445+
[TestCase]
446+
public void TestSubscribeBalanceUpdates()
447+
{
448+
var indexer = new ChainIndexer(Chain.TestnetArbitrumSepolia);
449+
var streamOptions = new WebRPCStreamOptions<SubscribeBalanceUpdatesReturn>(
450+
OnSubscribeEventsMessageReceived,
451+
OnWebRPCErrorReceived);
452+
453+
var contractAddress = "0x4ab3b16e9d3328f6d8025e71cefc64305ae4fe9c";
454+
indexer.SubscribeBalanceUpdates(new SubscribeBalanceUpdatesArgs(contractAddress), streamOptions);
455+
}
456+
457+
[Test]
458+
public async Task TestBalanceUpdateSubscriptionReceived()
459+
{
460+
Chain chain = Chain.ArbitrumNova;
461+
bool eventReceived = false;
462+
IIndexer indexer = new ChainIndexer(chain);
463+
var streamOptions = new WebRPCStreamOptions<SubscribeBalanceUpdatesReturn>(
464+
(@return =>
465+
{
466+
Assert.IsNotNull(@return);
467+
Assert.IsNotNull(@return.balance);
468+
if (!@return.balance.accountAddress.IsZeroAddress())
469+
{
470+
Assert.AreEqual(BigInteger.One, @return.balance.balance);
471+
}
472+
eventReceived = true;
473+
}),
474+
OnWebRPCErrorReceived);
475+
476+
ERC1155 universallyMintable = new ERC1155("0x0ee3af1874789245467e7482f042ced9c5171073");
477+
478+
indexer.SubscribeBalanceUpdates(new SubscribeBalanceUpdatesArgs(universallyMintable.Contract.GetAddress()), streamOptions);
479+
480+
await DoMintTransaction(chain);
481+
482+
while (!eventReceived)
483+
{
484+
await Task.Yield();
485+
}
486+
}
487+
488+
[TestCase]
489+
public void TestAbortStreams()
490+
{
491+
new ChainIndexer(Chain.TestnetArbitrumSepolia).AbortStreams();
492+
}
493+
494+
[TearDown]
495+
public void UnsubscribeFromEvents()
496+
{
497+
new ChainIndexer(Chain.ArbitrumNova).AbortStreams();
498+
}
499+
500+
private void OnSubscribeReceiptsMessageReceived(SubscribeReceiptsReturn @event)
501+
{
502+
Debug.Log($"Receipt Event Received - hash: {@event.receipt.txnHash}");
503+
}
504+
505+
private void OnSubscribeEventsMessageReceived(SubscribeEventsReturn @event)
506+
{
507+
Debug.Log($"Contract Event Received - {@event.log.type} {@event.log.contractType}: {@event.log.txnHash}");
508+
}
509+
510+
private void OnSubscribeEventsMessageReceived(SubscribeBalanceUpdatesReturn @event)
511+
{
512+
Debug.Log($"Balance Update Received - {@event.balance.accountAddress} owns {@event.balance.balance}");
513+
}
514+
515+
private void OnWebRPCErrorReceived(WebRPCError error)
516+
{
517+
Debug.LogError($"OnWebRPCErrorReceived: {error.msg}");
518+
}
302519
}
303520
}

Assets/SequenceSDK/Indexer/Tests/MockHttpHandler.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,15 @@ public Task<string> HttpPost(string chainID, string endPoint, object args, int r
2626
}
2727
return Task.FromResult(_response);
2828
}
29+
30+
public void HttpStream<T>(string chainID, string endPoint, object args, WebRPCStreamOptions<T> options, int retries = 0)
31+
{
32+
throw new NotImplementedException();
33+
}
34+
35+
public void AbortStreams()
36+
{
37+
throw new NotImplementedException();
38+
}
2939
}
3040
}

Assets/SequenceSDK/Indexer/Tests/SequenceIndexerTests.asmdef

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@
77
"GUID:0acc523941302664db1f4e527237feb3",
88
"GUID:a35e3a53d4439435f8b36ed2c6158cd8",
99
"GUID:b4f9c0f8f363f439b9e337f79050f189",
10-
"GUID:403077141e1554429a890cbc129df651"
10+
"GUID:403077141e1554429a890cbc129df651",
11+
"GUID:040286810a82b46ed9acd6d70bfbbfd4",
12+
"SequenceEmbeddedWallet",
13+
"SequenceAuthentication"
1114
],
1215
"includePlatforms": [
1316
"Editor"

Packages/Sequence-Unity/Sequence/SequenceFrontend/Scripts/UI/SequenceSampleUI.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System;
12
using Sequence.EmbeddedWallet;
23
using UnityEngine;
34

Packages/Sequence-Unity/Sequence/SequenceSDK/Ethereum/Address/Address.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,4 +82,19 @@ public override bool CanConvert(Type objectType)
8282
return true;
8383
}
8484
}
85+
86+
public static class AddressExtensions
87+
{
88+
public static bool IsZeroAddress(this Address address)
89+
{
90+
return IsZeroAddress(address.Value);
91+
}
92+
93+
public static bool IsZeroAddress(this string address)
94+
{
95+
string toCheck = address.WithoutHexPrefix();
96+
toCheck = toCheck.Replace("0", "");
97+
return toCheck.Length == 0;
98+
}
99+
}
85100
}

Packages/Sequence-Unity/Sequence/SequenceSDK/Ethereum/Provider/DataTypes/TransactionReceipt.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ namespace Sequence
66
[System.Serializable]
77
public class TransactionReceipt
88
{
9+
public string txnHash;
910
public string transactionHash;
1011
public string transactionIndex;
1112
public string blockHash;
@@ -22,6 +23,4 @@ public class TransactionReceipt
2223
public string root;
2324
public string status;
2425
}
25-
26-
2726
}

Packages/Sequence-Unity/Sequence/SequenceSDK/Indexer/ChainIndexer.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,5 +148,25 @@ public Task<GetTransactionHistoryReturn> GetTransactionHistory(GetTransactionHis
148148
{
149149
return Indexer.GetTransactionHistory(ChainId, args, 0, _customHttpHandler, this);
150150
}
151+
152+
public void SubscribeReceipts(SubscribeReceiptsArgs args, WebRPCStreamOptions<SubscribeReceiptsReturn> options)
153+
{
154+
Indexer.SubscribeReceipts(ChainId, args, options, this);
155+
}
156+
157+
public void SubscribeEvents(SubscribeEventsArgs args, WebRPCStreamOptions<SubscribeEventsReturn> options)
158+
{
159+
Indexer.SubscribeEvents(ChainId, args, options, this);
160+
}
161+
162+
public void SubscribeBalanceUpdates(SubscribeBalanceUpdatesArgs args, WebRPCStreamOptions<SubscribeBalanceUpdatesReturn> options)
163+
{
164+
Indexer.SubscribeBalanceUpdates(ChainId, args, options, this);
165+
}
166+
167+
public void AbortStreams()
168+
{
169+
Indexer.AbortStreams(this);
170+
}
151171
}
152172
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
namespace Sequence
2+
{
3+
[System.Serializable]
4+
public class EventDecoded
5+
{
6+
public string topicHash;
7+
public string eventSig;
8+
public string[] types;
9+
public string[] names;
10+
public string[] values;
11+
}
12+
}

Packages/Sequence-Unity/Sequence/SequenceSDK/Indexer/DataTypes/EventDecoded.cs.meta

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
namespace Sequence
2+
{
3+
[System.Serializable]
4+
public class EventFilter
5+
{
6+
public string[] events;
7+
public string[] contractAddresses;
8+
public string[] accounts;
9+
public string[] tokenIDs;
10+
}
11+
}

0 commit comments

Comments
 (0)