# 合约流程

## 编辑合约

您可以基于任何支持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](https://697599853-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MGA-UkTDbvYelRQIPZp%2Fsync%2F525b64f7a2da0119133dfe77c0931a7873755add.png?generation=1615421517010576\&alt=media)

## 编译合约

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

![Compile smart contract](https://697599853-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MGA-UkTDbvYelRQIPZp%2Fsync%2Fa7c0065354e35b8f19115aa5498833f2df40f089.png?generation=1615421523190684\&alt=media)

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

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

### 获取合同bytecode

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

![delpoy icon](https://697599853-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MGA-UkTDbvYelRQIPZp%2Fsync%2Fbbd38c16a53ed8ba6ac0408071a3bddb5c68ddb2.png?generation=1615421524194988\&alt=media)

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

![deploy](https://697599853-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MGA-UkTDbvYelRQIPZp%2Fsync%2F6c6b307c5fb19f8f1765941693da5326bf41f5ff.png?generation=1615421520171505\&alt=media)

点击绿色查看图标。

![correct](https://697599853-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MGA-UkTDbvYelRQIPZp%2Fsync%2F67fe3bb731889c19e9a68295f26558f27a49d38a.png?generation=1615421518117861\&alt=media)

您将见到

![input](https://697599853-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MGA-UkTDbvYelRQIPZp%2Fsync%2F24f4b25f984eb688d3f02ca5ba21f3f0d4c31951.png?generation=1615421522023184\&alt=media)

“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](https://697599853-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MGA-UkTDbvYelRQIPZp%2Fsync%2F8ecf669d7eda891645d03a4ebb8bd11c413d2834.png?generation=1615421519178098\&alt=media)

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

![set method](https://697599853-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MGA-UkTDbvYelRQIPZp%2Fsync%2Fcd5d8d10a43209d7868f630405597e859deb3c4c.png?generation=1615421521162391\&alt=media)

调用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主网上。
