Dacade平台SUI Move挑战者合约实践——去中心化自由职业市场(Decentralized Freelance Marketplace)
rzexin 2024.02.24
SUI
区块链的智能合约平台,使雇主和自由职业者能够进行无需信任的交易。该平台利用Move语言开发智能合约,提供创建自由职业项目(freelance gigs
)、处理付款、争议解决和各种其他功能。https://github.com/Tevin-Isaac/sui-marketplace-move/blob/master/sources/marketplace.move
后续贴出的代码,均使用修复后的代码。
struct FreelanceGig has key, store {
id: UID,
client: address,
freelancer: address,
description: vector<u8>,
price: u64,
escrow: Balance<SUI>,
workSubmitted: bool,
dispute: bool,
}
create_gig
)FreelanceGig
)是一个共享对象 public entry fun create_gig(description: vector<u8>, price: u64, ctx: &mut TxContext) {
let gig_id = object::new(ctx);
transfer::share_object(FreelanceGig {
id: gig_id,
client: tx_context::sender(ctx),
freelancer: @0x0, // Set to an initial value, can be updated later
description: description,
price: price,
escrow: balance::zero<SUI>(),
workSubmitted: false,
dispute: false,
});
}
bid_on_gig
)只要该临时工作未被竞标,任何人都可以进行申请
注:一般雇主会发布他们需要完成的任务或项目,然后自由职业者可以对这些项目进行竞标,提出他们愿意接受这个工作以及他们的报价。雇主通常会根据报价、经验、技能和以往的工作表现等因素来选择最适合的自由职业者。本合约简化这块逻辑,是让最先的竞标者将会得到该工作,后续有用户再来竞标,将会直接报错。
public entry fun bid_on_gig(gig: &mut FreelanceGig, ctx: &mut TxContext) {
assert!(gig.freelancer == @0x0, EInvalidBid);
gig.freelancer = tx_context::sender(ctx);
}
submit_work
) public entry fun submit_work(gig: &mut FreelanceGig, ctx: &mut TxContext) {
assert!(gig.freelancer == tx_context::sender(ctx), EInvalidWork);
gig.workSubmitted = true;
}
public entry fun dispute_gig(gig_id: UID, ctx: &mut TxContext) {
let gig = object::borrow_mut<FreelanceGig>(gig_id, ctx);
assert!(gig.client == tx_context::sender(ctx), EDispute);
gig.dispute = true;
}
resolve_dispute
)public entry fun resolve_dispute(gig: &mut FreelanceGig, resolved: bool, ctx: &mut TxContext) {
assert!(gig.client == tx_context::sender(ctx), EDispute);
assert!(!gig.dispute, EAlreadyResolved);
let amount = balance::value(&gig.escrow);
let take_coin = coin::take(&mut gig.escrow, amount, ctx);
let recipient;
if (resolved) {
// Transfer funds to the freelancer
recipient = gig.freelancer
} else {
// Refund funds to the client
recipient = gig.client;
};
transfer::public_transfer(take_coin, recipient);
// Reset gig state
gig.freelancer = @0x0;
gig.workSubmitted = false;
gig.dispute = false;
}
release_payment
) public entry fun release_payment(gig: &mut FreelanceGig, ctx: &mut TxContext) {
assert!(gig.client == tx_context::sender(ctx), ENotFreelancer);
assert!(gig.workSubmitted && !gig.dispute, EInvalidWork);
// Transfer funds to the freelancer
let amount = balance::value(& gig.escrow);
let take_coin = coin::take(&mut gig.escrow, amount, ctx);
transfer::public_transfer(take_coin, gig.freelancer);
// Reset gig state
gig.freelancer = @0x0;
gig.workSubmitted = false;
gig.dispute = false;
}
public entry fun cancel_gig(gig: &mut FreelanceGig, ctx: &mut TxContext) {
assert!(gig.client == tx_context::sender(ctx) || gig.freelancer == tx_context::sender(ctx), ENotFreelancer);
// Refund funds to the client if not yet paid
if (gig.freelancer != @0x0 && !gig.workSubmitted && !gig.dispute) {
let amount = balance::value(&gig.escrow);
let take_coin = coin::take(&mut gig.escrow, amount, ctx);
transfer::public_transfer(take_coin, gig.client);
};
// Reset gig state
gig.freelancer = @0x0;
gig.workSubmitted = false;
gig.dispute = false;
}
public entry fun withdraw_earnings(gig: &mut FreelanceGig, amount: u64, ctx: &mut TxContext) {
// Withdraw earnings from the freelancer's balance
let freelancer_id = object::new(ctx);
let recipient = tx_context::sender(ctx);
assert!(gig.freelancer == recipient, ENotFreelancer);
let take_coin = coin::take(&mut gig.escrow, amount, ctx);
let freelancer = Freelancer {
id : freelancer_id,
balance: coin::into_balance(take_coin),
};
transfer::public_transfer(freelancer, recipient);
}
public entry fun get_freelancer_balance(freelancer: &Freelancer): u64 {
balance::value(&freelancer.balance)
}
public entry fun add_funds_to_gig(gig: &mut FreelanceGig, payment: Coin<SUI>, ctx: &mut TxContext) {
assert!(tx_context::sender(ctx) == gig.client, ENotFreelancer);
coin::put(&mut gig.escrow, payment);
}
public entry fun request_refund(gig: &mut FreelanceGig, ctx: &mut TxContext) {
assert!(tx_context::sender(ctx) == gig.client, ENotFreelancer);
assert!(gig.workSubmitted == false, EInvalidWithdrawal);
// Refund funds to the client
let amount = balance::value(& gig.escrow);
let take_coin = coin::take(&mut gig.escrow, amount, ctx);
transfer::public_transfer(take_coin, gig.client);
// Reset gig state
gig.freelancer = @0x0;
gig.workSubmitted = false;
gig.dispute = false;
}
别名 | 地址 | 角色 |
---|---|---|
Jason | 0x5c5882d73a6e5b6ea1743fb028eff5e0d7cc8b7ae123d27856c5fe666d91569a |
雇主 |
Alice | 0x2d178b9704706393d2630fe6cf9415c2c50b181e9e3c7a977237bb2929f82d19 |
雇员 |
Bob | 0xf2e6ffef7d0543e258d4c47a53d6fa9872de4630cc186950accbd83415b009f0 |
雇员 |
export JASON=0x5c5882d73a6e5b6ea1743fb028eff5e0d7cc8b7ae123d27856c5fe666d91569a
export ALICE=0x2d178b9704706393d2630fe6cf9415c2c50b181e9e3c7a977237bb2929f82d19
export BOB=0xf2e6ffef7d0543e258d4c47a53d6fa9872de4630cc186950accbd83415b009f0
切换到Jason账号
sui client publish --gas-budget 100000000
export PACKAGE_ID=0x4a57fbaf781579664efc618db090dd3d4818b811dd0fb3a91a9eb6403c371953
create_gig
)切换到Jason
export DESC="test"
export PRICE=100
sui client call --function create_gig --package $PACKAGE_ID --module freelance_marketplace --args $DESC $PRICE --gas-budget 10000000
# PACKAGE_ID::freelance_marketplace::FreelanceGig
export GIG=0x4a423df0135adadb67dcd04a7fe8f4680e972b1a98b2b5197a87873d4bb014b3
sui client object $GIG
export COIN=0x9dd8c0daf2bbdcd4efaf179cdef6e9383b80a1de2b7851f6293e8f721037d7cf # 800
sui client call --function add_funds_to_gig --package $PACKAGE_ID --module freelance_marketplace --args $GIG $COIN --gas-budget 10000000
sui client object $GIG
bid_on_gig
)切换到Alice
若Alice已经应聘,Bob再次应聘的话,将会报错:
Error executing transaction: Failure { error: "MoveAbort(MoveLocation { module: ModuleId { address: 4a57fbaf781579664efc618db090dd3d4818b811dd0fb3a91a9eb6403c371953, name: Identifier(\"freelance_marketplace\") }, function: 3, instruction: 12, function_name: Some(\"bid_on_gig\") }, 1) in command 0", }
sui client call --function bid_on_gig --package $PACKAGE_ID --module freelance_marketplace --args $GIG --gas-budget 10000000
sui client object $GIG
submit_work
)sui client call --function submit_work --package $PACKAGE_ID --module freelance_marketplace --args $GIG --gas-budget 10000000
sui client object $GIG
release_payment
)切换Jason
sui client call --function release_payment --package $PACKAGE_ID --module freelance_marketplace --args $GIG --gas-budget 10000000
sui client object 0xaa336e6e334debd8282b3f460f47c18da7bd69d78ded5c88acb33e749b583d28
工作对象已经被重置。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!