# 合约流程

## 编辑合约

您可以基于任何支持solidity的编辑器编写合约。下述将基于[remix在线编辑器](https://remix.ethereum.org/#optimize=false\&runs=200\&evmVersion=null\&version=soljson-v0.7.6+commit.7338295f.js) 为例，进行说明。

为了叙述方便，我们使用如下的简单合约示例：

```
pragma solidity >=0.4.24 <=0.7.6 ;

contract SimpleStorage {
    uint storedData;

    function set(uint x) public {
        storedData = x;
    }

    function get() public view returns (uint) {
        return storedData;
    }
}
```

(注意：由于SCDO主网兼容 Istanbul版本的EVM，开发合约时建议使用的solidity版本不大于0.7.6。SCDO 合约虚拟机目前不支持 EVM Berlin 版本的功能。)

下面的图片是 Remix 在线编辑器的首页演示:

![RemixIde](/files/-MVTc1TJv6OD--9NEZQw)

## 编译合约

将合约写好并保存后，可以使用remix的编译功能来编译合约并检查可能的语法错误。如屏幕截图所示，单击“编译”按钮以编译示例合约。如果有错误，编译器将指向可能发生错误的位置。

![Compile smart contract](/files/-MVV4mtpwiZtd3rbt4PB)

### 设置自己的测试环境

成功编译合约后，我们可以部署合约并对其进行测试。我们建议的最佳实践是设置SCDO私有链/专有链节点，然后部署合约在此链上，并进行测试。如果您对测试结果满意，则可以将合约部署到SCDO主网。我们的测试节点是在Ubuntu中设置的。

### 获取合同bytecode

如 Remix IDE显示的, 在合约成功编译后, 点击 Remix IDE 左边显示栏 的 "Deploy" 图标。见下图：

![delpoy icon](/files/-MVTc1TLFeWZv_8DQhf0)

如果没有错误， 你将会看到下图所示的：

![deploy](/files/-MVV4mtqr0giEyjLMH3P)

点击绿色查看图标。

![correct](/files/-MVV4mtrC-tXdGEz7ZD-)

您将见到

![input](/files/-MVV4mtskHFEa55VhmTZ)

“input”字段中的值是合约的字节码。单击字节码字符串旁边的复制图标，将其复制到剪贴板。然后将副本保存到安全的地方。字节码如下：

```
0x608060405234801561001057600080fd5b5060df8061001f6000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a723058209e18a0a3a2dc0fa6b26ca8a3b915b69344f7a214ce5510d0bc21f948fb0ff0750029
```

### 用client tool 部署合约

* 准备一个SCDO帐户，并确保有足够的余额来部署合约。在这里，我们使用片1的帐户1S010a3fe1668c7cab5923fe0f77cb25ec21f644f1,同时并保存帐户密钥文件。
* 您可以下载 [SCDO release](https://github.com/scdoproject/go-scdo/releases) Mac/Windows/Linux node 和 client tools.

注意：密钥库文件是由以下命令生成的

```
./client savekey --privatekey "the private key paired with 1S010a3fe1668c7cab5923fe0f77cb25ec21f644f1" --file 1S010a3fe1668c7cab5923fe0f77cb25ec21f644f1.keystore --shard 1
```

* 启动一个私链节点 node (我们的例子启动的是片1的一个节点）
* 使用sendtx 命令部署合同.

```
 ./client sendtx --amount 0  --address 0.0.0.0:8027 --payload 0x608060405234801561001057600080fd5b5060df8061001f6000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a723058209e18a0a3a2dc0fa6b26ca8a3b915b69344f7a214ce5510d0bc21f948fb0ff0750029 --from 1S010a3fe1668c7cab5923fe0f77cb25ec21f644f1.keystore
```

sendtx 参数 address 是启动的node的 ip 地址，这里用的是局部ip 地址; "amount" 是交易token量 (以 Wen为单位), 对部署合约，一般设置为0; from 是前面用savekey 命令生成的密码文件；payload 是合约的bytecode（字节码）; gas 是交易需要的最低gas (默认值 20000).

上述命令执行的结果是：

```
transaction sent successfully
{
    "Data": {
        "AccountNonce": 12,
        "Amount": 0,
        "From": "1S010a3fe1668c7cab5923fe0f77cb25ec21f644f1",
        "GasLimit": 200000,
        "GasPrice": 10,
        "Payload": "0x608060405234801561001057600080fd5b5060df8061001f6000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a723058209e18a0a3a2dc0fa6b26ca8a3b915b69344f7a214ce5510d0bc21f948fb0ff0750029",
        "Timestamp": 0,
        "To": "0S0000000000000000000000000000000000000000",
        "Type": 0
    },
    "Hash": "0x08c45b71dd7c151071f222fb6d1216248425e977255d5923dbade76c32abd1b0",
    "Signature": {
        "Sig": "9IawOq9cHp6Cmmj7i7YD7oxMNB+Zc28YmJuUzpA7S9INLiGP6ysdYK/AC9jZH3CF+kUJYvBWsIwXEWx2s/s/aQA="
    }
}
```

根据返回结果的Hash查看合约部署结果：

```
./client getreceipt --address 0.0.0.0:8027 --hash 0x08c45b71dd7c151071f222fb6d1216248425e977255d5923dbade76c32abd1b0
```

得到如下结果：

```
{
    "contract": "1S01f671dfc64128d285e178c1f6e7bf640d420002",
    "failed": false,
    "poststate": "0x3c7e3c77abf149d2d59e2d94d134611314751e22b940a2f22be9b2e2c74fb9b6",
    "result": "0x6080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a723058209e18a0a3a2dc0fa6b26ca8a3b915b69344f7a214ce5510d0bc21f948fb0ff0750029",
    "totalFee": 802130,
    "txhash": "0x08c45b71dd7c151071f222fb6d1216248425e977255d5923dbade76c32abd1b0",
    "usedGas": 80213
}
```

结果中failed为false表明合约部署成功，contract的值为合约地址。

## 调用合约

### 通过remix获得调用方法的字节码

使用client sendtx命令调用合约需要提供合约调用方法（包括参数设定）的payload信息(bytecode/字节码)。这个信息可以通过remix获得。在Remix IDE 左边的控制窗口，Deploy 的下面，可以看到本示例合同的set和get方法。在set右侧填入参数值（这里是22)，点击set，即可得到调用set方法（包括参数值设定）的字节码了。

![methods](/files/-MVV4mttiiLW1hEWmwID)

在Remix IDE 右下方日志窗口可以看到上面点击结果。点击详情可查看调用详情，其中input的值即为本示例set方法调用的字节码 (参数设置为22)。如下图所示：

![set method](/files/-MVV4mtuc0laY7bu-fyW)

调用set方法的字节码是：

```
0x60fe47b10000000000000000000000000000000000000000000000000000000000000016
```

### 使用 sendtx 调用合约方法

如下的命令调用上述合约中的set方法，参数payload 是我们前面得到的字节码，from为发起交易的账户，to为合约地址

```
./client sendtx --amount 0   --payload  --address 0.0.0.0:8027 --payload 0x60fe47b10000000000000000000000000000000000000000000000000000000000000016 --from 1S017f6215c30f1505e0d42769c5472b410d6bf961.keystore --to 1S01f671dfc64128d285e178c1f6e7bf640d420002
```

执行结果如下：

```
transaction sent successfully
{
    "Data": {
        "AccountNonce": 13,
        "Amount": 0,
        "From": "1S010a3fe1668c7cab5923fe0f77cb25ec21f644f1",
        "GasLimit": 200000,
        "GasPrice": 10,
        "Payload": "0x60fe47b10000000000000000000000000000000000000000000000000000000000000016",
        "Timestamp": 0,
        "To": "1S0126ba0710ad416638a7f0e5a113e9b6be4b0002",
        "Type": 0
    },
    "Hash": "0xb26dae6efc9942c6655a6e5baa372f6d3388b62ac50011466a7b6c105ee6e01e",
    "Signature": {
        "Sig": "bt/Nh0UyKrCxTxoP/gyeTgE8mHVmVmZHCQHJ14pGePJHblZrS1vI/6aE2d2WXUSqLYGnSqFWoaXkxbOa7hco+wA="
    }
}
```

使用上面结果的hash, 通过查询receipt信息，可以获取set方法的调用结果：

```
./client getreceipt --hash 0xb26dae6efc9942c6655a6e5baa372f6d3388b62ac50011466a7b6c105ee6e01e
```

得到如下结果：

{ "contract": "0x", "failed": false, "poststate": "0x328868cd36c074185bd1ccf4e905728b0f36de9fd06743e93b87483ae3872bd1", "result": "0x", "totalFee": 266690, "txhash": "0xb26dae6efc9942c6655a6e5baa372f6d3388b62ac50011466a7b6c105ee6e01e", "usedGas": 26669 }

**注意：调用合约的账户必须是与合约地址同一分片，SCDO目前不支持跨片合约调用**

### 使用call调用合约方法

对于仅获取变量值而不改变合约状态的方法，可以通过call来调用。在我们的示例中，获取get的bytecode (字节码） 和获取set 方法的字节码类似。get的字节码如下：

```
 0x6d4ce63c
```

用call调用get 方法：

```
client call --payload 0x6d4ce63c --to 0x47a99059219055cf8277d5d7dff933446edb0012
```

得到如下结果：

```
{
    "contract": "0x",
    "failed": false,
    "poststate": "0x2673977b8565ad747d1dff04dccaa424afcb1e81c3e07e994eeef538d25a1a06",
    "result": "0x0000000000000000000000000000000000000000000000000000000000000016",
    "totalFee": 21696,
    "txhash": "0x169ac2e722ddfc99a2368aecd4462cbf92a43320c2cf5e18341492bfb00fd4ec",
    "usedGas": 21696
}
```

可以看到，result显示的变量值为之前通过set方法设置的22 (十六进制表示）。

## Deploy to SCDO mainnet

如前面几节中所示，对合同进行了充分的测试后，您可以按照与将其部署到专用网络相同的步骤，将其部署到SCDO主网上。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://scdo-project.gitbook.io/scdo-wiki/zhong-wen/ji-yu-scdo-kai-fa-bu-shu-he-yue-liu-cheng.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
