urbit/pkg/arvo/lib/ethio.hoon
2019-11-11 21:36:32 -08:00

163 lines
4.3 KiB
Plaintext

:: ethio: Asynchronous Ethereum input/output functions.
::.
/+ threadio
=, ethereum-types
=, able:jael
::
=> |%
+$ topics (list ?(@ux (list @ux)))
--
|%
:: +request-rpc: send rpc request, with retry
::
++ request-rpc
|= [url=@ta id=(unit @t) req=request:rpc:ethereum]
=/ m (thread:threadio ,json)
^- form:m
|^ %+ (retry:threadio json) `10
=/ m (thread:threadio ,(unit json))
^- form:m
=/ =request:http
:* method=%'POST'
url=url
header-list=['Content-Type'^'application/json' ~]
^= body
%- some %- as-octt:mimes:html
%- en-json:html
(request-to-json:rpc:ethereum id req)
==
;< ~ bind:m (send-request:threadio request)
;< rep=(unit client-response:iris) bind:m
take-maybe-response:threadio
?~ rep
(pure:m ~)
(parse-response u.rep)
::
++ parse-response
|= =client-response:iris
=/ m (thread:threadio ,(unit json))
^- form:m
?> ?=(%finished -.client-response)
?~ full-file.client-response
(pure:m ~)
=/ body=@t q.data.u.full-file.client-response
=/ jon=(unit json) (de-json:html body)
?~ jon
(pure:m ~)
=, dejs-soft:format
=/ array=(unit (list response:rpc:jstd))
((ar parse-one-response) u.jon)
?~ array
=/ res=(unit response:rpc:jstd) (parse-one-response u.jon)
?~ res
(thread-fail:threadio %request-rpc-parse-error >id< ~)
?: ?=(%error -.u.res)
(thread-fail:threadio %request-rpc-error >id< >+.res< ~)
?. ?=(%result -.u.res)
(thread-fail:threadio %request-rpc-fail >u.res< ~)
(pure:m `res.u.res)
(thread-fail:threadio %request-rpc-batch >%not-implemented< ~)
:: (pure:m `[%batch u.array])
::
++ parse-one-response
|= =json
^- (unit response:rpc:jstd)
=/ res=(unit [@t ^json])
%. json
=, dejs-soft:format
(ot id+so result+some ~)
?^ res `[%result u.res]
~| parse-one-response=json
:+ ~ %error %- need
%. json
=, dejs-soft:format
(ot id+so error+(ot code+no message+so ~) ~)
--
:: +read-contract: calls a read function on a contract, produces result hex
::
++ read-contract
|= [url=@t proto-read-request:rpc:ethereum]
=/ m (thread:threadio ,@t)
;< =json bind:m
%^ request-rpc url id
:+ %eth-call
^- call:rpc:ethereum
[~ to ~ ~ ~ `tape`(encode-call:rpc:ethereum function arguments)]
[%label %latest]
?. ?=(%s -.json) (thread-fail:threadio %request-rpc-fail >json< ~)
(pure:m p.json)
::
++ get-latest-block
|= url=@ta
=/ m (thread:threadio ,block)
^- form:m
;< =json bind:m
(request-rpc url `'block number' %eth-block-number ~)
(get-block-by-number url (parse-eth-block-number:rpc:ethereum json))
::
++ get-block-by-number
|= [url=@ta =number:block]
=/ m (thread:threadio ,block)
^- form:m
|^
;< =json bind:m
%+ request-rpc url
:- `'block by number'
[%eth-get-block-by-number number |]
=/ =block (parse-block json)
?. =(number number.id.block)
(thread-fail:threadio %reorg-detected >number< >block< ~)
(pure:m block)
::
++ parse-block
|= =json
^- block
=< [[&1 &2] |2]
^- [@ @ @]
~| json
%. json
=, dejs:format
%- ot
:~ hash+parse-hex-result:rpc:ethereum
number+parse-hex-result:rpc:ethereum
'parentHash'^parse-hex-result:rpc:ethereum
==
--
::
++ get-logs-by-hash
|= [url=@ta =hash:block contracts=(list address) =topics]
=/ m (thread:threadio (list event-log:rpc:ethereum))
^- form:m
;< =json bind:m
%+ request-rpc url
:* `'logs by hash'
%eth-get-logs-by-hash
hash
contracts
topics
==
%- pure:m
(parse-event-logs:rpc:ethereum json)
::
++ get-logs-by-range
|= $: url=@ta
contracts=(list address)
=topics
=from=number:block
=to=number:block
==
=/ m (thread:threadio (list event-log:rpc:ethereum))
^- form:m
;< =json bind:m
%+ request-rpc url
:* `'logs by range'
%eth-get-logs
`number+from-number
`number+to-number
contracts
topics
==
%- pure:m
(parse-event-logs:rpc:ethereum json)
--