guidewip

A decentralized Bike Sharing project | Part 1

In this article, I'm collecting some ideas about how to create a bike-sharing project using W3bstream.

Post Header Image

Updated:


TIPS COLLECTED

...loading

SHARE

Instructions

Reference links

GitHub Repository of this project: https://github.com/machinefi/Bike-Sharing-DePIN-Webinar
W3bstream javascript client: https://github.com/machinefi/w3bstream-client-js

Create an IoTeX Developer account

Make sure you have a blockchain wallet funded with IOTX Test tokens:
  1. Add the IoTeX Testnet RPC to Metamask
  2. Create a “bike owner” account in Metamask
  3. Login to developers.iotex.io
  4. In your dashboard, connect Metamask and claim some IOTX Test tokens
  5. Copy your account private key (ideally, the deployer account should not be the bike owner, I'm using the same account for brevity).

Create the template project

npx [email protected] bike-sharing

\ \/ \/ / ___/ \__ \ \____ \\____ \
\ /\___ \ / __ \| |_> > |_> >
\/\_//____ > (____ / __/| __/
\/ \/|__| |__|


✔ 💰 include an erc20 token template? (Y/n) · true
✔ 🖼️ include an erc721 token template? (Y/n) · false
✔ 👤 include an onchain device registration and binding template? (Y/n) · false
✔ 🤖 include a device simulator template? (Y/n) · true



Deploy the ERC20 token

cd bike-sharing

optionally open vs code in the folder:
code .

input your developer private key in the .env file
echo IOTEX_PRIVATE_KEY=61f4ef093be2d4e362bec0f65b1be3db6642a749942f330b2a659c71badb982b > .env

Deploy the token contract:
npm run deploy:testnet

Import the token contract in your “bike owner” Metamask wallet.

Create the W3bstream logic

Clean the applet template

  1. Rename erc20.ts to handle_new_ride.ts
  2. Rename handler to handle_new_ride.ts
  3. Delete unused functions
  4. Empty the main handler

Code the applet

Replace the token contract address
import { GetDataByRID, JSON, Log, SendTx } from "@w3bstream/wasm-sdk";

import { buildTxData } from "../utils/build-tx";


const MINT_FUNCTION_ADDR = "40c10f19";
const CHAIN_ID = 4690;
const TOKEN_CONTRACT_ADDRESS = "0xF50018BdeD7cb3DaC940A34ebb8DDA87134FAf01";

// This handler is called when a ride is completed.
// In this case the Bike will send a message like this
// {
// bike_owner: "0x1234567890123456789012345678901234567890",
// ride_duration: 123,
// ride_distance: 123,
// }
export function handle_ride_completed(rid: i32): i32 {
Log("--- New ride completed message received ---");
const message = GetDataByRID(rid);
Log("Device message: " + message);

const message_json = JSON.parse(message) as JSON.Obj;

let bike_owner = message_json.getString("bike_owner");
if (bike_owner == null) { assert(false, "bike_owner field not found"); return 1;}

let ride_duration = message_json.getInteger("ride_duration");
if (ride_duration == null) { assert(false, "ride_duration field not found"); return 1;}

let ride_distance = message_json.getInteger("ride_distance");
if (ride_distance == null) { assert(false, "ride_distance field not found"); return 1;}

// Let's now calculat the value of this ride
// We want to give a cost per km of 0.1 tokens
// and a cost per minute of 0.01 tokens
const cost_per_km: number = 1 / 1000;
const cost_per_minute: number = 0.1 / 60;
const ride_cost: number =
(cost_per_km * f64(ride_distance.valueOf())) +
(cost_per_minute * f64(ride_duration.valueOf()));

Log("Ride cost: " + ride_cost.toString());

// As the project owners we want to keep a fee of 10% of the ride cost
const fee: number = ride_cost * 0.1;

// So let's calculate the amount of tokens to send to the bike owner
const TOKEN_AMOUNT = ride_cost - fee;

Log("Token amount: " + TOKEN_AMOUNT.toString());

// and finally send the payment to the bike owner
mintRewards<number>(bike_owner.valueOf(), TOKEN_AMOUNT);

return 0;
}

function mintRewards<T>(ownerAddress: string, amount: T): void {
const txData = buildTxData(MINT_FUNCTION_ADDR, ownerAddress, amount);
const res = SendTx(CHAIN_ID, TOKEN_CONTRACT_ADDRESS, "0", txData);
Log("Send tx result:" + res);
}



Build the applet

npm run asbuild


Deploy the applet as a WS Project

Create a new device

Wire the event handler

handle_ride_completed

Send a test message

{
"bike_owner": "0x2C37a2cBcFacCdD0625b4E3151d6260149eE866B",
"ride_duration": 3600,
"ride_distance": 15000
}


Introduce Env Variables

const TOKEN_CONTRACT = GetEnv("TOKEN_CONTRACT")


Code the simulator

Empty index.ts
Install the w3bstream client
cd simulator
npm install --save w3bstream-client-js
npm install axios

import { W3bstreamClient } from "w3bstream-client-js";

const URL = "http_route";
const API_KEY = "api_key";

const client = new W3bstreamClient(URL, API_KEY);

const header = {
deviceId: "device_id",
eventType: "event_type",
};

// const payload = Buffer.from("test data", "utf8"); or
const payload = {
data: "data",
};

main();

async function main() {
try {
const res = await client.publish(header, payload);

console.log(JSON.stringify(res.data, null, 2));
} catch (error) {
console.error(error);
}
}


Get the route Get the Device token and use as API Key Set the Event name: RIDE_COMPLETED set the device id: bike_001
Set the payload

bike_owner: "0x2C37a2cBcFacCdD0625b4E3151d6260149eE866B",
ride_duration: 3600,
ride_distance: 15000



Build

tsc
node dist/index.js


Docs

IoTeX Docs


IoTeX Developerslogo

[email protected]