こんにちはhabr!最近、ロシア語を話す聴衆がブロックチェーンの世界に入り、そこで発展するためのチュートリアルがほとんどないことに気づきました。Ethereumのスマートコントラクトに関する記事を共有することにしました。この記事はかつて私を大いに助け、ブロックチェーンの世界を掘り下げ、そこでスマートな契約を開発しました。このリンクの元の記事。
物を売買できるオークションについて聞いたことがあるかもしれません。これは非常に便利ですが、売り手はオークション管理会社にサービス料金を支払うために収益の約10%を要します。
会社が取引自体の一部をだまして支払いを受けた場合、だまされたかどうかをどうやって知ることができますか?
これは、分散インストールが最適なソリューションであるところです。
第三者がいない場合、売り手は安全な方法でより多くを稼ぐことができます。
機能リスト
オークションの作成
賭けをする
オークション終了
ツール
前提条件
Github
, :
https://github.com/openberry-ac/Auction
?
- - , .
- , , - , , .
-
- Web3.js
:
-
Ethereum, Solidity , , -.
Remix AuctionBox.sol :
// AuctionBox.sol
// We will be using Solidity version 0.5.3
pragma solidity 0.5.3;
// Importing OpenZeppelin's SafeMath Implementation
import "https://github.com/OpenZeppelin/openzeppelin-solidity/contracts/math/SafeMath.sol";
contract AuctionBox{
Auction[] public auctions;
function createAuction (
string memory _title,
uint _startPrice,
string memory _description
) public{
// set the new instance
Auction newAuction = new Auction(msg.sender, _title, _startPrice, _description);
// push the auction address to auctions array
auctions.push(newAuction);
}
function returnAllAuctions() public view returns(Auction[] memory){
return auctions;
}
}
contract Auction {
using SafeMath for uint256;
address payable private owner;
string title;
uint startPrice;
string description;
enum State{Default, Running, Finalized}
State public auctionState;
uint public highestPrice;
address payable public highestBidder;
mapping(address => uint) public bids;
/** @dev constructor to creat an auction
* @param _owner who call createAuction() in AuctionBox contract
* @param _title the title of the auction
* @param _startPrice the start price of the auction
* @param _description the description of the auction
*/
constructor(
address payable _owner,
string memory _title,
uint _startPrice,
string memory _description
) public {
// initialize auction
owner = _owner;
title = _title;
startPrice = _startPrice;
description = _description;
auctionState = State.Running;
}
modifier notOwner(){
require(msg.sender != owner);
_;
}
/** @dev Function to place a bid
* @return true
*/
function placeBid() public payable notOwner returns(bool) {
require(auctionState == State.Running);
require(msg.value > 0);
// update the current bid
// uint currentBid = bids[msg.sender] + msg.value;
uint currentBid = bids[msg.sender].add(msg.value);
require(currentBid > highestPrice);
// set the currentBid links with msg.sender
bids[msg.sender] = currentBid;
// update the highest price
highestPrice = currentBid;
highestBidder = msg.sender;
return true;
}
function finalizeAuction() public{
//the owner and bidders can finalize the auction.
require(msg.sender == owner || bids[msg.sender] > 0);
address payable recipiant;
uint value;
// owner can get highestPrice
if(msg.sender == owner){
recipiant = owner;
value = highestPrice;
}
// highestBidder can get no money
else if (msg.sender == highestBidder){
recipiant = highestBidder;
value = 0;
}
// Other bidders can get back the money
else {
recipiant = msg.sender;
value = bids[msg.sender];
}
// initialize the value
bids[msg.sender] = 0;
recipiant.transfer(value);
auctionState = State.Finalized;
}
/** @dev Function to return the contents od the auction
* @return the title of the auction
* @return the start price of the auction
* @return the description of the auction
* @return the state of the auction
*/
function returnContents() public view returns(
string memory,
uint,
string memory,
State
) {
return (
title,
startPrice,
description,
auctionState
);
}
}
. , , «AuctionBox», !
, , AuctionBox.
Remix Ropsten.
, , Remix: AuctionBox .
!
createAuction .
returnAllAuctions !
-
- , , -.
, , . ( /Powershell Windows):
# git clone the project template
git clone -b boilerplate --single-branch https://github.com/openberry-ac/Auction.git
# go inside the folder
cd Auction
# install packages needed in the web application
npm install
# install web3, this is for connecting the contract
npm install -s web3@1.0.0-beta.37
# To run the app
npm run dev
web3.js
web3.js , :
// web3.js
import Web3 from 'web3';
if (window.ethereum) {
window.web3 = new Web3(ethereum);
try {
// Request account access if needed
ethereum.enable();
} catch (error) {
// User denied account access...
}
} else if (window.web3) { // Legacy dapp browsers...
window.web3 = new Web3(web3.currentProvider);
} else { // Non-dapp browsers...
console.log('Non-Ethereum browser detected. You should consider trying MetaMask!');
}
console.log(web3);
export default web3;
, web3
, Metamask, . -.
MetaMask , . «» :
-
ABI - , -. ABI, Remix , Compile ABI Details, :
, « » « » , :
ABI ABI.
, AuctionBoxInstance.js AuctionInstance.js e contracts, ABI «s , :
//AuctionBoxInstance.js
import web3 from './web3';
const address = ''// THE CONTRACT ADDRESS
const abi = []// THE ABI
const instance = new web3.eth.Contract(abi, address);
export default instance;
// AuctionInstance.js
import web3 from './web3';
const abi = []// THE ABI
// Here is just only abi because we haven't created auction yet.
export default (address) => {
const instance = new web3.eth.Contract(abi, address);
return instance;
};
, , . , , . App.vue src !
beforeMount
, .
// App.vue
beforeMount() {
// get auctionBox method: returnAllAuctions()
auctionBox.methods
.returnAllAuctions()
.call()
.then((auctions) => {
console.log(auctions);
// set the amount of auctions
this.amount = auctions.length;
});
},
, , .
// App.vue
createAuction() {
// get accounts
web3.eth.getAccounts().then((accounts) => {
// convert 'ether' to 'wei'
const startPrice = web3.utils.toWei(this.startPrice, 'ether');
// createAuction in AuctionBox contract
this.isLoad = true;
return auctionBox.methods.createAuction(this.title, startPrice, this.description)
.send({ from: accounts[0] });
}).then(() => {
// initialize forms
this.isLoad = false;
this.title = '';
this.startPrice = '';
this.description = '';
// get the previous auction
return auctionBox.methods.returnAllAuctions().call();
}).then((auctions) => {
const index = auctions.length - 1;
console.log(auctions[index]);
// get the contract address of the previous auction
this.auctionAddress = auctions[index];
// set the address as the parameter
const auctionInstance = auction(auctions[index]);
return auctionInstance.methods.returnContents().call();
})
.then((lists) => {
console.log(lists);
const auctionlists = lists;
// convert 'wei' to 'ether'
auctionlists[1] = web3.utils.fromWei(auctionlists[1], 'ether');
this.auctionCard = auctionlists;
// show up the auction at the bottom of the page
this.isShow = true;
this.amount += 1;
})
.catch((err) => {
console.log(err);
});
},
, .
// App.vue
handleSubmit() {
// convert 'ether' to 'wei'
const bidPriceWei = web3.utils.toWei(this.bidPrice, 'ether');
// get the wallet adddress
const fromAddress = web3.eth.accounts.givenProvider.selectedAddress;
// set the address as the parameter
const selectedAuction = auction(this.auctionAddress);
this.isBid = true;
// placeBid in Auction contract
selectedAuction.methods
.placeBid()
.send({
from: fromAddress,
value: bidPriceWei,
})
.then(() => {
this.isBid = false;
// increase the number of bidders
this.bidders += 1;
this.bidPrice = '';
});
},
, .
// App.vue
handleFinalize() {
// get accounts
web3.eth.getAccounts().then((accounts) => {
// set the address as the parameter
const selectedAuction = auction(this.auctionAddress);
this.isFin = true;
// finalizeAuction in Auction contract
selectedAuction.methods
.finalizeAuction()
.send({ from: accounts[0] })
.then(() => {
this.isFin = false;
this.finalizeStatus = 'finalized';
});
});
},
Remix, .
9 , :
!!
, . - , ! :
: , , . , ( ), .
. , .
, - web3.js. , Vue.js, .
では、次は何ですか?
これは実際のオークションアプリケーションでは重要であるため、「期限」のロジックを追加することをお勧めします。複雑さを避けて時間を短縮するために、今はスキップしましたが、ビルドしてみたけれ ば、大いに役立ちます。
このチュートリアルの完全なコードが必要な場合は、ここで確認できます。