::Hash, _>(env_types::Hash)
@@ -138,6 +160,35 @@ impl<'a> ContractMessageTranscoder<'a> {
}
}
+ /// Attempt to create a [`ContractMessageTranscoder`] from the metadata file at the given path.
+ pub fn load(metadata_path: P) -> Result
+ where
+ P: AsRef,
+ {
+ let path = metadata_path.as_ref();
+ let file = File::open(path)
+ .context(format!("Failed to open metadata file {}", path.display()))?;
+ let metadata: contract_metadata::ContractMetadata = serde_json::from_reader(file)
+ .context(format!(
+ "Failed to deserialize metadata file {}",
+ path.display()
+ ))?;
+ let ink_metadata = serde_json::from_value(serde_json::Value::Object(
+ metadata.abi,
+ ))
+ .context(format!(
+ "Failed to deserialize ink project metadata from file {}",
+ path.display()
+ ))?;
+ if let ink_metadata::MetadataVersioned::V3(ink_project) = ink_metadata {
+ Ok(Self::new(ink_project))
+ } else {
+ Err(anyhow::anyhow!(
+ "Unsupported ink metadata version. Expected V1"
+ ))
+ }
+ }
+
pub fn encode(&self, name: &str, args: I) -> Result>
where
I: IntoIterator- ,
@@ -166,12 +217,21 @@ impl<'a> ContractMessageTranscoder<'a> {
let mut encoded = selector.to_bytes().to_vec();
for (spec, arg) in spec_args.iter().zip(args) {
let value = scon::parse_value(arg.as_ref())?;
- self.transcoder
- .encode(spec.ty().ty().id(), &value, &mut encoded)?;
+ self.transcoder.encode(
+ self.metadata.registry(),
+ spec.ty().ty().id(),
+ &value,
+ &mut encoded,
+ )?;
}
Ok(encoded)
}
+ pub fn decode(&self, type_id: u32, input: &mut &[u8]) -> Result {
+ self.transcoder
+ .decode(self.metadata.registry(), type_id, input)
+ }
+
fn constructors(&self) -> impl Iterator
- > {
self.metadata.spec().constructors().iter()
}
@@ -213,7 +273,7 @@ impl<'a> ContractMessageTranscoder<'a> {
let mut args = Vec::new();
for arg in event_spec.args() {
let name = arg.label().to_string();
- let value = self.transcoder.decode(arg.ty().ty().id(), data)?;
+ let value = self.decode(arg.ty().ty().id(), data)?;
args.push((Value::String(name), value));
}
@@ -240,7 +300,7 @@ impl<'a> ContractMessageTranscoder<'a> {
let mut args = Vec::new();
for arg in msg_spec.args() {
let name = arg.label().to_string();
- let value = self.transcoder.decode(arg.ty().ty().id(), data)?;
+ let value = self.decode(arg.ty().ty().id(), data)?;
args.push((Value::String(name), value));
}
@@ -267,7 +327,7 @@ impl<'a> ContractMessageTranscoder<'a> {
let mut args = Vec::new();
for arg in msg_spec.args() {
let name = arg.label().to_string();
- let value = self.transcoder.decode(arg.ty().ty().id(), data)?;
+ let value = self.decode(arg.ty().ty().id(), data)?;
args.push((Value::String(name), value));
}
@@ -282,7 +342,7 @@ impl<'a> ContractMessageTranscoder<'a> {
anyhow::anyhow!("Failed to find message spec with name '{}'", name)
})?;
if let Some(return_ty) = msg_spec.return_type().opt_type() {
- self.transcoder.decode(return_ty.ty().id(), data)
+ self.decode(return_ty.ty().id(), data)
} else {
Ok(Value::Unit)
}
@@ -434,7 +494,7 @@ mod tests {
#[test]
fn encode_single_primitive_arg() -> Result<()> {
let metadata = generate_metadata();
- let transcoder = ContractMessageTranscoder::new(&metadata);
+ let transcoder = ContractMessageTranscoder::new(metadata);
let encoded = transcoder.encode("new", &["true"])?;
// encoded args follow the 4 byte selector
@@ -447,7 +507,7 @@ mod tests {
#[test]
fn encode_account_id_custom_ss58_encoding() -> Result<()> {
let metadata = generate_metadata();
- let transcoder = ContractMessageTranscoder::new(&metadata);
+ let transcoder = ContractMessageTranscoder::new(metadata);
let encoded = transcoder.encode(
"set_account_id",
@@ -468,7 +528,7 @@ mod tests {
#[test]
fn encode_account_ids_vec_args() -> Result<()> {
let metadata = generate_metadata();
- let transcoder = ContractMessageTranscoder::new(&metadata);
+ let transcoder = ContractMessageTranscoder::new(metadata);
let encoded = transcoder.encode(
"set_account_ids_vec",
@@ -495,7 +555,7 @@ mod tests {
#[test]
fn encode_primitive_vec_args() -> Result<()> {
let metadata = generate_metadata();
- let transcoder = ContractMessageTranscoder::new(&metadata);
+ let transcoder = ContractMessageTranscoder::new(metadata);
let encoded = transcoder.encode("primitive_vec_args", &["[1, 2]"])?;
@@ -510,7 +570,7 @@ mod tests {
#[test]
fn encode_uint_hex_literals() -> Result<()> {
let metadata = generate_metadata();
- let transcoder = ContractMessageTranscoder::new(&metadata);
+ let transcoder = ContractMessageTranscoder::new(metadata);
let encoded = transcoder.encode(
"uint_args",
@@ -540,7 +600,7 @@ mod tests {
#[test]
fn encode_uint_arr_hex_literals() -> Result<()> {
let metadata = generate_metadata();
- let transcoder = ContractMessageTranscoder::new(&metadata);
+ let transcoder = ContractMessageTranscoder::new(metadata);
let encoded =
transcoder.encode("uint_array_args", &["[0xDE, 0xAD, 0xBE, 0xEF]"])?;
@@ -556,7 +616,7 @@ mod tests {
#[test]
fn decode_primitive_return() -> Result<()> {
let metadata = generate_metadata();
- let transcoder = ContractMessageTranscoder::new(&metadata);
+ let transcoder = ContractMessageTranscoder::new(metadata);
let encoded = true.encode();
let decoded = transcoder.decode_return("get", &mut &encoded[..])?;
@@ -568,7 +628,7 @@ mod tests {
#[test]
fn decode_contract_event() -> Result<()> {
let metadata = generate_metadata();
- let transcoder = ContractMessageTranscoder::new(&metadata);
+ let transcoder = ContractMessageTranscoder::new(metadata);
// raw encoded event with event index prefix
let encoded = (0u8, [0u32; 32], [1u32; 32]).encode();
@@ -582,7 +642,7 @@ mod tests {
#[test]
fn decode_hash_as_hex_encoded_string() -> Result<()> {
let metadata = generate_metadata();
- let transcoder = ContractMessageTranscoder::new(&metadata);
+ let transcoder = ContractMessageTranscoder::new(metadata);
let hash = [
52u8, 40, 235, 225, 70, 245, 184, 36, 21, 218, 130, 114, 75, 207, 117, 240,
@@ -615,7 +675,7 @@ mod tests {
#[test]
fn decode_contract_message() -> Result<()> {
let metadata = generate_metadata();
- let transcoder = ContractMessageTranscoder::new(&metadata);
+ let transcoder = ContractMessageTranscoder::new(metadata);
let encoded_bytes = hex::decode("633aa551").unwrap();
let _ = transcoder.decode_contract_message(&mut &encoded_bytes[..])?;
diff --git a/transcode/src/transcoder.rs b/transcode/src/transcoder.rs
index a64775fc3..d72074de3 100644
--- a/transcode/src/transcoder.rs
+++ b/transcode/src/transcoder.rs
@@ -41,56 +41,55 @@ use std::{
/// Encode strings to SCALE encoded output.
/// Decode SCALE encoded input into `Value` objects.
-pub struct Transcoder<'a> {
- registry: &'a PortableRegistry,
+pub struct Transcoder {
env_types: EnvTypesTranscoder,
}
-impl<'a> Transcoder<'a> {
- pub fn new(registry: &'a PortableRegistry, env_types: EnvTypesTranscoder) -> Self {
- Self {
- registry,
- env_types,
- }
- }
-
- pub fn encoder(&self) -> Encoder {
- Encoder::new(self.registry, &self.env_types)
+impl Transcoder {
+ pub fn new(env_types: EnvTypesTranscoder) -> Self {
+ Self { env_types }
}
- pub fn encode(&self, type_id: u32, value: &Value, output: &mut O) -> Result<()>
+ pub fn encode(
+ &self,
+ registry: &PortableRegistry,
+ type_id: u32,
+ value: &Value,
+ output: &mut O,
+ ) -> Result<()>
where
O: Output + Debug,
{
- self.encoder().encode(type_id, value, output)
- }
-
- pub fn decoder(&self) -> Decoder {
- Decoder::new(self.registry, &self.env_types)
+ let encoder = Encoder::new(registry, &self.env_types);
+ encoder.encode(type_id, value, output)
}
- pub fn decode(&self, type_id: u32, input: &mut &[u8]) -> Result {
- self.decoder().decode(type_id, input)
+ pub fn decode(
+ &self,
+ registry: &PortableRegistry,
+ type_id: u32,
+ input: &mut &[u8],
+ ) -> Result {
+ let decoder = Decoder::new(registry, &self.env_types);
+ decoder.decode(type_id, input)
}
}
/// Construct a [`Transcoder`], allows registering custom transcoders for certain types.
-pub struct TranscoderBuilder<'a> {
- registry: &'a PortableRegistry,
+pub struct TranscoderBuilder {
types_by_path: TypesByPath,
encoders: HashMap>,
decoders: HashMap>,
}
-impl<'a> TranscoderBuilder<'a> {
- pub fn new(registry: &'a PortableRegistry) -> Self {
+impl TranscoderBuilder {
+ pub fn new(registry: &PortableRegistry) -> Self {
let types_by_path = registry
.types()
.iter()
.map(|ty| (PathKey::from(ty.ty().path()), ty.id()))
.collect::();
Self {
- registry,
types_by_path,
encoders: HashMap::new(),
decoders: HashMap::new(),
@@ -171,9 +170,9 @@ impl<'a> TranscoderBuilder<'a> {
this
}
- pub fn done(self) -> Transcoder<'a> {
+ pub fn done(self) -> Transcoder {
let env_types_transcoder = EnvTypesTranscoder::new(self.encoders, self.decoders);
- Transcoder::new(self.registry, env_types_transcoder)
+ Transcoder::new(env_types_transcoder)
}
}
@@ -221,8 +220,8 @@ mod tests {
let value = scon::parse_value(input)?;
let mut output = Vec::new();
- transcoder.encode(ty, &value, &mut output)?;
- let decoded = transcoder.decode(ty, &mut &output[..])?;
+ transcoder.encode(®istry, ty, &value, &mut output)?;
+ let decoded = transcoder.decode(®istry, ty, &mut &output[..])?;
assert_eq!(expected_output, decoded, "decoding");
Ok(())
}
@@ -236,13 +235,13 @@ mod tests {
#[test]
fn transcode_char_unsupported() -> Result<()> {
let (registry, ty) = registry_with_type::()?;
- let transcoder = Transcoder::new(®istry, Default::default());
+ let transcoder = Transcoder::new(Default::default());
let encoded = u32::from('c').encode();
assert!(transcoder
- .encode(ty, &Value::Char('c'), &mut Vec::new())
+ .encode(®istry, ty, &Value::Char('c'), &mut Vec::new())
.is_err());
- assert!(transcoder.decode(ty, &mut &encoded[..]).is_err());
+ assert!(transcoder.decode(®istry, ty, &mut &encoded[..]).is_err());
Ok(())
}