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.
Instructions
Reference links
Create an IoTeX Developer account
Make sure you have a blockchain wallet funded with IOTX Test tokens:
- Add the IoTeX Testnet RPC to Metamask
- Create a “bike owner” account in Metamask
- Login to developers.iotex.io
- In your dashboard, connect Metamask and claim some IOTX Test tokens
- 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
- Rename
erc20.ts
tohandle_new_ride.ts
- Rename handler to
handle_new_ride.ts
- Delete unused functions
- 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 simulatornpm install --save w3bstream-client-jsnpm 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"); orconst 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
tscnode dist/index.js