diff --git a/package.json b/package.json index 2191490..2b0979e 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,11 @@ "format": "prettier --write README.md \"src/**/*.{js,jsx,ts,tsx,json,md}\"", "preview": "vite preview" }, + "pnpm": { + "overrides": { + "smoldot": "2.0.23" + } + }, "dependencies": { "@polkadot-api/descriptors": "^0.0.1", "@radix-ui/react-dialog": "^1.0.5", @@ -25,6 +30,7 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "rxjs": "^7.8.1", + "smoldot": "2.0.23", "tailwind-merge": "^2.2.2", "tailwindcss-animate": "^1.0.7" }, @@ -69,6 +75,14 @@ "ksmAh": { "wsUrl": "wss://kusama-asset-hub-rpc.polkadot.io", "metadata": "ksmAh.scale" + }, + "roc": { + "chain": "rococo_v2_2", + "metadata": "roc.scale" + }, + "rocAh": { + "wsUrl": "wss://rococo-asset-hub-rpc.dwellir.com", + "metadata": "rocAh.scale" } } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a91cb46..4b6f7bb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4,6 +4,9 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false +overrides: + smoldot: 2.0.23 + dependencies: '@polkadot-api/descriptors': specifier: ^0.0.1 @@ -44,6 +47,9 @@ dependencies: rxjs: specifier: ^7.8.1 version: 7.8.1 + smoldot: + specifier: 2.0.23 + version: 2.0.23 tailwind-merge: specifier: ^2.2.2 version: 2.2.2 @@ -966,7 +972,7 @@ packages: /@polkadot-api/sm-provider@0.0.1(smoldot@2.0.23): resolution: {integrity: sha512-ujT8YbFAbskoKtCfn5uBRIVG020BD+mCvyW/EwN5FhFm0U2KMIyglsuZkEEanZjC1u/JCt1Ido0py1ze2Yzkww==} peerDependencies: - smoldot: '>=2' + smoldot: 2.0.23 dependencies: '@polkadot-api/json-rpc-provider': 0.0.1 '@polkadot-api/json-rpc-provider-proxy': 0.0.1 @@ -976,7 +982,7 @@ packages: /@polkadot-api/smoldot@0.2.0: resolution: {integrity: sha512-3zmg9wv9a6479LrymKE7dHjl/oTBDjXLEfuToqoxxfFcn3tlMsOCNE2BdxIxWqIeGilhW63qhNXadHv+vb+Upw==} dependencies: - smoldot: 2.0.22 + smoldot: 2.0.23 transitivePeerDependencies: - bufferutil - utf-8-validate @@ -2928,15 +2934,6 @@ packages: engines: {node: '>=8'} dev: false - /smoldot@2.0.22: - resolution: {integrity: sha512-B50vRgTY6v3baYH6uCgL15tfaag5tcS2o/P5q1OiXcKGv1axZDfz2dzzMuIkVpyMR2ug11F6EAtQlmYBQd292g==} - dependencies: - ws: 8.15.0 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - dev: false - /smoldot@2.0.23: resolution: {integrity: sha512-rZOHZoL6iSdjl3nEHaZmIAvFjaSsK/pkI2G6m46Ua1xNurcIZByyjLnMrlY5jm1rasdJDHFnNmasGBgeQFyLcQ==} dependencies: diff --git a/roc.scale b/roc.scale new file mode 100644 index 0000000..6669716 Binary files /dev/null and b/roc.scale differ diff --git a/rocAh.scale b/rocAh.scale new file mode 100644 index 0000000..e8ccb95 Binary files /dev/null and b/rocAh.scale differ diff --git a/src/api/chains.ts b/src/api/chains.ts index 4d5a5d8..4ef48f6 100644 --- a/src/api/chains.ts +++ b/src/api/chains.ts @@ -1,9 +1,10 @@ import dot from "./dot" import ksm from "./ksm" import wnd from "./wnd" +import roc from "./roc" import { AssetId, AssetInChain, ChainId } from "./types" -const assetsInChains = [...dot, ...ksm, ...wnd] +const assetsInChains = [...dot, ...ksm, ...wnd, ...roc] export const chains = new Map>() assetsInChains.forEach((assetinChain) => { @@ -17,6 +18,7 @@ export const ASSET_DECIMALS: Record = { DOT: 10, KSM: 12, WND: 12, + ROC: 12, } export const CHAIN_NAMES: Record = { @@ -26,4 +28,6 @@ export const CHAIN_NAMES: Record = { ksmAh: "Kusama AssetHub", wnd: "Westend RelayChain", wndAh: "Westend AssetHub", + roc: "Rococo RelayChain", + rocAh: "Rococo AssetHub", } diff --git a/src/api/clients/index.ts b/src/api/clients/index.ts index e727c0d..3144f19 100644 --- a/src/api/clients/index.ts +++ b/src/api/clients/index.ts @@ -6,3 +6,6 @@ export { ksmAhClient } from "./ksmAh" export { wndClient } from "./wnd" export { wndAhClient } from "./wndAh" + +export { rocClient } from "./roc" +export { rocAhClient } from "./rocAh" diff --git a/src/api/clients/roc.ts b/src/api/clients/roc.ts new file mode 100644 index 0000000..ac8d947 --- /dev/null +++ b/src/api/clients/roc.ts @@ -0,0 +1,9 @@ +import { createClient } from "polkadot-api" +import { getSmProvider } from "polkadot-api/sm-provider" +import { smoldot } from "./smoldot" + +export const rocRelayChain = import("polkadot-api/chains/rococo_v2_2").then( + ({ chainSpec }) => smoldot.addChain({ chainSpec }), +) + +export const rocClient = createClient(getSmProvider(rocRelayChain)) diff --git a/src/api/clients/rocAh.ts b/src/api/clients/rocAh.ts new file mode 100644 index 0000000..f8c6185 --- /dev/null +++ b/src/api/clients/rocAh.ts @@ -0,0 +1,32 @@ +import { createClient } from "polkadot-api" +import { getSmProvider } from "polkadot-api/sm-provider" +import { smoldot } from "./smoldot" +import { rocRelayChain } from "./roc" + +const chainSpec = `{ + "name": "Rococo Asset Hub", + "id": "asset-hub-rococo", + "chainType": "Live", + "bootNodes": [ + "/dns/rococo-asset-hub-bootnode-0.polkadot.io/tcp/30333/p2p/12D3KooWRrZMndHAopzao34uGsN7srjS3gh9nAjTGKLSyJeU31Lg", + "/dns/rococo-asset-hub-bootnode-1.polkadot.io/tcp/30333/p2p/12D3KooWAewimoNJqMaiiV5pYiowA5hLuh5JS5QiRJCCyWVrrSTS" + ], + "telemetryEndpoints": null, + "protocolId": null, + "properties": { + "tokenDecimals": 12, + "tokenSymbol": "ROC" + }, + "relay_chain": "rococo_v2_2", + "para_id": 1000, + "codeSubstitutes": {}, + "genesis": { + "stateRootHash": "0xad0224198565f04f9f7a6120231d310f9280669ec3395b898dd2bb69e1deb87d" + } +}` + +const smoldotParaChain = rocRelayChain.then((relayChain) => + smoldot.addChain({ chainSpec, potentialRelayChains: [relayChain] }), +) + +export const rocAhClient = createClient(getSmProvider(smoldotParaChain)) diff --git a/src/api/clients/smoldot.ts b/src/api/clients/smoldot.ts index 713a339..250e079 100644 --- a/src/api/clients/smoldot.ts +++ b/src/api/clients/smoldot.ts @@ -1,4 +1,78 @@ import SmWorker from "polkadot-api/smoldot/worker?worker" import { startFromWorker } from "polkadot-api/smoldot/from-worker" -export const smoldot = startFromWorker(new SmWorker()) +/* +interface QueueNode { + value: T + next?: QueueNode +} + +export default class Queue { + private first?: QueueNode + private last?: QueueNode + + constructor(...vals: T[]) { + if (vals.length === 0) return + vals.forEach((val) => this.push(val)) + } + + push(value: T) { + const nextLast: QueueNode = { value } + if (this.last === undefined) { + this.last = nextLast + this.first = this.last + } else { + this.last.next = nextLast + this.last = nextLast + } + } + + pop() { + const result = this.first?.value + if (this.first) { + this.first = this.first.next + if (!this.first) { + this.last = undefined + } + } + return result + } + + peek() { + return this.first?.value + } +} + +const messages = new Queue() + +let tickDate = "" + +const setTickDate = () => { + tickDate = new Date().toISOString() + setTimeout(setTickDate, 0) +} +setTickDate() + +const getTickDate = () => tickDate +*/ + +export const smoldot = startFromWorker( + new SmWorker() /*, { + maxLogLevel: 9, + logCallback: (level: number, target: string, message: string) => { + messages.push(`${getTickDate()} (${level})${target}\n${message}\n\n`) + }, +}*/, +) +/*;(window as any).getLogs = () => { + console.log("touch the window now!") + setTimeout(() => { + console.log("putting the logs in place") + let data = `` + while (messages.peek() !== undefined) { + data += messages.pop()! + } + navigator.clipboard.writeText(data) + console.log("copied!") + }, 3_000) +}*/ diff --git a/src/api/roc/ah.ts b/src/api/roc/ah.ts new file mode 100644 index 0000000..b2b6f8a --- /dev/null +++ b/src/api/roc/ah.ts @@ -0,0 +1,73 @@ +import { + DotXcmV3Junctions, + DotXcmV3MultiassetAssetId, + XcmV3Junction, + XcmV3JunctionNetworkId, + XcmV3MultiassetFungibility, + XcmVersionedMultiAssets, + rocAh as descriptors, +} from "@polkadot-api/descriptors" +import { rocAhClient } from "@/api/clients" +import { AssetInChain } from "../types" +import { + fromAssetHubToForeign, + fromAssetHubToRelay, + getNativeAsset, + watchAccoutFreeBalance, + watchForeingAssetAccoutFreeBalance, +} from "../common" + +const api = rocAhClient.getTypedApi(descriptors) + +const chain = "rocAh" +const roc: AssetInChain = { + chain, + symbol: "ROC", + watchFreeBalance: watchAccoutFreeBalance(api), + teleport: { + roc: (...args) => + api.tx.PolkadotXcm.limited_teleport_assets(fromAssetHubToRelay(...args)), + wndAh: (from, amount, to) => + api.tx.PolkadotXcm.limited_reserve_transfer_assets( + fromAssetHubToForeign( + XcmV3JunctionNetworkId.Westend(), + 1000, + getNativeAsset(1, amount), + from, + to, + ), + ), + }, +} + +const wndInRocAh: Parameters[0] = { + parents: 2, + interior: DotXcmV3Junctions.X1( + XcmV3Junction.GlobalConsensus(XcmV3JunctionNetworkId.Westend()), + ), +} + +const wnd: AssetInChain = { + chain, + symbol: "WND", + watchFreeBalance: watchForeingAssetAccoutFreeBalance(api, wndInRocAh), + teleport: { + wndAh: (from, amount, to) => + api.tx.PolkadotXcm.limited_reserve_transfer_assets( + fromAssetHubToForeign( + XcmV3JunctionNetworkId.Westend(), + 1000, + XcmVersionedMultiAssets.V3([ + { + id: DotXcmV3MultiassetAssetId.Concrete(wndInRocAh), + fun: XcmV3MultiassetFungibility.Fungible(amount), + }, + ]), + from, + to, + ), + ), + }, +} + +export default [wnd, roc] diff --git a/src/api/roc/index.ts b/src/api/roc/index.ts new file mode 100644 index 0000000..2b9dd85 --- /dev/null +++ b/src/api/roc/index.ts @@ -0,0 +1,4 @@ +import relay from "./relay" +import ah from "./ah" + +export default [...relay, ...ah] diff --git a/src/api/roc/relay.ts b/src/api/roc/relay.ts new file mode 100644 index 0000000..0564c0c --- /dev/null +++ b/src/api/roc/relay.ts @@ -0,0 +1,18 @@ +import { roc as descriptors } from "@polkadot-api/descriptors" +import { rocClient } from "@/api/clients" +import { AssetInChain } from "../types" +import { fromRelayToAssetHub, watchAccoutFreeBalance } from "../common" + +const api = rocClient.getTypedApi(descriptors) + +const roc: AssetInChain = { + chain: "roc", + symbol: "ROC", + watchFreeBalance: watchAccoutFreeBalance(api), + teleport: { + rocAh: (...args) => + api.tx.XcmPallet.limited_teleport_assets(fromRelayToAssetHub(...args)), + }, +} + +export default [roc] diff --git a/src/api/types.ts b/src/api/types.ts index 8b6420d..4cefc23 100644 --- a/src/api/types.ts +++ b/src/api/types.ts @@ -1,8 +1,16 @@ import type { Observable } from "rxjs" import type { PolkadotSigner, SS58String, Transaction } from "polkadot-api" -export type ChainId = "dot" | "dotAh" | "wnd" | "wndAh" | "ksm" | "ksmAh" -export type AssetId = "DOT" | "KSM" | "WND" +export type ChainId = + | "dot" + | "dotAh" + | "wnd" + | "wndAh" + | "ksm" + | "ksmAh" + | "roc" + | "rocAh" +export type AssetId = "DOT" | "KSM" | "WND" | "ROC" export type TeleportAsset = ( from: PolkadotSigner, diff --git a/src/api/wnd/ah.ts b/src/api/wnd/ah.ts index d8d2608..84cc73d 100644 --- a/src/api/wnd/ah.ts +++ b/src/api/wnd/ah.ts @@ -1,7 +1,21 @@ -import { wndAssethub as descriptors } from "@polkadot-api/descriptors" +import { + DotXcmV3Junctions, + DotXcmV3MultiassetAssetId, + XcmV3Junction, + XcmV3JunctionNetworkId, + XcmV3MultiassetFungibility, + XcmVersionedMultiAssets, + wndAssethub as descriptors, +} from "@polkadot-api/descriptors" import { wndAhClient } from "@/api/clients" import { AssetInChain } from "../types" -import { fromAssetHubToRelay, watchAccoutFreeBalance } from "../common" +import { + fromAssetHubToForeign, + fromAssetHubToRelay, + getNativeAsset, + watchAccoutFreeBalance, + watchForeingAssetAccoutFreeBalance, +} from "../common" const api = wndAhClient.getTypedApi(descriptors) @@ -12,7 +26,47 @@ const wnd: AssetInChain = { teleport: { wnd: (...args) => api.tx.PolkadotXcm.limited_teleport_assets(fromAssetHubToRelay(...args)), + rocAh: (from, amount, to) => + api.tx.PolkadotXcm.limited_reserve_transfer_assets( + fromAssetHubToForeign( + XcmV3JunctionNetworkId.Rococo(), + 1000, + getNativeAsset(1, amount), + from, + to, + ), + ), }, } -export default [wnd] +const rocInWndAh: Parameters[0] = { + parents: 2, + interior: DotXcmV3Junctions.X1( + XcmV3Junction.GlobalConsensus(XcmV3JunctionNetworkId.Rococo()), + ), +} + +const roc: AssetInChain = { + chain: "wndAh", + symbol: "ROC", + watchFreeBalance: watchForeingAssetAccoutFreeBalance(api, rocInWndAh), + teleport: { + rocAh: (from, amount, to) => + api.tx.PolkadotXcm.limited_reserve_transfer_assets( + fromAssetHubToForeign( + XcmV3JunctionNetworkId.Rococo(), + 1000, + XcmVersionedMultiAssets.V3([ + { + id: DotXcmV3MultiassetAssetId.Concrete(rocInWndAh), + fun: XcmV3MultiassetFungibility.Fungible(amount), + }, + ]), + from, + to, + ), + ), + }, +} + +export default [wnd, roc]