git.delta.rocks / unique-network / refs/commits / 2d71e7a206db

difftreelog

source

pallets/nft/src/eth/abi.rs4.7 KiBsourcehistory
1//! TODO: I misunterstood therminology, abi IS rlp encoded, so2//! this module should be replaced with rlp crate34use sp_core::H160;56#[cfg(feature = "std")]7use std;8#[cfg(not(feature = "std"))]9use sp_std as std;1011use std::vec::Vec;1213const ABI_ALIGNMENT: usize = 32;1415type Result<T> = std::result::Result<T, &'static str>;1617pub struct AbiReader<'i> {18	buf: &'i [u8],19	offset: usize,20}21impl<'i> AbiReader<'i> {22	pub fn new_call(buf: &'i [u8]) -> Result<(u32, Self)> {23		if buf.len() < 4 {24			return Err("missing method id")25		}26		let mut method_id = [0; 4];27		method_id.copy_from_slice(&buf[0..4]);2829		Ok((u32::from_be_bytes(method_id), Self {30			buf,31			offset: 4,32		}))33	}3435	fn read_padleft<const S: usize>(&mut self) -> Result<[u8; S]> {36		if self.buf.len() - self.offset < 32 {37			return Err("missing padding")38		}39		let mut block = [0; S];40		// Verify padding is empty41		if !self.buf[self.offset..self.offset + ABI_ALIGNMENT - S].iter().all(|&v| v == 0) {42			return Err("non zero padding (wrong types?)")43		}44		block.copy_from_slice(&self.buf[self.offset + ABI_ALIGNMENT - S..self.offset + ABI_ALIGNMENT]);45		self.offset += ABI_ALIGNMENT;46		Ok(block)47	}4849	pub fn address(&mut self) -> Result<H160> {50		Ok(H160(self.read_padleft()?))51	}5253	pub fn uint32(&mut self) -> Result<u32> {54		Ok(u32::from_be_bytes(self.read_padleft()?))55	}5657	pub fn uint128(&mut self) -> Result<u128> {58		Ok(u128::from_be_bytes(self.read_padleft()?))59	}6061	pub fn uint256(&mut self) -> Result<u128> {62		self.uint128()63	}6465	pub fn uint64(&mut self) -> Result<usize> {66		Ok(usize::from_be_bytes(self.read_padleft()?))67	}68	69	fn subresult(&mut self) -> Result<AbiReader<'i>> {70		let offset = self.uint64()?;71		if offset > usize::MAX {72			return Err("subresult overflow");73		}74		Ok(AbiReader {75			buf: &self.buf,76			offset: offset + self.offset,77		})78	}7980	pub fn is_finished(&self) -> bool {81		self.buf.len() == self.offset82	}83}8485pub struct AbiWriter {86	static_part: Vec<u8>,87	dynamic_part: Vec<(usize, AbiWriter)>,88}89impl AbiWriter {90	pub fn new() -> Self {91		Self {92			static_part: Vec::new(),93			dynamic_part: Vec::new(),94		}95	}96	pub fn new_call(method_id: u32) -> Self {97		let mut val = Self::new();98		val.static_part.extend(&method_id.to_be_bytes());99		val100	}101102	fn write_padleft(&mut self, block: &[u8]) {103		assert!(block.len() <= ABI_ALIGNMENT);104		self.static_part.extend(&[0; ABI_ALIGNMENT][0..ABI_ALIGNMENT - block.len()]);105		self.static_part.extend(block);106	}107108	fn write_padright(&mut self, bytes: &[u8]) {109		assert!(bytes.len() <= ABI_ALIGNMENT);110		self.static_part.extend(bytes);111		self.static_part.extend(&[0; ABI_ALIGNMENT][0..ABI_ALIGNMENT - bytes.len()]);112	}113114	pub fn address(&mut self, address: H160) {115		self.write_padleft(&address.0)	116	}117118	pub fn bool(&mut self, value: bool) {119		self.write_padleft(&[if value { 1 } else { 0 }])120	}121122	pub fn uint8(&mut self, value: u8) {123		self.write_padleft(&[value])124	}125126	pub fn uint128(&mut self, value: u128) {127		self.write_padleft(&u128::to_be_bytes(value))128	}129	130	/// This method writes u128, and exists only for convenience, because there is131	/// no u256 support in rust132	pub fn uint256(&mut self, value: u128) {133		self.uint128(value)134	}135136	pub fn write_usize(&mut self, value: usize) {137		self.write_padleft(&usize::to_be_bytes(value))138	}139140	pub fn write_u8(&mut self, value: u8) {141		self.write_padleft(&[value])142	}143144	pub fn write_subresult(&mut self, result: Self) {145		self.dynamic_part.push((self.static_part.len(), result));146		// Empty block, to be filled later147		self.write_padleft(&[]);148	}149150	pub fn memory(&mut self, value: &[u8]) {151		let mut sub = Self::new();152		sub.write_usize(value.len());153		for chunk in value.chunks(ABI_ALIGNMENT) {154			sub.write_padright(chunk);155		}156		self.write_subresult(sub);157	}158159	pub fn string(&mut self, value: &str) {160		self.memory(value.as_bytes())161	}162163	pub fn finish(mut self) -> Vec<u8> {164		for (static_offset, part) in self.dynamic_part {165			let part_offset = self.static_part.len();166167			let encoded_dynamic_offset = usize::to_be_bytes(part_offset - static_offset);168			self.static_part169				[static_offset + ABI_ALIGNMENT - encoded_dynamic_offset.len()..static_offset + ABI_ALIGNMENT]170				.copy_from_slice(&encoded_dynamic_offset);171			self.static_part.extend(part.finish())172		}173		self.static_part174	}175}176177#[macro_export]178macro_rules! abi_decode {179	($reader:expr, $($name:ident: $typ:ident),+ $(,)?) => {180		$(181			let $name = $reader.$typ()?;182		)+183	}184}185186#[macro_export]187macro_rules! abi_encode {188	($($typ:ident($value:expr)),* $(,)?) => {{189		#[allow(unused_mut)]190		let mut writer = crate::eth::abi::AbiWriter::new();191		$(192			writer.$typ($value);193		)*194		writer195	}};196	(call $val:expr; $($typ:ident($value:expr)),* $(,)?) => {{197		#[allow(unused_mut)]198		let mut writer = AbiWriter::new_call($val);199		$(200			writer.$typ($value);201		)*202		writer203	}}204}