1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
//! This module provides simple utilities for loading and parsing `.contract` files in context of `drink` tests.

use std::{path::PathBuf, rc::Rc};

use contract_metadata::ContractMetadata;
use contract_transcode::ContractMessageTranscoder;

use crate::{DrinkResult, Error};

/// A struct representing the result of parsing a `.contract` bundle file.
///
/// It can be used with the following methods of the `Session` struct:
/// - `deploy_bundle`
/// - `deploy_bundle_and`
/// - `upload_bundle`
/// - `upload_bundle_and`
#[derive(Clone)]
pub struct ContractBundle {
    /// WASM blob of the contract
    pub wasm: Vec<u8>,
    /// Transcoder derived from the ABI/metadata
    pub transcoder: Rc<ContractMessageTranscoder>,
}

impl ContractBundle {
    /// Load and parse the information in a `.contract` bundle under `path`, producing a
    /// `ContractBundle` struct.
    pub fn load<P>(path: P) -> DrinkResult<Self>
    where
        P: AsRef<std::path::Path>,
    {
        let metadata: ContractMetadata = ContractMetadata::load(&path).map_err(|e| {
            Error::BundleLoadFailed(format!("Failed to load the contract file:\n{e:?}"))
        })?;

        let ink_metadata = serde_json::from_value(serde_json::Value::Object(metadata.abi))
            .map_err(|e| {
                Error::BundleLoadFailed(format!(
                    "Failed to parse metadata from the contract file:\n{e:?}"
                ))
            })?;

        let transcoder = Rc::new(ContractMessageTranscoder::new(ink_metadata));

        let wasm = metadata
            .source
            .wasm
            .ok_or(Error::BundleLoadFailed(
                "Failed to get the WASM blob from the contract file".to_string(),
            ))?
            .0;

        Ok(Self { wasm, transcoder })
    }

    /// Load the `.contract` bundle (`contract_file_name`) located in the `project_dir`` working directory.
    ///
    /// This is meant to be used predominantly by the `local_contract_file!` macro.
    pub fn local(project_dir: &str, contract_file_name: String) -> Self {
        let mut path = PathBuf::from(project_dir);
        path.push("target");
        path.push("ink");
        path.push(contract_file_name);
        Self::load(path).expect("Loading the local bundle failed")
    }
}

/// A convenience macro that allows you to load a bundle found in the target directory
/// of the current project.
#[macro_export]
macro_rules! local_contract_file {
    () => {
        drink::ContractBundle::local(
            env!("CARGO_MANIFEST_DIR"),
            env!("CARGO_CRATE_NAME").to_owned() + ".contract",
        )
    };
}