SmartWeave开发教程
0xE43a
February 14th, 2022

作者:Xiang|W3.Hitchhiker

修订:Evelyn|W3.Hitchhiker

官方智能合约参考文档

(↑点击此链接框,打开文档)

SmartWeave

SmartWeave 使用 AR 代币使开发人员能够使用 Javascript 构建所有类型的智能合约应用程序。

与以太坊智能合约区别:

  1. SmartWeave 合约是用 JavaScript 编码的(前端开发语言),不需要像学习 Solidity 那样学习新的编程语言。
  2. 在以太坊上,将合约更新到最新状态的客户端是矿工,而在 Arweave 上,每次都会在客户端上更新状态。所以构建 SmartWeave 合约得注意,使用SmartWeave 并不适用所有的dapp。

由于 SW 合约本身是在客户端更新的,为了获取合约的最新状态,客户端需要通过每次交互来找到其最新的有效状态。与使用ardb从 Arweave 获取交易等其他选项相比,可能会很慢。

SmartWeave 合约分为三部分:

  • 合约源 (the contract source)
  • 状态 (the state)
  • 执行者 (SmartWeaveJS)

合约状态

为了评估合约状态,SmartWeave 协议客户端:

  1. 将所有合约的交互交易加载到请求的区块高度。
  2. 对交互事务进行排序。交互的顺序首先由交互交易区块高度(即交易在链中被挖掘的时间)决定,其次由sha256(transactionId + blockHash). 完整的顺序是[ block_height, sha256(transactionId + blockHash) ].
  3. 将排序后的交互应用到合约的handler功能上——评估合约的状态直到请求的区块高度。

合约源

合约源就是代码本身,用 JavaScript 编写。这是将在客户端(执行者)上运行以更新状态并获取最新且有效的状态的合约。合约它定义了项目将是什么,以及您希望它做什么。

合约源永远不会改变,这可以保证用户使用的东西永远是真实的。

开始测试

状态通常是写合约的第一件事,让我们编写一些简单的代码测试,每次调用increment函数时都会增加调用者的余额。 caller 是与该合约源交互的钱包地址。

export function handle(state, action) {
  const balances = state.balances;
  const input = action.input;
  const caller = action.caller;
  
  if(input.function === 'increment') {
      // If the caller already is a key of balances, increment, if not, set it to 1.
      if(caller in balances) {
        balances[caller]++;
      } else {
        balances[caller] = 1;
      }
  }
}

(该文件保存为first.js。)

所有 SmartWeave 合约都必须以函数(state,action){} 开头,因为这是执行程序调用的函数。其他所有内容都应该在该handle函数中。

现在handle本身很混乱,因为我们不知道stateaction参数是什么。我们先解释一下这个action。 动作参数 action 是在执行 SmartWeave 合约时发送的动作,每次你想要对 SW 合约进行更新时,你都需要发送输入交易,这通常包括函数名称input.function和任何其他参数你需要和它一起发送。目前这种情况下,我们不需要发送任何其他内容,但例如我们可以发送input.qty来指定我们想要增加余额的数量,这也需要在合约源代码中指定才能正常工作。请记住,这是由钱包所有者控制的,因此我们需要在接收用户数据时始终具备条件,以防止出现意外的情况。

动作参数也将调用者作为该对象的键。同样,调用者是运行该函数的人。这是唯一起作用的两个键:action: input and caller.

状态(the state)

状态是合约状态,它让用户知道你的合约的更新是什么,以及它在哪里,在执行的那一刻。 这个会随着时间的推移(在客户端)更新,而合约源永远不会改变。
当我们第一次创建合约时,我们还需要发送一个状态,也就是初始状态。

开始测试

我们可以在我们的合约源中看到,状态是一个 balances 对象,其中包括钱包地址(caller)作为键,并且每个调用者键都有一个数字作为其值。 在这个例子中,让我们为自己添加一些余额作为初始状态,状态是一个 JSON 对象:

{
    "balances": {
        "S2aewhZzchiyRsAisLAdZKudF6r9JlO_WDSGkaLGMZ4": 10000
    }
}

(该文件保存为first.json)

这表明当第一个人去读我们的合约时,第一个状态是这个地址有 1,000 个该代币余额。

状态和合约源都必须是发送到 Arweave 的单独交易,并且都只部署一次。 之后,通过发送包含input交易来更新状态。

部署

在说执行者之前,我们先来看看应该如何处理合约源和初始状态。 这两个都只是普通的交易,但带有一些特殊的标签。 我们可以使用 SmartWeaveJS 作为 CLI 工具来部署这些合约。

首先安装smartweave包(建议使用最新的稳定node版本):

npm install -g smartweave

然后可以通过以下指令部署合约:

smartweave create [SRC LOCATION] [INITIAL STATE FILE] --key-file [YOUR KEYFILE]

SRC LOCATION 是指的合约源,INITIAL STATE FILE是初始状态文件,YOUR KEYFILE 是指生成钱包时的keyfile文件。参考下图配置:

交易ID: _PMfm736sE_pqPS-FQvYgkwqbm-8VJBPGlQRTm89ZBE

读取合约状态:

smartweave read [CONTRACT TXID]

这样就成功部署了您的第一个 SmartWeave 合约。

与合约交互(写合约):

smartweave write [CONTRACT TXID] --key-file [YOUR KEYFILE] \

  --input "[CONTRACT INPUT STRING HERE]"

如果要测试不写入主网,与测试网络交互,请将 --dry-run 附加到 --interact 调用中.

但由于我们是来学习的,所以也可以了解下使用 ArweaveJS 手动创建这些交易。参考以下代码:

import Arweave from 'arweave';
const arweave = Arweave.init({
    host: 'arweave.net',
    protocol: 'https',
    port: 443
});
async function createContract() {
    // Let's first create the contract transaction.
    const contractTx = await arweave.createTransaction({ data: contractSource }, wallet);
    contractTx.addTag('App-Name', 'SmartWeaveContractSource');
    contractTx.addTag('App-Version', '0.3.0');
    contractTx.addTag('Content-Type', 'application/javascript');
    
    // Sign
    await arweave.transactions.sign(contractTx, wallet);
    // Let's keep the ID, it will be used in the state transaction.
    const contractSourceTxId = contractTx.id;
    
    // Deploy the contract source
    await arweave.transactions.post(contractTx);
    
    // Now, let's create the Initial State transaction
    const initialStateTx = await arweave.createTransaction({ data: initialState }, wallet);
    initialState.addTag('App-Name', 'SmartWeaveContract');
    initialState.addTag('App-Version', '0.3.0');
    initialState.addTag('Contract-Src', contractSourceTxId);
    initialState.addTag('Content-Type', 'application/json');
    
    // Sign
    await arweave.transactions.sign(initialState, wallet);
    const initialStateTxId = initialState.id;
    // Deploy
    await arweave.transactions.post(initialState);
}
createContract()

使用ArCode部署合约

类似于以太坊的remix,AR也有自己的网页端部署工具

(↓点击此链接框,打开网页)

点击左下方登陆钱包,这里可以下载AR的钱包插件ArConnect进行连接,如果没有,可以先去下载。

进入后可以使用studio自带的代币合约部署,然后点击坐上的火箭图标进行部署。

此时需要选择部署的钱包,方法,部署网络,合约源,合约初始状态等。

部署成功后会获取交易ID

TX: YdVWeK5ftuIBmCTEbNQCwSFT13KZIJsuJ6OaVqjFvoY

这样就成功部署token-pst合约了。

与合约交互,读取合约数据:

与合约交互,写合约数据:

Arweave TX
KsmHU7lq7hX7AI34tTg71ScVEi3DU5dpZHQcwrADE18
Ethereum Address
0xE43a21Ee76b591fe6E479da8a8a388FCfea6F77F
Content Digest
pCFDyQfHHMvfQlV52doX8TPCHGYoXjaY-zJkjJLIvO4