Order Platform

Endless Go SDK Quick Start

1. Order Platform Move Contract

1.1 Contract Overview

The contract provides a decentralized framework for creating and managing orders within an e-commerce ecosystem. It defines the complete lifecycle of an order, from creation to completion, including payment, shipping, and cancellation. The system is built on the Endless blockchain, utilizing EndlessCoin for payments and a table-based storage system for scalability.

1.2 Core Concepts

1.2.1 Order Lifecycle (State Machine)

The core of the contract is a state machine that represents the lifecycle of an order. Each order progresses through a series of statuses, and transitions are governed by specific rules and function calls.

The statuses are defined as constants:

  • STATUS_PENDING_PAYMENT (0): The initial state after an order is created. Awaiting payment from the buyer.

  • STATUS_PAID (1): The buyer has successfully transferred the funds to the seller.

  • STATUS_SHIPPED (2): The seller has marked the order as shipped.

  • STATUS_COMPLETED (3): The buyer has confirmed receipt of the item. (Note: The function for this is currently commented out but is part of the intended design).

  • STATUS_CANCELLED (4): The order has been cancelled by either the buyer or the seller under specific conditions.

A typical successful order flow is: PENDING_PAYMENT -> PAID -> SHIPPED -> COMPLETED

1.2.2 Roles

There are two primary roles in this system:

  • Buyer: The user who creates and pays for the order.

  • Seller: The user who receives payment and ships the item.

Each state-changing function includes assertions to ensure that the transaction signer has the correct role for the intended action (e.g., only the buyer can pay, only the seller can ship).

1.2.3 Economy

All financial transactions are conducted using the native EndlessCoin(EDS). Prices and payments are specified in veins, the smallest unit of EndlessCoin, to ensure precision and avoid floating-point issues. 1 EDS = 100_000_000 Veins.

1.3 Data Structures (On-Chain State)

The contract's state is managed by two singleton resources, stored under the deployer's account (@order_platform).

1.3.1 Resources

  • OrderCounter:

    • A singleton resource that ensures every order receives a unique, sequential ID.

    • next_order_id: u64: A counter that is incremented each time a new order is created.

  • Orders:

    • A singleton resource that acts as the central repository for all orders.

    • orders: Table<u64, Order>: A scalable map (Table) that links a unique order_id (u64) to its corresponding Order struct. This allows for efficient lookups, insertions, and modifications.

1.3.2 Structs

  • Order:

    • The primary data structure representing an individual order. It has store and drop abilities, meaning it can be stored in global storage but cannot be copied.

    • order_id: u64: Unique identifier.

    • buyer: address: The address of the buyer.

    • seller: address: The address of the seller.

    • item_id: String: A string identifier for the product.

    • quantity: u128: The number of items ordered.

    • unit_price: u128: The price per item in Veins.

    • total_price: u128: The calculated total price (quantity * unit_price).

    • status: u8: The current status of the order, corresponding to the status constants.

  • OrderData:

    • A read-only representation of an order's data. It has copy, drop, and store abilities, making it suitable for returning from #[view] functions. Its structure mirrors the Order struct.

1.4 Events

The contract emits events at key points in the order lifecycle. This allows off-chain services, indexers, and user interfaces to monitor and react to on-chain activity without needing to query the state directly.

  • OrderCreatedEvent: Emitted when create_order is successfully called.

  • OrderPaidEvent: Emitted when pay_order is successfully called.

  • OrderShippedEvent: Emitted when ship_order is successfully called.

  • OrderCancelledEvent: Emitted when cancel_order is successfully called.

  • OrderCompletedEvent: Emitted when an order is marked as complete.

1.5 Functions (Module API)

1.5.1 Initialization Function

  • init_module(deployer: &signer):

    • A private function that must be called once by the module deployer to initialize the OrderCounter and Orders resources.

    • It includes an assertion to prevent re-initialization.

1.5.2 Entry Functions (State-Changing)

  • create_order(...):

    • Allows a buyer to create a new order.

    • It calculates the total_price, assigns a new order_id, stores the Order struct in the Orders table, and emits an OrderCreatedEvent.

  • pay_order(...):

    • Allows the buyer to pay for an order that is in the STATUS_PENDING_PAYMENT.

    • Preconditions: The order must exist, the signer must be the buyer, the status must be PENDING_PAYMENT, and the payment amount must match the total_price.

    • It transfers EndlessCoin from the buyer to the seller, updates the order status to STATUS_PAID, and emits an OrderPaidEvent.

  • ship_order(...):

    • Allows the seller to mark a paid order as shipped.

    • Preconditions: The order must exist, the signer must be the seller, and the status must be STATUS_PAID.

    • It updates the order status to STATUS_SHIPPED and emits an OrderShippedEvent.

  • cancel_order(...):

    • Allows a buyer or seller to cancel an order based on specific rules.

    • Preconditions:

      • A buyer can cancel if the status is PENDING_PAYMENT or PAID.

      • A seller can cancel only if the status is PENDING_PAYMENT.

      • The signer must be either the buyer or the seller.

    • It updates the order status to STATUS_CANCELLED and emits an OrderCancelledEvent.

    • Note: This function does not currently handle refund logic for paid cancellations. This would be a required enhancement for a production system.

1.5.3 View Functions (Read-Only)

  • get_order_details(order_id: u64): OrderData:

    • A public, read-only function that returns the OrderData for a given order_id.

    • It asserts that the order exists.

  • get_order_status(order_id: u64): u8:

    • A public, read-only function that returns just the status of a given order_id.

1.6 Error Handling

The module defines a set of comprehensive error codes to provide clear reasons for transaction failures.

  • E_NOT_INITIALIZED (1): The module has not been initialized.

  • E_ORDER_NOT_FOUND (2): The specified order_id does not exist.

  • E_INVALID_ORDER_STATUS (3): The action is not allowed in the order's current state.

  • E_INSUFFICIENT_FUNDS (4): The buyer does not have enough coins to pay.

  • E_SENDER_NOT_BUYER (5): The transaction was signed by an address other than the buyer's.

  • E_SENDER_NOT_SELLER (6): The transaction was signed by an address other than the seller's.

  • E_PAYMENT_AMOUNT_MISMATCH (7): The payment amount does not match the order's total price.

  • E_COIN_TRANSFER_FAILED (9): A generic error for coin transfer failures.

  • E_NOT_AUTHORIZED (10): The signer is neither the buyer nor the seller for a restricted action.

1.7 Future Enhancements

  • Implement complete_order: Add the entry function to allow buyers to mark an order as STATUS_COMPLETED.

  • Refund on Cancellation: Implement logic in cancel_order to automatically refund the buyer if a PAID order is cancelled.

  • Reputation System: Add a mechanism for buyers and sellers to rate each other after an order is completed.

  • Dispute Resolution: Introduce a mechanism for handling disputes, potentially involving a trusted third party or a decentralized arbitration process.

1.8 Deploy Contract

1.8.1 Create project folder

1.8.2 Create move contract folder

1.8.3 Init contract project

1.8.4 Implementing the contract according to the above design

The complete contract is in the file {path}\endless-orders\move\sources\orders.move

1.8.5 Craete contract deplay account

1.8.6 Modify contract address

Modify [addresses] field in {path}\endless-orders\move\Move.toml

"0xdcf462ef1bad8ed0901043126048acdbf6446f486eee2a38a12ddf8b727a2cc6"'s base58 format.

1.8.7 Deploy contract

Follow the prompts: type yes when asked for a Do you want to submit a transaction for a range of... and press Enter.

2. Use Go SDK to interact with contracts

Before you begin, please ensure that you have the Go language environment and VS Code installed on your system.

2.1 Install Go

  1. Download Go: Visit the official Go download page, download and install the latest version of Go for your operating system.

  2. Configure Environment Variables: The installer usually configures the environment variables automatically. If not, manually add the Go bin directory (e.g., C:\Go\bin or /usr/local/go/bin) to your system's PATH environment variable.

  3. Verify Installation: Open a terminal or command prompt and enter the following command to verify that Go is installed correctly:

    If you see the version number output, the installation was successful.

2.2 Install Visual Studio Code

Visit the official VS Code website to download and install the version suitable for your operating system.

2.2.1 Install the Go Extension

VS Code supports development in different languages through extensions. For Go, we need to install the official Go extension.

  1. Open VS Code.

  2. Click the Extensions icon in the sidebar or use the shortcut Ctrl+Shift+X.

  3. Enter Go in the search box.

  4. Find the official extension published by the Go Team at Google and click Install.

Install Go Extension

2.2..2 Install Go Development Tools

The Go extension relies on some command-line tools to provide advanced features like code completion, formatting, definition jumping, and debugging (e.g., gopls, dlv).

  1. After installing the Go extension, a notification will usually appear in the bottom right corner suggesting you install these dependency tools. Click Install All.

  2. If you miss the notification, you can also install them manually:

    • Open the Command Palette: Ctrl+Shift+P (Windows/Linux) or Cmd+Shift+P (macOS).

    • Type Go: Install/Update Tools and press Enter.

    • Check all the tools in the list, then click OK.

    VS Code will automatically execute the go install command in the terminal to install these tools. Please ensure your network can access Go's domains.

2.3 Create Your Go Project

2.3.1 Initialize a Go Module

Since Go 1.11, Go Modules are the official way to manage project dependencies. Run the following command in the project root directory to initialize a module:

After execution, a go.mod file will be generated in the directory.

2.3.2 Create the main.go File

Create a file named main.go in the project root directory and enter the following "Hello, World!" code:

2.3.3 Add endless-go-sdk and cobra

In order to call the endless on-chain contract and conveniently process command line instructions, we need to add dependencies endless-go-sdk and cobra.

To facilitate the processing of command line commands, we added cobra package.

2.3.4 Create project structure directories and files

main.go: program entry root.go: root Command order.go: All cli commands and parameter definitions and parsing of each command web3.go: All commands and interactions with on-chain contracts

2.3.5 Register root command

Definition a rootCmd in cmd/root.go

Then we can call its Execute() function in main.go as as follows

2.3.6 Create an account and faucet EDS on testnet

2.3.6.1 Create an account

An account is essentially a public-private key pair and an account address derived from them. We save the generated private key and account address locally, so that when needed, we can directly read the file and construct an account to interact with the chain.

  • 1 Define and register the Create account command In cmd/order.go define and register the command, they call the corresponding specific implementation in web3/web3.go to complete the entire function.

  • 2 Implement the Create account command

In this way, we have implemented a function to create an account and save it.

  • 3 Create an account named alice

2.3.6.2 faucet EDS on testnet for alice

  • 1 Define and register the Faucet Account command Add the following code to the cmd/order.go

Add faucetAccountCmd to init function.

  • 2 Implement the Faucet account command In order to easy for loading of an account, we implement a function in web3/web3.go

To interact with the blockchain, you need to build an endless.Client object. The endless.Client provides a Faucet function, which can directly get a EDS on the test network. To send a transaction, you need to pass in the SequenceNumber of the account. The new account does not exist on the chain and has no SequenceNumber. Therefore, err = client.Faucet(*account) will directly report an error. In this case, you need to set the SequenceNumber of the account to 0.

At this point, all the functions of Faucet account are completed

  • 3 Faucet EDS on testnet for alice

2.3.7 Call the function of the published contract

So far, we have not interacted with the contract we published. Now let's create an order using our contract.

2.3.7.1 Create order subcommand

We put all interactive commands with the orders contract to the order subcommand. First define a orderCmd in cmd/order.go

Then register orderCmd to rootCmd

2.3.7.2 Implement Create Order Command for order subcommand

  • 1 Define and register createOrderCmd for orderCmd in cmd/order.go

  • 2 Define contract address and module address In endless, one address can publish multiple contracts, and each contract can be called a module. Such as 0x4 address is EndlessToken package. It contains Six modules, including coin,collection,nft,property_map,royalty and token. EndlessToken package

Define endless-orders address and orders module in web3/web3.go.

Use GetContractAddress to get the contract address

  • 3 Implement createOrderCmd

Serialize Arguments: The function's arguments (quantity, unitPrice, itemId) are serialized into the BCS (Binary Canonical Serialization) format, which is required by the Endless blockchain.

  • quantity and unitPrice are converted to u128.

  • itemId is serialized as a string.

Construct Entry Function Payload: It builds an endless.EntryFunction struct. This struct specifies the target smart contract to call,

  • Module: The contract's on-chain address (retrieved via GetContractAddress) and the module name (orders).

  • Function: The name of the function to call (create_order).

  • Args: The serialized arguments for the function call: seller's address, item ID, quantity, and unit price.

In this way, we have completed the function of creating orders on the chain.

  • 4 Create an order on chain

Visit the Official Endless Scan Website,can find the event orders::OrderCreatedEvent,or you can Parse the UserTransaction returned by WaitForTransaction to extract this event. We can know the newly created order id is 1.

2.3.7.3 Implementing Other Order Subcommands

Similar to the order creation process described in 2.3.7.2, you can implement other commands other order commands such as order payment, order shipping, etc., The complete functional implementation is already in cmd/order.go and web3/web3.go in the latest code repository. It is important to note that when Go language json parses the field type of the returned object, sometimes the type it parses is not the type you expected. That is why when calling the view function get_order_status, its return value is converted to float64 in Go. For example, when calling the get_order_status view function, its return value is treated as a float64 in Go.

Last updated