//SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.17;
contract Purchase{
//商品的價格
? ? uint public value;
? ? //賣家地址,可接收轉(zhuǎn)賬
? ? address payable public seller;
? ? //買家地址,可接收轉(zhuǎn)賬
? ? address payable public buyer;
? ? /*
? ? 定義了一個狀態(tài)enum,標(biāo)識訂單的四種狀態(tài)*/
? ? enum State{
Created,Locked,Release,Inactive
? ? }
//定義了一個公共狀態(tài)變量,類型是一個枚舉.
? ? Statepublic state;
? ? //定義了一個標(biāo)識符號,用于判斷滿足條件,用于校驗輸入?yún)?shù)的便捷方法
? ? modifier condition(bool condition_){
require(condition_);
? ? ? ? _;
? ? }
//定義了一個錯誤,只有buyer可以調(diào)用的方法,如果其他人調(diào)用,則觸發(fā)這個錯誤.
? ? error OnlyBuyer();
? ? //定義了一個錯誤,只有seller可以調(diào)用的方法,如果其他人調(diào)用,則觸發(fā)這個錯誤
? ? error OnlySeller();
? ? //只有特定狀態(tài)才可以調(diào)用當(dāng)前方法,如果其他狀態(tài)下調(diào)用該方法,則觸發(fā)這個錯誤
? ? error InvalidState();
? ? //提供的值必須是一個偶數(shù).否則就觸發(fā)這個錯誤.
? ? error ValueNotEven();
? ? /*
? ? 在添加了這個 onlyBuyer標(biāo)記的函數(shù)體, 首先執(zhí)行onlyBuyer() 這里的東西,然后再執(zhí)行函數(shù)體中的代碼,提高代碼的復(fù)用性*/
? ? modifier onlyBuyer(){
if(msg.sender != buyer)
revert OnlyBuyer();
? ? ? ? _;
? ? }
/*
? ? 定義了一個修飾語? onlySeller,標(biāo)記了這個修飾符的函數(shù)的,先執(zhí)行當(dāng)前修飾語中的內(nèi)容,然后再執(zhí)行之后的代碼*/
? ? modifier onlySeller(){
if(msg.sender!=seller){
revert OnlySeller();
? ? ? ? }
_;
? ? }
/*
? ? 定義了一個修飾符inState ,所有添加了這個修飾語的函數(shù),都必須執(zhí)行這里的校驗邏輯,再執(zhí)行之后的代碼,將統(tǒng)一的狀態(tài)校驗放在一個代碼塊中,提高代碼的復(fù)用性*/
? ? modifier inState(State state_){
if(state != state_){
revert InvalidState();
? ? ? ? }
_;
? ? }
event Aborted();
? ? event PurchaseConfirmed();
? ? event ItemReceived();
? ? event SellerRefunded();
? ? constructor() payable {
seller = payable(msg.sender);
? ? ? ? value = msg.value /2;
? ? ? ? if((2 * value)!= msg.value)
revert ValueNotEven();
? ? }
/*
? ? 定義了一個供外部調(diào)用的abort方法
只有賣家能調(diào)用這個方法
? ? 只有當(dāng)前狀態(tài)為Created才能調(diào)用該方法*/
? ? function abort()external onlySeller inState(State.Created){
emit Aborted();
? ? ? ? state = State.Inactive;
? ? ? ? seller.transfer(address(this).balance);
? ? }
/*
? ? 定義了一個供外部調(diào)用的確認(rèn)購買函數(shù), 調(diào)用當(dāng)前方法,要求當(dāng)前狀態(tài)必須為已創(chuàng)建,并且當(dāng)前傳遞參數(shù)中msg.value必須是狀態(tài)變量value的兩倍.
? ? 并且當(dāng)前函數(shù)是可以向指定地址轉(zhuǎn)賬.
*/
? ? function confirmPurchase()external inState(State.Created) condition(msg.value == (2*value))payable {
emit PurchaseConfirmed();//發(fā)送購買確認(rèn)的事件
? ? ? ? buyer = payable(msg.sender);//將調(diào)用方地址轉(zhuǎn)為可接收轉(zhuǎn)賬的地址,并且將狀態(tài)修改為已經(jīng)鎖定
? ? ? ? state = State.Locked;
? ? }
/*
? ? 定義了一個供外部訪問的確認(rèn)已收到的函數(shù), 該方法只允許買家身份調(diào)用,并且狀態(tài)必須為已鎖定*/
? ? function confirmReceived()external onlyBuyer inState(State.Locked) {
emit ItemReceived();
? ? ? ? state = State.Release;
? ? ? ? buyer.transfer(value);//向買家轉(zhuǎn)賬value的金額
? ? }
/*
? ? 定義了一個供外部訪問的退款給賣家的方法. 并且只有賣家可以調(diào)用,并且狀態(tài)必須為release
*/
? ? function refundSeller()external onlySeller inState(State.Release) {
emit SellerRefunded();//發(fā)送賣家退款的事件
? ? ? ? state = State.Inactive;//將狀態(tài)設(shè)置為失效狀態(tài)
? ? ? ? seller.transfer(3 * value);//給賣家轉(zhuǎn)三倍value的款
? ? }
}