BTC
ETH
HTX
SOL
BNB
시장 동향 보기
简中
繁中
English
日本語
한국어
ภาษาไทย
Tiếng Việt

분산형 오라클 머신인 Chainlink에 연결하여 가격을 제공하고 DeFi 콜 옵션 거래 플랫폼 예제를 개발합니다.

Chainlink
特邀专栏作者
2020-11-17 05:17
이 기사는 약 11317자로, 전체를 읽는 데 약 17분이 소요됩니다
이 기사에서는 Chainlink 가격 피드 오라클을 사용하여 이더리움 메인넷에서 Solidity로 간단한 콜 옵션 DeFi 거래 플랫폼을 개발하는 방법을 알려드립니다.
AI 요약
펼치기
이 기사에서는 Chainlink 가격 피드 오라클을 사용하여 이더리움 메인넷에서 Solidity로 간단한 콜 옵션 DeFi 거래 플랫폼을 개발하는 방법을 알려드립니다.

DeFi의 광범위한 범주에는 다음과 같은 많은 스마트 계약 애플리케이션 시나리오가 포함됩니다.블록체인 투표유동성 채굴유동성 채굴체인링크 가격 피드체인링크 가격 피드Oracle은 Solidity를 사용하여 Ethereum 메인넷에서 간단한 콜 옵션 DeFi 거래 플랫폼을 개발합니다. 물론 이 예제를 약간 수정하여 풋 옵션 거래 플랫폼을 개발할 수도 있습니다. 이 플랫폼은 강력한 기능을 가지고 있습니다. 즉, 모든 가치 전송은 스마트 계약을 통해 수행되며 거래의 양 당사자는 중간 당사자를 거치지 않고 직접 거래를 수행할 수 있습니다. 따라서 이 프로세스에는 제3자가 관여하지 않으며 가장 일반적인 DeFi 애플리케이션인 스마트 계약과 분산형 체인링크 가격 피드만 포함됩니다. 탈중앙화 옵션 거래 플랫폼 개발에는 다음이 포함됩니다.

  • Solidity에서 문자열 비교

  • 정수를 고정된 소수점 이하 자릿수로 변환

  • LINK와 같은 토큰 인터페이스 생성 및 초기화

  • 사용자/스마트 계약 간 토큰 전송

  • 토큰 전송 승인

  • SafeMath

  • 스마트 계약 ABI 인터페이스

  • require()로 트랜잭션 상태 실행

  • Ethereum msg.Value와 토큰 가치 거래와의 차이점

  • int와 uint 간 변환

  • 수취인 주소

  • 마지막으로 Chainlink 데이터 집계 인터페이스를 사용하여 DeFi 가격 데이터를 얻습니다.

그리고GitHub그리고Remix관련 코드를 확인하십시오. 본격적으로 시작하기 전에 옵션 계약이 무엇인지 간단히 소개하겠습니다. 옵션 계약은 특정 날짜까지 합의된 가격으로 거래를 실행할 수 있는 옵션을 제공합니다. 구체적으로 옵션계약의 내용이 주식이나 토큰 등의 자산을 매수하는 것이라면 이를 콜옵션이라고 합니다. 또한 이 기사의 샘플 코드는 옵션을 넣기 위해 약간 수정될 수 있습니다. 풋옵션은 콜옵션의 반대 개념으로 자산을 사는 것이 아니라 파는 것입니다. 다음은 옵션과 관련된 일부 고유 명사입니다.

  • 스트라이크 가격: 자산의 합의된 매수/매도 가격

  • Option Fee: 계약 매수 시 매도자에게 지불하는 수수료

  • 만료일: 계약이 종료되는 시간

  • 스트라이크: 구매자가 자산을 스트라이크 가격으로 사거나 팔 수 있는 권리를 행사하는 행위

호출을 개발하든 입력을 개발하든 관계없이 가져오기, 생성자 및 전역 변수의 기본 요소가 필요합니다.

pragma solidity ^0.6.7;

import "https://github.com/smartcontractkit/chainlink/blob/develop/evm-contracts/src/v0.6/interfaces/LinkTokenInterface.sol";

import "https://github.com/smartcontractkit/chainlink/blob/master/evm-contracts/src/v0.6/interfaces/AggregatorV3Interface.sol";

import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/SafeMath.sol";

contract chainlinkOptions {

// 오버플로 안전 연산자

using SafeMath for uint;

// 가격 피드 인터페이스

AggregatorV3Interface internal ethFeed;

AggregatorV3Interface internal linkFeed;

//LINK 토큰 인터페이스

LinkTokenInterface internal LINK;

uint ethPrice;

uint linkPrice;

//문자열 해시 값 미리 계산

bytes32 ethHash = keccak256(abi.encodePacked("ETH"));

bytes32 linkHash = keccak256(abi.encodePacked("LINK"));

address payable contractAddr;

//옵션은 구조체형 배열로 저장

struct option {

uint strike; //Price in USD (18 decimal places) option allows buyer to purchase tokens at

uint premium; //Fee in contract token that option writer charges

uint expiry; //Unix timestamp of expiration time

uint amount; //Amount of tokens the option contract is for

bool exercised; //Has option been exercised

bool canceled; //Has option been canceled

uint id; //Unique ID of option, also array index

uint latestCost; //Helper to show last updated cost to exercise

address payable writer; //Issuer of option

address payable buyer; //Buyer of option

}

option[] public ethOpts;

option[] public linkOpts;

//Kovan 피드 가격: https://docs.chain.link/docs/reference-contracts

constructor() public {

// ETH/USD에 대한 Kovan 가격 피드

ethFeed = AggregatorV3Interface(0x9326BFA02ADD2366b30bacB125260Af641031331);

//LINK/USD Kovan 피드 가격

linkFeed = AggregatorV3Interface(0x396c5E36DD0a0F5a5D33dae44368D4193f69a1F0);

//Kovan의 링크 토큰 주소

LINK = LinkTokenInterface(0xa36085F69e2889c224210F603D836748e7dC0088);

contractAddr = payable(address(this));

}

가져올 때 가격 피드 기능을 실현하기 위해 Chainlink의 데이터 수집기 ​​인터페이스에 액세스하고 LINK 토큰 인터페이스에 액세스해야 합니다(참고: 여기에서 송금하려면 LINK를 사용해야 하므로 토큰 계약의 ERC20 기능을 사용해야 합니다) . 마지막으로 수입OpenZeppelin의 SafeMath기본 제공 오버플로 검사를 수행하는 표준 라이브러리 작업인 계약인 반면 Solidity는 기본 제공 연산자에 오버플로 검사를 포함하지 않습니다.

체인링크 가격 피드

체인링크 가격 피드

//최신 LINK 가격 반환

function getLinkPrice() public view returns (uint) {

(

uint80 roundID,

int price,

uint startedAt,

uint timeStamp,

uint80 answeredInRound

) = linkFeed.latestRoundData();

//이 라운드가 아직 종료되지 않은 경우 타임스탬프는 0입니다.

require(timeStamp > 0, "Round not complete");

//가격은 절대 음수가 아니므로 int를 uint로 변환할 수 있습니다.

//가격은 소수점 이하 8자리이며 10자리를 더하면 18자리가 됩니다.

return uint(price);

}

첫 번째 레벨 제목

콜 옵션 계약 작성

//사용자가 보류 통화 옵션을 작성할 수 있도록 허용

// 수령한 토큰 종류, 행사가격(토큰은 USD로 표기, 소수점 이하 18자리), 옵션 수수료(토큰의 소수점과 동일), 만료일(유닉스), 계약 수량의 토큰

function writeOption(string memory token, uint strike, uint premium, uint expiry, uint tknAmt) public payable {

bytes32 tokenHash = keccak256(abi.encodePacked(token));

require(tokenHash == ethHash || tokenHash == linkHash, "Only ETH and LINK tokens are supported");

updatePrices();

if (tokenHash == ethHash) {

require(msg.value == tknAmt, "Incorrect amount of ETH supplied");

uint latestCost = strike.mul(tknAmt).div(ethPrice.mul(10**10)); //이더로 표시된 운동 비용, 소수점 조정

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

} else {

require(LINK.transferFrom(msg.sender, contractAddr, tknAmt), "Incorrect amount of LINK supplied");

uint latestCost = strike.mul(tknAmt).div(linkPrice.mul(10**10));

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

}

}

이미지 설명


LINK 토큰에 대한 LINK 옵션 계약을 작성하고 Unix 만료 시간을 설정하고 행사 가격은 $10이며 옵션 수수료는 0.1 LINK입니다.

첫 번째 레벨 제목

계약 ABI 인터페이스

Etherscan에서 계약을 볼 때 Read Contract와 Write Contract라는 두 개의 탭이 있습니다. 이 두 탭을 사용하여 계약과 상호 작용할 수 있습니다. 예: LINK 토큰 메인 네트워크 컨트랙트. Etherscan은 이러한 기능이 무엇이며 계약의 ABI를 통해 호출하는 방법을 알고 있습니다. JSON 형식을 사용하여 ABI를 호출하고 함수 호출 매개변수를 지정합니다. 메인 네트워크에서 직접 호출할 수 있지만 Kovan의 LINK 컨트랙트는 이 모듈을 가져와야 합니다. 당신은 할 수 있습니다LinkToken이미지 설명

이미지 설명

첫 번째 레벨 제목

콜 옵션 구매

//콜 옵션을 구매하려면 토큰, 옵션 ID 및 결제가 필요합니다.

function buyOption(string memory token, uint ID) public payable {

bytes32 tokenHash = keccak256(abi.encodePacked(token));

require(tokenHash == ethHash || tokenHash == linkHash, "Only ETH and LINK tokens are supported");

updatePrices();

if (tokenHash == ethHash) {

require(!ethOpts[ID].canceled && ethOpts[ID].expiry > now, "Option is canceled/expired and cannot be bought");

//구매자가 옵션 프리미엄을 지불합니다.

require(msg.value == ethOpts[ID].premium, "Incorrect amount of ETH sent for premium");

//판매자는 옵션 수수료를 받습니다.

ethOpts[ID].writer.transfer(ethOpts[ID].premium);

ethOpts[ID].buyer = msg.sender;

} else {

require(!linkOpts[ID].canceled && linkOpts[ID].expiry > now, "Option is canceled/expired and cannot be bought");

//매수자로부터 매도자에게 옵션 프리미엄 이전

require(LINK.transferFrom(msg.sender, linkOpts[ID].writer, linkOpts[ID].premium), "Incorrect amount of LINK sent for premium");

linkOpts[ID].buyer = msg.sender;

}

}

첫 번째 레벨 제목

운동 옵션

// 운동 콜 옵션, 토큰 필요, 옵션 ID 및 지불

function exercise(string memory token, uint ID) public payable {

//옵션이 만료되지 않고 행사되지 않은 경우 옵션 소유자가 행사할 수 있습니다.

//옵션을 행사하기 위해서는 구매자가 판매자에게 행사가격*수량만큼의 금액을 지불하고 계약서에서 합의한 토큰수만큼을 받아야 합니다.

bytes32 tokenHash = keccak256(abi.encodePacked(token));

require(tokenHash == ethHash || tokenHash == linkHash, "Only ETH and LINK tokens are supported");

if (tokenHash == ethHash) {

require(ethOpts[ID].buyer == msg.sender, "You do not own this option");

require(!ethOpts[ID].exercised, "Option has already been exercised");

require(ethOpts[ID].expiry > now, "Option is expired");

// 조건 충족, 결제

updatePrices();

// 운동비

uint exerciseVal = ethOpts[ID].strike*ethOpts[ID].amount;

//체인링크에 연결하여 가격을 공급하고 이더리움으로 변환

uint equivEth = exerciseVal.div(ethPrice.mul(10**10)); //피드 가격의 소수점 이하 8자리를 18로 변환

//구매자는 옵션을 행사하기 위해 행사 가격*수량에 해당하는 이더를 지불합니다.

require(msg.value == equivEth, "Incorrect LINK amount sent to exercise");

//판매자에게 운동비 지급

ethOpts[ID].writer.transfer(equivEth);

//구매자에게 이더 계약금액만큼 지급

msg.sender.transfer(ethOpts[ID].amount);

ethOpts[ID].exercised = true;

} else {

require(linkOpts[ID].buyer == msg.sender, "You do not own this option");

require(!linkOpts[ID].exercised, "Option has already been exercised");

require(linkOpts[ID].expiry > now, "Option is expired");

updatePrices();

uint exerciseVal = linkOpts[ID].strike*linkOpts[ID].amount;

uint equivLink = exerciseVal.div(linkPrice.mul(10**10));

//매수인이 옵션을 행사하고 행사수수료를 매도인에게 지급

require(LINK.transferFrom(msg.sender, linkOpts[ID].writer, equivLink), "Incorrect LINK amount sent to exercise");

//판매자에게 LINK 토큰의 계약 금액을 지불

require(LINK.transfer(msg.sender, linkOpts[ID].amount), "Error: buyer was not paid");

linkOpts[ID].exercised = true;

}

}

이미지 설명

예: 트랜잭션이 하나 이상의 조건을 충족하지 않을 때 Remix 출력 결과.

조건이 충족되면 판매자에게 운동수수료가 지급되고, 구매자에게는 계약된 토큰의 개수가 지급됩니다. 옵션을 행사할 때 구매자는 행사 가격으로 각 토큰을 구매해야 합니다. 그러나 행사 가격은 USD로 표시되고 계약 크기는 Ether 또는 LINK로 표시됩니다. 따라서 우리는 운동 수수료에 해당하는 ETH 또는 LINK의 양을 계산하기 위해 Chainlink 가격 피드에 액세스해야 합니다. 동등한 ETH 또는 LINK로 변환한 후 전송을 시작할 수 있습니다. 돈을 송금할 때 위에서 언급한 방법을 사용해야 합니다. 즉, 에테르 통화는 msg.value/address.transfer 함수를 호출하고 LINK는 transferFrom() 함수를 호출합니다.

첫 번째 레벨 제목

계약취소/자금삭제

// 판매자가 거래를 성공적으로 종료하지 못한 옵션에서 계약을 취소하거나 환불받을 수 있습니다.

function cancelOption(string memory token, uint ID) public payable {

bytes32 tokenHash = keccak256(abi.encodePacked(token));

require(tokenHash == ethHash || tokenHash == linkHash, "Only ETH and LINK tokens are supported");

if (tokenHash == ethHash) {

require(msg.sender == ethOpts[ID].writer, "You did not write this option");

// 취소 또는 구매한 적이 없어야 합니다.

require(!ethOpts[ID].canceled && ethOpts[ID].buyer == address(0), "This option cannot be canceled");

ethOpts[ID].writer.transfer(ethOpts[ID].amount);

ethOpts[ID].canceled = true;

} else {

require(msg.sender == linkOpts[ID].writer, "You did not write this option");

require(!linkOpts[ID].canceled && linkOpts[ID].buyer == address(0), "This option cannot be canceled");

require(LINK.transferFrom(address(this), linkOpts[ID].writer, linkOpts[ID].amount), "Incorrect amount of LINK sent");

linkOpts[ID].canceled = true;

}

}

//판매자가 만료, 미결제 및 취소되지 않은 옵션에서 자금을 상환할 수 있도록 허용합니다.

function retrieveExpiredFunds(string memory token, uint ID) public payable {

bytes32 tokenHash = keccak256(abi.encodePacked(token));

require(tokenHash == ethHash || tokenHash == linkHash, "Only ETH and LINK tokens are supported");

if (tokenHash == ethHash) {

require(msg.sender == ethOpts[ID].writer, "You did not write this option");

//만료되어야 하며, 행사되거나 취소되어서는 안 됩니다.

require(ethOpts[ID].expiry <= now && !ethOpts[ID].exercised && !ethOpts[ID].canceled, "This option is not eligible for withdraw");

ethOpts[ID].writer.transfer(ethOpts[ID].amount);

//취소 플래그를 true로 수정하여 여러 번 상환하지 않도록 합니다.

ethOpts[ID].canceled = true;

} else {

require(msg.sender == linkOpts[ID].writer, "You did not write this option");

require(linkOpts[ID].expiry <= now && !linkOpts[ID].exercised && !linkOpts[ID].canceled, "This option is not eligible for withdraw");

require(LINK.transferFrom(address(this), linkOpts[ID].writer, linkOpts[ID].amount), "Incorrect amount of LINK sent");

linkOpts[ID].canceled = true;

}

}

시장이 변동함에 따라 판매자는 옵션이 판매되지 않은 경우 옵션 계약을 취소하고 자금을 상환할 수 있습니다. 마찬가지로 옵션이 행사되지 않고 만료되면 판매자는 확실히 계약의 자금을 상환하기를 원할 것입니다. 따라서 cancelOption() 및 retrieveExpiredFunds() 함수를 추가했습니다.

이 두 함수의 가장 중요한 포인트는 성공적으로 호출하기 위해서는 상환 조건이 충족되어야 한다는 것입니다. 판매자가 자금을 상환하려면 특정 조건을 충족해야 하며 한 번만 상환할 수 있습니다. 판매자는 판매가 완료된 계약을 취소할 수 없으므로 구매자의 주소가 여전히 초기값 0인지 확인해야 합니다. 또한 해당 옵션이 취소되지 않았는지 확인 후 환불해 주셔야 합니다. 옵션이 만료된 후 자금을 상환하면 상황이 약간 달라집니다. 이 경우 옵션이 판매되었지만 행사되지 않았을 수 있으며 자금은 여전히 ​​판매자에게 반환되어야 합니다. 계약이 만료되어 행사되지 않았음을 확인하고자 합니다. 그런 다음 옵션의 취소 플래그를 true로 설정하여 조건이 충족되면 환불합니다.

이 기사가 메인넷에서 즉시 Chainlink 사용 사례를 개발하고 Solidity의 고유한 기능을 이해하는 데 도움이 되기를 바랍니다. Chainlink 기능에 대해 자세히 알아보려면 다음을 확인하세요.Chainlink VRF(검증 가능한 임의 함수) 또는 참조Chainlink 공정한 주문 서비스, Chainlink가 광부 선행 문제를 해결하는 방법을 알아보십시오.

그리고 우리와 함께개발자 문서그리고 우리와 함께Discord문의하기.여기를 클릭문의하기.

Chainlink
DeFi
开发者
期权
Odaily 공식 커뮤니티에 가입하세요