番外篇:我在dacade赚了100SUI

事先说明,本篇文章不是广告,只是讲述我如何在Dacade的挑战中赢得了100SUI的经历。如果大家有疑问可以自己去dacade官网查看,仔细辨别:https://dacade.org/communities/sui/challenges/19885730-fb83-477a-b95b-4ab265b61438

这是我在dacede中提现100SUI的截图:

这个挑战的要求是

  • 在DEFI领域创建创新项目,例如用于交易所,贷款平台或产量耕作应用程序的原型。

  • 确保项目的高质量代码:结构良好,高效,最佳实践,详细的代码注释并没有错误。

按照上述要求编写,70分以上就能获得100SUI。他们的评分分为两个部分,一个是原创分满分60,另外一个部分则是代码质量分满分40分。原创是非常重要的分数,建议大家在写之前看看历次已经得分的提交,如果有人写过的功能最好就不要写了,原创分低的话很难超过70。高质量代码他们也给出了范例,可以拉优秀的代码下来研究一下再写

代码提写完代码提交到代码仓库,并在dacade中提交你的代码仓库地址,接下来只需要等待审核就可以啦。根据我的观察审核周期是在一周到一个月不等,只要审核通过就会收到邮件。

下面我介绍一下我在dacade审核通过的代码,希望能给大家一起启发:

我编写的是一个公平公开的租房平台,可以防止提灯定损。在这平台中有三个角色:平台管理员,房东,房客。房东发布租房信息,房客租房时需要缴纳房租和押金,房租将会打款给房东,而押金则交由平台托管。等房租到期房东验房并管理员审核之后才能扣除押金,房客退房时退还剩余押金。

租房平台对象:

#![allow(unused)]
fn main() {
public struct RentalPlatform has key {
    // uid of the RentalPlatform object
    id: UID,
    // deposit stored on the rental platform, key is house object id,value is the amount of deposit
    deposit_pool: Table<ID, u64>,
    balance: Balance<SUI>,
    // rental notices on the platform, key is house object id
    notices: Table<ID, RentalNotice>,
    //owner of platform
    owner: address,
}
}

这是一个共享对象,不仅保存了房东发布的租房信息(notices),还保存了租房押金,balance就是所有租房押金的总和,deposit_pool保存了每个房屋的押金明细。

还有一个平台管理员的对象,是一个独有对象,创建它主要是为了权限管理,只有拥有这个对象的上下文才能请求比如审核验房报告的接口。这个对象是在创建租房平台的接口中创建并转交给请求者的。

#![allow(unused)]
fn main() {
//presents Rental platform administrator
public struct Admin has key, store {
	// uid of admin object
	id: UID,
}
}

租房信息由房东发布,包含租金押金等信息:

#![allow(unused)]
fn main() {
//If the landlord wants to rent out a house, they first need to issue a rental notice
public struct RentalNotice has key,store  {
    // uid of the RentalNotice object
    id: UID,
    // the amount of gas to be paid per month
    monthly_rent: u64,
    // the amount of gas to be deposited 
    deposit: u64,
    // the id of the house object
    house_id: ID,
    // account address of landlord
    landlord: address,
}
}

房屋对象则是房屋的虚拟化,租房前房东拥有它,租房后租客拥有它:

#![allow(unused)]
fn main() {
// present a house object
public struct House has key {
    // uid of the house object
    id: UID,
    // The square of the house area
    area: u64,
    // The owner of the house
    owner: address,
    // A set of house photo links
    photo: String,
    // The landlord's description of the house
    description: String
}
}

租客想租房,就需要签订租房合同,租房合同一旦创建不可改变,不可销毁,所以这里的租房合同是一个不可变对象:

#![allow(unused)]
fn main() {
// present a house rentle contract object
public struct Lease has key,store {
    // uid of the Lease object
    id: UID,
    //uid of house object
    house_id: ID,
    // Tenant's account address
    tenant: address,
    // Landlord's account address
    landlord: address,
    // The month plan to rent
    tenancy: u32,
    // The mount of gas already paid
    paid_rent: u64,
    // The mount of gas already paid for deposit
    paid_deposit: u64,
}
}

在租约到期之后,房东需要出具验房报告并提交给管理员审核,以获取房屋损坏的赔偿。验房报告包含房屋损伤相关的证明

#![allow(unused)]
fn main() {
//presents inspection report object.The landlord submits the inspection report, and the administrator reviews the inspection report
public struct Inspection has key,store {
    // uid of the Inspection object
    id: UID,
    //id of the house object
    house_id: ID,
    //id of the lease object
    lease_id: ID,
    //Damage level, from 0 to 3, evaluated by the landlord
    damage: u8,
    //Description of damage details submitted by the landlord
    damage_description: String,
    //Photos of the damaged area submitted by the landlord
    damage_photo: String,
    //Damage level evaluated by administrator
    damage_assessment_ret: u8,
    //Deducting the deposit based on the damage to the house
    deduct_deposit: u64,
    //Used to mark whether the administrator reviews or not
    review_status: u8,
}
}

最后我再挑选几个主要的接口讲解一下。分别是房东发布租房信息、租客交钱签订租房合同、房东交房给租客、房东验房并提交报告、平台管理员审核验房报告并给与房东补偿,租客退房并领取剩余押金。

  • 房东发布租房信息

    #![allow(unused)]
    fn main() {
    //The landlord releases a rental message, creates a rentalnotice object and create a  house object
    public fun post_rental_notice(platform: &mut RentalPlatform, monthly_rent: u64, housing_area: u64, description: vector<u8>, photo: vector<u8>, ctx: &mut TxContext): House {
        //caculate deposit by monthly_rent
        let deposit = (monthly_rent * DEPOSIT_PERCENT) / 100;
    
        let house = House {
            id: object::new(ctx),
            area: housing_area,
            owner: tx_context::sender(ctx),
            photo: string::utf8(photo),
            description:string::utf8(description),
        };
        let rentalnotice = RentalNotice{
            id: object::new(ctx),
            deposit: deposit,
            monthly_rent: monthly_rent,
            house_id: object::uid_to_inner(&house.id),
            landlord: tx_context::sender(ctx),
        };
    
        table::add<ID, RentalNotice>(&mut platform.notices, object::uid_to_inner(&house.id), rentalnotice);
    
        house
    }
    }
  • 租客交钱签订租房合同

    这个接口暂时只接收SUI币的coin,如果缴纳的金额不正确将会报错。在这个事务中,一旦租房成功,租房合约签订完毕,租房信息将会被删除。押金归入到了平台的balance字段,租金打入了房东账户。

    #![allow(unused)]
    fn main() {
    //call pay_rent function,transfer rent coin object  to landlord, deposit will be managed by platform.
    public entry fun pay_rent_and_transfer(platform: &mut RentalPlatform, house_address: address, tenancy: u32,  paid: Coin<SUI>, ctx: &mut TxContext) {
        let house_id: ID = object::id_from_address(house_address);
        let (rent_coin, deposit_coin, landlord) = pay_rent(platform, house_id, tenancy, paid, ctx);
        transfer::public_transfer(rent_coin, landlord);
        balance::join(&mut platform.balance, coin::into_balance(deposit_coin));
    }
    //Tenants pay rent and sign rental contracts
    public fun pay_rent(platform: &mut RentalPlatform, house_id: ID, tenancy: u32,  paid: Coin<SUI>, ctx: &mut TxContext): (Coin<SUI>, Coin<SUI>, address) {
        assert!(tenancy > 0, ETenancyIncorrect);
        assert!(table::contains<ID, RentalNotice>(&platform.notices, house_id), EInvalidNotice);
    
        let notice = table::borrow<ID, RentalNotice>(&platform.notices, house_id);
        assert!(!table::contains<ID, u64>(&platform.deposit_pool, notice.house_id), EInvalidHouse);
    
    
        let rent = notice.monthly_rent * (tenancy as u64);
        let total_fee = rent + notice.deposit;
        assert!(total_fee == coin::value(&paid), EInvalidSuiAmount);
    
        //the deposit is stored by rental platform
        let deposit_coin = coin::split<SUI>(&mut paid, notice.deposit, ctx);
        table::add<ID, u64>(&mut platform.deposit_pool, notice.house_id, notice.deposit);
    
        //lease is a Immutable object
        let lease = Lease {
            id: object::new(ctx),
            tenant: tx_context::sender(ctx),
            landlord: notice.landlord,
            tenancy: tenancy,
            paid_rent: rent,
            paid_deposit: notice.deposit,
            house_id: notice.house_id,
        };
        transfer::public_freeze_object(lease);
    
        //remove notice from platform
        let RentalNotice{id: notice_id, monthly_rent: _, deposit: _, house_id: _, landlord: landlord } = table::remove<ID, RentalNotice>(&mut platform.notices, house_id);
        object::delete(notice_id);
    
    
        (paid, deposit_coin, landlord)
    }
    }
  • 房东交房给租客

    这个接口非常简单,就是转移house的所有权给租客

    #![allow(unused)]
    fn main() {
    //After the tenant pays the rent, the landlord transfers the house to the tenant
    public entry fun transfer_house_to_tenant(lease: &Lease, house: House) {
        transfer::transfer(house, lease.tenant)
    }
    }
  • 房东验房并提交报告

    房东需要对房屋损伤评级,1-4级分别赔偿押金的0%,10%,50%,100%。具体赔付结果需要管理员定级。

    #![allow(unused)]
    fn main() {
    //Rent expires, landlord inspects and submits inspection report
    public entry fun landlord_inspect(lease: &Lease, damage: u8, damage_description: vector<u8>, damage_photo: vector<u8>, ctx: &mut TxContext) {
        assert!(lease.landlord == tx_context::sender(ctx), ENoPermission);
        assert!(damage >= DAMAGE_LEVEL_0 && damage <= DAMAGE_LEVEL_3, EDamageIncorrect);
        let inspection = Inspection{
            id: object::new(ctx),
            house_id: lease.house_id,
            lease_id: object::uid_to_inner(&lease.id),
            damage: damage,
            damage_description: string::utf8(damage_description),
            damage_photo: string::utf8(damage_photo),
            damage_assessment_ret: DAMAGE_LEVEL_UNKNOWN,
            deduct_deposit: 0,
            review_status: WAITING_FOR_REVIEW
        };
    
        transfer::public_share_object(inspection);
    }
    }
  • 平台管理员审核验房报告并给与房东补偿

    这个接口只有管理员可以请求,在这个事务里将审核验房报告,并对房屋评级、取出这个房屋的押金,根据评级结果赔偿一部分给房东、deposit_pool也要同步减去已经取走的押金。

    #![allow(unused)]
    fn main() {
        //The platform administrator reviews the inspection report and deducts the deposit as compensation for the landlord
    public entry fun review_inspection_report(platform: &mut RentalPlatform, lease: &Lease, inspection: &mut Inspection, _: &Admin, damage: u8, ctx: &mut TxContext)  {
        assert!(lease.house_id == inspection.house_id, EWrongParams);
        assert!(inspection.review_status == WAITING_FOR_REVIEW, EInspectionReviewed);
        assert!(table::contains<ID, u64>(&platform.deposit_pool, lease.house_id), EInvalidDeposit);
    
        let deduct_deposit:u64 = calculate_deduct_deposit(lease.paid_deposit, damage);
        let deposit_amount = table::borrow_mut<ID, u64>(&mut platform.deposit_pool, lease.house_id);
    
        assert!(deduct_deposit <= balance::value<SUI>(&platform.balance), EInsufficientBalance);
    
        inspection.damage_assessment_ret = damage;
        inspection.review_status = REVIEWED;
        inspection.deduct_deposit = deduct_deposit;
    
        if (deduct_deposit > 0) {
            *deposit_amount = *deposit_amount - deduct_deposit; 
    
            let deduct_coin = coin::take<SUI>(&mut platform.balance, deduct_deposit, ctx);
            transfer_deposit(deduct_coin, lease.landlord)
        };
    }
    
    }
  • 租客退房并领取剩余押金

    租客将房屋退还给房东,领取部分押金。清除租房平台押金和押金明细。

#![allow(unused)]
fn main() {
//The tenant returns the room to the landlord,collects deposit 
public entry fun tenant_return_house_and_transfer(platform: &mut RentalPlatform, lease: &Lease, house: House, ctx: &mut TxContext) {
    let house = tenant_return_house(platform, lease, house, ctx);

    transfer::transfer(house, lease.landlord)
}
//The tenant returns the room to the landlord and receives the deposit
public fun tenant_return_house(platform: &mut RentalPlatform, lease: &Lease, house: House, ctx: &mut TxContext): House {
    assert!(lease.house_id == object::uid_to_inner(&house.id), EWrongParams);
    assert!(lease.tenant == tx_context::sender(ctx), ENoPermission);
    assert!(table::contains<ID, u64>(&platform.deposit_pool, lease.house_id), EInvalidDeposit);

    let deposit = table::borrow(&platform.deposit_pool, lease.house_id);
    assert!(*deposit <= balance::value<SUI>(&platform.balance), EInsufficientBalance);

    //If there is still any remaining deposit, refund it to the tenant
    if (*deposit > 0) {
        let deposit_coin = coin::take<SUI>(&mut platform.balance, *deposit, ctx);
        transfer_deposit(deposit_coin, tx_context::sender(ctx));
    };

    let _ = table::remove<ID, u64>(&mut platform.deposit_pool, lease.house_id);

    house
}
}

其实这种赢奖励的机会并不少,大家在学习Web3的过程中应该积极参与这些活动,用金钱激励自己才能学的更快更深刻。

了解更多活动:

  • telegram: t.me/move_cn
  • QQ群: 79489587