diff --git a/client/README.md b/client/README.md new file mode 100644 index 0000000..97198ba --- /dev/null +++ b/client/README.md @@ -0,0 +1,18 @@ +# Share ride client + +## Design considerations +- Support for phantom wallet. +- Arweave for storing the ride details. +- Escrow for secure token exchange b/w the riders. + +## Mint +For the ease of testing mint authority is hardcoded in the client source code. + +### Creating a mint for development + +To create a mint public key with our mint authority use the npm script +```sh +npm run create-mint +``` + +Copy and paste the mint public key to [mint.ts](https://github.com/shamin/share-ride/blob/main/client/src/app/web3/provider/account/mint.ts) file. \ No newline at end of file diff --git a/client/index.html b/client/index.html index 01d9287..765b778 100644 --- a/client/index.html +++ b/client/index.html @@ -2,7 +2,7 @@ - + Share Ride App diff --git a/client/package.json b/client/package.json index 8391903..332ccd7 100644 --- a/client/package.json +++ b/client/package.json @@ -5,7 +5,8 @@ "start": "npm run dev", "build": "tsc && vite build", "serve": "vite preview", - "create-mint": "node scripts/createMint.js" + "create-mint": "node scripts/createMint.js", + "deploy": "npx surge dist share-ride.surge.sh" }, "dependencies": { "@project-serum/anchor": "^0.13.2", diff --git a/client/src/app/pages/auth/login.tsx b/client/src/app/pages/auth/login.tsx index 042486b..f69aa4e 100644 --- a/client/src/app/pages/auth/login.tsx +++ b/client/src/app/pages/auth/login.tsx @@ -20,7 +20,7 @@ export const Login = () => {
share ride logo -

Welcome back to share ride

+

Welcome back to Share Ride

Ready to go somewhere? Connect your wallet to get started.

diff --git a/client/src/app/pages/dashboard/loadingModal.tsx b/client/src/app/pages/dashboard/loadingModal.tsx index ab95b10..ebca4fa 100644 --- a/client/src/app/pages/dashboard/loadingModal.tsx +++ b/client/src/app/pages/dashboard/loadingModal.tsx @@ -18,6 +18,8 @@ const LoadingModal: React.FC = ({ confirmLabel="Custom Label" hasClose={false} hasFooter={false} + shouldCloseOnOverlayClick={false} + shouldCloseOnEscapePress={false} >
diff --git a/client/src/app/pages/home/home.tsx b/client/src/app/pages/home/home.tsx index 05c8105..7d16eed 100644 --- a/client/src/app/pages/home/home.tsx +++ b/client/src/app/pages/home/home.tsx @@ -3,14 +3,7 @@ import { Table, Button } from "evergreen-ui"; import { useHistory } from "react-router-dom"; import "./home.scss"; import { useShareRide } from "../../web3/provider"; - -type Ride = { - id: string, - from: string, - to: string, - date: string, - driver: string, -} +import { Ride } from "../../web3/provider/state"; const formatDate = (d: Date) => { let dd: string | number = d.getDate(); @@ -26,6 +19,10 @@ const formatDate = (d: Date) => { return dd + "/" + mm + "/" + yyyy; }; +const ridersAccepted = (rides: Ride[]) => { + return rides.map((r)=>r.selectedSeats).reduce((a, b) => a + b, 0) +} + export const Home = () => { const { wallet, shareRideState, completeRide } = useShareRide(); const walletKey = wallet?.publicKey?.toBase58(); @@ -146,7 +143,7 @@ export const Home = () => { {ride.seatsOffered} - {ride.riders.length} + {ridersAccepted(ride.riders)} diff --git a/client/src/app/pages/offer/offer.tsx b/client/src/app/pages/offer/offer.tsx index f3ee31f..2d1e762 100644 --- a/client/src/app/pages/offer/offer.tsx +++ b/client/src/app/pages/offer/offer.tsx @@ -37,7 +37,6 @@ export const Offer = () => { const { addDriver, loadDrivers, - loading, showCompleteModal, setShowCompleteModal, } = shareRideState; @@ -176,7 +175,6 @@ export const Offer = () => {
{ + {(tokenAccount?.amount || 0) < + Math.ceil(d.costPerKm * distance * seatsRequired) && ( +
+ + + +
+ )} +
- {d.selectedSeats} - {d.costPerKm} - {Math.ceil(d.costPerKm * distance * seatsRequired)} - ))} diff --git a/client/src/app/web3/idls/share_ride.json b/client/src/app/web3/idls/share_ride.json index f39cc20..097945b 100644 --- a/client/src/app/web3/idls/share_ride.json +++ b/client/src/app/web3/idls/share_ride.json @@ -104,6 +104,24 @@ } } ] + }, + { + "name": "removeDriver", + "accounts": [ + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "archive", + "type": { + "defined": "Archive" + } + } + ] } ] }, @@ -129,6 +147,6 @@ } ], "metadata": { - "address": "HtdnYeMXt5yCQi8KsKQnjH5ZyqYN9ePiGZCxvWyMwpNZ" + "address": "3LL5Wa7JN4cNyPoXdCnxUnJUoLLFWANaRRjirRTtARtS" } } \ No newline at end of file diff --git a/client/src/app/web3/idls/share_ride_escrow.json b/client/src/app/web3/idls/share_ride_escrow.json index 719efa6..c2280d3 100644 --- a/client/src/app/web3/idls/share_ride_escrow.json +++ b/client/src/app/web3/idls/share_ride_escrow.json @@ -107,6 +107,6 @@ } ], "metadata": { - "address": "5THBvQbhwDsAoaULFvJkwinvYsyLjPqvmWwWpcS8kjbu" + "address": "LRo4uMZpDDXpHiWgspg8yMgvHqjSRGBZkJpdawfhonL" } } \ No newline at end of file diff --git a/client/src/app/web3/provider/account/index.ts b/client/src/app/web3/provider/account/index.ts index a8dede9..51f4e36 100644 --- a/client/src/app/web3/provider/account/index.ts +++ b/client/src/app/web3/provider/account/index.ts @@ -21,9 +21,10 @@ const getToken = () => { export const useTokenAccount = ( provider: Provider, - setLoadingText: React.Dispatch> + setLoadingText: (loadingText: string) => void ) => { const [tokenAccount, setTokenAccount] = useState(); + const [tokenAccountCreateLoading, setTokenAccountCreateLoading] = useState(false); const loadTokenAccount = async () => { console.log("Loading token account"); @@ -33,7 +34,9 @@ export const useTokenAccount = ( setLoadingText( "Token account does not exist. Creating a new token account." ); + setTokenAccountCreateLoading(true) token = (await createTokenAccount(provider, mintPublicKey)).toString(); + setTokenAccountCreateLoading(false) saveToken(token); } @@ -68,5 +71,6 @@ export const useTokenAccount = ( tokenAccount, loadTokenAccount, mintAmountToTokenAccount, + tokenAccountCreateLoading, }; }; diff --git a/client/src/app/web3/provider/account/mint.ts b/client/src/app/web3/provider/account/mint.ts index 80c3d3b..b81c461 100644 --- a/client/src/app/web3/provider/account/mint.ts +++ b/client/src/app/web3/provider/account/mint.ts @@ -3,7 +3,7 @@ import { PublicKey } from "@solana/web3.js"; import mintAccountJson from "./mint-account.json"; export const mintPublicKey = new PublicKey( - "G8i3di2WFBtYYgfksynQ2gL7pEqc68bYMSWcqAEuEjxF" + "CjhAyWDmUXxKTfUefqGVsnd1uXk82sAT4q8R5usbxYtz" ); export const getMintAuthority = () => { diff --git a/client/src/app/web3/provider/account/tokenAccount.ts b/client/src/app/web3/provider/account/tokenAccount.ts index 8c082b6..cfc8ed6 100644 --- a/client/src/app/web3/provider/account/tokenAccount.ts +++ b/client/src/app/web3/provider/account/tokenAccount.ts @@ -53,7 +53,9 @@ export async function createTokenAccount( provider.wallet.publicKey )) ); + console.log("Creating token account") await provider.send(transaction, [newAccountPubkey]); + console.log("Token account complete") return newAccountPubkey.publicKey; } diff --git a/client/src/app/web3/provider/index.tsx b/client/src/app/web3/provider/index.tsx index 8a95992..c260ef8 100644 --- a/client/src/app/web3/provider/index.tsx +++ b/client/src/app/web3/provider/index.tsx @@ -48,17 +48,22 @@ const ShareRideProviderProvider: React.FC = ({ children, }: ShareRideProviderProviderProps) => { const [wallet, setWallet] = useState(); - const [loadingText, setLoadingText] = useState(""); + const [loadingText, _setLoadingText] = useState(""); const [provider, setProvider] = useState(); // const [tokenAccount, setTokenAccount] = useState(); - const { tokenAccount, loadTokenAccount, mintAmountToTokenAccount } = + + const setLoadingText = (loading: string) => { + _setLoadingText(loading); + }; + + const { tokenAccount, loadTokenAccount, mintAmountToTokenAccount, tokenAccountCreateLoading } = useTokenAccount(provider as Provider, setLoadingText); const loadWallet = useCallback(async () => { const _wallet = await connectWallet(); setWallet(_wallet); const provider = new SolanaProvider( - new Connection(SolanaNetworks.LOCAL), + new Connection(SolanaNetworks.DEV), _wallet, {} ); @@ -91,23 +96,31 @@ const ShareRideProviderProvider: React.FC = ({ }; const completeRide = async (driverId: string) => { - const rides = shareRideState.rides.filter(({ driveId }) => driveId === driverId) + const rides = shareRideState.rides.filter( + ({ driveId }) => driveId === driverId + ); console.log("Complete ride", rides); - console.log("Remove driver", driverId) - console.log("Remove rides", rides.map((r)=>r.archiveId)) -  setLoadingText("Transfering sherekhans to your account") + console.log("Remove driver", driverId); + console.log( + "Remove rides", + rides.map((r) => r.archiveId) + ); + setLoadingText("Transfering sherekhans to your account"); if (provider && tokenAccount) { - await Promise.all(rides.map(async (r)=>{ - await exchangeEscrow(provider, tokenAccount, r.escrow) - })) + await Promise.all( + rides.map(async (r) => { + await exchangeEscrow(provider, tokenAccount, r.escrow); + }) + ); } - setLoadingText("Reloading token account") + setLoadingText("Reloading token account"); await loadTokenAccount(); await shareRideState.removeDriver(driverId); - setLoadingText("") + setLoadingText("Reloading rides"); + await shareRideState.loadDrivers(); //TODO: Fix this hardcoded ride // console.log(shareRideState.rides); @@ -131,7 +144,7 @@ const ShareRideProviderProvider: React.FC = ({ intializeEscrow: _intializeEscrow, exchangeEscrow: _exchangeEscrow, mintAmountToTokenAccount, - loadingText, + loadingText: tokenAccountCreateLoading ? "Creating token account" : loadingText, completeRide, }), [wallet, shareRideState, tokenAccount, provider] diff --git a/client/src/app/web3/provider/state/arweave.ts b/client/src/app/web3/provider/state/arweave.ts index a046e80..0dee3ed 100644 --- a/client/src/app/web3/provider/state/arweave.ts +++ b/client/src/app/web3/provider/state/arweave.ts @@ -1,6 +1,7 @@ import Arweave from "arweave"; import { JWKInterface } from "arweave/node/lib/wallet"; import TestWeave from "testweave-sdk"; +import WalletJson from "./wallet.json"; export type ArweaveDriver = { archive: string; @@ -10,18 +11,27 @@ class ArweaveService { arweave: Arweave; testWeave?: TestWeave; walletKey?: JWKInterface; + isLocal = false; - constructor() { - this.arweave = Arweave.init({ - host: "localhost", - port: 1984, - protocol: "http", - }); + constructor({ localhost = false }: { localhost?: boolean }) { + this.isLocal = localhost; + if (localhost) { + this.arweave = Arweave.init({ + host: "localhost", + port: 1984, + protocol: "http", + }); - TestWeave.init(this.arweave).then((testWeave: any) => { - this.testWeave = testWeave; - this.walletKey = this.testWeave?.rootJWK; - }); + TestWeave.init(this.arweave).then((testWeave: any) => { + this.testWeave = testWeave; + this.walletKey = this.testWeave?.rootJWK; + }); + } else { + this.arweave = Arweave.init({ + host: 'arweave.net' + }); + this.walletKey = WalletJson; + } } async saveData(message: unknown): Promise { @@ -34,8 +44,10 @@ class ArweaveService { await this.arweave.transactions.sign(transaction, this.walletKey!); await this.arweave.transactions.post(transaction); console.log("posted transaction", transaction); - await this.testWeave!.mine(); // need this to force immediate mine of related block - console.log("forced mine"); + if (this.isLocal) { + console.log("forced mine"); + await this.testWeave!.mine(); // need this to force immediate mine of related block + } const status = await this.arweave.transactions.getStatus(transaction.id); console.log("saveData status", status); return transaction.id; @@ -43,13 +55,18 @@ class ArweaveService { async getData(drivers: Array): Promise> { const arweaveData = drivers.map(async ({ archive }) => { - const data = await this.arweave.transactions.getData(archive, { - decode: true, - string: true, - }); - return {...JSON.parse(data?.toString()), archiveId: archive}; + try { + const data = await this.arweave.transactions.getData(archive, { + decode: true, + string: true, + }); + return { ...JSON.parse(data?.toString()), archiveId: archive }; + } catch(err) { + return null + } }); - return Promise.all(arweaveData); + const data = await Promise.all(arweaveData); + return data.filter((d)=>d!==null) } } diff --git a/client/src/app/web3/provider/state/index.ts b/client/src/app/web3/provider/state/index.ts index b937845..14f96ca 100644 --- a/client/src/app/web3/provider/state/index.ts +++ b/client/src/app/web3/provider/state/index.ts @@ -31,6 +31,7 @@ export interface Ride { riderKey: string; driveId: string; escrow: string; + selectedSeats: number; } export interface ShareRideState { @@ -48,7 +49,7 @@ export interface ShareRideState { export const useShareRideState = ( provider: Provider | undefined, tokenAccount: AccountInfo | undefined, - setLoadingText: React.Dispatch> + setLoadingText: (loadingText: string) => void ): ShareRideState => { const [drivers, setDrivers] = useState([]); const [rides, setRides] = useState([]); diff --git a/client/src/app/web3/provider/state/model.ts b/client/src/app/web3/provider/state/model.ts index 25d8675..9f1698d 100644 --- a/client/src/app/web3/provider/state/model.ts +++ b/client/src/app/web3/provider/state/model.ts @@ -26,7 +26,7 @@ export class ShareRideModel { constructor(provider: Provider) { this.provider = provider; this.program = loadShareRideProgram(provider); - this.arweaveService = new ArweaveService(); + this.arweaveService = new ArweaveService({ localhost: false }); } async initialize() { diff --git a/client/src/app/web3/provider/state/types.ts b/client/src/app/web3/provider/state/types.ts deleted file mode 100644 index e69de29..0000000 diff --git a/client/src/app/web3/provider/state/wallet.json b/client/src/app/web3/provider/state/wallet.json new file mode 100644 index 0000000..07874c7 --- /dev/null +++ b/client/src/app/web3/provider/state/wallet.json @@ -0,0 +1 @@ +{"kty":"RSA","n":"wdse-vltArVirJTervumwFm38CQ62a_-UoOecREngo7TPZW6EBgvuT-14zjl91Rk6qvoX7_CB5GdBOzP5Zid8TpPFD4CGphhARQzF0H0mwWSoS0EKFcuJytVU-PB5kCub-QwyyvUwCBvhCjSGCMp6UQf6kzGp_wrESoMP1e4TEmpnO_56xQhj5ebHc2J-bgJI1nVCVkAEMq9c6Emc7tktDN3rSTtLv23b6U2uKOoW_0AlP-8ENlT7-wdsz3-fxQrurlwvwJpWwE4Smbu8IvDsh1RQekBzt9fGInTPIjEBFKRGPKXpmZJNUILejy3nFoKwvXZc2CXoVrMIR7ax2LETiOasiZzz3YRrMa4-GYeTJ4DV4upkG-mElobj1w5XKrUKkOtiPdE6lzISu5cFVzbQfD4ZZWqsopITZ8wv4oUyuMDez0d-qLjTJEd6MvKiqbVVg00bLZXVNbsGzfsr8EPdbFc1fDdx06GtEVhtg3NR9UrK2kJHTOOJXToWKOX67gwYBKLKSUSeSs9sZQOS7ouEPoqkjOurg4BAfnr4RnuBHIkg-mQGYZH3DeExeXVxBj_TwSb1fTD6BYpVJtjqcmW1bwDkSTB-nJ2CNPv_D4aEUWqADUjAkMuL2I30utyvcUcmS-mtc12Ab4eUaR1pDozBUZhox3oBwzHCdCHJmtZmNM","e":"AQAB","d":"ZFJ9yexjGc-87Qtt4qihN1I2-rQFMLr_prwuttzl0Y8QiwJ9c-7QY9Iw0xKTEFhAkaG9dC_MvhYBaJcVUACXXEuMuTEN7a2GJgTKG_MqHz_XDko5qJbVb7fhRLTNl9dJbuZsyfg49eTTUVW-xHcOLYXv7lUlSbIap5tXE0DWQ8SrXmhiseGNLL6Mq_O-v9kaAY1vzpKckhQZz0lKmQIVr5wjBxvhEzyCPekGVK99ZX2dW36tWRrfcX6EMEqY9jL-HnfxfShGVa5f70EtzpbGA9tgPffT07eNgylwhBdTOdlw9bQ1_wtYP5OaVPwvGV8Pyq1oh2kpj3tpwIozNpRKei3RwOrsaRwVWlSwakhe9cG1mEunH0-5HBlvPMIUhCK4Ogp2XeVY8lwlJcjPaYm3pZ4OYdHr2ve4bwQEgtIBXtx6N3ksHZK1dVPZ91pKtpsFKIuoHshlcZEnWdEHnq8sSL1Qu7jypqgsLBLBMEU4eUdZgP5yweLXFjSTuwnDAX2y3f6WCf773l4SGwsErbnTI6gXzxNcWXPSJ91c9YKWCjpgItJE2UwTOg_FKKfPwU8liqWdAs8CeBMv2p3-4yHaA0TUXnatcnvPjx_SIHTtkQG6B5Cc-ub7CV1fsgSR-InXSYpF8b-WT1VYls3vhkXuQGSGNmxwgpm_ll2HNwJUQeE","p":"-A_krtNTkDbWLDibUjt9MO3lmNSOR2sS46LOENEtqklsvjqyHlawsbkqg1832k3fqMW_D-kRS_wfLeAhuJbNnPEfZnCBAXUh__fMu0AxKYgjH0GRyb4FrGz6vWtB4UBzWQvbR9AghiPxsSI2-ROKItvOORIrAag3BFk1H8AryIRkaQEHYPpoQN2hVBzinyiJ9AKOUoWLygvjLQLIqHVpOaW47dwWObp0NdH1f4iUoVDs3X9XB-nmFjRcW_LqCTIgHxXzbBbv0wxwvikQgwla-btnoqFnBkDk4fdINTXYjyxbtUA6cd87ZtPkHozmgnHxEGXNN8pXDf0cJ8LRLB5kbw","q":"yA8sx3H1HbEf5RXxll4RsWnoadqxQCtzQtFaTIOzw16nZnfg7wo-8Y_KmMfFA_o7Ya4bg98ubOs-YXexqnO_ZVe9qoJuMlSIZQNdRySBHmi8z7Dlm74J0zQyj5GlA69O1w1e8kBoWqVVBQGriTObs46dObf2aOatplEgdE78CyyatDo1adXYI7Ts6pd2V08YQSfuTGCucl2trHpUIwFAETKErXKHeUNb2MOB1QNq1W_Pwcnqthp5o6EsMdeyMIyGR8I0enkIzTqXwfQ1A7FKPnF_8hc-J9aNvGrQyTqXpfP1XgYEerd7Kjbcs7kvzaO-p8I03Ri2h6n0M9nD80Xr3Q","dp":"E7ZvndT9VwCElI8LCMXhdPnyvOpnRBWmMqDFb2CwGFAtbBCOBwssj3L_heETNy3pEChmvoTu8vLeJ28gPuL9A_PFYwadudftE8JFarv3LC29XMaBJ18KZGFkq5jSa2wLvo_KpTJM41wH4OOvKqv61jpRcQeYk1Eizh2osxU6ZXzf3dhPFc3QaxcxstV4zN0T2Wg6lyQ1r6CyNOl7uKdb7VDWGVDcE0pV4dEFiVT5OriLmi58ZAyaVDlk_YmYP5LUKqQ76-MGu-bJLtNklIUxzZau7aWV4lFV3v8fpdrZkscbopOwEUyEE-_SuPrJdqRHW947KKvTrzDmA-LfbHod0Q","dq":"vb6Wy_trbePmylJLtkA2K7y1MGC5KJGNWlxRdqybPLtzrh4Y-t8O3_FvSASA-crFs1l8w1BUKf3cRnlNysrJRwc23peiiJ3gV14fhDA9Pmg8XAf9Xf-aNfUV11Fd3ubQser-mGk6EG8q-fqhhRmrnVuwB2RRkyDmpg3f6DBZoQeHG1TyABVQUF1zLvTEyv47lOCYhVxVWCc9Z48GacTvzN_LMu6jSwH2BNs5Mp1xIEpSFAy8TkdCA04EKqnXWXCOk1TAjUBqdqwR72T9OylVr2_a1_Pvgb1e5MuyhojJ-B4wJCM08GdBq8IpBVSo4DNjypzJosGjrXwmH191GDDDCQ","qi":"QV8I_FJkVGiLY1uxVKCXrOd9Q5cS508iwZOhHUZEAikv9ouXfYqiEN9vmH9nz3PvPIetadBoRqQiN_qM_qTdkwWSDPVFLTtJl4skkIsAda_v2w8-N8fzAekgbiEbBj8hgGSxbk3qdtNHCQzQFsTYi8l7xZPVi2qtxDplMjdClAKqM7GYec1Q2_NWfiIiPEQF2lYK2xm3BaKkoxCoIOvupJErHc-0sFOclikn0LFY8NWwU0r90JY18wISdXPyKftHiE2C2m6RkWSAnQ-igSwryV5gpd0sDDclH1erkX1TtNmjBZeUvnkMmDtt8PoXYFBoSS2KKMkWhLHrxhnkiwJwgA"} \ No newline at end of file diff --git a/client/src/assets/images/logo-white.png b/client/src/assets/images/logo-white.png index 4fe5d47..5d4741b 100644 Binary files a/client/src/assets/images/logo-white.png and b/client/src/assets/images/logo-white.png differ diff --git a/client/src/assets/images/logo.png b/client/src/assets/images/logo.png index 52c322e..5d4741b 100644 Binary files a/client/src/assets/images/logo.png and b/client/src/assets/images/logo.png differ diff --git a/client/src/favicon.png b/client/src/favicon.png new file mode 100644 index 0000000..5d4741b Binary files /dev/null and b/client/src/favicon.png differ diff --git a/client/src/logo.png b/client/src/logo.png new file mode 100644 index 0000000..5d4741b Binary files /dev/null and b/client/src/logo.png differ diff --git a/client/tsconfig.json b/client/tsconfig.json index 013e6c5..24d7a74 100644 --- a/client/tsconfig.json +++ b/client/tsconfig.json @@ -3,7 +3,7 @@ "target": "ESNext", "lib": ["DOM", "DOM.Iterable", "ESNext"], "allowJs": false, - "skipLibCheck": false, + "skipLibCheck": true, "esModuleInterop": false, "allowSyntheticDefaultImports": true, "strict": true, @@ -13,7 +13,7 @@ "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, - "jsx": "react" + "jsx": "react", }, "include": ["./src"] } diff --git a/client/vite.config.ts b/client/vite.config.ts index e1056f8..4b8c4b1 100644 --- a/client/vite.config.ts +++ b/client/vite.config.ts @@ -7,7 +7,9 @@ export default defineConfig({ server: { port: 5000 }, - plugins: [reactRefresh(), polyfillNode()], + plugins: [reactRefresh(), + // polyfillNode() + ], optimizeDeps: { exclude: ["web3"], // <= The libraries that need shimming should be excluded from dependency optimization. }, diff --git a/program/Anchor.toml b/program/Anchor.toml index 9406c8f..6992691 100644 --- a/program/Anchor.toml +++ b/program/Anchor.toml @@ -1,5 +1,5 @@ [provider] -cluster = "localnet" +cluster = "devnet" wallet = "~/.config/solana/id.json" [scripts] diff --git a/program/README.md b/program/README.md index 2228a30..dc3dc00 100644 --- a/program/README.md +++ b/program/README.md @@ -2,11 +2,20 @@ We use anchor to manage the share ride programs -## Deploy programs -```sh -# Deploy the programs and build the idls -anchor deploy +## Development +### Build the programs +``` +anchor build +``` + +### Test the programs +``` +anchor test +``` -# Copy the idls to the client -./copy-idls.sh -``` \ No newline at end of file +### Deploy programs +Deploy the programs, build the idls and copy the generated idls to client + +```sh +npm run deploy +``` diff --git a/program/package.json b/program/package.json index 6072bd6..020edc3 100644 --- a/program/package.json +++ b/program/package.json @@ -7,6 +7,7 @@ "test": "tests" }, "scripts": { + "build": "anchor build", "deploy": "anchor deploy && ./copy-idls.sh", "test": "mocha -t 1000000 --require @babel/register tests/" },