像Twitter这样的社交媒体平台拥有丰富的数据,展示了全世界人们所关心的热门话题。我们正在进入一个数据驱动的世界,而Chainlink提供了一个渠道,将这个庞大的数据集安全地连接到链上世界,为我们的社交媒体生活带来智能合约的可靠性和透明度保证。

在这次的实战演练中,我们将介绍如何让你的智能合约连接到Twitter API。具体来说,我们将解释如何从智能合约中发出一条推文,但是围绕社交媒体进行数据分析和智能合约的执行所展示出来的可能性却是无限的。

构造函数

pragma solidity ^0.6.12;

import "https://github.com/smartcontractkit/chainlink/evm-contracts/src/v0.6/ChainlinkClient.sol";

contract ChainlinkTwitter is ChainlinkClient {
    address private oracle;
    bytes32 private jobId;
    uint256 private fee;
    uint256 public statusCode;
    
    //only the contract owner should be able to tweet
    address payable owner;
    modifier onlyOwner {
    require(msg.sender == owner);
    _;
    }

    constructor() public {
        setPublicChainlinkToken();
        oracle = 0x4CF0507fe3236DedDbE6cD18508f35D9b5e16e7C; // oracle address
        jobId = "948db03c9576480a8fa0545bee5b28ab"; //job id
        fee = 11 * 10 ** 17; // 1.1 LINK
        owner = msg.sender;
    }

我们从熟悉的ChainlinkClient导入和继承开始。导入ChainlinkClient合约包含了构建请求、提交给一个或多个Chainlink节点,并接收回复所需的所有功能。只需定义你选择的oracle地址,该节点为其Twitter Job提供的作业规范ID(job spec ID),并定义该节点处理请求所需的费用。此外,我们还定义了onlyOwner修饰符,这样只有创建合约的地址才能通过这个合约发推特。

Tweet 函数

//tweets the supplied string
    function tweet(string memory twt) public onlyOwner{
        Chainlink.Request memory req = buildChainlinkRequest(jobId, address(this), this.fulfill.selector);
        //req.add("endpoint", "https://api.twitter.com/1.1/statuses/update.json");
        req.add("status", twt);
        req.add("copyPath", "statusCode")
        sendChainlinkRequestTo(oracle, req, fee);
    }
    
    //callback function
    function fulfill(bytes32 _requestId, uint256 _statusCode) public recordChainlinkFulfillment(_requestId) {
        statusCode = _statusCode;
    }


构建了合约之后,发推特就非常简单了。tweet函数接收要推送的字符串,创建请求结构体,并将其提交给定义的Chainlink节点。请求结构中需要两个字段:statuscopyPathstatus,即我们希望发布的推文,在Twitter外部适配器中被定义为一个输入,该节点将运行它来完成这项工作。而 copyPath 则是所有Chainlink节点支持的默认适配器的一部分,它告诉节点如何解析JSON输出。此外,endpoint 可以指定为不同的Twitter端点,具有不同的功能,但适配器默即可发布推文状态,因此目前不需要关心这一参数。

{
  jobRunID: 0,
  data: { result: 1315380402618499000 },
  result: 1315380402618499000,
  statusCode: 200
}

上面是外部适配器的JSON输出示例,在其market.link列表上提供。我们希望得到该推文的statusCode来确认它是否成功。statusCode是输出的JSON结构中第一层的key,所以路径只是 statusCode。如果我们希望检索 data: {result: },其中result是第二层的key,我们可以使用点符号将路径指定为 data.result。更多关于Copy和其他适配器的信息在Chainlink适配器文档页面提供。

构建好包含tweet和要返回的路径的请求,就可以提交请求,之后就会被节点处理,并在 fulfill() 回调中返回 statusCode。用户合约端只需要构建和提交请求即可,因为大部分繁重的工作都由Chainlink节点处理。

Twitter外部适配器和节点配置

在节点方面,有几件事我们必须做。

  • 安装并运行Twitter外部适配器
  • 在节点和适配器之间建立一个桥接器
  • 创建一个使用桥接器的工作规范(job spec)

正如Twitter适配器列表中所概述的那样,在使用yarn运行适配器之前,需要四个环境变量来定义Twitter API的连接访问。

TWITTER_CONSUMER_KEY
TWITTER_CONSUMER_SECRET
TWITTER_ACCESS_TOKEN_KEY
TWITTER_ACCESS_TOKEN_SECRET

git clone https://github.com/tweether-protocol/twitter-cl-ea
cd twitter-cl-ea
yarn
yarn start

默认情况下,适配器监听端口为8080。请注意,如果你的节点和适配器不是运行在同一个容器中,或者不是本地的,localhost:8080对它们来说是不一样的。在这种情况下,当你定义连接节点的桥接器时,你需要根据你的适配器运行的位置,指定你的docker容器的IP(172.x.x.x)或你的主机的本地IP(192.168.1.x)。也可以将适配器托管在一台单独的机器上,在这种情况下,您可以指定它的公共IP或本地IP,如果它在同一个局域网内。

在您的节点和适配器之间定义一个桥接器非常简单。只需在你的节点界面上填写新建网桥页面,并输入适配器的URL(适配器IP:8080),给它起个名字,并指定你想要的最低确认数和费用金额。

现在适配器已经运行并连接到您的节点,我们需要定义一个作业规范(job spec),以便在智能合约请求调用桥接器时使用它。在节点仪表板的New Job部分里,我们定义了一个JSON规范,说明什么会启动一个作业(job),以及这个job会执行什么任务(task)。

在这个 Twitter 适配器的情况下,我们的作业规范(job spec)应该是这样的。

{
 "initiators": [
   {
     "type": "runlog",
     "params": {
       "address": "YOUR ORACLE CONTRACT ADDRESS HERE"
     }
   }
 ],
 "tasks": [
   {
     "type": "twitter-cl-ea",
     "confirmations": null,
     "params": {
     }
   },
   {
     "type": "copy",
     "confirmations": null,
     "params": {
     }
   },
   {
     "type": "ethuint256",
     "confirmations": null,
     "params": {
     }
   },
   {
     "type": "ethtx",
     "confirmations": null,
     "params": {
     }
   }
 ],
 "startAt": null,
 "endAt": null
}

首先是触发器(initiator)。用来告诉节点要监控哪个oracle合约,并从哪个oracle合约上获取job。这与前面创建请求智能合约时使用的oracle地址相同。请求被发送到链上的这个oracle,由于节点正在监控它的作业请求(job requests),所以当请求进来时,它将启动这个job。更多关于部署这个oracle合约的内容,可以在Fulfilling Chainlink Requests文档页找到。

接下来是任务(tasks)。当然,我们这里需要的是Twitter任务--只需填写Twitter适配器的桥接器名称即可。接下来我们定义了copy adapter任务,这样它就会处理请求中的copyPath,然后用ethuint256适配器将输出转换为unit256,最后用ethtx适配器将答案提交回链上。至此,节点设置就完成了。在创建这个job spec时,会提供一个job ID,而请求合约在形成请求时使用的就是这个job ID。

结束语

希望这个演练能够帮助进一步展示Chainlink将任何API连接到您的智能合约的潜力,同时也解释了节点运营方处理这些任务所需的一些配置。

如果你是开发者,想要快速为你的应用连接到Chainlink的价格参考数据,访问开发者文档,并接入Discord技术讨论。如果你想要安排一个电话来更深入讨论Matic/Chainlink的集成,请在此处联系。

English channels

Website |  Twitter | Reddit | YouTube | Telegram | Events | GitHub | Price Feeds | DeFi

中文渠道

中文官网 | 知乎 | SegmentFault | CSDN |