# Order Platform

### 1. Order Platform Move Contract <a href="#id-1-order-platform-move-contract" id="id-1-order-platform-move-contract"></a>

#### 1.1 Contract Overview <a href="#id-11-contract-overview" id="id-11-contract-overview"></a>

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 <a href="#id-12-core-concepts" id="id-12-core-concepts"></a>

**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) <a href="#id-13-data-structures-on-chain-state" id="id-13-data-structures-on-chain-state"></a>

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 <a href="#id-14-events" id="id-14-events"></a>

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) <a href="#id-15-functions-module-api" id="id-15-functions-module-api"></a>

**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 <a href="#id-16-error-handling" id="id-16-error-handling"></a>

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 <a href="#id-17-future-enhancements" id="id-17-future-enhancements"></a>

* **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 <a href="#id-18-deploy-contract" id="id-18-deploy-contract"></a>

**1.8.1 Create project folder**

```
{path}>mkdir endless-orders
{path}>cd endless-orders
```

**1.8.2 Create move contract folder**

```
{path}\endless-orders>mkdir move
{path}\endless-orders>cd move

```

**1.8.3 Init contract project**

```
{path}\endless-orders\move>endless move init --name endless-orders
Success
{path}\endless-orders\move>dir
2025/07/02  11:14    <DIR>          .
2025/07/02  11:13    <DIR>          ..
2025/07/02  11:14               253 Move.toml
2025/07/02  11:14    <DIR>          scripts
2025/07/02  11:14    <DIR>          sources
2025/07/02  11:14    <DIR>          tests
```

**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**

```
{path}\endless-orders\move>endless init
Configuring for profile default
Choose network from [testnet, mainnet, local, custom | defaults to testnet]

No network given, using testnet...
Enter your private key as a hex literal (0x...) [Current: None | No input: Generate new key (or keep one if present)]

No key given, generating key...
Account 0xdcf462ef1bad8ed0901043126048acdbf6446f486eee2a38a12ddf8b727a2cc6 doesn't exist, creating it and funding it with 100000000 Veins
Account 0xdcf462ef1bad8ed0901043126048acdbf6446f486eee2a38a12ddf8b727a2cc6 funded successfully

---
Endless CLI is now set up for account 0xdcf462ef1bad8ed0901043126048acdbf6446f486eee2a38a12ddf8b727a2cc6 as profile default!  Run `endless --help` for more information about commands
Success
```

**1.8.6 Modify contract address**

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

```
[addresses]
order_platform = "FsWq9ZonkCHLZfoRG3Ci8PGr7ps3Mo5mqLGyE1CyRNhb"
```

"0xdcf462ef1bad8ed0901043126048acdbf6446f486eee2a38a12ddf8b727a2cc6"'s base58 format.

**1.8.7 Deploy contract**

```
{path}\endless-orders\move>endless move publish
Compiling, may take a little while to download git dependencies...
INCLUDING DEPENDENCY EndlessFramework
INCLUDING DEPENDENCY EndlessStdlib
INCLUDING DEPENDENCY MoveStdlib
BUILDING endless-orders
package size 5577 bytes
Do you want to submit a transaction for a range of [402000 - 603000] Veins at a gas unit price of 100 Veins? [yes/no] >
yes
transaction_hash:8xsoY7xrNNXuV4t1CSiyECFoJD1YMjw9fHwZejxzu4gu
gas_used:4020
gas_unit_price:100
sender:dcf462ef1bad8ed0901043126048acdbf6446f486eee2a38a12ddf8b727a2cc6
sequence_number:0
success:true
timestamp_us:1751426811613310
version:250249525
vm_status:Executed successfully
```

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 <a href="#id-2-use-go-sdk-to-interact-with-contracts" id="id-2-use-go-sdk-to-interact-with-contracts"></a>

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

#### 2.1 Install Go <a href="#id-21-install-go" id="id-21-install-go"></a>

1. **Download Go**: Visit the [official Go download page](https://golang.org/dl/), 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:

   ```sh
   {path}\endless-orders>go version
   go version go1.24.4 windows/amd64
   ```

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

#### 2.2 Install Visual Studio Code <a href="#id-22-install-visual-studio-code" id="id-22-install-visual-studio-code"></a>

Visit the [official VS Code website](https://code.visualstudio.com/) 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](https://code.visualstudio.com/assets/docs/languages/go/go-extension.png)

**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 <a href="#id-23-create-your-go-project" id="id-23-create-your-go-project"></a>

**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:

```sh
# Replace "endless-orders" with your module path, which is usually your code repository address
{path}\endless-orders>go mod init endless-orders
go: creating new go.mod: module endless-orders
```

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:

```go
package main

import "fmt"

func main() {
    fmt.Println("Hello, Endless!")
}
```

**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.

```
go get -u github.com/endless-labs/endless-go-sdk
```

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

```
go get -u github.com/spf13/cobra
```

**2.3.4 Create project structure directories and files**

```
endless-orders
│─main.go
│
├─cmd
│	│─ order.go
│	│─ root.go
│
└─web3
	│─ web3.go
```

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

```
package cmd

import (
	"fmt"
	"os"

	"github.com/spf13/cobra"
)

var rootCmd = &cobra.Command{
	Use:   "order-cli",
	Short: "A CLI to interact with the order_platform::orders Move contract",
	Long:  `A command-line interface to create, manage, and query orders on the Endless blockchain.`,
	CompletionOptions: cobra.CompletionOptions{DisableDefaultCmd: true},
}

func Execute() {
	if err := rootCmd.Execute(); err != nil {
		fmt.Fprintf(os.Stderr, "Whoops. There was an error while executing your CLI '%s'", err)
		os.Exit(1)
	}
}

```

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

```
package main

import "endless-orders/cmd"

func main() {
	cmd.Execute()
}
```

**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.

```
// order.go
package cmd

import (
	"endless-orders/web3"
	"fmt"
	"strconv"

	"github.com/spf13/cobra"
)

// Create Account Command
var createAccountCmd = &cobra.Command{
	Use:   "create_account [account-name]",
	Short: "Creates a new account",
	Long:  `Creates a new account and saves it locally.`,
	Args:  cobra.ExactArgs(1),
	Run: func(cmd *cobra.Command, args []string) {
		accountName := args[0]
		web3.CreateAccount(accountName)
	},
}

func init() {
	// Add the order command to the root command
	rootCmd.AddCommand(createAccountCmd)
}

```

* 2 Implement the `Create account` command

```
// web3.go
package web3

import (
	"encoding/hex"
	"encoding/json"
	"fmt"
	"math/big"
	"os"
	"sync"

	"github.com/endless-labs/endless-go-sdk"
	"github.com/endless-labs/endless-go-sdk/bcs"
	"github.com/endless-labs/endless-go-sdk/crypto"
)

// AccountData holds the information for a saved account
type AccountData struct {
	PrivateKey string `json:"private_key"`
	Address    string `json:"address"`
}


func CreateAccount(accountName string) {
	// Create a new Ed25519 account
	account, err := endless.NewEd25519Account()
	if err != nil {
		panic("Failed to create account: " + err.Error())
	}

	// Save the account to a file
	privateKeyBytes := account.Signer.(*crypto.Ed25519PrivateKey).Bytes()

	data := AccountData{
		PrivateKey: hex.EncodeToString(privateKeyBytes),
		Address:    account.Address.String(),
	}

	fileContent, err := json.MarshalIndent(data, "", "  ")
	if err != nil {
		panic("Failed to marshal account data: " + err.Error())
	}

	err = os.WriteFile(accountName+".json", fileContent, 0644)
	if err != nil {
		panic("Failed to save account file: " + err.Error())
	}

	fmt.Printf("Account '%s' created.\n", accountName)
	fmt.Printf("Address: %s\n", account.Address.String())
	fmt.Printf("Saved to %s.json\n", accountName)
}

```

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

* 3 Create an account named alice

```
{path}\endless-orders>go build
{path}\endless-orders>endless-orders.exe create_account alice
Account 'alice' created.
Address: GVFJPNkqkdH9hx5CwFGnFPUFzbDUaBjdCB3U8WkKrce3
Saved to alice.json
```

**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

```
// Faucet Account Command
var faucetAccountCmd = &cobra.Command{
	Use:   "faucet_account [account-name]",
	Short: "Funds an account from the faucet",
	Long:  `Requests funds from the faucet for a given account.`,
	Args:  cobra.ExactArgs(1),
	Run: func(cmd *cobra.Command, args []string) {
		accountName := args[0]
		web3.FaucetAccount(accountName)
	},
}

```

Add faucetAccountCmd to init function.

```
// Add the order command to the root command  
  rootCmd.AddCommand(createAccountCmd)
  rootCmd.AddCommand(faucetAccountCmd)
```

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

```
func LoadAccount(accountName string) *endless.Account {
	// Load the account from the file
	fileContent, err := os.ReadFile(accountName + ".json")
	if err != nil {
		panic("Failed to read account file: " + err.Error())
	}

	var data AccountData
	err = json.Unmarshal(fileContent, &data)
	if err != nil {
		panic("Failed to unmarshal account data: " + err.Error())
	}

	privateKeyBytes, err := hex.DecodeString(data.PrivateKey)
	if err != nil {
		panic("Failed to decode private key: " + err.Error())
	}
	privateKey := &crypto.Ed25519PrivateKey{}
	err = privateKey.FromBytes(privateKeyBytes)
	if err != nil {
		panic("privateKey key is not valid")
	}
	account, err := endless.NewAccountFromSigner(privateKey)
	if err != nil {
		panic("NewAccountFromSigner is not valid")
	}
	return account
}
```

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.`

```
func FaucetAccount(accountName string) {
	// Load the account from the file
	account := LoadAccount(accountName)
	// Create a client for Endless
	client, err := endless.NewClient(endless.TestnetConfig)
	if err != nil {
		panic("Failed to create client:" + err.Error())
	}

	// Fund the account from the faucet
	// err = client.Faucet(*account, endless.SequenceNumber(0)) // Use the sequence number to skip fetching it
	// Use the sequence number to skip fetching it
	err = client.Faucet(*account)
	if err != nil {
		pre_err := err
		err = client.Faucet(*account, endless.SequenceNumber(0))
		if err != nil {
			panic("Failed to fund account:" + pre_err.Error())
		}
	}

	Balance, err := client.AccountEDSBalance(account.Address)
	if err != nil {
		panic("Failed to get account balance:" + err.Error())
	}

	fmt.Printf("Successfully funded account '%s' from the faucet '%s'.\n", accountName, Balance)

}
```

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

* 3 Faucet EDS on testnet for alice

```
{path}\endless-orders>go build
{path}\endless-orders>endless-orders.exe faucet_account alice
Successfully funded account 'alice' from the faucet '1000000000'.
```

**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

```
var orderCmd = &cobra.Command{
	Use:   "order",
	Short: "Manage orders",
	Long:  `The main command to manage orders on the order platform.`,
}
```

Then register orderCmd to rootCmd

```
func init() {
	// Add the order command to the root command
	rootCmd.AddCommand(orderCmd)
	rootCmd.AddCommand(createAccountCmd)
	rootCmd.AddCommand(faucetAccountCmd)
}

```

**2.3.7.2 Implement Create Order Command for order subcommand**

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

```
// Create Order Command
var createOrderCmd = &cobra.Command{
	Use:   "create",
	Short: "Creates a new order",
	Long:  `Creates a new order with the status PENDING_PAYMENT.`,
	Run: func(cmd *cobra.Command, args []string) {
		buyerName, _ := cmd.Flags().GetString("buyer")
		sellerName, _ := cmd.Flags().GetString("seller-name")
		itemId, _ := cmd.Flags().GetString("item-id")
		quantity, _ := cmd.Flags().GetUint64("quantity")
		unitPrice, _ := cmd.Flags().GetUint64("unit-price")
		web3.CreateOrder(buyerName, sellerName, itemId, quantity, unitPrice)
	},
}
```

```
func init() {

  // Add subcommands to the order command
	orderCmd.AddCommand(createOrderCmd)

	// Add flags for the create command
	createOrderCmd.Flags().String("buyer", "", "Address of the buyer (signer)")
	createOrderCmd.Flags().String("seller-name", "", "Address of the seller")
	createOrderCmd.Flags().String("item-id", "", "ID of the item being ordered")
	createOrderCmd.Flags().Uint64("quantity", 0, "Quantity of the item to order")
	createOrderCmd.Flags().Uint64("unit-price", 0, "Price per unit of the item")

	createOrderCmd.MarkFlagRequired("buyer")
	createOrderCmd.MarkFlagRequired("seller-name")
	createOrderCmd.MarkFlagRequired("item-id")
	createOrderCmd.MarkFlagRequired("quantity")
	createOrderCmd.MarkFlagRequired("unit-price")

	// Add the order command to the root command
	rootCmd.AddCommand(orderCmd)
	rootCmd.AddCommand(createAccountCmd)
	rootCmd.AddCommand(faucetAccountCmd)
}

```

* 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](https://scan.endless.link/account/0x4/modules/code/coin?network=testnet)

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

```
func GetContractAddress() *endless.AccountAddress {
	once.Do(func() {
		a := &endless.AccountAddress{}
		addrErr = a.ParseStringRelaxed("FsWq9ZonkCHLZfoRG3Ci8PGr7ps3Mo5mqLGyE1CyRNhb")
		if addrErr == nil {
			addr = a
		} else {
			panic("GetContractAddress Faild.")
		}
	})
	return addr
}

var CONTRACT_MODULE = "orders"
```

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.

```
func CreateOrder(buyerName, sellerName, itemId string, quantity, unitPrice uint64) {
	buyer := LoadAccount(buyerName)
	seller := LoadAccount(sellerName)
	fmt.Printf("Creating order for buyer: %s  seller:%s\n", buyer.Address.String(), seller.Address.String())

	quantity_u128, err := bcs.SerializeU128(*big.NewInt(int64(quantity)))
	if err != nil {
		panic("quantity format error.")
	}
	unitPrice_u128, err := bcs.SerializeU128(*big.NewInt(int64(unitPrice)))
	if err != nil {
		panic("quantity format error.")
	}

	itemId_bytes, err := bcs.SerializeSingle(func(ser *bcs.Serializer) {
		ser.WriteString(itemId)
	})
	if err != nil {
		panic("failed to serialize itemId.")
	}

	entryFunction := endless.EntryFunction{
		Module: endless.ModuleId{
			Address: *GetContractAddress(),
			Name:    CONTRACT_MODULE,
		},
		Function: "create_order",
		ArgTypes: []endless.TypeTag{},
		Args: [][]byte{
			seller.Address[:],
			itemId_bytes,
			quantity_u128,
			unitPrice_u128,
		},
	}

	client, err := endless.NewClient(endless.TestnetConfig)
	if err != nil {
		panic("Failed to create client:" + err.Error())
	}

	rawTxn, err := client.BuildTransaction(
		buyer.AccountAddress(),
		endless.TransactionPayload{
			Payload: &entryFunction,
		},
	)
	if err != nil {
		panic("Failed to build transaction:" + err.Error())
	}

	// 2. Simulate transaction (optional)
	// This is useful for understanding how much the transaction will cost
	// and to ensure that the transaction is valid before sending it to the network
	// This is optional, but recommended
	simulationResult, err := client.SimulateTransaction(rawTxn, buyer)
	if err != nil {
		panic("Failed to simulate transaction:" + err.Error())
	}
	fmt.Printf("\n================ Simulation ================\n")
	fmt.Printf("Gas unit price: %d\n", simulationResult[0].GasUnitPrice)
	fmt.Printf("Gas used: %d\n", simulationResult[0].GasUsed)
	fmt.Printf("Total gas fee: %d\n", simulationResult[0].GasUsed*simulationResult[0].GasUnitPrice)
	fmt.Printf("Status: %s\n", simulationResult[0].VmStatus)
	if !simulationResult[0].Success {
		panic("Simulate transaction error.")
	}

	// 3. Sign transaction
	signedTxn, err := rawTxn.SignedTransaction(buyer)
	if err != nil {
		panic("Failed to sign transaction:" + err.Error())
	}

	// 4. Submit transaction
	submitResult, err := client.SubmitTransaction(signedTxn)
	if err != nil {
		panic("Failed to submit transaction:" + err.Error())
	}
	txnHash := submitResult.Hash

	fmt.Printf("txnHash: %s\n", txnHash)

	// 5. Wait for the transaction to complete
	userTransaction, err := client.WaitForTransaction(txnHash)
	if err != nil {
		panic("Failed to wait for transaction:" + err.Error())
	}
	if !userTransaction.Success {
		panic("Failed to on chain success:" + userTransaction.VmStatus)
	}

}
```

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

* 4 Create an order on chain

```
{path}\endless-orders>go build
{path}\endless-orders>endless-orders.exe order create --buyer alice --seller-name bob --item-id "items-00001" --quantity 100 --unit-price 100000
Creating order for buyer: GVFJPNkqkdH9hx5CwFGnFPUFzbDUaBjdCB3U8WkKrce3  seller:C6nCccsGQ6A6JqoGPS8S7n8xA7YRphsibp2Ba1yZNk2f

================ Simulation ================
Gas unit price: 100
Gas used: 475
Total gas fee: 47500
Status: Executed successfully
txnHash: 0xcc8e12ce5a32ce1d0384254ac7ef44cfae3e241e4b2cf2802fa7cd88060e7962
```

Visit the [Official Endless Scan Website](https://scan.endless.link/txn/0xcc8e12ce5a32ce1d0384254ac7ef44cfae3e241e4b2cf2802fa7cd88060e7962/events?network=testnet),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.

```
// FsWq9ZonkCHLZfoRG3Ci8PGr7ps3Mo5mqLGyE1CyRNhb::orders::OrderCreatedEvent
{
  "buyer": "GVFJPNkqkdH9hx5CwFGnFPUFzbDUaBjdCB3U8WkKrce3",
  "order_id": "1",
  "seller": "C6nCccsGQ6A6JqoGPS8S7n8xA7YRphsibp2Ba1yZNk2f",
  "total_price": "10000000"
}
```

**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.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.endless.link/endless/devbuild/build/show-cases/order-platform.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
