ink_primitives/
abi.rs

1// Copyright (C) ink! contributors.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Abstractions for ABI representation and encoding/decoding.
16
17use ink_prelude::vec::Vec;
18
19use crate::sol::{
20    SolDecode,
21    SolEncode,
22};
23
24/// ABI spec for encoding/decoding contract calls.
25#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
26pub enum Abi {
27    /// ink! ABI spec (uses Parity's SCALE codec for input/output encode/decode).
28    Ink,
29    /// Solidity ABI encoding.
30    Sol,
31}
32
33/// Marker type for ink! ABI and SCALE encoding.
34///
35/// Used with [`AbiEncodeWith`], [`AbiDecodeWith`] and `DecodeMessageResult`.
36#[derive(Debug, Default, Clone, Copy)]
37pub struct Ink;
38
39/// Marker type for Solidity ABI.
40///
41/// Used with [`AbiEncodeWith`], [`AbiDecodeWith`] and `DecodeMessageResult`.
42#[derive(Debug, Default, Clone, Copy)]
43pub struct Sol;
44
45/// Trait for ABI-specific encoding with support for both slice and vector buffers.
46pub trait AbiEncodeWith<Abi> {
47    /// Encodes the data into a new vector.
48    fn encode_with(&self) -> Vec<u8>;
49
50    /// Encodes the data into a fixed-size buffer, returning the number of bytes written.
51    fn encode_to_slice(&self, buffer: &mut [u8]) -> usize;
52
53    /// Encodes the data into a dynamically resizing vector.
54    fn encode_to_vec(&self, buffer: &mut Vec<u8>);
55
56    /// Encodes the value as a topic (i.e. an indexed event parameter).
57    ///
58    /// # Note
59    ///
60    /// The provided hashing function depends on the ABI i.e.
61    /// - BLAKE2b for ink! ABI
62    /// - Keccak-256 for Solidity ABI
63    fn encode_topic<H>(&self, hasher: H) -> [u8; 32]
64    where
65        H: Fn(&[u8], &mut [u8; 32]);
66}
67
68/// Trait for ABI-specific decoding.
69pub trait AbiDecodeWith<Abi>: Sized {
70    /// The error type that can occur during decoding.
71    type Error: core::fmt::Debug;
72    /// Decodes the data from a buffer using the provided ABI.
73    fn decode_with(buffer: &[u8]) -> Result<Self, Self::Error>;
74}
75
76impl<T: scale::Encode> AbiEncodeWith<Ink> for T {
77    fn encode_with(&self) -> Vec<u8> {
78        scale::Encode::encode(self)
79    }
80
81    fn encode_to_slice(&self, buffer: &mut [u8]) -> usize {
82        let encoded = scale::Encode::encode(self);
83        let len = encoded.len();
84        debug_assert!(
85            len <= buffer.len(),
86            "encode scope buffer overflowed, encoded len is {} but buffer len is {}",
87            len,
88            buffer.len()
89        );
90        buffer[..len].copy_from_slice(&encoded);
91        len
92    }
93
94    fn encode_to_vec(&self, buffer: &mut Vec<u8>) {
95        scale::Encode::encode_to(self, buffer);
96    }
97
98    fn encode_topic<H>(&self, hasher: H) -> [u8; 32]
99    where
100        H: Fn(&[u8], &mut [u8; 32]),
101    {
102        let encoded = scale::Encode::encode(self);
103        let len = encoded.len();
104        let mut output = [0u8; 32];
105        if encoded.len() <= 32 {
106            output.as_mut()[0..len].copy_from_slice(&encoded);
107        } else {
108            hasher(&encoded, &mut output);
109        }
110        output
111    }
112}
113
114impl<T: scale::Decode> AbiDecodeWith<Ink> for T {
115    type Error = scale::Error;
116    fn decode_with(buffer: &[u8]) -> Result<Self, Self::Error> {
117        scale::Decode::decode(&mut &buffer[..])
118    }
119}
120
121impl<T> AbiEncodeWith<Sol> for T
122where
123    T: for<'a> SolEncode<'a>,
124{
125    fn encode_with(&self) -> Vec<u8> {
126        SolEncode::encode(self)
127    }
128
129    fn encode_to_slice(&self, buffer: &mut [u8]) -> usize {
130        let encoded = SolEncode::encode(self);
131        let len = encoded.len();
132        debug_assert!(
133            len <= buffer.len(),
134            "encode scope buffer overflowed, encoded len is {} but buffer len is {}",
135            len,
136            buffer.len()
137        );
138        buffer[..len].copy_from_slice(&encoded);
139        len
140    }
141
142    fn encode_to_vec(&self, buffer: &mut Vec<u8>) {
143        buffer.extend_from_slice(&T::encode(self));
144    }
145
146    fn encode_topic<H>(&self, hasher: H) -> [u8; 32]
147    where
148        H: Fn(&[u8], &mut [u8; 32]),
149    {
150        SolEncode::encode_topic(self, hasher)
151    }
152}
153
154impl<T: SolDecode> AbiDecodeWith<Sol> for T {
155    type Error = crate::sol::Error;
156    fn decode_with(buffer: &[u8]) -> Result<Self, Self::Error> {
157        T::decode(buffer)
158    }
159}