@@ -6,20 +6,31 @@ import io.emeraldpay.dshackle.config.TokensConfig
66import io.emeraldpay.dshackle.test.EthereumUpstreamMock
77import io.emeraldpay.dshackle.test.MultistreamHolderMock
88import io.emeraldpay.dshackle.test.ReaderMock
9- import io.emeraldpay.dshackle.upstream.Multistream
109import io.emeraldpay.dshackle.upstream.MultistreamHolder
11- import io.emeraldpay.dshackle.reader.Reader
10+ import io.emeraldpay.dshackle.upstream.ethereum.ERC20Balance
11+ import io.emeraldpay.dshackle.upstream.ethereum.EthereumMultistream
12+ import io.emeraldpay.dshackle.upstream.ethereum.EthereumSubscribe
1213import io.emeraldpay.dshackle.upstream.ethereum.EthereumUpstream
14+ import io.emeraldpay.dshackle.upstream.ethereum.subscribe.ConnectLogs
15+ import io.emeraldpay.dshackle.upstream.ethereum.subscribe.json.LogMessage
1316import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcRequest
1417import io.emeraldpay.dshackle.upstream.rpcclient.JsonRpcResponse
18+ import io.emeraldpay.etherjar.domain.BlockHash
19+ import io.emeraldpay.etherjar.domain.TransactionId
20+ import io.emeraldpay.etherjar.hex.Hex32
1521import io.emeraldpay.grpc.Chain
1622import io.emeraldpay.etherjar.domain.Address
1723import io.emeraldpay.etherjar.erc20.ERC20Token
1824import io.emeraldpay.etherjar.hex.HexData
1925import io.emeraldpay.etherjar.rpc.json.TransactionCallJson
26+ import reactor.core.publisher.Flux
2027import reactor.core.publisher.Mono
28+ import reactor.test.StepVerifier
29+ import spock.lang.Ignore
2130import spock.lang.Specification
2231
32+ import java.time.Duration
33+
2334class TrackERC20AddressSpec extends Specification {
2435
2536 def " Init with single token" () {
@@ -121,38 +132,6 @@ class TrackERC20AddressSpec extends Specification {
121132 supportSai
122133 }
123134
124- def " Gets balance from upstream" () {
125- setup :
126- ReaderMock api = new ReaderMock ()
127- .with(
128- new JsonRpcRequest (" eth_call" , [
129- new TransactionCallJson (). tap { json ->
130- json. setTo(Address . from(" 0x54EedeAC495271d0F6B175474E89094C44Da98b9" ))
131- json. setData(HexData . from(" 0x70a0823100000000000000000000000016c15c65ad00b6dfbcc2cb8a7b6c2d0103a3883b" ))
132- },
133- " latest"
134- ]),
135- JsonRpcResponse . ok(' "0x0000000000000000000000000000000000000000000000000000001f28d72868"' )
136- )
137-
138- EthereumUpstream upstream = new EthereumUpstreamMock (Chain . ETHEREUM , api)
139- MultistreamHolder ups = new MultistreamHolderMock (Chain . ETHEREUM , upstream)
140- TrackERC20Address track = new TrackERC20Address (ups, new TokensConfig ([]))
141-
142- TrackERC20Address.TrackedAddress address = new TrackERC20Address.TrackedAddress (
143- Chain . ETHEREUM ,
144- Address . from(" 0x16c15c65ad00b6dfbcc2cb8a7b6c2d0103a3883b" ),
145- new ERC20Token (Address . from(" 0x54EedeAC495271d0F6B175474E89094C44Da98b9" )),
146- " test" ,
147- BigInteger . valueOf(1234 )
148- )
149- when :
150- def act = track. getBalance(address). block()
151-
152- then :
153- act. toLong() == 0x1f28d72868
154- }
155-
156135 def " Builds response" () {
157136 setup :
158137 TrackERC20Address track = new TrackERC20Address (Stub (MultistreamHolder ), new TokensConfig ([]))
@@ -175,4 +154,89 @@ class TrackERC20AddressSpec extends Specification {
175154 .setBalance(" 1234" )
176155 .build()
177156 }
157+
158+ def " Check balance when event happens" () {
159+ setup :
160+ def events = [
161+ new LogMessage (
162+ Address . from(" 0x54EedeAC495271d0F6B175474E89094C44Da98b9" ),
163+ BlockHash . from(" 0x0c0d2969c843d0b61fbab1b2302cf24d6681b2ae0a140a3c2908990d048f7631" ),
164+ 13668750 ,
165+ HexData . from(" 0x0000000000000000000000000000000000000000000000000000000048f2fc7b" ),
166+ 1 ,
167+ [
168+ Hex32 . from(" 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" ),
169+ Hex32 . from(" 0x000000000000000000000000b02f1329d6a6acef07a763258f8509c2847a0a3e" ),
170+ Hex32 . from(" 0x00000000000000000000000016c15c65ad00b6dfbcc2cb8a7b6c2d0103a3883b" )
171+ ],
172+ TransactionId . from(" 0x5a7898e27120575c33d3d0179af3b6353c7268bbad4255df079ed26b743a21a5" ),
173+ 1 ,
174+ false
175+ )
176+ ]
177+ def logs = Mock (ConnectLogs ) {
178+ 1 * start(
179+ [Address . from(" 0x54EedeAC495271d0F6B175474E89094C44Da98b9" )],
180+ [Hex32 . from(" 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" )]
181+ ) >> { args ->
182+ println (" ConnectLogs.start $args " )
183+ Flux . fromIterable(events)
184+ }
185+ }
186+ def sub = Mock (EthereumSubscribe ) {
187+ 1 * getLogs() >> logs
188+ }
189+ def up = Mock (EthereumMultistream ) {
190+ 1 * getSubscribe() >> sub
191+ _ * cast(EthereumMultistream ) >> { args ->
192+ it
193+ }
194+ }
195+ def mup = Mock (MultistreamHolder ) {
196+ _ * getUpstream(Chain . ETHEREUM ) >> up
197+ }
198+ TokensConfig tokens = new TokensConfig ([
199+ new TokensConfig.Token (). tap {
200+ id = " test"
201+ blockchain = Chain . ETHEREUM
202+ name = " TEST"
203+ type = TokensConfig.Type . ERC20
204+ address = Address . from(" 0x54EedeAC495271d0F6B175474E89094C44Da98b9" )
205+ }
206+ ])
207+ TrackERC20Address track = new TrackERC20Address (mup, tokens)
208+ track. init()
209+ track. erc20Balance = Mock (ERC20Balance ) {
210+ 2 * it. getBalance(_, _, _) >>> [
211+ Mono . just(100000. toBigInteger()),
212+ Mono . just(150000. toBigInteger())
213+ ]
214+ }
215+ def request = BlockchainOuterClass.BalanceRequest . newBuilder()
216+ .setAddress(
217+ Common.AnyAddress . newBuilder()
218+ .setAddressSingle(Common.SingleAddress . newBuilder(). setAddress(" 0x16c15c65ad00b6dfbcc2cb8a7b6c2d0103a3883b" ))
219+ )
220+ .setAsset(
221+ Common.Asset . newBuilder()
222+ .setChain(Common.ChainRef . CHAIN_ETHEREUM )
223+ .setCode(" TEST" )
224+ )
225+ .build()
226+ when :
227+ def act = track. subscribe(request)
228+
229+ then :
230+ StepVerifier . create(act)
231+ .expectNextMatches {
232+ println (" Received: $it " )
233+ it. getBalance() == " 100000"
234+ }
235+ .expectNextMatches {
236+ println (" Received: $it " )
237+ it. getBalance() == " 150000"
238+ }
239+ .expectComplete()
240+ .verify(Duration . ofSeconds(1 ))
241+ }
178242}
0 commit comments