abi.gno
12.51 Kb · 463 lines
1package zkgm
2
3import (
4 "bytes"
5 "errors"
6
7 "gno.land/p/onbloc/encoding/abi"
8 u256 "gno.land/p/onbloc/math/uint256"
9)
10
11var InstructionSchema = abi.Schema{Fields: []abi.Field{
12 {Type: abi.TypeUint8}, // version
13 {Type: abi.TypeUint8}, // opcode
14 {Type: abi.TypeBytes}, // operand
15}}
16
17var CallSchema = abi.Schema{Fields: []abi.Field{
18 {Type: abi.TypeBytes}, // sender
19 {Type: abi.TypeBool}, // eureka
20 {Type: abi.TypeBytes}, // contract_address / contractAddress
21 {Type: abi.TypeBytes}, // contract_calldata / contractCalldata
22}}
23
24var ZkgmPacketSchema = abi.Schema{Fields: []abi.Field{
25 {Type: abi.TypeBytes32}, // salt
26 {Type: abi.TypeUint256}, // path
27 {Type: abi.TypeStruct, Sub: &InstructionSchema}, // instruction
28}}
29
30var ForwardSchema = abi.Schema{Fields: []abi.Field{
31 {Type: abi.TypeUint256}, // path
32 {Type: abi.TypeUint64}, // timeout_height / timeoutHeight
33 {Type: abi.TypeUint64}, // timeout_timestamp / timeoutTimestamp
34 {Type: abi.TypeStruct, Sub: &InstructionSchema}, // instruction
35}}
36
37var BatchSchema = abi.Schema{Fields: []abi.Field{
38 {Type: abi.TypeArray, Elem: &abi.Field{Type: abi.TypeStruct, Sub: &InstructionSchema}}, // instructions
39}}
40
41var TokenOrderV2Schema = abi.Schema{Fields: []abi.Field{
42 {Type: abi.TypeBytes}, // sender
43 {Type: abi.TypeBytes}, // receiver
44 {Type: abi.TypeBytes}, // base_token / baseToken
45 {Type: abi.TypeUint256}, // base_amount / baseAmount
46 {Type: abi.TypeBytes}, // quote_token / quoteToken
47 {Type: abi.TypeUint256}, // quote_amount / quoteAmount
48 {Type: abi.TypeUint8}, // kind
49 {Type: abi.TypeBytes}, // metadata
50}}
51
52var TokenOrderV1Schema = abi.Schema{Fields: []abi.Field{
53 {Type: abi.TypeBytes}, // sender
54 {Type: abi.TypeBytes}, // receiver
55 {Type: abi.TypeBytes}, // base_token / baseToken
56 {Type: abi.TypeUint256}, // base_amount / baseAmount
57 {Type: abi.TypeString}, // base_token_symbol / baseTokenSymbol
58 {Type: abi.TypeString}, // base_token_name / baseTokenName
59 {Type: abi.TypeUint8}, // base_token_decimals / baseTokenDecimals
60 {Type: abi.TypeUint256}, // base_token_path / baseTokenPath
61 {Type: abi.TypeBytes}, // quote_token / quoteToken
62 {Type: abi.TypeUint256}, // quote_amount / quoteAmount
63}}
64
65var AckSchema = abi.Schema{Fields: []abi.Field{
66 {Type: abi.TypeUint256}, // tag
67 {Type: abi.TypeBytes}, // inner_ack / innerAck
68}}
69
70var BatchAckSchema = abi.Schema{Fields: []abi.Field{
71 {Type: abi.TypeArray, Elem: &abi.Field{Type: abi.TypeBytes}}, // acknowledgements
72}}
73
74var TokenOrderAckSchema = abi.Schema{Fields: []abi.Field{
75 {Type: abi.TypeUint256}, // fill_type / fillType
76 {Type: abi.TypeBytes}, // market_maker / marketMaker
77}}
78
79var TokenMetadataSchema = abi.Schema{Fields: []abi.Field{
80 {Type: abi.TypeBytes}, // implementation
81 {Type: abi.TypeBytes}, // initializer
82}}
83
84// tokenInitializerSelector is the first 4 bytes of
85// keccak256("initialize(address,address,string,string,uint8)"), the ZkgmERC20
86// contract's initializer. Every TokenMetadata.Initializer carries this
87// calldata verbatim regardless of what the wrapped token's origin is
88// (Gno-native GRC20/native, or a real EVM ERC20): a receiving EVM chain only
89// knows how to deploy and initialize a ZkgmERC20 clone from this exact wire
90// format, so a Gno-only encoding is not a valid substitute for it.
91var tokenInitializerSelector = []byte{0x84, 0x20, 0xce, 0x99}
92
93// TokenInitializerSchema mirrors the Solidity ABI params for ZkgmERC20's
94// initialize(address authority, address minter, string name, string symbol,
95// uint8 decimals), excluding the 4-byte selector. It is not a Union ZKGM
96// top-level struct in com.rs or Types.sol.
97var TokenInitializerSchema = abi.Schema{Fields: []abi.Field{
98 {Type: abi.TypeAddress}, // authority
99 {Type: abi.TypeAddress}, // minter
100 {Type: abi.TypeString}, // name
101 {Type: abi.TypeString}, // symbol
102 {Type: abi.TypeUint8}, // decimals
103}}
104
105var SolverMetadataSchema = abi.Schema{Fields: []abi.Field{
106 {Type: abi.TypeBytes}, // solverAddress / solver_address
107 {Type: abi.TypeBytes}, // metadata
108}}
109
110// PredictWrappedTokenSchema mirrors abi.encode(path, channel, token) used by Union's
111// _predictWrappedToken helper.
112var PredictWrappedTokenSchema = abi.Schema{Fields: []abi.Field{
113 {Type: abi.TypeUint256}, // path
114 {Type: abi.TypeUint32}, // channel / channelId
115 {Type: abi.TypeBytes}, // token / baseToken
116}}
117
118// PredictV2Schema mirrors abi.encode(path, channel, token, metadataImage) used
119// by Union's _predictWrappedTokenFromMetadataImageV2 helper.
120var PredictV2Schema = abi.Schema{Fields: []abi.Field{
121 {Type: abi.TypeUint256}, // path
122 {Type: abi.TypeUint32}, // channel / channelId
123 {Type: abi.TypeBytes}, // token / baseToken
124 {Type: abi.TypeUint256}, // metadataImage
125}}
126
127func EncodeZkgmPacket(p ZkgmPacket) ([]byte, error) {
128 return abi.Encode(ZkgmPacketSchema, []any{
129 p.Salt,
130 p.Path,
131 instructionValues(p.Instruction),
132 })
133}
134
135func DecodeZkgmPacket(data []byte) (ZkgmPacket, error) {
136 out, err := abi.Decode(ZkgmPacketSchema, data)
137 if err != nil {
138 return ZkgmPacket{}, err
139 }
140
141 return ZkgmPacket{
142 Salt: out[0].([32]byte),
143 Path: out[1].(*u256.Uint),
144 Instruction: instructionFromValues(out[2].([]any)),
145 }, nil
146}
147
148func EncodeInstruction(ins Instruction) ([]byte, error) {
149 return abi.Encode(InstructionSchema, instructionValues(ins))
150}
151
152func DecodeInstruction(data []byte) (Instruction, error) {
153 out, err := abi.Decode(InstructionSchema, data)
154 if err != nil {
155 return Instruction{}, err
156 }
157
158 return instructionFromValues(out), nil
159}
160
161func EncodeForward(f Forward) ([]byte, error) {
162 return abi.Encode(ForwardSchema, []any{
163 f.Path,
164 f.TimeoutHeight,
165 f.TimeoutTimestamp,
166 instructionValues(f.Instruction),
167 })
168}
169
170func DecodeForward(data []byte) (Forward, error) {
171 out, err := abi.Decode(ForwardSchema, data)
172 if err != nil {
173 return Forward{}, err
174 }
175
176 return Forward{
177 Path: out[0].(*u256.Uint),
178 TimeoutHeight: out[1].(uint64),
179 TimeoutTimestamp: out[2].(uint64),
180 Instruction: instructionFromValues(out[3].([]any)),
181 }, nil
182}
183
184func EncodeCall(c Call) ([]byte, error) {
185 return abi.Encode(CallSchema, []any{
186 c.Sender,
187 c.Eureka,
188 c.ContractAddress,
189 c.ContractCalldata,
190 })
191}
192
193func DecodeCall(data []byte) (Call, error) {
194 out, err := abi.Decode(CallSchema, data)
195 if err != nil {
196 return Call{}, err
197 }
198
199 return Call{
200 Sender: out[0].([]byte),
201 Eureka: out[1].(bool),
202 ContractAddress: out[2].([]byte),
203 ContractCalldata: out[3].([]byte),
204 }, nil
205}
206
207func EncodeBatch(b Batch) ([]byte, error) {
208 items := make([]any, len(b.Instructions))
209 for i, ins := range b.Instructions {
210 items[i] = instructionValues(ins)
211 }
212
213 return abi.Encode(BatchSchema, []any{items})
214}
215
216func DecodeBatch(data []byte) (Batch, error) {
217 out, err := abi.Decode(BatchSchema, data)
218 if err != nil {
219 return Batch{}, err
220 }
221
222 items := out[0].([]any)
223 instructions := make([]Instruction, len(items))
224
225 for i, item := range items {
226 instructions[i] = instructionFromValues(item.([]any))
227 }
228
229 return Batch{Instructions: instructions}, nil
230}
231
232func EncodeTokenOrderV1(o TokenOrderV1) ([]byte, error) {
233 return abi.Encode(TokenOrderV1Schema, []any{
234 o.Sender,
235 o.Receiver,
236 o.BaseToken,
237 o.BaseAmount,
238 o.BaseTokenSymbol,
239 o.BaseTokenName,
240 o.BaseTokenDecimals,
241 o.BaseTokenPath,
242 o.QuoteToken,
243 o.QuoteAmount,
244 })
245}
246
247func DecodeTokenOrderV1(data []byte) (TokenOrderV1, error) {
248 out, err := abi.Decode(TokenOrderV1Schema, data)
249 if err != nil {
250 return TokenOrderV1{}, err
251 }
252
253 return TokenOrderV1{
254 Sender: out[0].([]byte),
255 Receiver: out[1].([]byte),
256 BaseToken: out[2].([]byte),
257 BaseAmount: out[3].(*u256.Uint),
258 BaseTokenSymbol: out[4].(string),
259 BaseTokenName: out[5].(string),
260 BaseTokenDecimals: out[6].(uint8),
261 BaseTokenPath: out[7].(*u256.Uint),
262 QuoteToken: out[8].([]byte),
263 QuoteAmount: out[9].(*u256.Uint),
264 }, nil
265}
266
267func EncodeTokenOrderV2(o TokenOrderV2) ([]byte, error) {
268 return abi.Encode(TokenOrderV2Schema, []any{
269 o.Sender,
270 o.Receiver,
271 o.BaseToken,
272 o.BaseAmount,
273 o.QuoteToken,
274 o.QuoteAmount,
275 o.Kind,
276 o.Metadata,
277 })
278}
279
280func DecodeTokenOrderV2(data []byte) (TokenOrderV2, error) {
281 out, err := abi.Decode(TokenOrderV2Schema, data)
282 if err != nil {
283 return TokenOrderV2{}, err
284 }
285
286 return TokenOrderV2{
287 Sender: out[0].([]byte),
288 Receiver: out[1].([]byte),
289 BaseToken: out[2].([]byte),
290 BaseAmount: out[3].(*u256.Uint),
291 QuoteToken: out[4].([]byte),
292 QuoteAmount: out[5].(*u256.Uint),
293 Kind: out[6].(uint8),
294 Metadata: out[7].([]byte),
295 }, nil
296}
297
298// EncodeTokenInitializer encodes the ZkgmERC20 initialize(...) calldata
299// carried in TokenMetadata.Initializer. i.Authority/i.Minter default to the
300// zero address when nil; callers that need a real EVM authority/minter
301// (production sends targeting a real chain) set them explicitly.
302func EncodeTokenInitializer(i TokenInitializer) ([]byte, error) {
303 // Authority/Minter are EVM-only addresses (the Gno chain has no notion of
304 // either); fill with the 20-byte zero address when the caller left them nil.
305 authority := i.Authority
306 if len(authority) == 0 {
307 authority = make([]byte, 20)
308 }
309
310 minter := i.Minter
311 if len(minter) == 0 {
312 minter = make([]byte, 20)
313 }
314
315 body, err := abi.Encode(TokenInitializerSchema, []any{
316 authority,
317 minter,
318 i.Name,
319 i.Symbol,
320 i.Decimals,
321 })
322 if err != nil {
323 return nil, err
324 }
325
326 return append(append([]byte{}, tokenInitializerSelector...), body...), nil
327}
328
329// DecodeTokenInitializer decodes the ZkgmERC20 initialize(...) calldata
330// carried in TokenMetadata.Initializer, round-tripping every field encoded by
331// EncodeTokenInitializer (including Authority/Minter, which a receiving Gno
332// chain otherwise has no use for beyond display/reconstruction).
333func DecodeTokenInitializer(data []byte) (TokenInitializer, error) {
334 if len(data) < 4 || !bytes.Equal(data[:4], tokenInitializerSelector) {
335 return TokenInitializer{}, errors.New("zkgm: unrecognized token initializer selector")
336 }
337
338 out, err := abi.Decode(TokenInitializerSchema, data[4:])
339 if err != nil {
340 return TokenInitializer{}, err
341 }
342
343 return TokenInitializer{
344 Authority: out[0].([]byte),
345 Minter: out[1].([]byte),
346 Name: out[2].(string),
347 Symbol: out[3].(string),
348 Decimals: out[4].(uint8),
349 }, nil
350}
351
352func EncodeTokenMetadata(m TokenMetadata) ([]byte, error) {
353 return abi.Encode(TokenMetadataSchema, []any{
354 m.Implementation,
355 m.Initializer,
356 })
357}
358
359func DecodeTokenMetadata(data []byte) (TokenMetadata, error) {
360 out, err := abi.Decode(TokenMetadataSchema, data)
361 if err != nil {
362 return TokenMetadata{}, err
363 }
364
365 return TokenMetadata{
366 Implementation: out[0].([]byte),
367 Initializer: out[1].([]byte),
368 }, nil
369}
370
371func EncodeSolverMetadata(m SolverMetadata) ([]byte, error) {
372 return abi.Encode(SolverMetadataSchema, []any{
373 m.SolverAddress,
374 m.Metadata,
375 })
376}
377
378func DecodeSolverMetadata(data []byte) (SolverMetadata, error) {
379 out, err := abi.Decode(SolverMetadataSchema, data)
380 if err != nil {
381 return SolverMetadata{}, err
382 }
383
384 return SolverMetadata{
385 SolverAddress: out[0].([]byte),
386 Metadata: out[1].([]byte),
387 }, nil
388}
389
390func EncodeAck(a Ack) ([]byte, error) {
391 return abi.Encode(AckSchema, []any{
392 a.Tag,
393 a.InnerAck,
394 })
395}
396
397func DecodeAck(data []byte) (Ack, error) {
398 out, err := abi.Decode(AckSchema, data)
399 if err != nil {
400 return Ack{}, err
401 }
402
403 return Ack{
404 Tag: out[0].(*u256.Uint),
405 InnerAck: out[1].([]byte),
406 }, nil
407}
408
409func EncodeBatchAck(a BatchAck) ([]byte, error) {
410 items := make([]any, len(a.Acknowledgements))
411 for i, ack := range a.Acknowledgements {
412 items[i] = ack
413 }
414
415 return abi.Encode(BatchAckSchema, []any{items})
416}
417
418func DecodeBatchAck(data []byte) (BatchAck, error) {
419 out, err := abi.Decode(BatchAckSchema, data)
420 if err != nil {
421 return BatchAck{}, err
422 }
423
424 items := out[0].([]any)
425 acks := make([][]byte, len(items))
426
427 for i, item := range items {
428 acks[i] = item.([]byte)
429 }
430
431 return BatchAck{Acknowledgements: acks}, nil
432}
433
434func EncodeTokenOrderAck(a TokenOrderAck) ([]byte, error) {
435 return abi.Encode(TokenOrderAckSchema, []any{
436 a.FillType,
437 a.MarketMaker,
438 })
439}
440
441func DecodeTokenOrderAck(data []byte) (TokenOrderAck, error) {
442 out, err := abi.Decode(TokenOrderAckSchema, data)
443 if err != nil {
444 return TokenOrderAck{}, err
445 }
446
447 return TokenOrderAck{
448 FillType: out[0].(*u256.Uint),
449 MarketMaker: out[1].([]byte),
450 }, nil
451}
452
453func instructionValues(ins Instruction) []any {
454 return []any{ins.Version, ins.Opcode, ins.Operand}
455}
456
457func instructionFromValues(values []any) Instruction {
458 return Instruction{
459 Version: values[0].(uint8),
460 Opcode: values[1].(uint8),
461 Operand: values[2].([]byte),
462 }
463}