Как сделать вызов API в солидности? - PullRequest
1 голос
/ 28 мая 2020

У меня есть смарт-контракт, который я пытаюсь заключить, он выплачивает вознаграждение победителям моего турнира по League of Legends. Однако у меня возникла проблема. Мне нужно сделать вызов API, чтобы определить победителя матча, у меня есть простой URL, который я сделал.

"example-winner.com/winner"

И он возвращает простой JSON с адресом победителя:

{"winner":"0xa7D0......."}

Однако я не уверен, как вызвать API-вызов внешней функции. Я знаю, что мне нужно использовать какую-то технологию oracle.

Есть мысли? Ниже мой код:

pragma solidity ^0.4.24;
contract LeagueWinners{
    address public manager;
    address[] public players;
    uint256 MINIMUM = 1000000000000000;
    constructor() public{
        manager = msg.sender;
    }
    function enter() public payable{
        assert(msg.value > MINIMUM);
        players.push(msg.sender);
    }
    function getWinner() public{
        assert(msg.sender == manager);
        // TODO
        // Get the winner from the API call
        result = 0; // the result of the API call
        players[result].transfer(address(this).balance);
        // returns an adress object
        // all units of transfer are in wei
        players = new address[](0);
        // this empties the dynamic array
    }
}

Ответы [ 3 ]

2 голосов
/ 29 мая 2020

Вы можете использовать Chainlink в качестве Oracle.

Как многие уже упоминали, вам понадобится oracle, чтобы получить вызов API. Важно отметить, что ваш контракт на самом деле просит oracle сделать ваш вызов API за вас, а не сам вызов API. Это потому, что блокчейн детерминирован c. Для получения дополнительной информации см. этот поток .

Чтобы ответить на ваш вопрос, вы можете использовать децентрализованный oracle сервис Chainlink .

You'd добавить функцию:

  function getWinner() 
    public
    onlyOwner
  {
    Chainlink.Request memory req = buildChainlinkRequest(JOB, address(this), this.fulfill.selector);
    req.add("get", "example-winner.com/winner");
    req.add("path", "winner");
    sendChainlinkRequestTo(ORACLE, req, ORACLE_PAYMENT);
  }

В целях следующего примера мы будем делать вид, что вы хотите вернуть uint256 вместо адреса. Вы можете вернуть bytes32, а затем преобразовать его в адрес, но для простоты предположим, что API возвращает индекс победителя. Вам нужно будет найти узел и jobId, которые могут сделать запрос http.get и вернуть объект uint256. Вы можете найти узлы и вакансии по ссылке market.link . Каждый tes tnet (Ropsten, Mai nnet, Kovan, et c) имеет разные адреса узлов, поэтому убедитесь, что вы выбрали правильные.

Для этой демонстрации мы будем использовать LinkPool. узел ropsten

address ORACLE=0x83F00b902cbf06E316C95F51cbEeD9D2572a349a;
bytes32 JOB= "c179a8180e034cf5a341488406c32827";

В идеале вы должны выбрать количество узлов для выполнения вашей работы, чтобы сделать ее недоверчивой и децентрализованной. Вы можете прочитать здесь для получения дополнительной информации о предварительных координаторах и агрегировании данных. раскрытие информации Я являюсь автором этого блога

Ваш полный контракт будет выглядеть так:

pragma solidity ^0.6.0;

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


contract GetData is ChainlinkClient {
    uint256 indexOfWinner;
    address public manager;
    address payable[] public players;
    uint256 MINIMUM = 1000000000000000;
  
  // The address of an oracle 
    address ORACLE=0x83F00b902cbf06E316C95F51cbEeD9D2572a349a;
    //bytes32 JOB= "93fedd3377a54d8dac6b4ceadd78ac34";
    bytes32 JOB= "c179a8180e034cf5a341488406c32827";
    uint256 ORACLE_PAYMENT = 1 * LINK;

  constructor() public {
    setPublicChainlinkToken();
    manager = msg.sender;
  }

function getWinnerAddress() 
    public
    onlyOwner
  {
    Chainlink.Request memory req = buildChainlinkRequest(JOB, address(this), this.fulfill.selector);
    req.add("get", "example-winner.com/winner");
    req.add("path", "winner");
    sendChainlinkRequestTo(ORACLE, req, ORACLE_PAYMENT);
  }

  // When the URL finishes, the response is routed to this function
  function fulfill(bytes32 _requestId, uint256 _index)
    public
    recordChainlinkFulfillment(_requestId)
  {
    indexOfWinner = _index;
    assert(msg.sender == manager);
    players[indexOfWinner].transfer(address(this).balance);
    players = new address payable[](0);
  }
  
  function enter() public payable{
        assert(msg.value > MINIMUM);
        players.push(msg.sender);
    } 
    
  modifier onlyOwner() {
    require(msg.sender == manager);
    _;
  }
    
    // Allows the owner to withdraw their LINK on this contract
  function withdrawLink() external onlyOwner() {
    LinkTokenInterface _link = LinkTokenInterface(chainlinkTokenAddress());
    require(_link.transfer(msg.sender, _link.balanceOf(address(this))), "Unable to transfer");
  }
  
  
}

Это сделает все, что вам нужно.

Если вы не можете настроить API для возврата uint, вы можете вернуть bytes32, а затем преобразовать его в адрес или строку.

 function bytes32ToStr(bytes32 _bytes32) public pure returns (string memory) {
     bytes memory bytesArray = new bytes(32);
     for (uint256 i; i < 32; i++) {
         bytesArray[i] = _bytes32[i];
         }
     return string(bytesArray);
     }
0 голосов
/ 28 мая 2020

Вы не можете. Виртуальная машина не имеет ввода-вывода вне самой цепочки блоков. Вместо этого вам нужно будет сообщить своему смарт-контракту, кто победил, и тогда смарт-контракт сможет просто прочитать значение этой переменной.

Этот шаблон проектирования также известен как «oracle». Google "Ethereum oracle" для получения дополнительной информации.

Обычно ваш веб-сервер может вызывать ваш смарт-контракт. Ваш смарт-контракт не может вызывать ваш веб-сервер. Если вам нужен смарт-контракт для доступа к стороннему сервису, ваш веб-сервер должен будет сделать запрос, а затем передать результат в solidity, вызвав функцию в вашем смарт-контракте.

0 голосов
/ 28 мая 2020

Вы неправильно объяснили, что пытаетесь сделать. У вас проблемы с кодом надежности? а точнее со своим сервером? Вот отредактированная версия. Посмотрим, поможет ли это.

pragma solidity ^0.4.24;
contract LeagueWinners{
    address public manager;
    //address[] public players;
    uint256 MINIMUM = 1000000000000000;
    constructor() public{
        manager = msg.sender;
    }

    struct Player {
        address playerAddress;
        uint score;
    }

    Player[] public players;


    // i prefer passing arguments this way
    function enter(uint value) public payable{
        assert(msg.value > MINIMUM);
        players.push(Player(msg.sender, value));
    }

    //call this to get the address of winner
    function winningPlayer() public view
            returns (address winner)
    {
        uint winningScore = 0;
        for (uint p = 0; p < players.length; p++) {
            if (players[p].score > winningScore) {
                winningScore = players[p].score;
                winner = players[p].playerAddress;
            }
        }
    }

    // call this to transfer fund
    function getWinner() public{
        require(msg.sender == manager, "Only a manager is allowed to perform this operation");
        // TODO

        address winner = winningPlayer();
        // Get the winner from the API call
        //uint result = 0; // the result of the API call
        winner.transfer(address(this).balance);
        // returns an adress object
        // all units of transfer are in wei
        delete players;
        // this empties the dynamic array
    }
}

По крайней мере, это то, что я понимаю под вашим вопросом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...