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
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
/*
 * Copyright 2018-2019 TON DEV SOLUTIONS LTD.
 *
 * Licensed under the SOFTWARE EVALUATION License (the "License"); you may not use
 * this file except in compliance with the License.  You may obtain a copy of the
 * License at: https://ton.dev/licenses
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific TON DEV software governing permissions and
 * limitations under the License.
 */

use crate::{Ed25519KeyPair, TonResult, TonError, TonAddress};
use serde_json::Value;
use crate::interop::{InteropContext, Interop};

#[derive(Serialize)]
#[allow(non_snake_case)]
pub(crate) struct ParamsOfDeploy {
    pub abi: serde_json::Value,
    pub constructorParams: serde_json::Value,
    pub imageBase64: String,
    pub keyPair: Ed25519KeyPair,
}

#[derive(Serialize)]
#[allow(non_snake_case)]
pub(crate) struct ParamsOfGetDeployAddress {
    pub abi: serde_json::Value,
    pub imageBase64: String,
    pub keyPair: Ed25519KeyPair,
}

/// Result of `deploy` and `get_deploy_address` function running. Contains address of the contract
#[allow(non_snake_case)]
#[derive(Serialize, Deserialize)]
pub struct ResultOfDeploy {
    pub address: TonAddress,
}

#[derive(Serialize)]
#[allow(non_snake_case)]
pub(crate) struct ParamsOfRun {
    pub address: TonAddress,
    pub abi: serde_json::Value,
    pub functionName: String,
    pub input: serde_json::Value,
    pub keyPair: Option<Ed25519KeyPair>,
}

/// Result of `run` function running. Contains parameters returned by contract function
#[allow(non_snake_case)]
#[derive(Serialize, Deserialize)]
pub struct ResultOfRun {
    pub output: Value
}

/// Contract management struct
pub struct TonContracts {
    context: InteropContext,
}

impl TonContracts {
    pub(crate) fn new(context: InteropContext) -> Self {
        Self { context }
    }

    /// Get address for contract deploying
    pub fn get_deploy_address(
        &self,
        code: &[u8],
        keys: &Ed25519KeyPair,
    ) -> TonResult<TonAddress> {
        let result: TonAddress = Interop::json_request(
            self.context,
            "contracts.deploy.address",
            ParamsOfGetDeployAddress {
                abi: Value::Null,
                imageBase64: base64::encode(code),
                keyPair: keys.clone(),
            })?;
        Ok(result)
    }

    /// Deploy contract to TON blockchain
    pub fn deploy(
        &self,
        abi: &str,
        code: &[u8],
        constructor_params: Value,
        keys: &Ed25519KeyPair,
    ) -> TonResult<TonAddress> {
        let abi = serde_json::from_str(abi)
            .map_err(|_|TonError::invalid_params("deploy"))?;
        let result: ResultOfDeploy = Interop::json_request(self.context, "contracts.deploy", ParamsOfDeploy {
            abi,
            constructorParams: constructor_params,
            imageBase64: base64::encode(code),
            keyPair: keys.clone(),
        })?;
        Ok(result.address)
    }

    /// Run the contract function with given parameters
    pub fn run(
        &self,
        address: &TonAddress,
        abi: &str,
        function_name: &str,
        input: Value,
        keys: Option<&Ed25519KeyPair>,
    ) -> TonResult<Value> {
        let abi = serde_json::from_str(abi)
            .map_err(|_|TonError::invalid_params("run"))?;
        let result: ResultOfRun = Interop::json_request(self.context, "contracts.run", ParamsOfRun {
            address: address.clone(),
            abi,
            functionName: function_name.to_string(),
            input,
            keyPair: if let Some(keys) = keys { Some(keys.clone()) } else { None },
        })?;
        Ok(result.output)
    }
}