11use crate :: {
22 dotrain_add_order_lsp:: LANG_SERVICES ,
3- frontmatter:: { try_parse_frontmatter, FrontmatterError } ,
43 transaction:: { TransactionArgs , TransactionArgsError } ,
54} ;
65use alloy_ethers_typecast:: transaction:: {
7- ReadableClientError , ReadableClientHttp , WritableClientError , WriteTransaction ,
8- WriteTransactionStatus ,
6+ ReadContractParameters , ReadableClientError , ReadableClientHttp , WritableClientError ,
7+ WriteTransaction , WriteTransactionStatus ,
98} ;
109use alloy_primitives:: { hex:: FromHexError , Address , U256 } ;
11- use dotrain:: { error:: ComposeError , RainDocument } ;
10+ use dotrain:: { error:: ComposeError , RainDocument , Rebind } ;
1211use rain_interpreter_dispair:: { DISPair , DISPairError } ;
1312use rain_interpreter_parser:: { Parser , ParserError , ParserV1 } ;
1413use rain_metadata:: {
1514 ContentEncoding , ContentLanguage , ContentType , Error as RainMetaError , KnownMagic ,
1615 RainMetaDocumentV1Item ,
1716} ;
18- use rain_orderbook_bindings:: IOrderBookV3 :: { addOrderCall, EvaluableConfigV3 , OrderConfigV2 } ;
17+ use rain_orderbook_app_settings:: deployment:: Deployment ;
18+ use rain_orderbook_bindings:: {
19+ IOrderBookV3 :: { addOrderCall, EvaluableConfigV3 , OrderConfigV2 , IO } ,
20+ ERC20 :: decimalsCall,
21+ } ;
1922use serde:: { Deserialize , Serialize } ;
2023use serde_bytes:: ByteBuf ;
24+ use std:: collections:: HashMap ;
2125use thiserror:: Error ;
2226
2327pub static ORDERBOOK_ORDER_ENTRYPOINTS : [ & str ; 2 ] = [ "calculate-io" , "handle-io" ] ;
@@ -26,8 +30,6 @@ pub static ORDERBOOK_ORDER_ENTRYPOINTS: [&str; 2] = ["calculate-io", "handle-io"
2630pub enum AddOrderArgsError {
2731 #[ error( "Empty Front Matter" ) ]
2832 EmptyFrontmatter ,
29- #[ error( "Front Matter: {0}" ) ]
30- FrontmatterError ( #[ from] FrontmatterError ) ,
3133 #[ error( transparent) ]
3234 DISPairError ( #[ from] DISPairError ) ,
3335 #[ error( transparent) ]
@@ -47,40 +49,88 @@ pub enum AddOrderArgsError {
4749}
4850
4951#[ derive( Serialize , Deserialize , Clone ) ]
52+ #[ serde( rename = "kebab-case" ) ]
5053pub struct AddOrderArgs {
51- /// Text of a dotrain file describing an addOrder call
52- /// Text MUST have strict yaml frontmatter of the following structure
53- ///
54- /// ```yaml
55- /// orderbook:
56- /// order:
57- /// deployer: 0x1111111111111111111111111111111111111111
58- /// valid-inputs:
59- /// - address: 0x2222222222222222222222222222222222222222
60- /// decimals: 18
61- /// vault-id: 0x1234
62- /// valid-outputs:
63- /// - address: 0x5555555555555555555555555555555555555555
64- /// decimals: 8
65- /// vault-id: 0x5678
66- /// ```
67- ///
68- /// Text MUST have valid dotrain body succeding frontmatter.
69- /// The dotrain body must contain two entrypoints: `calulate-io` and `handle-io`.
7054 pub dotrain : String ,
55+ pub inputs : Vec < IO > ,
56+ pub outputs : Vec < IO > ,
57+ pub deployer : Address ,
58+ pub bindings : HashMap < String , String > ,
7159}
7260
7361impl AddOrderArgs {
62+ /// create a new instance from Deployment
63+ pub async fn new_from_deployment (
64+ dotrain : String ,
65+ deployment : Deployment ,
66+ ) -> Result < AddOrderArgs , AddOrderArgsError > {
67+ let mut inputs = vec ! [ ] ;
68+ for input in & deployment. order . inputs {
69+ if let Some ( decimals) = input. token . decimals {
70+ inputs. push ( IO {
71+ token : input. token . address ,
72+ vaultId : input. vault_id ,
73+ decimals,
74+ } ) ;
75+ } else {
76+ let client = ReadableClientHttp :: new_from_url ( input. token . network . rpc . to_string ( ) ) ?;
77+ let parameters = ReadContractParameters {
78+ address : input. token . address ,
79+ call : decimalsCall { } ,
80+ block_number : None ,
81+ } ;
82+ let decimals = client. read ( parameters) . await ?. _0 ;
83+ inputs. push ( IO {
84+ token : input. token . address ,
85+ vaultId : input. vault_id ,
86+ decimals,
87+ } ) ;
88+ }
89+ }
90+
91+ let mut outputs = vec ! [ ] ;
92+ for output in & deployment. order . inputs {
93+ if let Some ( decimals) = output. token . decimals {
94+ outputs. push ( IO {
95+ token : output. token . address ,
96+ vaultId : output. vault_id ,
97+ decimals,
98+ } ) ;
99+ } else {
100+ let client =
101+ ReadableClientHttp :: new_from_url ( output. token . network . rpc . to_string ( ) ) ?;
102+ let parameters = ReadContractParameters {
103+ address : output. token . address ,
104+ call : decimalsCall { } ,
105+ block_number : None ,
106+ } ;
107+ let decimals = client. read ( parameters) . await ?. _0 ;
108+ outputs. push ( IO {
109+ token : output. token . address ,
110+ vaultId : output. vault_id ,
111+ decimals,
112+ } ) ;
113+ }
114+ }
115+
116+ Ok ( AddOrderArgs {
117+ dotrain : dotrain. to_string ( ) ,
118+ inputs,
119+ outputs,
120+ deployer : deployment. scenario . deployer . address ,
121+ bindings : deployment. scenario . bindings . to_owned ( ) ,
122+ } )
123+ }
124+
74125 /// Read parser address from deployer contract, then call parser to parse rainlang into bytecode and constants
75126 async fn try_parse_rainlang (
76127 & self ,
77128 rpc_url : String ,
78- deployer : Address ,
79129 rainlang : String ,
80130 ) -> Result < ( Vec < u8 > , Vec < U256 > ) , AddOrderArgsError > {
81131 let client = ReadableClientHttp :: new_from_url ( rpc_url)
82132 . map_err ( AddOrderArgsError :: ReadableClientError ) ?;
83- let dispair = DISPair :: from_deployer ( deployer, client. clone ( ) )
133+ let dispair = DISPair :: from_deployer ( self . deployer , client. clone ( ) )
84134 . await
85135 . map_err ( AddOrderArgsError :: DISPairError ) ?;
86136
@@ -116,27 +166,29 @@ impl AddOrderArgs {
116166 // Parse file into dotrain document
117167 let meta_store = LANG_SERVICES . meta_store ( ) ;
118168
119- let frontmatter = RainDocument :: get_front_matter ( & self . dotrain )
120- . ok_or ( AddOrderArgsError :: EmptyFrontmatter ) ?;
121-
122- // Prepare call
123- let ( deployer, valid_inputs, valid_outputs, rebinds) = try_parse_frontmatter ( frontmatter) ?;
169+ let mut rebinds = None ;
170+ if !self . bindings . is_empty ( ) {
171+ rebinds = Some (
172+ self . bindings
173+ . iter ( )
174+ . map ( |( key, value) | Rebind ( key. clone ( ) , value. clone ( ) ) )
175+ . collect ( ) ,
176+ ) ;
177+ } ;
124178
125179 let dotrain_doc =
126180 RainDocument :: create ( self . dotrain . clone ( ) , Some ( meta_store) , None , rebinds) ;
127181 let rainlang = dotrain_doc. compose ( & ORDERBOOK_ORDER_ENTRYPOINTS ) ?;
128182
129- let ( bytecode, constants) = self
130- . try_parse_rainlang ( rpc_url, deployer, rainlang. clone ( ) )
131- . await ?;
183+ let ( bytecode, constants) = self . try_parse_rainlang ( rpc_url, rainlang. clone ( ) ) . await ?;
132184 let meta = self . try_generate_meta ( rainlang) ?;
133185
134186 Ok ( addOrderCall {
135187 config : OrderConfigV2 {
136- validInputs : valid_inputs ,
137- validOutputs : valid_outputs ,
188+ validInputs : self . inputs . clone ( ) ,
189+ validOutputs : self . outputs . clone ( ) ,
138190 evaluableConfig : EvaluableConfigV3 {
139- deployer,
191+ deployer : self . deployer ,
140192 bytecode,
141193 constants,
142194 } ,
@@ -182,7 +234,13 @@ max-amount: 100e18,
182234price: 2e18;
183235" ,
184236 ) ;
185- let args = AddOrderArgs { dotrain : "" . into ( ) } ;
237+ let args = AddOrderArgs {
238+ dotrain : "" . into ( ) ,
239+ inputs : vec ! [ ] ,
240+ outputs : vec ! [ ] ,
241+ bindings : HashMap :: new ( ) ,
242+ deployer : Address :: default ( ) ,
243+ } ;
186244
187245 let meta_bytes = args. try_generate_meta ( dotrain_body) . unwrap ( ) ;
188246 assert_eq ! (
0 commit comments