区块链网站|NFTS Chainlink(Link) 通过访问分散预测机Chainlink feed开发DeFi看涨期权交易平台的实例

通过访问分散预测机Chainlink feed开发DeFi看涨期权交易平台的实例

广告位

接入去中心化预言机Chainlink喂价开发DeFi看涨期权交易平台实例

DeFi包括许多智能合约应用场景,如区块链投票、去中心化彩票、流动性挖掘和去中心化交易平台。本文将教你如何利用Chainlink价格预测机在以太坊主网上开发一个简单的具有Solidity的看涨期权DeFi交易平台。当然,你也可以稍微修改一下这个例子,开发一个看跌期权交易平台。这个平台有一个强大的功能,就是所有的价值转移都是通过智能合约进行的,交易双方可以绕过中间方直接进行交易。所以这个过程不包括任何第三方,只有智能合约和去中心化的Chainlink费,这是最典型的DeFi应用。开发分散式期权交易平台将涵盖以下内容:

比较字符串的可靠性

将整数转换为固定位数的小数。

创建并初始化一个pass接口,如LINK。

用户/智能合同之间的转移通行证

通行证转让的批准

安全数学

智能合同ABI接口

要求执行交易状态

以太坊味精。价值及其与卡的价值交易的差异

在int和uint之间转换

应付款地址

最后,使用Chainlink数据聚合器的接口来获取DeFi价格数据。

可以在GitHub和Remix上查看相关代码。在正式开始之前,先简单介绍一下什么是期权合约。期权合约赋予你在一定期限前选择以约定价格执行交易的权利。具体来说,如果期权合约的内容是购买股票或债券等资产,则称为看涨期权。此外,本文中的示例代码可以修改成一个put选项。看跌期权正好与看涨期权相反,其内容不是买入资产而是卖出资产。以下是一些与期权相关的专有术语:

执行价格:约定的资产购买/出售价格。

期权费:购买合同时支付给卖方的费用。

到期日:合同终止的时间。

行权:买方行使权利,以行权价格买卖资产的行为。

无论是开发看涨期权还是看跌期权,都需要导入、构造函数、全局变量等基本元素。

^0.6.7实用主义;

导入“https://github . com/smartcontractkit/chain link/blob/develop/EVM-contracts/src/v 0.6/interfaces/linktokeninterface . sol”;

导入“https://github . com/smartcontractkit/chain link/blob/master/EVM-contracts/src/v 0.6/interfaces/aggregator v3 interface . sol”;

导入“https://github . com/open zeppelin/open zeppelin-contracts/blob/master/contracts/math/safe math . sol”;

合同链接选项{

//溢出安全运算符

为uint使用SafeMath

//价格馈送接口

AggregatorV3Interface内部ethFeed

AggregatorV3Interface内部linkFeed

//链接传递接口

LinkTokenInterface内部链接;

uint ethPrice

uint linkPrice

//预先计算字符串哈希值

bytes 32 ETH hash=keccak 256(ABI . encodepacked(\’ ETH \’);

bytes 32 LINK hash=ke ccak 256(ABI . encode packed(\’ LINK \’));

应付合同地址;

//选项存储为结构化数组。

结构选项{

uint罢工;//美元价格(18位小数)选项允许买家在以下位置购买代币

uint溢价;//期权作者收取的合同令牌费用

uint到期;//到期时间的Unix时间戳

单位金额;//期权合约的令牌数量

布尔行使;//选项是否已被执行

bool取消;//选项是否已取消

uint id//选项的唯一ID,也是数组索引

uint latestCost//帮助器显示最近更新的锻炼成本

应付帐款书写人地址;//期权发行人

应付买方地址;//期权购买者

}

选项公共方法;

option public linkOpts

//科万饲料价格:https://docs.chain.link/docs/reference-contracts

公共构造函数{

//以太坊的Kovan feed价格/美元

eth feed=aggregator v3 interface(0x 9326 BFA 02 add 2366 b 30 bacb 125260 af 641031331);

//LINK/Kovan feed价格为美元

link feed=aggregator v3 interface(0x 396 C5 e 36 DD 0 a 0 F5 a5d 33 DAE 44368d 4193 f 69 a1f 0);

//Kovan上的LINK pass地址

LINK=LinkTokenInterface(0xa 36085 f 69 e 2889 c 224210 f 603d 836748 e 7 DC 0088);

contractAddr=payable(地址(this));

}

导入时需要访问Chainlink的数据聚合器接口实现价馈功能,访问LINK pass接口(注意:这里需要使用pass契约的ERC20函数进行转账)。最后,我们导入OpenZeppelin的SafeMath契约,这是一个执行内置溢出检查操作的标准库,而Solidity的内置运算符不包含溢出检查。

接下来,我们重新定义操作类型和uint,使用导入的SafeMath,定义我们的feed价格,链接接口,价格变量,计算以太坊和链接字符串(后面会用到)的keccak256哈希值,地址变量存储我们的合约地址。需要注意的是,地址定义为“应付”,因为我们的合同需要在这个地址支付。然后构造完成后,将接口初始化为Kovan契约地址,这样就可以调用契约函数,用“address(this)”设置契约地址。我们把地址转换成“应付”,因为否则地址会返回无法支付的地址类型。至于选项本身的数据类型,可以使用结构化数组,也可以使用结构化链表。使用标准数组的好处是我们可以直接访问选项,这是链表做不到的,但同时删除标准数组中的值也是非常昂贵的。所以我们不删除选项,只标记为“过期”或“取消”,这样可以牺牲存储空间来换取计算速度和简单性。最后,购买、出售和行使期权可以通过O(1)运算降低天然气成本。

链接馈送价格//返回最新的链接价格

函数getLinkPrice公共视图返回(uint) {

uint80 roundID,

内部价格,

uint开始于,

uint时间戳,

uint80回答回合

)=linkFeed.latestRoundData

//如果这一轮还没有结束,时间戳为0

require(时间戳为0,“轮次未完成”);

//价格永远不会是负数,所以可以把int转换成uint

//价格小数点后有8位数。之后还需要加10位成为18位。

返回单位(价格);

}

首先,我们实现两个getter函数来获取以太坊和链接feed price。以太坊的功能和上面的链接功能是一样的,唯一的区别就是获取以太坊的费用。这将调用latestRoundData函数来检查我们的初始饲料价格,并将自动返回最新的分散市场聚合价格数据。因为这是查看功能,连油费都不要!我们对默认的feed getter函数进行了调整,将价格从int转换为uint,以匹配后来使用uint的函数。这里注意这个转换是可以的,因为价格永远不可能是负数,所以不会用到int的符号位。在类型之间转换时,需要考虑这些细节。

撰写买入期权合约//允许用户撰写持有买入期权。

//收到的通票类型、行权价格(通票以美元计价,保留18位小数位)、期权费(与通票小数位相同)、到期日(unix)、合约中的通票数量。

函数writeOption(字符串内存令牌、uint strike、uint premium、uint expiry、uint tknAmt) public payable {

bytes 32 token hash=ke ccak 256(ABI . encode packed(token));

require(token hash==ETH hash | | token hash==LINK hash,\’仅支持ETH和LINK令牌\’);

更新价格;

if (tokenHash==ethHash) {

require(msg.value==tknAmt,\’提供的ETH数量不正确\’);

uint latest cost=strike . mul(tknAmt)。p(eth price . mul(10 * * 10));//以以太币计价的行权费用,小数位调整。

ethOpts.push(option(strike,premium,expiry,tknAmt,false,false,ethOpts.length,latestCost,msg.sender,address(0)));

}否则{

require(LINK . transfer from(msg . sender,contractAddr,tknAmt),\’提供的链接数量不正确\’);

uint latest cost=strike . mul(tknAmt)。p(link price . mul(10 * * 10));

linkOpts.push(option(strike,premium,expiry,tknAmt,false,false,linkOpts.length,latestCost,msg.sender,address(0)));

}

}

完成初始设置并连接了饲料价格后,我们接下来可以调用该函数。首先,写一份期权合约。调用卖方的writeOption函数,填写期权的具体参数,小数点后留18位。有必要在此指定小数位数,以确保合同中使用的所有参数具有统一的格式。比如整数777没有小数点,但是如果我们规定的逻辑是保留两位小数,那么就表示为7.77。我们这里的规则是小数点后保留18位,因为以太坊和LINK都是18位小数。如果小数点不足18位,可以加0变成18位。接下来,我们可以第一次使用之前计算的以太坊和LINK string的哈希值。我们需要比较字符串,才能知道卖方期权合约针对的是什么样的关口。但是Solidity不支持字符串之间的==运算,因为它的长度是动态的。我们不需要编写一个函数来逐字节比较字符串,只需要使用keccak256 hash函数计算每个字符串的32位hash值,直接进行比较即可。只要哈希值相同,字符串就相同。既然我们知道了卖家用的是什么样的通行证,我们就可以心中有个目标了。如果是以太币,我们可以用msg.value来确认转入期权合约的以太币金额是否正确。我们可以根据需要的功能严格执行。如果require的第一个字段为false,交易将被拒绝,无法继续进行。这样可以保证所有期权合约的转让完全符合之前约定的金额(tknAmnt)。通过检查后,我们可以创建期权合约,并提供所有必要的字段生成结构。基于当前以太坊价格,使用SafeMath函数代替内置运算符计算当前行权期权的LatestCost。使用Chainlink的updatePrices helper函数获取当前价格,这将更新全球以太坊和链接价格。注意ethPrice要乘以10的10次方。这样做是因为Chainlink feed返回8位小数的美元价格,但是如上所述,我们目前的标准是18位小数。所以加10个零可以调整到小数点后18位,符合以太坊和LINK Pass的格式。最后,我们把期权的结构压入ethOpts的数组,这样期权合约就写好了,里面有足够的钱。

写一个LINK pass的LINK期权合约,设置Unix到期时间,行权价10美元,期权费0.1 LINK。

如果是联系期权合约,那么就需要做一些修改。Msg.value只提供交易中以太币的金额。所以要想保证链接量充足,就需要直接访问链接通契约。我们之前已经导入并初始化了LINK pass接口,所以可以访问所有的LINK pass函数,其中一个是transferFrom,可以将LINK从一个地址转移到另一个地址。当然,我们不能允许任何契约随便转让你的链接资产,所以必须先调用LINK的approve函数,指定允许转让的链接数量和转让到的契约地址。

ABI界面当您在Etherscan上查看合同时,会出现两个选项卡,即阅读合同和撰写合同。您可以使用这两个选项卡与合同进行交互。比如:链接主网合同。以太扫描知道这些函数是什么,以及如何通过契约的ABI调用它们。使用JSON格式调用ABI,并指定函数调用参数。可以直接在主网上调用,但是Kovan上的链接契约需要导入这个模块。你可以在LinkToken的Github上查看ABI。幸运的是,在生产系统中,所有这些都可以通过web3js的接口来处理,用户可以使用一个简单的MetaMask请求进行批准。然而,在我们的开发示例中,暂时需要手动操作。

进口的ABI通过MEW与Kovan上的链接合同进行交互。

批准Kovan上的链接合同,以转入/转出100个链接通行证。

购买看涨期权//购买看涨期权需要通行证、期权ID和付款。

function buyOption(字符串内存令牌,uint ID) public payable {

bytes 32 token hash=ke ccak 256(ABI . encode packed(token));

require(令牌哈希==以太哈希| |令牌哈希==链接哈希,’仅支持埃塞俄比亚和环令牌\’);

更新价格;

if (tokenHash==ethHash) {

要求(!方法[ID].已取消方法[ID].立即到期,\’期权已取消/到期,不能购买\’);

//买家支付期权费

require(msg.value==ethOpts[ID]).溢价,\”为溢价发送的埃塞俄比亚金额不正确\”);

//卖家收到期权费

ethOpts[ID]。作家。transfer(ethOpts[ID].溢价);

方法[ID].买家=消息发送者

}否则{

要求(!linkOpts[ID].已取消linkOpts[ID].立即到期,\’期权已取消/到期,不能购买\’);

//将期权费从买家转给卖家

要求(链接。转自(msg。发件人,linkOpts[ID]).编写器,linkOpts[ID].溢价),”为保险费发送的链接数量不正确\”);

linkOpts[ID].买家=消息发送者

}

}

现在期权合约创建完成且资金充足。接下来就等人来买了!买家只需表明购买以太币或环期权的意愿以及期权身份证明即可。由于期权数组被定义成公开的,因此可以直接查看,无需支付气体费,买家可以查看所有期权合约及其身份证明字段。选择完期权合约后,我们再次调用需要函数验证期权费用的支付金额是否正确。这次,我们不仅需要确认消息值(仅针对以太币),还需要将期权费用转给卖家坚固性。中的所有以太币地址都有一个地址。转移函数,我们调用这个函数将期权费用从合约转账给卖家。然后设置期权合约的买家地址字段,就完成购买了!如果是环的话,操作就稍微简单一些。可以用转移自函数直接将买家的期权费转账给卖家(注:需要先批准)。如果是以太币的话,期权费则需要先经过合约再到卖家地址。

行使期权//行使看涨期权,需要通证,期权身份证明和付款

函数练习(字符串存储令牌,uint ID)公共支付{

//如果期权没到期且还没有被行使,则允许期权所有者行使

//要行使期权,买家需向卖家支付行权价格*数量的金额,并获得合约中约定数量的通证

字节32令牌哈希=ke ccak 256(ABI。编码打包(令牌));

require(令牌哈希==以太哈希| |令牌哈希==链接哈希,’仅支持埃塞俄比亚和环令牌\’);

if (tokenHash==ethHash) {

要求(方法[ID]。\’买方==消息发送方,\’您不拥有此选项\’);

要求(!方法[ID].行权,\’期权已经行权\’);

要求(方法[ID]。立即到期,\”期权已到期\”);

//符合条件,进行付款

更新价格;

//行权费用

uint exerciseVal=ethOpts[ID].strike*ethOpts[ID].金额;

//接入链环喂价换算成以太币

uint equi veth=练习值。p(eth价格。mul(10 * * 10));//将喂价的8位小数转换成18位

//买家支付与行权价格*数量等值的以太币,行使期权。

require(msg.value==equivEth,\’发送到练习的链接数量不正确\’);

//向卖家支付行权费

ethOpts[ID]。作家。转移(equi veth);

//向买家支付合约数量的以太币

味精。发件人。transfer(ethOpts[ID]).金额);

方法[ID].行使=真;

}否则{

require(linkOpts[ID].\’买方==消息发送方,\’您不拥有此选项\’);

要求(!linkOpts[ID].行权,\’期权已经行权\’);

require(linkOpts[ID].立即到期,\”期权已到期\”);

更新价格;

uint exerciseVal=linkOpts[ID].strike*linkOpts[ID].金额;

uint equiv link=练习值。p(链接价格。mul(10 * * 10));

//买家行权,向卖家支付行权费

要求(链接。转自(msg。发件人,linkOpts[ID]).writer,equivLink),\’发送到练习的链接数量不正确\’);

//向卖家支付合约数量的环通证

要求(链接。转移(消息。发件人,linkOpts[ID]).金额),\’错误:买家未付款\’);

linkOpts[ID].行使=真;

}

}

对于期权所有者来说,如果以太坊或LINK的价格超过行权价格,就可以获利。这样,他们愿意行使期权,以行使价购买通行证。这个时候首先要确认几个条件,即:契约归消息发送方所有;合同尚未执行;现在期权还没到期。如果不满足上述任何条件,交易将被撤销。

示例:当事务不满足一个或多个条件时,重新混合输出的结果。

如果所有条件都满足,行权费用支付给卖方,合约量的通行证支付给买方。行权时,买方需要以行权价购买每张通行证。但行权价格以美元计价,而合约数量以以太币或LINK计价。因此,我们需要访问Chainlink来计算相当于行使费的以太坊或link的金额。转换成等价以太坊或者链接后,就可以开始传送了。转账时需要使用前面提到的方法,即以太坊调用msg.value/address.transfer函数,LINK调用transferFrom函数。

以上是期权成功行权的完整交易过程。链接价格为11.56美元,合同执行价格为10美元,数量为1个链接。换句话说,买家只需要花10美元而不是11.56美元来购买一个链接。0/11.56=0.86,即买家只需要花费0.86个链接就可以获得1个链接。算上0.1LINK的期权费,总利润是0.04LINK。

取消合约/删除资金//允许卖方取消合约或从未成功交易的期权中退回资金。

函数取消选项(字符串内存令牌,uint ID)公共应付款{

bytes 32 token hash=ke ccak 256(ABI . encode packed(token));

require(token hash==ETH hash | | token hash==LINK hash,\’仅支持ETH和LINK令牌\’);

if (tokenHash==ethHash) {

require(msg . sender==ethOpts[ID]。writer,‘你没有写这个选项’);

//必须还没有被取消或购买

要求(!ethOpts[ID]。已取消方法[ID]。buyer==address(0),\’此选项不能取消\’);

ethOpts[ID]. writer . transfer(ethOpts[ID].金额);

ethOpts[ID]。取消=真;

}否则{

require(msg . sender==link opts[ID]。writer,‘你没有写这个选项’);

要求(!linkOpts[ID]。已取消linkOpts[ID]。buyer==address(0),\’此选项不能取消\’);

require(link . transfer from(address(this),linkOpts[ID]。编写器,linkOpts[ID]。金额)、“发送的链接金额不正确”);

linkOpts[ID]。取消=真;

}

}

//允许卖方从到期、未执行和未取消的期权中赎回资金。

函数retrieveExpiredFunds(字符串内存令牌,uint ID) public payable {

bytes 32 token hash=ke ccak 256(ABI . encode packed(token));

require(token hash==ETH hash | | token hash==LINK hash,\’仅支持ETH和LINK令牌\’);

if (tokenHash==ethHash) {

require(msg . sender==ethOpts[ID]。writer,‘你没有写这个选项’);

//必须处于到期、未行权、未注销状态。

require(方法[ID].满期

ethOpts[ID]. writer . transfer(ethOpts[ID].金额);

//将取消标志修改为true,以避免多次赎回。

ethOpts[ID]。取消=真;

}否则{

require(msg . sender==link opts[ID]。writer,‘你没有写这个选项’);

require(linkOpts[ID].满期

require(link . transfer from(address(this),linkOpts[ID]。编写器,linkOpts[ID]。金额)、“发送的链接金额不正确”);

linkOpts[ID]。取消=真;

}

}

随着市场波动,如果期权还没有卖出,卖方可以取消期权合同,赎回资金。同样,如果期权到期未行权,卖方肯定会想赎回合约中的资金。因此,我们添加了cancelOption和retrieveExpiredFunds函数。

这两个功能最关键的一点是必须满足赎回条件才能呼叫成功。卖方赎回资金必须满足一定条件,且只能赎回一次。卖方不能取消已售出的合同,所以我们必须确保买方的地址仍然是初始值0。另外,我们还要确定选项没有被取消,然后退款。如果在期权到期后赎回资金,情况会略有不同。在这种情况下,期权可能已经卖出,但尚未行权,资金仍应返还给卖方。我们需要确认合约已经到期,还没有行权。然后还要把期权的取消标志设置为真,满足条件就退款。

希望这篇文章能帮助你马上开发主网站的Chainlink用例,让你了解Solidity的独特功能。如果你想了解更多关于Chainlink函数的信息,请查看Chainlink VRF(可验证随机函数)或Chainlink公平排序服务,了解Chainlink如何解决矿工抢人的问题。

如果您是一名开发人员,并且希望将智能合约快速连接到离线数据和系统,请查看我们的开发人员文档,并加入我们关于Discord的技术讨论组。如果您希望通过电话讨论整合的细节,请联系我们。

广告位
本文来自网络,不代表区块链网站|NFTS立场,转载请注明出处:https://www.qklwz.com/jzb/link/18393.html

作者: 买土地

上一篇
下一篇

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

返回顶部