Sui Move 实现一个简单的票务系统

  • Nigdle
  • 更新于 2024-05-01 17:27
  • 阅读 978

Sui Move 实现一个简单的票务系统 —— 做自己的掌权者,任何人都可以创立独属于自己管理的服务机构,并通过票务订单的形式发售各式各样的服务内容......

一:功能介绍

做自己的掌权者,任何人都可以创立独属于自己管理的服务机构,并通过票务订单的形式发售各式各样的服务内容,与此同时,系统还提供套票管理,管理人员可以根据需求创建套餐,修改其中包含的服务或者套餐优惠价格,购买者后续则通过票务订单来享受权益服务,更细化的功能如下:

  • 任何人都可以创立/注销自己的服务机构。
  • 服务机构经营者可以发售更具化的服务内容。
  • 服务机构经营者可以按照自己的意愿组建套餐,并制定优惠价格。
  • 单个服务以及服务套餐都存在下架功能。
  • 购买了对应票务订单的人可以凭借票根享受服务(当且仅当这项服务被提供,对应钱款才会转移给经营者)。
  • 如果经营者下架了已售出票务的服务内容,或者这所服务机构已倒闭,当买家持票根上门时,钱款将直接返还给他/她。
  • 已购买的服务可以进行自主退货,但是会收取 $\text {10}\%$ 的费用,该笔费用将进入对应经营者的链上进行存储。
  • 服务机构经营者可以将存储在链上的利润提现到自己的钱包(提现金额不低于 $\text {100}$),这个过程当中,票务系统的发布者将收取 $\text 1\%$​ 的抽成。

二:结构设计

2.1 ADMIN

整个票务系统的发布者标识由 $\mathit {One}$-$\mathit {Time}$-$\mathit {Witness}$ 来生成,这需要一个与模块同名但全大写的结构:

public struct ADMIN has drop {}

2.2 OrganizationList

这个一个共享的对象,其中存储了所有服务机构的相关信息,任何操作都需要通过它作为入口进行:

public struct OrganizationList has key {
    id: UID,
    organizations: Table<ID, ServiceOrganization>,
    organizations_ids: vector<ID>,
    publisher_income: Balance<SUI>,
}

2.3 ServiceOrganizationCap

用来标识一所服务机构的所有者,如果说,根据机构的 $\mathit {ID}$ 就可以借助上面的对象找到对应的服务机构,那么这个对象的拥有者才是真正有权限修改这所机构中提供的服务内容的人,它只需要做标识用,不需要存储其它任何东西:

public struct ServiceOrganizationCap has key {
    id: UID,
}

2.4 ServiceOrganization

具体的服务机构对象,它被存储在OrganizationList当中,其中最关键的东西是如何维护单项服务以及服务套餐:

public struct ServiceOrganization has store {
    organization_name: String,
    services: Table<ID, Service>,
    services_ids: vector<ID>,
    package_services: Table<ID, PackageServices>,
    package_services_ids: vector<ID>,
    income: Balance<SUI>,
}

2.5 Service and PackageServices

  • Service

单项服务,只需要服务名称和其价格:

public struct Service has store, drop {
    service_name: String,
    price: u64,
}
  • PackageServices

服务套餐,除了价格之外,还需要套餐内包含的所有服务的 $\mathit {ID}$:

public struct PackageServices has store {
    services: vector<ID>,
    price: u64,
}

2.6 ServiceCertification

顾客购买了单项服务的凭证,记录了他/她是在哪一所服务机构购买的哪一项服务,付款金额也暂存在其中:

public struct ServiceCertification has key {
    id: UID,
    organization_id: ID,
    service_id: ID,
    purchase_price: Balance<SUI>,
}

2.7 PackageServicesCertification

顾客购买了服务套餐的凭证,记录了他/她是在哪一所服务机构购买的哪一种套餐,付款金额也暂存在其中:

public struct PackageServicesCertification has key {
    id: UID,
    organization_id: ID,
    package_services_id: ID,
    services: vector<ID>,
    purchase_price: Balance<SUI>,
}

2.8 Event

为了便于交互,设计了一系列事件对象结构,在特定情形下触发,以告知关键更改(多为涉及金额方面的变更):

public struct OrganizationListEvent has copy, drop {
    organization_name: String,
    organization_id: ID,
}

public struct ServiceEvent has copy, drop {
    service_name: String,
    service_id: ID,
}

public struct PackageServicesEvent has copy, drop {
    services: vector<String>,
    package_services_id: ID,
}

public struct RefundEvent has copy, drop {
    note: String,
    value: u64,
}

public struct EnjoyEvent has copy, drop {
    note: String,
}

三:功能实现

3.1 withdraw

提现分为票务系统发布者提现和服务机构管理者提现,前者需要Publisher,后者需要拥有对应的ServiceOrganizationCap同时账户内当前收益不少于 $\text {100}$,且服务机构在提现的同时,将支付给系统发布者一笔 $\text 1\%$ 的抽成。

entry fun publisher_withdraw(_: &Publisher, organization_list: &mut OrganizationList, ctx: &mut TxContext) {
    // check balance
    assert!(organization_list.publisher_income.value() > 0, ENotIncome);

    // get all balance
    let all_balance = organization_list.publisher_income.withdraw_all();
    // transfer the coin to the publisher
    transfer::public_transfer(coin::from_balance(all_balance, ctx), ctx.sender());
}

// in order to make the withdrawal function more versatile
#[allow(lint(self_transfer))]
fun organization_withdraw_(service_organization: &mut ServiceOrganization, publisher_income: &mut Balance<SUI>, ctx: &mut TxContext) {
    // check balance
    assert!(service_organization.income.value() >= 100, ENotEnoughIncome);

    // get all amount
    let amount = service_organization.income.value();
    // split 1%
    let publisher_earned = service_organization.income.split(amount / 100);
    // join to the publisher_balance
    publisher_income.join(publisher_earned);

    // get the remaining balance
    let all_balance = service_organization.income.withdraw_all();
    // transfer the coin to the organization owner
    transfer::public_transfer(coin::from_balance(all_balance, ctx), ctx.sender());
}

entry fun organization_withdraw(service_organization_cap: &ServiceOrganizationCap, organization_list: &mut OrganizationList, ctx: &mut TxContext) {
    // the fact that `service_organization_cap` exists means that `organization_list` must own what it corresponds to
    // so we don’t need to judge here

    // get id
    let organization_id = object::id(service_organization_cap);
    // get and return service organization
    let service_organization = &mut organization_list.organizations[organization_id];

    // withdraw
    organization_withdraw_(service_organization, &mut organization_list.publisher_income, ctx);
}

3.2 create_service_organization

创建ServiceOrganization及其对应的ServiceOrganizationCap,前者存储入OrganizationList,后者则移交给这笔交易的发送者,也就是这所服务机构的管理者:

entry fun create_service_organization(organization_list: &mut OrganizationList, organization_name: String, ctx: &mut TxContext) {
    // create service organization cap
    let service_organization_cap = ServiceOrganizationCap {id: object::new(ctx)};

    // create service organization
    let service_organization = ServiceOrganization {
        organization_name,
        services: table::new<ID, Service>(ctx),
        services_ids: vector<ID>[],
        package_services: table::new<ID, PackageServices>(ctx),
        package_services_ids: vector<ID>[],
        income: balance::zero(),
    };

    // get service_organization_cap id as service_organization id
    let service_organization_id = object::id(&service_organization_cap);
    // store service_organization to organization_list
    organization_list.organizations.add(service_organization_id, service_organization);
    organization_list.organizations_ids.push_back(service_organization_id);

    // transfer service_organization_cap to the organization owner
    transfer::transfer(service_organization_cap, ctx.sender());
}

3.3 destroy_service_organization

注销服务机构,需要有service_organization_cap权限,解构这个权限对象,同时将对应的机构从OrganizationList当中移除,别忘记将单独取出来的ServiceOrganization也进行解构,尤其是其中的Balance<SUI>要妥善处理:

entry fun destroy_service_organization(service_organization_cap: ServiceOrganizationCap, organization_list: &mut OrganizationList, ctx: &mut TxContext) {
    // get id
    let ServiceOrganizationCap {id} = service_organization_cap;
    // get service organization
    let mut service_organization = organization_list.organizations.remove(id.to_inner());
    // get index
    let (_, index) = organization_list.organizations_ids.index_of(&id.to_inner());
    // remove index
    organization_list.organizations_ids.remove(index);
    // delete Service Organization Cap id
    object::delete(id);

    // withdraw
    if (service_organization.income.value() < 100) {
        // get all balance
        let all_balance = service_organization.income.withdraw_all();
        // transfer it to the owner
        transfer::public_transfer(coin::from_balance(all_balance, ctx), ctx.sender());
    } else {
        // use the withdrawal function
        organization_withdraw_(&mut service_organization, &mut organization_list.publisher_income, ctx);
    };

    // deconstruct ServiceOrganization
    let ServiceOrganization {
        organization_name: _,
        mut services,
        mut services_ids,
        mut package_services,
        mut package_services_ids,
        income,
    } = service_organization;

    // destroy services
    while (services_ids.length() > 0) {
        // get service id
        let id = services_ids.pop_back();
        // remove it
        services.remove(id); // return Service has ability drop
    };
    services.destroy_empty();
    services_ids.destroy_empty();

    // destroy package_services
    while (package_services_ids.length() > 0) {
        // get package id
        let id = package_services_ids.pop_back();
        // get services
        let PackageServices {
            mut services,
            price: _,
        } = package_services.remove(id);
        // clear and destroy services(vector)
        while (services.length() > 0) {
            services.pop_back();
        };
        services.destroy_empty();
    };
    package_services.destroy_empty();
    package_services_ids.destroy_empty();

    // destroy income
    income.destroy_zero();
}

3.4 create_service

创建Service并将其存储对应的ServiceOrganization当中:

entry fun create_service(service_organization_cap: &ServiceOrganizationCap, organization_list: &mut OrganizationList, service_name: String, price: u64, ctx: &mut TxContext) {
    // get ServiceOrganization
    let service_organization = get_service_organization(service_organization_cap, organization_list);

    // generate new id
    let id = object::id_from_address(ctx.fresh_object_address());
    // create Service
    let service = Service {
        service_name,
        price,
    };

    // store service
    service_organization.services.add(id, service);
    service_organization.services_ids.push_back(id);
}

3.5 destroy_service

移除(下架)一项服务,除了将其从ServiceOrganization当中删除之外,还需要更新含有这项服务的套餐,当删掉它之后,若是套餐内的服务少于两个,则不构成套餐,那么直接删除这个套餐,否则就只是将这项服务移出套餐,同时按照平均价格更新套餐售价:

fun update_package_services(service_organization_cap: &ServiceOrganizationCap, organization_list: &mut OrganizationList, service_id: ID) {
    // get ServiceOrganization
    let service_organization = get_service_organization(service_organization_cap, organization_list);

    // get package services ids
    let package_services_ids = &service_organization.package_services_ids;
    // get package services
    let package_services = &mut service_organization.package_services;

    let mut i = 0;
    let mut waiting_destroy_ids = vector<ID>[];
    while (i < package_services_ids.length()) {
        // get package id
        let package_id = package_services_ids[i];
        // get package_services
        let package_services = &mut package_services[package_id];
        // get services
        let services = &mut package_services.services;

        // don't contains then continue
        if (!services.contains(&service_id)) {
            i = i + 1;
            continue
        };

        // get index
        let (_, index) = services.index_of(&service_id);
        // remove it
        services.remove(index);

        // still have enough service(>= 2) then continue
        if (services.length() >= 2) {
            // decrease price
            let decrease_price = package_services.price / (services.length() + 1);
            package_services.price = package_services.price - decrease_price;

            i = i + 1;
            continue
        };

        // add to waiting destroy list
        waiting_destroy_ids.push_back(package_id);

        i = i + 1;
    };

    // destroy package services
    while (waiting_destroy_ids.length() > 0) {
        let package_id = waiting_destroy_ids.pop_back();
        destroy_package_services(service_organization_cap, organization_list, package_id);
    };
}

entry fun destroy_service(service_organization_cap: &ServiceOrganizationCap, organization_list: &mut OrganizationList, service_id: ID) {
    // get ServiceOrganization
    let service_organization = get_service_organization(service_organization_cap, organization_list);

    // check service_id
    assert!(service_organization.services_ids.contains(&service_id), ENotCorrectService);

    // get index of `services_ids`
    let (_, index) = service_organization.services_ids.index_of(&service_id);
    // remove it
    service_organization.services_ids.remove(index);

    // services remove
    service_organization.services.remove(service_id); // return Service has ability drop

    // update package services
    update_package_services(service_organization_cap, organization_list, service_id);
}

3.6 create_package_services

创建PackageServices并将其存入ServiceOrganization,其中,将套餐内含有的服务 $\mathit {ID}$ 列表存储这一行为,可以单独写成函数,为后续方便调用做准备:

entry fun modify_package_services(service_organization_cap: &ServiceOrganizationCap, organization_list: &mut OrganizationList, package_id: ID, services: vector<ID>) {
    // get ServiceOrganization
    let service_organization = get_service_organization(service_organization_cap, organization_list);

    // check package id
    assert!(service_organization.package_services_ids.contains(&package_id), ENotCorrectPackage);

    // check services
    let mut i = 0;
    while (i < services.length()) {
        let service_id = services[i];
        assert!(service_organization.services_ids.contains(&service_id), ENotAllCorrectService);
        i = i + 1;
    };

    // modify services
    let package_services = &mut service_organization.package_services[package_id];
    let store_services = &mut package_services.services;
    *store_services = services;
}

entry fun create_package_services(service_organization_cap: &ServiceOrganizationCap, organization_list: &mut OrganizationList, services: vector<ID>, ctx: &mut TxContext) {
    // get ServiceOrganization
    let service_organization = get_service_organization(service_organization_cap, organization_list);

    // get default price
    let default_price = get_default_price(service_organization, &services);

    create_package_services_and_price(service_organization_cap, organization_list, services, default_price, ctx);
}

entry fun create_package_services_and_price(service_organization_cap: &ServiceOrganizationCap, organization_list: &mut OrganizationList, services: vector<ID>, price: u64, ctx: &mut TxContext) {
    // get ServiceOrganization
    let service_organization = get_service_organization(service_organization_cap, organization_list);

    // generate new id
    let id = object::id_from_address(ctx.fresh_object_address());
    // init package serivces
    service_organization.package_services_ids.push_back(id);
    service_organization.package_services.add(id, PackageServices {
        services: vector<ID>[],
        price,
    });

    // store services
    modify_package_services(service_organization_cap, organization_list, id, services);
}

类似的,可以轻松写出修改价格等函数,这里就不再一一列举。

3.7 destroy_package_services

除了将其从ServiceOrganization移除之外,别忘了解构得到的PackageServices

entry fun destroy_package_services(service_organization_cap: &ServiceOrganizationCap, organization_list: &mut OrganizationList, package_id: ID) {
    // get ServiceOrganization
    let service_organization = get_service_organization(service_organization_cap, organization_list);

    // check package id
    assert!(service_organization.package_services_ids.contains(&package_id), ENotCorrectPackage);

    // get index of `package_services_ids`
    let (_, index) = service_organization.package_services_ids.index_of(&package_id);
    // remove it
    service_organization.package_services_ids.remove(index);

    // package_services remove
    let PackageServices {
        mut services,
        price: _,
    } = service_organization.package_services.remove(package_id);
    // clear vector
    while (services.length() > 0) {
        services.pop_back();
    };
    // destroy vector
    services.destroy_empty();
}

3.8 query_organization_list

查询当前有几所服务机构及其信息:

entry fun query_organization_list(organization_list: &OrganizationList) {
    // get organization ids
    let organization_ids = organization_list.borrow_organizations_ids();
    // get organizations
    let organizations = organization_list.borrow_organizations();

    let mut i = 0;
    while (i < organization_ids.length()) {
        // get organization_id
        let organization_id = organization_ids[i];
        // get organization
        let organization = &organizations[organization_id];
        // get organization_name
        let organization_name = organization.get_organization_name();

        // emit event
        event::emit(OrganizationListEvent {
            organization_name,
            organization_id,
        });

        i = i + 1;
    };
}

3.9 query_organization_services

查询某一所服务机构的详细信息,包括其提供的所有单项服务以及服务套餐:

entry fun query_organization_services(organization_id: ID, organization_list: &OrganizationList) {
    // get organizations
    let organizations = organization_list.borrow_organizations();
    // get organization
    let organization = &organizations[organization_id];

    // get services
    let services = organization.borrow_services();
    // get services_ids
    let services_ids = organization.borrow_services_ids();

    let mut i = 0;
    while (i < services_ids.length()) {
        // get service is
        let service_id = services_ids[i];
        // get service
        let service = &services[service_id];
        // get service name
        let service_name = service.get_service_name();

        // emit event
        event::emit(ServiceEvent {
            service_name,
            service_id,
        });

        i = i + 1;
    };

    // get package services
    let package_services = organization.borrow_package_services();
    // get package services ids
    let package_services_ids = organization.borrow_package_services_ids();

    i = 0;
    while (i < package_services_ids.length()) {
        // get package_id
        let package_id = package_services_ids[i];
        // get package_services
        let package_services = &package_services[package_id];
        // get services(ids)
        let services_ids = package_services.borrow_ids_from_package_services();

        // init services names
        let mut services_names = vector<String>[];
        while (services_names.length() < services.length()) {
            // get index
            let idx = services_names.length();
            // get service id
            let service_id = services_ids[idx];
            // get service
            let service = &services[service_id];
            // get service name
            let service_name = service.get_service_name();
            // push back
            services_names.push_back(service_name);
        };

        // emit event
        event::emit(PackageServicesEvent {
            services: services_names,
            package_services_id: package_id,
        });

        i = i + 1;
    };
}

3.10 buy_service

购买单项服务,创建凭证ServiceCertification并将其所有权转移给顾客:

entry fun buy_service(organization_list: &OrganizationList, organization_id: ID, service_id: ID, mut sui: Coin<SUI>, ctx: &mut TxContext) {
    // get organizations
    let organizations = organization_list.borrow_organizations();
    // get organizations ids
    let organizations_ids = organization_list.borrow_organizations_ids();
    // check organization_id
    assert!(organizations_ids.contains(&organization_id), ENotCorrectOrganizationID);

    // get organization
    let organization = &organizations[organization_id];
    // get services
    let services = organization.borrow_services();
    // get services ids
    let services_ids = organization.borrow_services_ids();
    // check service_id
    assert!(services_ids.contains(&service_id), ENotCorrectServiceID);

    // get service
    let service = &services[service_id];
    // get price
    let price = service.get_service_price();
    // check coin amount
    assert!(sui.value() >= price, ENotEnoughCoin);

    // split coin
    let pay_coin = sui.split(price, ctx);

    // deal with the remaining coin
    if (sui.value() > 0) {
        transfer::public_transfer(sui, ctx.sender());
    } else {
        sui.destroy_zero();
    };

    // create ServiceCertification
    let service_certification = ServiceCertification {
        id: object::new(ctx),
        organization_id,
        service_id,
        purchase_price: pay_coin.into_balance(),
    };
    // tranfer it
    transfer::transfer(service_certification, ctx.sender());
}

3.11 refund_service

对购买的单项服务进行退款,如果机构已经下架或者整个服务机构已经注销,则直接退款,否则将收取 $\text {10}\%$ 的手续费。

entry fun refund_service(service_certification: ServiceCertification, organization_list: &mut OrganizationList, ctx: &mut TxContext) {
    // deconstruct ServiceCertification
    let ServiceCertification {
        id,
        organization_id,
        service_id,
        mut purchase_price,
    } = service_certification;
    // delete id
    object::delete(id);

    // if the service organization has canceled, a direct refund will be issued
    // if the service has canceled, a direct refund will be issued
    if (check_organization_canceled(&organization_id, organization_list) || check_service_canceled(organization_id, &service_id, organization_list)) {
        event::emit(RefundEvent {
            note: string::utf8(b"service organization or service has canceled!"),
            value: purchase_price.value(),
        });
        transfer::public_transfer(coin::from_balance(purchase_price, ctx), ctx.sender());
        return
    };

    // for refunds due to your own reasons, a 10% fee will be charged
    let amount = purchase_price.value();
    // split
    let fee = purchase_price.split(amount / 10);
    organization_list.join_organization_balance(organization_id, fee);

    event::emit(RefundEvent {
        note: string::utf8(b"for refunds due to your own reasons, a 10% fee will be charged!"),
        value: purchase_price.value(),
    });

    // refunds
    transfer::public_transfer(coin::from_balance(purchase_price, ctx), ctx.sender());
}

3.12 enjoy_service

享受服务,解构ServiceCertification的同时,钱款转移到机构:

entry fun enjoy_service(service_certification: ServiceCertification, organization_list: &mut OrganizationList, ctx: &mut TxContext) {
    // deconstruct ServiceCertification
    let ServiceCertification {
        id,
        organization_id,
        service_id,
        purchase_price,
    } = service_certification;
    // delete id
    object::delete(id);

    // if the service organization has canceled, a direct refund will be issued
    // if the service has canceled, a direct refund will be issued
    if (check_organization_canceled(&organization_id, organization_list) || check_service_canceled(organization_id, &service_id, organization_list)) {
        event::emit(RefundEvent {
            note: string::utf8(b"service organization or service has canceled!"),
            value: purchase_price.value(),
        });
        transfer::public_transfer(coin::from_balance(purchase_price, ctx), ctx.sender());
        return
    };

    // pay coin
    organization_list.join_organization_balance(organization_id, purchase_price);

    event::emit(EnjoyEvent {
        note: string::utf8(b"good morning, and in case i don't see you, good afternoon, good evening, and good night!"),
    });
}

3.13 package_services(buy, refund, enjoy)

类似的,对于套餐服务,也可以编写出购买、退款和享受服务的功能函数,其中需要额外考虑的就是当用户拿着凭证享受服务的时候,其中部分服务已经下架了该如何处理(部分退款并将其 $\mathit {ID}$ 从凭证中移除),为了做到这一点,就多了一个函数来处理:

entry fun buy_package_services(organization_list: &OrganizationList, organization_id: ID, package_services_id: ID, mut sui: Coin<SUI>, ctx: &mut TxContext) {
    // get organizations
    let organizations = organization_list.borrow_organizations();
    // get organizations ids
    let organizations_ids = organization_list.borrow_organizations_ids();
    // check organization_id
    assert!(organizations_ids.contains(&organization_id), ENotCorrectOrganizationID);

    // get organization
    let organization = &organizations[organization_id];
    // get package services
    let package_services = organization.borrow_package_services();
    // get package services ids
    let package_services_ids = organization.borrow_package_services_ids();
    // check package_services_id
    assert!(package_services_ids.contains(&package_services_id), ENotCorrectPackageServicesID);

    // get package_services
    let package_services_contents = &package_services[package_services_id];
    // get price
    let price = package_services_contents.get_package_services_price();
    // check coin amount
    assert!(sui.value() >= price, ENotEnoughCoin);

    // split coin
    let pay_coin = sui.split(price, ctx);

    // deal with the remaining coin
    if (sui.value() > 0) {
        transfer::public_transfer(sui, ctx.sender());
    } else {
        sui.destroy_zero();
    };

    // create PackageServiceCertification
    let package_services_certification = PackageServicesCertification {
        id: object::new(ctx),
        organization_id,
        package_services_id,
        services: *package_services_contents.borrow_ids_from_package_services(),
        purchase_price: pay_coin.into_balance(),
    };

    // transfer it
    transfer::transfer(package_services_certification, ctx.sender());
}

entry fun refund_package_services(package_services_certification: PackageServicesCertification, organization_list: &mut OrganizationList, ctx: &mut TxContext) {
    // deconstruct PackageServicesCertification
    let PackageServicesCertification {
        id,
        organization_id,
        package_services_id,
        mut services,
        mut purchase_price,
    } = package_services_certification;
    // delete id
    object::delete(id);

    // if the service organization has canceled, a direct refund will be issued
    // if the package_services has canceled, a direct refund will be issued
    if (check_organization_canceled(&organization_id, organization_list) || check_package_services_canceled(organization_id, &package_services_id, organization_list)) {
        event::emit(RefundEvent {
            note: string::utf8(b"service organization or package services has canceled!"),
            value: purchase_price.value(),
        });
        transfer::public_transfer(coin::from_balance(purchase_price, ctx), ctx.sender());

        while (services.length() > 0) {
            services.pop_back();
        };
        services.destroy_empty();

        return
    };

    // if the corresponding service has been cancelled, the corresponding amount will be refunded directly
    refund_canceled_package_services(organization_id, organization_list, &mut services, &mut purchase_price, ctx);

    // for refunds due to your own reasons, a 10% fee will be charged
    let amount = purchase_price.value();
    // if all canceled then return
    if (amount == 0) {
        services.destroy_empty();
        purchase_price.destroy_zero();
        return
    };
    // split
    let fee = purchase_price.split(amount / 10);
    organization_list.join_organization_balance(organization_id, fee);

    event::emit(RefundEvent {
        note: string::utf8(b"for refunds due to your own reasons, a 10% fee will be charged!"),
        value: purchase_price.value(),
    });

    // refunds
    transfer::public_transfer(coin::from_balance(purchase_price, ctx), ctx.sender());

    // clear and destroy services
    while (services.length() > 0) {
        services.pop_back();
    };
    services.destroy_empty();
}

entry fun enjoy_package_services(mut package_services_certification: PackageServicesCertification, enjoy_services: vector<ID>, organization_list: &mut OrganizationList, ctx: &mut TxContext) {
    // get details
    let organization_id = package_services_certification.organization_id;
    let package_services_id = package_services_certification.package_services_id;
    let services = &mut package_services_certification.services;
    let purchase_price = &mut package_services_certification.purchase_price;

    // if the service organization has canceled, a direct refund will be issued
    // if the package_services has canceled, a direct refund will be issued
    if (check_organization_canceled(&organization_id, organization_list) || check_package_services_canceled(organization_id, &package_services_id, organization_list)) {
        event::emit(RefundEvent {
            note: string::utf8(b"service organization or package services has canceled!"),
            value: purchase_price.value(),
        });

        let amount = purchase_price.value();
        transfer::public_transfer(coin::take(purchase_price, amount, ctx), ctx.sender());

        // deconstruct
        let PackageServicesCertification {
            id,
            organization_id: _,
            package_services_id: _,
            mut services,
            purchase_price,
        } = package_services_certification;
        // delete id
        object::delete(id);
        // destroy
        purchase_price.destroy_zero();
        while (services.length() > 0) {
            services.pop_back();
        };
        services.destroy_empty();

        return
    };

    // if the corresponding service has been cancelled, the corresponding amount will be refunded directly
    refund_canceled_package_services(organization_id, organization_list, services, purchase_price, ctx);

    // if all canceled then return
    if (purchase_price.value() == 0) {
        // deconstruct
        let PackageServicesCertification {
            id,
            organization_id: _,
            package_services_id: _,
            services,
            purchase_price,
        } = package_services_certification;
        // delete id
        object::delete(id);
        // destroy
        services.destroy_empty();
        purchase_price.destroy_zero();

        return
    };

    // check enjoy_services
    let mut i = 0;
    while (i < enjoy_services.length()) {
        let service_id = enjoy_services[i];
        assert!(services.contains(&service_id), ENotCorrectServicesList);

        // remove this service
        let (_, index) = services.index_of(&service_id);
        services.remove(index);

        i = i + 1;
    };

    // get value
    let amount = purchase_price.value();
    // payout ratio = enjoy_services.length() / (enjoy_services.length() + services.length())
    // so we need to pay
    let need_to_pay = if (services.length() != 0) amount / (enjoy_services.length() + services.length()) * enjoy_services.length() else amount;

    // pay coin
    organization_list.join_organization_balance(organization_id, purchase_price.split(need_to_pay));

    event::emit(EnjoyEvent {
        note: string::utf8(b"good morning, and in case i don't see you, good afternoon, good evening, and good night!"),
    });

    if (purchase_price.value() == 0) {
        // deconstruct
        let PackageServicesCertification {
            id,
            organization_id: _,
            package_services_id: _,
            services,
            purchase_price,
        } = package_services_certification;
        // delete id
        object::delete(id);
        // destroy
        services.destroy_empty();
        purchase_price.destroy_zero();
    } else {
        // transfer to owner
        transfer::transfer(package_services_certification, ctx.sender());
    };
}

entry fun update_package_services(mut package_services_certification: PackageServicesCertification, organization_list: &OrganizationList, ctx: &mut TxContext) {
    // get details
    let organization_id = package_services_certification.organization_id;
    let package_services_id = package_services_certification.package_services_id;
    let services = &mut package_services_certification.services;
    let purchase_price = &mut package_services_certification.purchase_price;

    // if the service organization has canceled, a direct refund will be issued
    // if the package_services has canceled, a direct refund will be issued
    if (check_organization_canceled(&organization_id, organization_list) || check_package_services_canceled(organization_id, &package_services_id, organization_list)) {
        event::emit(RefundEvent {
            note: string::utf8(b"service organization or package services has canceled!"),
            value: purchase_price.value(),
        });

        let amount = purchase_price.value();
        transfer::public_transfer(coin::take(purchase_price, amount, ctx), ctx.sender());

        // deconstruct
        let PackageServicesCertification {
            id,
            organization_id: _,
            package_services_id: _,
            mut services,
            purchase_price,
        } = package_services_certification;
        // delete id
        object::delete(id);
        // destroy
        purchase_price.destroy_zero();
        while (services.length() > 0) {
            services.pop_back();
        };
        services.destroy_empty();

        return
    };

    // if the corresponding service has been cancelled, the corresponding amount will be refunded directly
    refund_canceled_package_services(organization_id, organization_list, services, purchase_price, ctx);

    // if all canceled then return
    if (purchase_price.value() == 0) {
        // deconstruct
        let PackageServicesCertification {
            id,
            organization_id: _,
            package_services_id: _,
            services,
            purchase_price,
        } = package_services_certification;
        // delete id
        object::delete(id);
        // destroy
        services.destroy_empty();
        purchase_price.destroy_zero();

        return
    };

    // still have services then transfer it to owner
    transfer::transfer(package_services_certification, ctx.sender());
}

3.14 code

完整代码可以点击查看,上文省略了很多辅助函数,都可以在里面详细查看到。

四:链上部署及测试

注意: 本篇测试内容部署在测试网($\mathit {testnet}$),由于功能众多,仅仅挑选了其中一部分进行。

4.1 publish

  • 运行命令

sui client publish --gas-budget 100000000

  • 重要输出
╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Object Changes                                                                                              │
├─────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Created Objects:                                                                                            │
│  ┌──                                                                                                        │
│  │ ObjectID: 0x1f4044ef7050a8305fcf33ce7aed3b91d34a9333ae7efc2af7205b3c286d5f30                             │
│  │ Sender: 0x9e4092b6a894e6b168aa1c6c009f5c1c1fcb83fb95e5aa39144e1d2be4ee0d67                               │
│  │ Owner: Shared                                                                                            │
│  │ ObjectType: 0x216202fdaae06b761222286300e18eb6ef24c2fe5cf7336b7f2da9ab97beea41::admin::OrganizationList  │
│  │ Version: 28131907                                                                                        │
│  │ Digest: ACTMHcXEBhVKkSPyWHG2utssZc2VtPenPx11iSkXQ1PP                                                     │
│  └──                                                                                                        │
│  ┌──                                                                                                        │
│  │ ObjectID: 0xa4eea40898c7a07fb6c19ff8f91eb7d1cd7972239ccf09dd980d3918710139d6                             │
│  │ Sender: 0x9e4092b6a894e6b168aa1c6c009f5c1c1fcb83fb95e5aa39144e1d2be4ee0d67                               │
│  │ Owner: Account Address ( 0x9e4092b6a894e6b168aa1c6c009f5c1c1fcb83fb95e5aa39144e1d2be4ee0d67 )            │
│  │ ObjectType: 0x2::package::UpgradeCap                                                                     │
│  │ Version: 28131907                                                                                        │
│  │ Digest: DfWZyiGJASyHRictNPZaXxBuscP95cBMzj8aU2HR9znb                                                     │
│  └──                                                                                                        │
│  ┌──                                                                                                        │
│  │ ObjectID: 0xcede98cf7512b7bb36d605eaa6b2b40c4d1fe0b5d95508a4a4bb1c9b6ea1e6ed                             │
│  │ Sender: 0x9e4092b6a894e6b168aa1c6c009f5c1c1fcb83fb95e5aa39144e1d2be4ee0d67                               │
│  │ Owner: Account Address ( 0x9e4092b6a894e6b168aa1c6c009f5c1c1fcb83fb95e5aa39144e1d2be4ee0d67 )            │
│  │ ObjectType: 0x2::package::Publisher                                                                      │
│  │ Version: 28131907                                                                                        │
│  │ Digest: 7ZTY3uhTAy66zuuQhzGuTuhd85WMbQbLgYCHER3enV7W                                                     │
│  └──                                                                                                        │
│ Mutated Objects:                                                                                            │
│  ┌──                                                                                                        │
│  │ ObjectID: 0x01676de212960b0689245914312ac6be3b4d5cffa0cae91ef527441b894f746a                             │
│  │ Sender: 0x9e4092b6a894e6b168aa1c6c009f5c1c1fcb83fb95e5aa39144e1d2be4ee0d67                               │
│  │ Owner: Account Address ( 0x9e4092b6a894e6b168aa1c6c009f5c1c1fcb83fb95e5aa39144e1d2be4ee0d67 )            │
│  │ ObjectType: 0x2::coin::Coin<0x2::sui::SUI>                                                               │
│  │ Version: 28131907                                                                                        │
│  │ Digest: EyVfUXRunZ1tUZJu9xPMPMfjVXECQdjDqrNaihwLKCVo                                                     │
│  └──                                                                                                        │
│ Published Objects:                                                                                          │
│  ┌──                                                                                                        │
│  │ PackageID: 0x216202fdaae06b761222286300e18eb6ef24c2fe5cf7336b7f2da9ab97beea41                            │
│  │ Version: 1                                                                                               │
│  │ Digest: 3pGSsGYWDBVZBvDzRMb9pgCqzQYixdFxPJPcDGUKTrzn                                                     │
│  │ Modules: admin, customer                                                                                 │
│  └──                                                                                                        │
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
  • 记录环境变量
export PACKAGE=0x216202fdaae06b761222286300e18eb6ef24c2fe5cf7336b7f2da9ab97beea41
export PUBLISHER=0xcede98cf7512b7bb36d605eaa6b2b40c4d1fe0b5d95508a4a4bb1c9b6ea1e6ed
export ORGANIZATIONLIST=0x1f4044ef7050a8305fcf33ce7aed3b91d34a9333ae7efc2af7205b3c286d5f30

4.2 create_service_organization

  • 运行命令

sui client call --package $PACKAGE --module admin --function create_service_organization --args $ORGANIZATIONLIST organization_test1 --gas-budget 100000000

  • 重要输出
╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Object Changes                                                                                                                                             │
├────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Created Objects:                                                                                                                                           │
│  ┌──                                                                                                                                                       │
│  │ ObjectID: 0x787784d9199ba7b4cc737968f757e51618161a20011a3587d47fc6a41a3d8d2f                                                                            │
│  │ Sender: 0x9e4092b6a894e6b168aa1c6c009f5c1c1fcb83fb95e5aa39144e1d2be4ee0d67                                                                              │
│  │ Owner: Object ID: ( 0xfd82ff66cfa34dd54a73800f6b84353687c196cddbb018e7e405262b8d198518 )                                                                │
│  │ ObjectType: 0x2::dynamic_field::Field<0x2::object::ID, 0x216202fdaae06b761222286300e18eb6ef24c2fe5cf7336b7f2da9ab97beea41::admin::ServiceOrganization>  │
│  │ Version: 28131908                                                                                                                                       │
│  │ Digest: mPs2f9vzsR4h6avMUmPuxmZjNvfqexXGiRjp5syAPmb                                                                                                     │
│  └──                                                                                                                                                       │
│  ┌──                                                                                                                                                       │
│  │ ObjectID: 0xea3dcaae81667ff00e5a7ac31326f1e5d5a8e5758ce4ef88f7230a4537bf2485                                                                            │
│  │ Sender: 0x9e4092b6a894e6b168aa1c6c009f5c1c1fcb83fb95e5aa39144e1d2be4ee0d67                                                                              │
│  │ Owner: Account Address ( 0x9e4092b6a894e6b168aa1c6c009f5c1c1fcb83fb95e5aa39144e1d2be4ee0d67 )                                                           │
│  │ ObjectType: 0x216202fdaae06b761222286300e18eb6ef24c2fe5cf7336b7f2da9ab97beea41::admin::ServiceOrganizationCap                                           │
│  │ Version: 28131908                                                                                                                                       │
│  │ Digest: PLRK1ZpfJ1SGcudcDcBdqDdTFBoPHLj2SAU3rgk8PZM                                                                                                     │
│  └──                                                                                                                                                       │
│ Mutated Objects:                                                                                                                                           │
│  ┌──                                                                                                                                                       │
│  │ ObjectID: 0x01676de212960b0689245914312ac6be3b4d5cffa0cae91ef527441b894f746a                                                                            │
│  │ Sender: 0x9e4092b6a894e6b168aa1c6c009f5c1c1fcb83fb95e5aa39144e1d2be4ee0d67                                                                              │
│  │ Owner: Account Address ( 0x9e4092b6a894e6b168aa1c6c009f5c1c1fcb83fb95e5aa39144e1d2be4ee0d67 )                                                           │
│  │ ObjectType: 0x2::coin::Coin<0x2::sui::SUI>                                                                                                              │
│  │ Version: 28131908                                                                                                                                       │
│  │ Digest: 5guVeUMee7L7qzXx919o1eKiBQK5hCcyyAnHJvBcfNdQ                                                                                                    │
│  └──                                                                                                                                                       │
│  ┌──                                                                                                                                                       │
│  │ ObjectID: 0x1f4044ef7050a8305fcf33ce7aed3b91d34a9333ae7efc2af7205b3c286d5f30                                                                            │
│  │ Sender: 0x9e4092b6a894e6b168aa1c6c009f5c1c1fcb83fb95e5aa39144e1d2be4ee0d67                                                                              │
│  │ Owner: Shared                                                                                                                                           │
│  │ ObjectType: 0x216202fdaae06b761222286300e18eb6ef24c2fe5cf7336b7f2da9ab97beea41::admin::OrganizationList                                                 │
│  │ Version: 28131908                                                                                                                                       │
│  │ Digest: B2ghJsWe8mez3cfMTuwoqJFV2p5rFxB4DZcXixxZKDR7                                                                                                    │
│  └──                                                                                                                                                       │
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
  • 记录环境变量

export SERVICEORGANIZATIONCAP=0xea3dcaae81667ff00e5a7ac31326f1e5d5a8e5758ce4ef88f7230a4537bf2485

4.3 create_service

  • 运行命令
sui client call --package $PACKAGE --module admin --function create_service --args $SERVICEORGANIZATIONCAP $ORGANIZATIONLIST service_test_1 50 --gas-budget 100000000
sui client call --package $PACKAGE --module admin --function create_service --args $SERVICEORGANIZATIONCAP $ORGANIZATIONLIST service_test_2 50 --gas-budget 100000000

4.4 switch address and query services

  • 切换用户

sui client switch --address peaceful-hiddenite

  • 查询服务机构列表
sui client call --package $PACKAGE --module customer --function query_organization_list --args $ORGANIZATIONLIST --gas-budget 100000000

# important output
╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Transaction Block Events                                                                                          │
├───────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│  ┌──                                                                                                              │
│  │ EventID: 9ewfm1HnvaaC2R4nnK7Zctcbb42XUMgzNLPRDFQm7BNj:0                                                        │
│  │ PackageID: 0x216202fdaae06b761222286300e18eb6ef24c2fe5cf7336b7f2da9ab97beea41                                  │
│  │ Transaction Module: customer                                                                                   │
│  │ Sender: 0xf6029b82e355f627b0e3d8941d63e139c4b73b495a2017ef48aaf17cc377457b                                     │
│  │ EventType: 0x216202fdaae06b761222286300e18eb6ef24c2fe5cf7336b7f2da9ab97beea41::customer::OrganizationListEvent │
│  │ ParsedJSON:                                                                                                    │
│  │   ┌───────────────────┬────────────────────────────────────────────────────────────────────┐                   │
│  │   │ organization_id   │ 0xea3dcaae81667ff00e5a7ac31326f1e5d5a8e5758ce4ef88f7230a4537bf2485 │                   │
│  │   ├───────────────────┼────────────────────────────────────────────────────────────────────┤                   │
│  │   │ organization_name │ organization_test1                                                 │                   │
│  │   └───────────────────┴────────────────────────────────────────────────────────────────────┘                   │
│  └──                                                                                                              │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯

# record ID
export ORGANIZATIONID=0xea3dcaae81667ff00e5a7ac31326f1e5d5a8e5758ce4ef88f7230a4537bf2485
  • 查询某一所机构内的所有服务
sui client call --package $PACKAGE --module customer --function query_organization_services --args $ORGANIZATIONID $ORGANIZATIONLIST --gas-budget 100000000

# important output
╭──────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Transaction Block Events                                                                                 │
├──────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│  ┌──                                                                                                     │
│  │ EventID: 97DF15Z7CKpc68AWv5jWLcUvTSAqkeTczHiMdseYgksA:0                                               │
│  │ PackageID: 0x216202fdaae06b761222286300e18eb6ef24c2fe5cf7336b7f2da9ab97beea41                         │
│  │ Transaction Module: customer                                                                          │
│  │ Sender: 0xf6029b82e355f627b0e3d8941d63e139c4b73b495a2017ef48aaf17cc377457b                            │
│  │ EventType: 0x216202fdaae06b761222286300e18eb6ef24c2fe5cf7336b7f2da9ab97beea41::customer::ServiceEvent │
│  │ ParsedJSON:                                                                                           │
│  │   ┌──────────────┬────────────────────────────────────────────────────────────────────┐               │
│  │   │ service_id   │ 0xb4a15bb46d38f61fc89bd942e8816caab6c48cc688dd4b2e023262eebd1c8951 │               │
│  │   ├──────────────┼────────────────────────────────────────────────────────────────────┤               │
│  │   │ service_name │ service_test_1                                                     │               │
│  │   └──────────────┴────────────────────────────────────────────────────────────────────┘               │
│  └──                                                                                                     │
│  ┌──                                                                                                     │
│  │ EventID: 97DF15Z7CKpc68AWv5jWLcUvTSAqkeTczHiMdseYgksA:1                                               │
│  │ PackageID: 0x216202fdaae06b761222286300e18eb6ef24c2fe5cf7336b7f2da9ab97beea41                         │
│  │ Transaction Module: customer                                                                          │
│  │ Sender: 0xf6029b82e355f627b0e3d8941d63e139c4b73b495a2017ef48aaf17cc377457b                            │
│  │ EventType: 0x216202fdaae06b761222286300e18eb6ef24c2fe5cf7336b7f2da9ab97beea41::customer::ServiceEvent │
│  │ ParsedJSON:                                                                                           │
│  │   ┌──────────────┬────────────────────────────────────────────────────────────────────┐               │
│  │   │ service_id   │ 0x6bd5e56f2ef6f5d2ff27ea55526e725fb1a50e0ecf29e839c05b4e7b2853ac43 │               │
│  │   ├──────────────┼────────────────────────────────────────────────────────────────────┤               │
│  │   │ service_name │ service_test_2                                                     │               │
│  │   └──────────────┴────────────────────────────────────────────────────────────────────┘               │
│  └──                                                                                                     │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────╯

# record ID
export SERVICE1ID=0xb4a15bb46d38f61fc89bd942e8816caab6c48cc688dd4b2e023262eebd1c8951
export SERVICE2ID=0x6bd5e56f2ef6f5d2ff27ea55526e725fb1a50e0ecf29e839c05b4e7b2853ac43

注意: 后续内容将省略用户切换这一步,所有的非服务机构管理方面的链上调用均由普通用户进行交易。

4.5 create_package_services

  • 运行命令

sui client call --package $PACKAGE --module admin --function create_package_services --args $SERVICEORGANIZATIONCAP $ORGANIZATIONLIST "[$SERVICE1ID, $SERVICE2ID]" --gas-budget 100000000

4.6 query_organization_services

  • 运行命令并设置环境变量
sui client call --package $PACKAGE --module customer --function query_organization_services --args $ORGANIZATIONID $ORGANIZATIONLIST --gas-budget 100000000

# important output
╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Transaction Block Events                                                                                         │
├──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│  ┌──                                                                                                             │
│  │ EventID: 5Fe2WvfW7f8LEjvHgExYu4qPRosjN7ci7oFRPwFvqpAe:0                                                       │
│  │ PackageID: 0x216202fdaae06b761222286300e18eb6ef24c2fe5cf7336b7f2da9ab97beea41                                 │
│  │ Transaction Module: customer                                                                                  │
│  │ Sender: 0x9e4092b6a894e6b168aa1c6c009f5c1c1fcb83fb95e5aa39144e1d2be4ee0d67                                    │
│  │ EventType: 0x216202fdaae06b761222286300e18eb6ef24c2fe5cf7336b7f2da9ab97beea41::customer::ServiceEvent         │
│  │ ParsedJSON:                                                                                                   │
│  │   ┌──────────────┬────────────────────────────────────────────────────────────────────┐                       │
│  │   │ service_id   │ 0xb4a15bb46d38f61fc89bd942e8816caab6c48cc688dd4b2e023262eebd1c8951 │                       │
│  │   ├──────────────┼────────────────────────────────────────────────────────────────────┤                       │
│  │   │ service_name │ service_test_1                                                     │                       │
│  │   └──────────────┴────────────────────────────────────────────────────────────────────┘                       │
│  └──                                                                                                             │
│  ┌──                                                                                                             │
│  │ EventID: 5Fe2WvfW7f8LEjvHgExYu4qPRosjN7ci7oFRPwFvqpAe:1                                                       │
│  │ PackageID: 0x216202fdaae06b761222286300e18eb6ef24c2fe5cf7336b7f2da9ab97beea41                                 │
│  │ Transaction Module: customer                                                                                  │
│  │ Sender: 0x9e4092b6a894e6b168aa1c6c009f5c1c1fcb83fb95e5aa39144e1d2be4ee0d67                                    │
│  │ EventType: 0x216202fdaae06b761222286300e18eb6ef24c2fe5cf7336b7f2da9ab97beea41::customer::ServiceEvent         │
│  │ ParsedJSON:                                                                                                   │
│  │   ┌──────────────┬────────────────────────────────────────────────────────────────────┐                       │
│  │   │ service_id   │ 0x6bd5e56f2ef6f5d2ff27ea55526e725fb1a50e0ecf29e839c05b4e7b2853ac43 │                       │
│  │   ├──────────────┼────────────────────────────────────────────────────────────────────┤                       │
│  │   │ service_name │ service_test_2                                                     │                       │
│  │   └──────────────┴────────────────────────────────────────────────────────────────────┘                       │
│  └──                                                                                                             │
│  ┌──                                                                                                             │
│  │ EventID: 5Fe2WvfW7f8LEjvHgExYu4qPRosjN7ci7oFRPwFvqpAe:2                                                       │
│  │ PackageID: 0x216202fdaae06b761222286300e18eb6ef24c2fe5cf7336b7f2da9ab97beea41                                 │
│  │ Transaction Module: customer                                                                                  │
│  │ Sender: 0x9e4092b6a894e6b168aa1c6c009f5c1c1fcb83fb95e5aa39144e1d2be4ee0d67                                    │
│  │ EventType: 0x216202fdaae06b761222286300e18eb6ef24c2fe5cf7336b7f2da9ab97beea41::customer::PackageServicesEvent │
│  │ ParsedJSON:                                                                                                   │
│  │   ┌─────────────────────┬────────────────────────────────────────────────────────────────────┐                │
│  │   │ package_services_id │ 0xd1f30ffcf54817a02da70251d4fd85949ecad34e772b0c4aee43304c705bc1c0 │                │
│  │   ├─────────────────────┼────────────────────────────────────────────────────────────────────┤                │
│  │   │ services            │ service_test_1                                                     │                │
│  │   │                     ├────────────────────────────────────────────────────────────────────┤                │
│  │   │                     │ service_test_2                                                     │                │
│  │   └─────────────────────┴────────────────────────────────────────────────────────────────────┘                │
│  └──                                                                                                             │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯

# record ID
export PACKAGESERVICEID=0xd1f30ffcf54817a02da70251d4fd85949ecad34e772b0c4aee43304c705bc1c0

4.7 buy_package_services

  • 运行命令
sui client gas

# output
╭────────────────────────────────────────────────────────────────────┬────────────────────┬──────────────────╮
│ gasCoinId                                                          │ mistBalance (MIST) │ suiBalance (SUI) │
├────────────────────────────────────────────────────────────────────┼────────────────────┼──────────────────┤
│ 0x516586df0c5e9c9567696840981f720d64335ac6e8ad409f4ba4843b8dc2274a │ 100                │ 0.00             │
│ 0x82ec01655d746b42dba5c5951841472e5d1715e74238a5ef8e39d0b0566dc3be │ 982798853          │ 0.98             │
│ 0x8ef6503cb330c4114bc7995a403adf4015190d8effc02504fd849377caa6499b │ 963358100          │ 0.96             │
│ 0xad3fa2545f5db01bd4d349871df5af4d6de913600e7e3e032d5229c006d35851 │ 100                │ 0.00             │
│ 0xcb24b30fe196f4f2ca6d5f8d87a273bf168f7f86f6b7ae3f1f20fc5cf447e557 │ 940920294          │ 0.94             │
│ 0xe4f2d7831241583d534271d8d777d7558290124779e98e03b059a2fe108d37b0 │ 989                │ 0.00             │
╰────────────────────────────────────────────────────────────────────┴────────────────────┴──────────────────╯

export COIN=0x82ec01655d746b42dba5c5951841472e5d1715e74238a5ef8e39d0b0566dc3be

sui client call --package $PACKAGE --module customer --function buy_package_services --args $ORGANIZATIONLIST $ORGANIZATIONID $PACKAGESERVICEID $COIN --gas-budget 100000000
  • 重要输出
╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Object Changes                                                                                                             │
├────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Created Objects:                                                                                                           │
│  ┌──                                                                                                                       │
│  │ ObjectID: 0x4e7eebf65218cf0ed484fdba0182434cdd24ff3140af950c228442447790b42c                                            │
│  │ Sender: 0xf6029b82e355f627b0e3d8941d63e139c4b73b495a2017ef48aaf17cc377457b                                              │
│  │ Owner: Account Address ( 0xf6029b82e355f627b0e3d8941d63e139c4b73b495a2017ef48aaf17cc377457b )                           │
│  │ ObjectType: 0x216202fdaae06b761222286300e18eb6ef24c2fe5cf7336b7f2da9ab97beea41::customer::PackageServicesCertification  │
│  │ Version: 28131913                                                                                                       │
│  │ Digest: 7fUc3pVppMEcQPQ1QRVwcp6Y9rWp5jKw2qfB76E1vze9                                                                    │
│  └──                                                                                                                       │
│ Mutated Objects:                                                                                                           │
│  ┌──                                                                                                                       │
│  │ ObjectID: 0x82ec01655d746b42dba5c5951841472e5d1715e74238a5ef8e39d0b0566dc3be                                            │
│  │ Sender: 0xf6029b82e355f627b0e3d8941d63e139c4b73b495a2017ef48aaf17cc377457b                                              │
│  │ Owner: Account Address ( 0xf6029b82e355f627b0e3d8941d63e139c4b73b495a2017ef48aaf17cc377457b )                           │
│  │ ObjectType: 0x2::coin::Coin<0x2::sui::SUI>                                                                              │
│  │ Version: 28131913                                                                                                       │
│  │ Digest: shAMmcj8Ca6SPC7TomPqxQviSdN4UQfwcZmKSJ2nNZ8                                                                     │
│  └──                                                                                                                       │
│  ┌──                                                                                                                       │
│  │ ObjectID: 0x8ef6503cb330c4114bc7995a403adf4015190d8effc02504fd849377caa6499b                                            │
│  │ Sender: 0xf6029b82e355f627b0e3d8941d63e139c4b73b495a2017ef48aaf17cc377457b                                              │
│  │ Owner: Account Address ( 0xf6029b82e355f627b0e3d8941d63e139c4b73b495a2017ef48aaf17cc377457b )                           │
│  │ ObjectType: 0x2::coin::Coin<0x2::sui::SUI>                                                                              │
│  │ Version: 28131913                                                                                                       │
│  │ Digest: ANDLCwxmDXNcurMemzk2fp22SWQfDdVVJkyYHQKhJj2k                                                                    │
│  └──                                                                                                                       │
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
  • 记录环境变量

export PACKAGESERVICESCERTIFICATION=0x4e7eebf65218cf0ed484fdba0182434cdd24ff3140af950c228442447790b42c

4.8 destroy_service and query

  • 下架(取消)服务

sui client call --package $PACKAGE --module admin --function destroy_service --args $SERVICEORGANIZATIONCAP $ORGANIZATIONLIST $SERVICE1ID --gas-budget 100000000

  • 查询
sui client call --package $PACKAGE --module customer --function query_organization_services --args $ORGANIZATIONID $ORGANIZATIONLIST --gas-budget 100000000

# important output
╭──────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Transaction Block Events                                                                                 │
├──────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│  ┌──                                                                                                     │
│  │ EventID: A8d3a5CHgpjpmK8HyLH1e4xs3ww15ary8JSw6ts8BUBL:0                                               │
│  │ PackageID: 0x216202fdaae06b761222286300e18eb6ef24c2fe5cf7336b7f2da9ab97beea41                         │
│  │ Transaction Module: customer                                                                          │
│  │ Sender: 0x9e4092b6a894e6b168aa1c6c009f5c1c1fcb83fb95e5aa39144e1d2be4ee0d67                            │
│  │ EventType: 0x216202fdaae06b761222286300e18eb6ef24c2fe5cf7336b7f2da9ab97beea41::customer::ServiceEvent │
│  │ ParsedJSON:                                                                                           │
│  │   ┌──────────────┬────────────────────────────────────────────────────────────────────┐               │
│  │   │ service_id   │ 0x6bd5e56f2ef6f5d2ff27ea55526e725fb1a50e0ecf29e839c05b4e7b2853ac43 │               │
│  │   ├──────────────┼────────────────────────────────────────────────────────────────────┤               │
│  │   │ service_name │ service_test_2                                                     │               │
│  │   └──────────────┴────────────────────────────────────────────────────────────────────┘               │
│  └──                                                                                                     │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────╯

4.9 update_package_services

  • 运行命令
sui client call --package $PACKAGE --module customer --function update_package_services --args $PACKAGESERVICESCERTIFICATION $ORGANIZATIONLIST --gas-budget 100000000

# important output
╭─────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Transaction Block Events                                                                                │
├─────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│  ┌──                                                                                                    │
│  │ EventID: FT639fjhsoFqeoU79XH21tJYmKKiKTwMb97A3KtWNGzG:0                                              │
│  │ PackageID: 0x216202fdaae06b761222286300e18eb6ef24c2fe5cf7336b7f2da9ab97beea41                        │
│  │ Transaction Module: customer                                                                         │
│  │ Sender: 0xf6029b82e355f627b0e3d8941d63e139c4b73b495a2017ef48aaf17cc377457b                           │
│  │ EventType: 0x216202fdaae06b761222286300e18eb6ef24c2fe5cf7336b7f2da9ab97beea41::customer::RefundEvent │
│  │ ParsedJSON:                                                                                          │
│  │   ┌───────┬────────────────────────────────────────────────────────┐                                 │
│  │   │ note  │ service organization or package services has canceled! │                                 │
│  │   ├───────┼────────────────────────────────────────────────────────┤                                 │
│  │   │ value │ 85                                                     │                                 │
│  │   └───────┴────────────────────────────────────────────────────────┘                                 │
│  └──                                                                                                    │
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────╯
  • 查询余额
sui client gas

# output
╭────────────────────────────────────────────────────────────────────┬────────────────────┬──────────────────╮
│ gasCoinId                                                          │ mistBalance (MIST) │ suiBalance (SUI) │
├────────────────────────────────────────────────────────────────────┼────────────────────┼──────────────────┤
│ 0x516586df0c5e9c9567696840981f720d64335ac6e8ad409f4ba4843b8dc2274a │ 100                │ 0.00             │
│ 0x82ec01655d746b42dba5c5951841472e5d1715e74238a5ef8e39d0b0566dc3be │ 983283808          │ 0.98             │
│ 0x8ef6503cb330c4114bc7995a403adf4015190d8effc02504fd849377caa6499b │ 959830340          │ 0.95             │
│ 0x9bfd02b5901fcdcce225336c009d881b191fad46b82158dc15b84e1346973523 │ 85                 │ 0.00             │
│ 0xad3fa2545f5db01bd4d349871df5af4d6de913600e7e3e032d5229c006d35851 │ 100                │ 0.00             │
│ 0xcb24b30fe196f4f2ca6d5f8d87a273bf168f7f86f6b7ae3f1f20fc5cf447e557 │ 940920294          │ 0.94             │
│ 0xe4f2d7831241583d534271d8d777d7558290124779e98e03b059a2fe108d37b0 │ 989                │ 0.00             │
╰────────────────────────────────────────────────────────────────────┴────────────────────┴──────────────────╯

4.10 buy service and enjoy

  • 购买单项服务
sui client call --package $PACKAGE --module customer --function buy_service --args $ORGANIZATIONLIST $ORGANIZATIONID $SERVICE2ID $COIN --gas-budget 100000000

# important output
╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Object Changes                                                                                                     │
├────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Created Objects:                                                                                                   │
│  ┌──                                                                                                               │
│  │ ObjectID: 0x65599566e55f6bef29d7e67c8d04d10b2c7701459e368fa6ef2288d3e7a0ce66                                    │
│  │ Sender: 0xf6029b82e355f627b0e3d8941d63e139c4b73b495a2017ef48aaf17cc377457b                                      │
│  │ Owner: Account Address ( 0xf6029b82e355f627b0e3d8941d63e139c4b73b495a2017ef48aaf17cc377457b )                   │
│  │ ObjectType: 0x216202fdaae06b761222286300e18eb6ef24c2fe5cf7336b7f2da9ab97beea41::customer::ServiceCertification  │
│  │ Version: 28131915                                                                                               │
│  │ Digest: CCaaGnshMomZHcpegnb4GB2k5TuYSogKxZ4ZdQGAp3h8                                                            │
│  └──                                                                                                               │
│ Mutated Objects:                                                                                                   │
│  ┌──                                                                                                               │
│  │ ObjectID: 0x82ec01655d746b42dba5c5951841472e5d1715e74238a5ef8e39d0b0566dc3be                                    │
│  │ Sender: 0xf6029b82e355f627b0e3d8941d63e139c4b73b495a2017ef48aaf17cc377457b                                      │
│  │ Owner: Account Address ( 0xf6029b82e355f627b0e3d8941d63e139c4b73b495a2017ef48aaf17cc377457b )                   │
│  │ ObjectType: 0x2::coin::Coin<0x2::sui::SUI>                                                                      │
│  │ Version: 28131915                                                                                               │
│  │ Digest: 4kHSso6yaPMmZ8VHFKvcbNJjdFLAtvCkJALStidq56ik                                                            │
│  └──                                                                                                               │
│  ┌──                                                                                                               │
│  │ ObjectID: 0x8ef6503cb330c4114bc7995a403adf4015190d8effc02504fd849377caa6499b                                    │
│  │ Sender: 0xf6029b82e355f627b0e3d8941d63e139c4b73b495a2017ef48aaf17cc377457b                                      │
│  │ Owner: Account Address ( 0xf6029b82e355f627b0e3d8941d63e139c4b73b495a2017ef48aaf17cc377457b )                   │
│  │ ObjectType: 0x2::coin::Coin<0x2::sui::SUI>                                                                      │
│  │ Version: 28131915                                                                                               │
│  │ Digest: 4vsaUViSYCkazVVrQHQqbXNT3VPFhb13cDpJTw5gE5mc                                                            │
│  └──                                                                                                               │
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯

# record ID
export SERVICECERTIFICATION=0x65599566e55f6bef29d7e67c8d04d10b2c7701459e368fa6ef2288d3e7a0ce66
  • 享受这一项服务
sui client call --package $PACKAGE --module customer --function enjoy_service --args $SERVICECERTIFICATION $ORGANIZATIONLIST --gas-budget 100000000

# important output
╭──────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Transaction Block Events                                                                                 │
├──────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│  ┌──                                                                                                     │
│  │ EventID: 61Rj3VYz3jC5KhPbe2jexoBfJd8Be7fGk6AMG9iffP5z:0                                               │
│  │ PackageID: 0x216202fdaae06b761222286300e18eb6ef24c2fe5cf7336b7f2da9ab97beea41                         │
│  │ Transaction Module: customer                                                                          │
│  │ Sender: 0xf6029b82e355f627b0e3d8941d63e139c4b73b495a2017ef48aaf17cc377457b                            │
│  │ EventType: 0x216202fdaae06b761222286300e18eb6ef24c2fe5cf7336b7f2da9ab97beea41::customer::EnjoyEvent   │
│  │ ParsedJSON:                                                                                           │
│  │   ┌──────┬──────────────────────────────────────────────────────────────────────────────────────────┐ │
│  │   │ note │ good morning, and in case i don't see you, good afternoon, good evening, and good night! │ │
│  │   └──────┴──────────────────────────────────────────────────────────────────────────────────────────┘ │
│  └──                                                                                                     │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────╯

4.11 withdraw

  • 服务机构提现
sui client call --package $PACKAGE --module admin --function organization_withdraw --args $SERVICEORGANIZATIONCAP $ORGANIZATIONLIST --gas-budget 100000000

# error
Error executing transaction: Failure {
    error: "MoveAbort(MoveLocation { module: ModuleId { address: 216202fdaae06b761222286300e18eb6ef24c2fe5cf7336b7f2da9ab97beea41, name: Identifier(\"admin\") }, function: 2, instruction: 14, function_name: Some(\"organization_withdraw_\") }, 1) in command 0",
}

因为收入少于 $\text {100}$,所以提现失败。<br>我们切换用户,再一次购买并享受一次价值 $\text {50}$ 的单项服务,之后再尝试发起这一笔交易。<br>现在,我们的收入是 $\text {100}$,服务机构将得到 $\text {99}$,而票务系统发布者将赚得 $\text {1}$,接下去我们将见证这一点。

  • 服务机构提现
sui client call --package $PACKAGE --module admin --function organization_withdraw --args $SERVICEORGANIZATIONCAP $ORGANIZATIONLIST --gas-budget 100000000

# query gas
sui client gas
╭────────────────────────────────────────────────────────────────────┬────────────────────┬──────────────────╮
│ gasCoinId                                                          │ mistBalance (MIST) │ suiBalance (SUI) │
├────────────────────────────────────────────────────────────────────┼────────────────────┼──────────────────┤
│ 0x01676de212960b0689245914312ac6be3b4d5cffa0cae91ef527441b894f746a │ 601182904          │ 0.60             │
│ 0x03335f68ff3616af7e000b113c56a5ad53e8e8209784ca0a5623f70997c8d948 │ 3182792690         │ 3.18             │
│ 0xd61fa7c67f44180f8987e9de59cae81e2b26215c6209e0a40bc782402344474d │ 99                 │ 0.00             │
│ 0xf0d1ea4828fe7391b41b2b07cc8c4c5fd1831aee6b6a4e5195b236dea20fbde4 │ 666                │ 0.00             │
╰────────────────────────────────────────────────────────────────────┴────────────────────┴──────────────────╯
  • 系统发布者提现
sui client call --package $PACKAGE --module admin --function publisher_withdraw --args $PUBLISHER $ORGANIZATIONLIST --gas-budget 100000000

# query gas
sui client gas
╭────────────────────────────────────────────────────────────────────┬────────────────────┬──────────────────╮
│ gasCoinId                                                          │ mistBalance (MIST) │ suiBalance (SUI) │
├────────────────────────────────────────────────────────────────────┼────────────────────┼──────────────────┤
│ 0x01676de212960b0689245914312ac6be3b4d5cffa0cae91ef527441b894f746a │ 599146796          │ 0.59             │
│ 0x03335f68ff3616af7e000b113c56a5ad53e8e8209784ca0a5623f70997c8d948 │ 3182792690         │ 3.18             │
│ 0x8eb492cda5672e5b87541b744962f927b40b3e67119dc5ba437ee8dfb4785595 │ 1                  │ 0.00             │
│ 0xd61fa7c67f44180f8987e9de59cae81e2b26215c6209e0a40bc782402344474d │ 99                 │ 0.00             │
│ 0xf0d1ea4828fe7391b41b2b07cc8c4c5fd1831aee6b6a4e5195b236dea20fbde4 │ 666                │ 0.00             │
╰────────────────────────────────────────────────────────────────────┴────────────────────┴──────────────────╯

五:加入组织,共同进步!

点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
Nigdle
Nigdle
0xa745...Fe19
江湖只有他的大名,没有他的介绍。