vertex_sdk/vertex_utils/
eip712_structs.rs

1#![allow(non_snake_case)]
2
3use crate::bindings::{endpoint, offchain_exchange};
4use crate::serialize_utils::{
5    deserialize_bytes20, deserialize_bytes32, deserialize_i128, deserialize_u128, deserialize_u64,
6    deserialize_vec_bytes32, serialize_bytes20, serialize_bytes32, serialize_i128, serialize_u128,
7    serialize_u64, serialize_vec_bytes32,
8};
9use ethers::prelude::*;
10use rkyv::{Archive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize};
11use serde::{Deserialize, Serialize};
12use std::fmt;
13use std::fmt::Debug;
14
15#[derive(
16    Archive,
17    RkyvDeserialize,
18    RkyvSerialize,
19    Serialize,
20    Deserialize,
21    Debug,
22    Clone,
23    Eip712,
24    EthAbiType,
25    Default,
26)]
27#[eip712()]
28#[archive(check_bytes)]
29#[allow(non_snake_case)]
30pub struct Order {
31    // #[ts(type = "string")]
32    #[serde(
33        serialize_with = "serialize_bytes32",
34        deserialize_with = "deserialize_bytes32"
35    )]
36    pub sender: [u8; 32],
37    #[serde(
38        serialize_with = "serialize_i128",
39        deserialize_with = "deserialize_i128"
40    )]
41    // #[ts(type = "BigNumberish")]
42    pub priceX18: i128,
43    #[serde(
44        serialize_with = "serialize_i128",
45        deserialize_with = "deserialize_i128"
46    )]
47    // #[ts(type = "BigNumberish")]
48    pub amount: i128, // positive: bid
49
50    // its really easy to get this mixed up because of all the bit shifts and custom encodings
51    // so we leave these private and only expose through the interface
52    #[serde(serialize_with = "serialize_u64", deserialize_with = "deserialize_u64")]
53    expiration: u64,
54    #[serde(serialize_with = "serialize_u64", deserialize_with = "deserialize_u64")]
55    nonce: u64,
56}
57
58#[derive(
59    Archive,
60    RkyvDeserialize,
61    RkyvSerialize,
62    Serialize,
63    Deserialize,
64    Debug,
65    Clone,
66    Eip712,
67    EthAbiType,
68    Default,
69)]
70#[eip712()]
71#[archive(check_bytes)]
72#[allow(non_snake_case)]
73pub struct IsolatedOrder {
74    // #[ts(type = "string")]
75    #[serde(
76        serialize_with = "serialize_bytes32",
77        deserialize_with = "deserialize_bytes32"
78    )]
79    pub sender: [u8; 32],
80    #[serde(
81        serialize_with = "serialize_i128",
82        deserialize_with = "deserialize_i128"
83    )]
84    // #[ts(type = "BigNumberish")]
85    pub priceX18: i128,
86    #[serde(
87        serialize_with = "serialize_i128",
88        deserialize_with = "deserialize_i128"
89    )]
90    // #[ts(type = "BigNumberish")]
91    pub amount: i128, // positive: bid
92    // its really easy to get this mixed up because of all the bit shifts and custom encodings
93    // so we leave these private and only expose through the interface
94    #[serde(serialize_with = "serialize_u64", deserialize_with = "deserialize_u64")]
95    expiration: u64,
96    #[serde(serialize_with = "serialize_u64", deserialize_with = "deserialize_u64")]
97    nonce: u64,
98    #[serde(
99        serialize_with = "serialize_i128",
100        deserialize_with = "deserialize_i128"
101    )]
102    pub margin: i128,
103}
104
105impl IsolatedOrder {
106    pub fn to_order(&self) -> Order {
107        Order::new(
108            self.sender,
109            self.priceX18,
110            self.amount,
111            self.expiration,
112            self.nonce,
113        )
114    }
115
116    pub fn from_binding(order: &endpoint::IsolatedOrder) -> Self {
117        Self {
118            sender: order.sender,
119            priceX18: order.price_x18,
120            amount: order.amount,
121            margin: order.margin,
122            expiration: order.expiration,
123            nonce: order.nonce,
124        }
125    }
126}
127
128#[allow(dead_code)]
129#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
130pub enum OrderType {
131    #[default]
132    Default,
133    ImmediateOrCancel,
134    FillOrKill,
135    PostOnly,
136}
137
138impl fmt::Display for OrderType {
139    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
140        match self {
141            OrderType::Default => write!(fmt, "default"),
142            OrderType::ImmediateOrCancel => write!(fmt, "ioc"),
143            OrderType::FillOrKill => write!(fmt, "fok"),
144            OrderType::PostOnly => write!(fmt, "post_only"),
145        }
146    }
147}
148
149impl OrderType {
150    pub fn taker_only(&self) -> bool {
151        match self {
152            OrderType::ImmediateOrCancel => true,
153            OrderType::FillOrKill => true,
154            _ => false,
155        }
156    }
157
158    fn expiration_bit(&self) -> u64 {
159        match self {
160            OrderType::Default => 0,
161            OrderType::ImmediateOrCancel => 1,
162            OrderType::FillOrKill => 2,
163            OrderType::PostOnly => 3,
164        }
165    }
166
167    pub fn apply_to_expiration(&self, expiration: u64) -> u64 {
168        expiration | (self.expiration_bit() << 62)
169    }
170}
171
172impl Order {
173    pub fn new(
174        sender: [u8; 32],
175        priceX18: i128,
176        amount: i128,
177        expiration: u64,
178        nonce: u64,
179    ) -> Self {
180        Self {
181            sender,
182            priceX18,
183            amount,
184            expiration,
185            nonce,
186        }
187    }
188
189    pub fn to_isolated_order_binding(&self, margin: i128) -> endpoint::IsolatedOrder {
190        endpoint::IsolatedOrder {
191            sender: self.sender,
192            price_x18: self.priceX18,
193            amount: self.amount,
194            margin,
195            expiration: self.expiration,
196            nonce: self.nonce,
197        }
198    }
199
200    pub fn to_offchain_exchange_binding(&self) -> offchain_exchange::Order {
201        offchain_exchange::Order {
202            sender: self.sender,
203            price_x18: self.priceX18,
204            amount: self.amount,
205            expiration: self.expiration,
206            nonce: self.nonce,
207        }
208    }
209
210    pub fn to_binding(&self) -> endpoint::Order {
211        endpoint::Order {
212            sender: self.sender,
213            price_x18: self.priceX18,
214            amount: self.amount,
215            expiration: self.expiration,
216            nonce: self.nonce,
217        }
218    }
219
220    pub fn to_signed_binding(&self, signature: &Bytes) -> endpoint::SignedOrder {
221        endpoint::SignedOrder {
222            order: self.to_binding(),
223            signature: signature.clone(),
224        }
225    }
226
227    pub fn to_offchain_exchange_signed_binding(
228        &self,
229        signature: &Bytes,
230    ) -> offchain_exchange::SignedOrder {
231        offchain_exchange::SignedOrder {
232            order: self.to_offchain_exchange_binding(),
233            signature: signature.clone(),
234        }
235    }
236
237    pub fn from_binding(order: &endpoint::Order) -> Self {
238        Self {
239            sender: order.sender,
240            priceX18: order.price_x18,
241            amount: order.amount,
242            expiration: order.expiration,
243            nonce: order.nonce,
244        }
245    }
246
247    pub fn raw_nonce(&self) -> u64 {
248        self.nonce
249    }
250
251    pub fn raw_expiration(&self) -> u64 {
252        self.expiration
253    }
254
255    pub fn expiration(&self) -> u64 {
256        self.expiration & ((1 << 58) - 1)
257    }
258
259    pub fn reduce_only(&self) -> bool {
260        (self.expiration & (1 << 61)) != 0
261    }
262
263    pub fn reserved_bits(&self) -> u64 {
264        (self.expiration >> 58) & ((1 << 3) - 1)
265    }
266
267    pub fn recv_time(&self) -> u64 {
268        self.nonce >> 20
269    }
270
271    pub fn is_trigger_order(&self) -> bool {
272        (self.nonce >> 63) == 1
273    }
274}
275
276#[derive(
277    Archive,
278    RkyvDeserialize,
279    RkyvSerialize,
280    Serialize,
281    Deserialize,
282    Debug,
283    Clone,
284    Eip712,
285    EthAbiType,
286)]
287#[eip712()]
288#[archive(check_bytes)]
289#[allow(non_snake_case)]
290pub struct Cancellation {
291    // #[ts(type = "string")]
292    #[serde(
293        serialize_with = "serialize_bytes32",
294        deserialize_with = "deserialize_bytes32"
295    )]
296    pub sender: [u8; 32],
297    pub productIds: Vec<u32>,
298    #[serde(
299        serialize_with = "serialize_vec_bytes32",
300        deserialize_with = "deserialize_vec_bytes32"
301    )]
302    pub digests: Vec<[u8; 32]>,
303    #[serde(serialize_with = "serialize_u64", deserialize_with = "deserialize_u64")]
304    pub nonce: u64,
305}
306
307impl Cancellation {
308    pub fn to_binding(&self) -> endpoint::Cancellation {
309        endpoint::Cancellation {
310            sender: self.sender,
311            product_ids: self.productIds.clone(),
312            digests: self.digests.clone(),
313            nonce: self.nonce,
314        }
315    }
316
317    pub fn to_signed_binding(&self, signature: &Bytes) -> endpoint::SignedCancellation {
318        endpoint::SignedCancellation {
319            cancellation: self.to_binding(),
320            signature: signature.clone(),
321        }
322    }
323
324    pub fn recv_time(&self) -> u64 {
325        self.nonce >> 20
326    }
327}
328
329#[derive(
330    Archive,
331    RkyvDeserialize,
332    RkyvSerialize,
333    Serialize,
334    Deserialize,
335    Debug,
336    Clone,
337    Eip712,
338    EthAbiType,
339)]
340#[eip712()]
341#[archive(check_bytes)]
342#[allow(non_snake_case)]
343pub struct CancellationProducts {
344    #[serde(
345        serialize_with = "serialize_bytes32",
346        deserialize_with = "deserialize_bytes32"
347    )]
348    pub sender: [u8; 32],
349    pub productIds: Vec<u32>,
350    #[serde(serialize_with = "serialize_u64", deserialize_with = "deserialize_u64")]
351    pub nonce: u64,
352}
353
354impl CancellationProducts {
355    pub fn to_binding(&self) -> endpoint::CancellationProducts {
356        endpoint::CancellationProducts {
357            sender: self.sender,
358            product_ids: self.productIds.clone(),
359            nonce: self.nonce,
360        }
361    }
362
363    pub fn to_signed_binding(&self, signature: &Bytes) -> endpoint::SignedCancellationProducts {
364        endpoint::SignedCancellationProducts {
365            cancellation_products: self.to_binding(),
366            signature: signature.clone(),
367        }
368    }
369
370    pub fn recv_time(&self) -> u64 {
371        self.nonce >> 20
372    }
373}
374
375#[derive(
376    Archive,
377    RkyvDeserialize,
378    RkyvSerialize,
379    Serialize,
380    Deserialize,
381    Debug,
382    Clone,
383    Eip712,
384    EthAbiType,
385)]
386#[eip712()]
387#[archive(check_bytes)]
388#[allow(non_snake_case)]
389pub struct LinkSigner {
390    #[serde(
391        serialize_with = "serialize_bytes32",
392        deserialize_with = "deserialize_bytes32"
393    )]
394    pub sender: [u8; 32],
395    #[serde(
396        serialize_with = "serialize_bytes32",
397        deserialize_with = "deserialize_bytes32"
398    )]
399    pub signer: [u8; 32],
400    #[serde(serialize_with = "serialize_u64", deserialize_with = "deserialize_u64")]
401    pub nonce: u64,
402}
403
404impl LinkSigner {
405    pub fn to_binding(&self) -> endpoint::LinkSigner {
406        endpoint::LinkSigner {
407            sender: self.sender,
408            signer: self.signer,
409            nonce: self.nonce,
410        }
411    }
412
413    pub fn to_signed_binding(&self, signature: &Bytes) -> endpoint::SignedLinkSigner {
414        endpoint::SignedLinkSigner {
415            tx: self.to_binding(),
416            signature: signature.clone(),
417        }
418    }
419
420    pub fn recv_time(&self) -> u64 {
421        self.nonce >> 20
422    }
423}
424
425#[derive(
426    Archive,
427    RkyvDeserialize,
428    RkyvSerialize,
429    Serialize,
430    Deserialize,
431    Debug,
432    Clone,
433    Eip712,
434    EthAbiType,
435)]
436#[eip712()]
437#[archive(check_bytes)]
438#[allow(non_snake_case)]
439pub struct LiquidateSubaccount {
440    // #[ts(type = "string")]
441    #[serde(
442        serialize_with = "serialize_bytes32",
443        deserialize_with = "deserialize_bytes32"
444    )]
445    pub sender: [u8; 32],
446    #[serde(
447        serialize_with = "serialize_bytes32",
448        deserialize_with = "deserialize_bytes32"
449    )]
450    pub liquidatee: [u8; 32],
451    pub productId: u32,
452    pub isEncodedSpread: bool,
453    #[serde(
454        serialize_with = "serialize_i128",
455        deserialize_with = "deserialize_i128"
456    )]
457    // #[ts(type = "BigNumberish")]
458    pub amount: i128,
459    #[serde(serialize_with = "serialize_u64", deserialize_with = "deserialize_u64")]
460    pub nonce: u64,
461}
462
463impl LiquidateSubaccount {
464    pub fn to_binding(&self) -> endpoint::LiquidateSubaccount {
465        endpoint::LiquidateSubaccount {
466            sender: self.sender,
467            liquidatee: self.liquidatee,
468            product_id: self.productId,
469            is_encoded_spread: self.isEncodedSpread,
470            amount: self.amount,
471            nonce: self.nonce,
472        }
473    }
474}
475
476#[derive(
477    Archive,
478    RkyvDeserialize,
479    RkyvSerialize,
480    Serialize,
481    Deserialize,
482    Debug,
483    Clone,
484    Eip712,
485    EthAbiType,
486)]
487#[eip712()]
488#[archive(check_bytes)]
489#[allow(non_snake_case)]
490pub struct WithdrawCollateral {
491    // #[ts(type = "string")]
492    #[serde(
493        serialize_with = "serialize_bytes32",
494        deserialize_with = "deserialize_bytes32"
495    )]
496    pub sender: [u8; 32],
497    pub productId: u32,
498    #[serde(
499        serialize_with = "serialize_u128",
500        deserialize_with = "deserialize_u128"
501    )]
502    // #[ts(type = "BigNumberish")]
503    pub amount: u128,
504    #[serde(serialize_with = "serialize_u64", deserialize_with = "deserialize_u64")]
505    pub nonce: u64,
506}
507
508impl WithdrawCollateral {
509    pub fn to_binding(&self) -> endpoint::WithdrawCollateral {
510        endpoint::WithdrawCollateral {
511            sender: self.sender,
512            product_id: self.productId,
513            amount: self.amount,
514            nonce: self.nonce,
515        }
516    }
517}
518
519#[derive(
520    Archive,
521    RkyvDeserialize,
522    RkyvSerialize,
523    Serialize,
524    Deserialize,
525    Debug,
526    Clone,
527    Eip712,
528    EthAbiType,
529)]
530#[eip712()]
531#[archive(check_bytes)]
532#[allow(non_snake_case)]
533pub struct MintLp {
534    // #[ts(type = "typestring")]
535    #[serde(
536        serialize_with = "serialize_bytes32",
537        deserialize_with = "deserialize_bytes32"
538    )]
539    pub sender: [u8; 32],
540    pub productId: u32,
541    #[serde(
542        serialize_with = "serialize_u128",
543        deserialize_with = "deserialize_u128"
544    )]
545    // #[ts(type = "BigNumberish")]
546    pub amountBase: u128,
547    #[serde(
548        serialize_with = "serialize_u128",
549        deserialize_with = "deserialize_u128"
550    )]
551    // #[ts(type = "BigNumberish")]
552    pub quoteAmountLow: u128,
553    #[serde(
554        serialize_with = "serialize_u128",
555        deserialize_with = "deserialize_u128"
556    )]
557    // #[ts(type = "BigNumberish")]
558    pub quoteAmountHigh: u128,
559    #[serde(serialize_with = "serialize_u64", deserialize_with = "deserialize_u64")]
560    pub nonce: u64,
561}
562
563impl MintLp {
564    pub fn to_binding(&self) -> endpoint::MintLp {
565        endpoint::MintLp {
566            sender: self.sender,
567            product_id: self.productId,
568            amount_base: self.amountBase,
569            quote_amount_low: self.quoteAmountLow,
570            quote_amount_high: self.quoteAmountHigh,
571            nonce: self.nonce,
572        }
573    }
574}
575
576#[derive(
577    Archive,
578    RkyvDeserialize,
579    RkyvSerialize,
580    Serialize,
581    Deserialize,
582    Debug,
583    Clone,
584    Eip712,
585    EthAbiType,
586)]
587#[eip712()]
588#[archive(check_bytes)]
589#[allow(non_snake_case)]
590pub struct BurnLp {
591    // #[ts(type = "string")]
592    #[serde(
593        serialize_with = "serialize_bytes32",
594        deserialize_with = "deserialize_bytes32"
595    )]
596    pub sender: [u8; 32],
597    pub productId: u32,
598    #[serde(
599        serialize_with = "serialize_u128",
600        deserialize_with = "deserialize_u128"
601    )]
602    // #[ts(type = "BigNumberish")]
603    pub amount: u128,
604    #[serde(serialize_with = "serialize_u64", deserialize_with = "deserialize_u64")]
605    pub nonce: u64,
606}
607
608impl BurnLp {
609    pub fn to_binding(&self) -> endpoint::BurnLp {
610        endpoint::BurnLp {
611            sender: self.sender,
612            product_id: self.productId,
613            amount: self.amount,
614            nonce: self.nonce,
615        }
616    }
617}
618
619#[derive(
620    Archive,
621    RkyvDeserialize,
622    RkyvSerialize,
623    Serialize,
624    Deserialize,
625    Debug,
626    Clone,
627    Eip712,
628    EthAbiType,
629)]
630#[eip712()]
631#[archive(check_bytes)]
632#[allow(non_snake_case)]
633pub struct MintVlp {
634    // #[ts(type = "typestring")]
635    #[serde(
636        serialize_with = "serialize_bytes32",
637        deserialize_with = "deserialize_bytes32"
638    )]
639    pub sender: [u8; 32],
640    #[serde(
641        serialize_with = "serialize_u128",
642        deserialize_with = "deserialize_u128"
643    )]
644    // #[ts(type = "BigNumberish")]
645    pub quoteAmount: u128,
646    #[serde(serialize_with = "serialize_u64", deserialize_with = "deserialize_u64")]
647    pub nonce: u64,
648}
649
650impl MintVlp {
651    pub fn to_binding(&self) -> endpoint::MintVlp {
652        endpoint::MintVlp {
653            sender: self.sender,
654            quote_amount: self.quoteAmount,
655            nonce: self.nonce,
656        }
657    }
658}
659
660#[derive(
661    Archive,
662    RkyvDeserialize,
663    RkyvSerialize,
664    Serialize,
665    Deserialize,
666    Debug,
667    Clone,
668    Eip712,
669    EthAbiType,
670)]
671#[eip712()]
672#[archive(check_bytes)]
673#[allow(non_snake_case)]
674pub struct BurnVlp {
675    // #[ts(type = "typestring")]
676    #[serde(
677        serialize_with = "serialize_bytes32",
678        deserialize_with = "deserialize_bytes32"
679    )]
680    pub sender: [u8; 32],
681    #[serde(
682        serialize_with = "serialize_u128",
683        deserialize_with = "deserialize_u128"
684    )]
685    // #[ts(type = "BigNumberish")]
686    pub vlpAmount: u128,
687    #[serde(serialize_with = "serialize_u64", deserialize_with = "deserialize_u64")]
688    pub nonce: u64,
689}
690
691impl BurnVlp {
692    pub fn to_binding(&self) -> endpoint::BurnVlp {
693        endpoint::BurnVlp {
694            sender: self.sender,
695            vlp_amount: self.vlpAmount,
696            nonce: self.nonce,
697        }
698    }
699}
700
701#[derive(
702    Archive,
703    RkyvDeserialize,
704    RkyvSerialize,
705    Serialize,
706    Deserialize,
707    Debug,
708    Clone,
709    Eip712,
710    EthAbiType,
711)]
712#[eip712()]
713#[archive(check_bytes)]
714#[allow(non_snake_case)]
715pub struct TransferQuote {
716    // #[ts(type = "string")]
717    #[serde(
718        serialize_with = "serialize_bytes32",
719        deserialize_with = "deserialize_bytes32"
720    )]
721    pub sender: [u8; 32],
722    #[serde(
723        serialize_with = "serialize_bytes32",
724        deserialize_with = "deserialize_bytes32"
725    )]
726    pub recipient: [u8; 32],
727    #[serde(
728        serialize_with = "serialize_u128",
729        deserialize_with = "deserialize_u128"
730    )]
731    // #[ts(type = "BigNumberish")]
732    pub amount: u128,
733    #[serde(serialize_with = "serialize_u64", deserialize_with = "deserialize_u64")]
734    pub nonce: u64,
735}
736
737impl TransferQuote {
738    pub fn to_binding(&self) -> endpoint::TransferQuote {
739        endpoint::TransferQuote {
740            sender: self.sender,
741            recipient: self.recipient,
742            amount: self.amount,
743            nonce: self.nonce,
744        }
745    }
746}
747
748#[derive(
749    Serialize,
750    Deserialize,
751    Clone,
752    Debug,
753    Default,
754    Eq,
755    PartialEq,
756    Eip712,
757    ethers :: contract :: EthAbiType,
758    ethers :: contract :: EthAbiCodec,
759)]
760#[eip712()]
761#[allow(non_snake_case)]
762pub struct ListTriggerOrders {
763    #[serde(
764        serialize_with = "serialize_bytes32",
765        deserialize_with = "deserialize_bytes32"
766    )]
767    pub sender: [u8; 32],
768    #[serde(serialize_with = "serialize_u64", deserialize_with = "deserialize_u64")]
769    pub recvTime: u64,
770}
771
772#[derive(
773    Serialize,
774    Deserialize,
775    Clone,
776    Debug,
777    Default,
778    Eq,
779    PartialEq,
780    ethers :: contract :: EthAbiType,
781    ethers :: contract :: EthAbiCodec,
782)]
783pub struct SignedListTriggerOrders {
784    pub tx: ListTriggerOrders,
785    pub signature: ethers::core::types::Bytes,
786}
787
788#[derive(
789    Serialize,
790    Deserialize,
791    Clone,
792    Debug,
793    Default,
794    Eq,
795    PartialEq,
796    Eip712,
797    ethers :: contract :: EthAbiType,
798    ethers :: contract :: EthAbiCodec,
799)]
800#[eip712()]
801#[allow(non_snake_case)]
802pub struct StreamAuthentication {
803    #[serde(
804        serialize_with = "serialize_bytes32",
805        deserialize_with = "deserialize_bytes32"
806    )]
807    pub sender: [u8; 32],
808    #[serde(serialize_with = "serialize_u64", deserialize_with = "deserialize_u64")]
809    pub expiration: u64,
810}
811
812#[derive(
813    Serialize,
814    Deserialize,
815    Clone,
816    Debug,
817    Default,
818    Eq,
819    PartialEq,
820    Eip712,
821    ethers :: contract :: EthAbiType,
822    ethers :: contract :: EthAbiCodec,
823)]
824#[eip712()]
825#[allow(non_snake_case)]
826pub struct TaskAuthentication {
827    #[serde(
828        serialize_with = "serialize_bytes20",
829        deserialize_with = "deserialize_bytes20"
830    )]
831    pub sender: [u8; 20],
832    #[serde(serialize_with = "serialize_u64", deserialize_with = "deserialize_u64")]
833    pub expiration: u64,
834}
835
836#[derive(
837    Serialize,
838    Deserialize,
839    Clone,
840    Debug,
841    Default,
842    Eq,
843    PartialEq,
844    Eip712,
845    ethers :: contract :: EthAbiType,
846    ethers :: contract :: EthAbiCodec,
847)]
848#[eip712()]
849#[allow(non_snake_case)]
850pub struct LeaderboardAuthentication {
851    #[serde(
852        serialize_with = "serialize_bytes32",
853        deserialize_with = "deserialize_bytes32"
854    )]
855    pub sender: [u8; 32],
856    #[serde(serialize_with = "serialize_u64", deserialize_with = "deserialize_u64")]
857    pub expiration: u64,
858}
859
860pub fn to_bytes12(s: &str) -> [u8; 12] {
861    let b = s.as_bytes();
862    let mut out = [0u8; 12];
863    let n = std::cmp::min(b.len(), 12);
864    out[..n].copy_from_slice(&b[..n]);
865    out
866}
867
868pub fn to_bytes32(address: H160, name: &str) -> [u8; 32] {
869    concat_to_bytes32(address.into(), to_bytes12(name))
870}
871
872pub fn concat_to_bytes32(address: [u8; 20], name: [u8; 12]) -> [u8; 32] {
873    let mut ret = [0; 32];
874    ret[..20].clone_from_slice(&address);
875    ret[20..].clone_from_slice(&name);
876    ret
877}
878
879pub fn from_bytes32(b: [u8; 32]) -> (H160, String) {
880    (
881        H160::from_slice(&b[..20]),
882        from_bytes12(b[20..].try_into().unwrap()),
883    )
884}
885
886pub fn from_bytes12(b: [u8; 12]) -> String {
887    String::from_utf8(b.to_vec()).unwrap()
888}