Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Typescript API, React UI and Operational Scripts #1117

Merged
merged 73 commits into from
Apr 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
508eb65
validate and execute send token
alistair-singh Jan 22, 2024
17dfa3b
wip
alistair-singh Jan 26, 2024
eafb642
wip
alistair-singh Feb 13, 2024
2a4330c
revert token change
alistair-singh Feb 13, 2024
4c18518
added ui skeleton
alistair-singh Feb 13, 2024
9c10fff
update
alistair-singh Feb 13, 2024
04012ea
update ui
alistair-singh Feb 14, 2024
5cf4b39
add infura
alistair-singh Feb 14, 2024
efe9592
submit
alistair-singh Feb 14, 2024
0470b01
publish
alistair-singh Feb 14, 2024
35b5846
finish checks
alistair-singh Feb 14, 2024
3bde189
added destination chain case
alistair-singh Feb 16, 2024
ae1f025
update ui
alistair-singh Feb 16, 2024
290835b
moved to module
alistair-singh Feb 19, 2024
f604009
split into different modules
alistair-singh Feb 19, 2024
78fcd57
refactorings
alistair-singh Feb 19, 2024
90f1515
added channel id generation
alistair-singh Feb 19, 2024
d31c058
fmt
alistair-singh Feb 19, 2024
5fea1be
remove test code
alistair-singh Feb 20, 2024
d2e095e
docs
alistair-singh Feb 21, 2024
7413ad4
remove logging
alistair-singh Feb 21, 2024
9d98bf2
refactor
alistair-singh Feb 22, 2024
575ed93
revert contract changes
alistair-singh Feb 22, 2024
e529fc6
improvements
alistair-singh Feb 25, 2024
2a3e8c2
cant use unions
alistair-singh Feb 25, 2024
6832acf
more fixes
alistair-singh Feb 26, 2024
e8a2cf8
fixes to paraIdFromAgent
alistair-singh Feb 27, 2024
bdfffb1
removed some todos
alistair-singh Feb 27, 2024
7ed2a67
minor fixes
alistair-singh Feb 29, 2024
c025b75
added config
alistair-singh Mar 4, 2024
c4e1d96
rebased
alistair-singh Mar 6, 2024
b6706d5
flesh out monitoring
alistair-singh Mar 7, 2024
be7b6b7
monitor accounts
alistair-singh Mar 7, 2024
08bf934
refactor transfer
alistair-singh Mar 7, 2024
86cd597
fix monitor
alistair-singh Mar 7, 2024
8321b5c
track via nonce
alistair-singh Mar 7, 2024
3df36ba
final fixes
alistair-singh Mar 7, 2024
bdd94b2
check extrinsic success
alistair-singh Mar 7, 2024
0a27d94
refactor
alistair-singh Mar 7, 2024
7813f42
more refactoring
alistair-singh Mar 7, 2024
c666a03
monitor downstream
alistair-singh Mar 7, 2024
ac3a06a
make sure message is delivered to downstream
alistair-singh Mar 8, 2024
3d2d631
fixes
alistair-singh Mar 10, 2024
8c3edaa
e2e
alistair-singh Mar 17, 2024
71407c4
add workflow
alistair-singh Mar 31, 2024
d12f35a
workflow
alistair-singh Mar 31, 2024
79885b1
fix syntax
alistair-singh Mar 31, 2024
a8cbe79
validate
alistair-singh Mar 31, 2024
45998c8
fix working dir
alistair-singh Mar 31, 2024
15ff2b6
more fixes
alistair-singh Mar 31, 2024
04b6747
more fixes
alistair-singh Mar 31, 2024
b0386eb
more fixes
alistair-singh Mar 31, 2024
8e81e11
fix
alistair-singh Mar 31, 2024
b70f623
fix
alistair-singh Mar 31, 2024
f7e9eba
disable git checks
alistair-singh Mar 31, 2024
3c96686
testing
alistair-singh Mar 31, 2024
ea28dea
remove secret
alistair-singh Mar 31, 2024
862cdf6
remove registry
alistair-singh Mar 31, 2024
9501003
Revert "remove secret"
alistair-singh Mar 31, 2024
bc83dfc
pause publishing
alistair-singh Mar 31, 2024
c5292bb
rename
alistair-singh Mar 31, 2024
619f803
remove file
alistair-singh Mar 31, 2024
940ce8d
versioned packages
alistair-singh Apr 3, 2024
c70ed50
add publish steps
alistair-singh Apr 3, 2024
fd5afc7
disable checks
alistair-singh Apr 3, 2024
4c65dad
change vars
alistair-singh Apr 3, 2024
2921510
change
alistair-singh Apr 3, 2024
12a9495
use key
alistair-singh Apr 3, 2024
cd09ae8
access public
alistair-singh Apr 3, 2024
9517f2b
on release
alistair-singh Apr 3, 2024
3c974be
remove test settings
alistair-singh Apr 3, 2024
9f07c85
bump versions
alistair-singh Apr 3, 2024
d7c4538
various fixes
alistair-singh Apr 8, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions .github/workflows/npm-publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
name: npm-publish

on:
release:
types: [published]

env:
NPM_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }}

jobs:
publish:
runs-on: snowbridge-runner
timeout-minutes: 15
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 2

- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1

- name: Build Contracts
working-directory: contracts
run: |
forge build

- name: Install Node.js
uses: actions/setup-node@v4
with:
node-version: '20.x'
registry-url: 'https://registry.npmjs.org'

- name: Install pnpm
uses: pnpm/action-setup@v3
with:
version: 8

- name: Build Contract Types
working-directory: web/packages/contract-types
run: |
pnpm install
pnpm typechain
pnpm build

- name: Build API
working-directory: web/packages/api
run: |
pnpm install
pnpm build

- name: Publish Contract Types
working-directory: web/packages/contract-types
run: |
pnpm publish

- name: Publish API
working-directory: web/packages/api
run: |
pnpm publish

3 changes: 3 additions & 0 deletions web/.npmrc
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
store-dir=.pnpm-store/
//registry.npmjs.org/:_authToken=${NPM_AUTH_TOKEN}
always-auth=false
access=public
14 changes: 7 additions & 7 deletions web/packages/api/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@snowbridge/api",
"version": "1.0.0",
"version": "0.1.2",
"description": "Snowbridge API client",
"license": "Apache-2.0",
"repository": {
Expand All @@ -26,14 +26,14 @@
"typescript": "^5.1.6"
},
"dependencies": {
"@ethersproject/abi": "^5.7.0",
"@ethersproject/bytes": "^5.7.0",
"@ethersproject/providers": "^5.7.0",
"@ethersproject/units": "^5.7.0",
"ethers": "^6.9.0",
"@polkadot/api": "^10.12.1",
"@polkadot/types": "^10.12.1",
"@polkadot/util": "^12.6.2",
"@polkadot/util-crypto": "^12.6.2",
"@polkadot/keyring": "^12.6.2",
"@snowbridge/contract-types": "workspace:*",
"@typechain/ethers-v5": "^11.1.1",
"ethers": "^5.7.0"
"@typechain/ethers-v6": "^0.5.1",
"rxjs": "^7.8.1"
}
}
110 changes: 89 additions & 21 deletions web/packages/api/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,63 +1,131 @@
// import "@polkadot/api-augment/polkadot"
import { ApiPromise, WsProvider } from "@polkadot/api"
import { ethers } from "ethers"
import { IGateway, IGateway__factory } from "@snowbridge/contract-types"
// import '@polkadot/api-augment/polkadot'
import { ApiPromise, WsProvider } from '@polkadot/api'
import { ethers } from 'ethers'
import { BeefyClient, BeefyClient__factory, IGateway, IGateway__factory } from '@snowbridge/contract-types'

interface Config {
ethereum: {
url: string
}
polkadot: {
url: string
url: {
bridgeHub: string
assetHub: string
relaychain: string
parachains?: string[]
}
}
appContracts: {
gateway: string
beefy: string
}
}

interface AppContracts {
gateway: IGateway
beefyClient: BeefyClient
}

class Context {
export class Context {
config: Config
ethereum: EthereumContext
polkadot: PolkadotContext

constructor(ethereum: EthereumContext, polkadot: PolkadotContext) {
constructor(config: Config, ethereum: EthereumContext, polkadot: PolkadotContext) {
this.config = config
this.ethereum = ethereum
this.polkadot = polkadot
}
}

class EthereumContext {
api: ethers.providers.WebSocketProvider
api: ethers.WebSocketProvider
contracts: AppContracts

constructor(api: ethers.providers.WebSocketProvider, contracts: AppContracts) {
constructor(api: ethers.WebSocketProvider, contracts: AppContracts) {
this.api = api
this.contracts = contracts
}
}

class PolkadotContext {
api: ApiPromise
constructor(api: ApiPromise) {
this.api = api
api: {
relaychain: ApiPromise
assetHub: ApiPromise
bridgeHub: ApiPromise
parachains: { [paraId: number]: ApiPromise }
}
constructor(relaychain: ApiPromise, assetHub: ApiPromise, bridgeHub: ApiPromise) {
this.api = {
relaychain: relaychain,
assetHub: assetHub,
bridgeHub: bridgeHub,
parachains: {}
}
}
}

// eslint-disable-next-line @typescript-eslint/no-unused-vars
const contextFactory = async (config: Config): Promise<Context> => {
let ethApi = new ethers.providers.WebSocketProvider(config.ethereum.url)
let polApi = await ApiPromise.create({
provider: new WsProvider(config.polkadot.url),
export const contextFactory = async (config: Config): Promise<Context> => {
const ethApi = new ethers.WebSocketProvider(config.ethereum.url)
const relaychainApi = await ApiPromise.create({
provider: new WsProvider(config.polkadot.url.relaychain),
})
const assetHubApi = await ApiPromise.create({
provider: new WsProvider(config.polkadot.url.assetHub),
})
const bridgeHubApi = await ApiPromise.create({
provider: new WsProvider(config.polkadot.url.bridgeHub),
})

let gatewayAddr = process.env["GatewayProxyAddress"]!
const gatewayAddr = config.appContracts.gateway
const beefyAddr = config.appContracts.beefy

let appContracts: AppContracts = {
const appContracts: AppContracts = {
//TODO: Get gateway address from bridgehub
gateway: IGateway__factory.connect(gatewayAddr, ethApi),
//TODO: Get beefy client from gateway
beefyClient: BeefyClient__factory.connect(beefyAddr, ethApi),
}

let ethCtx = new EthereumContext(ethApi, appContracts)
let polCtx = new PolkadotContext(polApi)
const ethCtx = new EthereumContext(ethApi, appContracts)
const polCtx = new PolkadotContext(relaychainApi, assetHubApi, bridgeHubApi)

return new Context(ethCtx, polCtx)
const context = new Context(config, ethCtx, polCtx)
for (const parachain of config.polkadot.url.parachains ?? []) {
await addParachainConnection(context, parachain)
}
return context
}

export const addParachainConnection = async (context: Context, url: string): Promise<void> => {
const api = await ApiPromise.create({
provider: new WsProvider(url)
})
const paraId = (await api.query.parachainInfo.parachainId()).toPrimitive() as number
if (paraId in context.polkadot.api.parachains) {
throw new Error(`${paraId} already added.`)
}
context.polkadot.api.parachains[paraId] = api
console.log(`${url} added with parachain id: ${paraId}`)
}

export const destroyContext = async (context: Context): Promise<void> => {
// clean up etheruem
await context.ethereum.contracts.beefyClient.removeAllListeners()
await context.ethereum.contracts.gateway.removeAllListeners()
await context.ethereum.api.destroy()
// clean up polkadot
await context.polkadot.api.relaychain.disconnect()
await context.polkadot.api.bridgeHub.disconnect()
await context.polkadot.api.assetHub.disconnect()

for (const paraId of Object.keys(context.polkadot.api.parachains)) {
await context.polkadot.api.parachains[Number(paraId)].disconnect()
}
}

export * as toPolkadot from './toPolkadot'
export * as toEthereum from './toEthereum'
export * as utils from './utils'
export * as status from './status'
52 changes: 52 additions & 0 deletions web/packages/api/src/query.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { ApiPromise } from '@polkadot/api'
import { Codec } from '@polkadot/types/types'
import { filter, firstValueFrom, take } from 'rxjs'

export const waitForMessageQueuePallet = async (
parachain: ApiPromise,
messageId: string | undefined,
siblingParachain: number,
eventFilter: (event: Codec) => boolean,
options = {
scanBlocks: 10,
}
): Promise<{ foundEvent?: Codec, allEvents: Codec, extrinsicSuccess: boolean }> => {
let extrinsicSuccess = false
let returnEvent = undefined
let receivedEvents = await firstValueFrom(
parachain.rx.query.system.events().pipe(
take(options.scanBlocks),
filter(events => {
let foundMessageQueue = false
let foundEvent = false
for (const event of (events as any)) {
let eventData = event.event.toPrimitive().data
if (parachain.events.messageQueue.Processed.is(event.event)
// TODO: Use SetTopic to forward the message id to the destination chain and then remove undefined check.
&& (messageId === undefined || eventData[0].toLowerCase() === messageId.toLowerCase())
&& eventData[1]?.sibling === siblingParachain) {

foundMessageQueue = true
extrinsicSuccess = eventData[3]
}

if (eventFilter(event)) {
foundEvent = true
returnEvent = event
}
}
return foundMessageQueue && ((extrinsicSuccess && foundEvent) || !extrinsicSuccess)
}),
),
{ defaultValue: undefined }
)

if (receivedEvents === undefined) {
throw Error('Timeout while waiting for event.')
}
return {
foundEvent: returnEvent,
allEvents: receivedEvents,
extrinsicSuccess: extrinsicSuccess
}
}
Loading