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

Feat: Base chain support for Superfluid #182

Merged
merged 10 commits into from
Sep 5, 2024
120 changes: 114 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 7 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
"messages",
"ethereum",
"solana",
"avalanche",
"avax",
"base",
"defi",
"dao",
"nft"
Expand All @@ -32,7 +35,8 @@
"Roman Gascoin <[email protected]>",
"Mike Hukiewitz <[email protected]>",
"Kelian Christophe <[email protected]>",
"Angel Manzano <[email protected]>"
"Angel Manzano <[email protected]>",
"Gerard Molina <[email protected]>"
],
"license": "MIT",
"engines": {
Expand Down Expand Up @@ -73,6 +77,7 @@
"packages/ethereum",
"packages/ethereum-ledger",
"packages/avalanche",
"packages/base",
"packages/nuls2",
"packages/cosmos",
"packages/solana",
Expand All @@ -83,4 +88,4 @@
"packages/client",
"packages/dns"
]
}
}
16 changes: 9 additions & 7 deletions packages/avalanche/src/account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@ import { KeyPair, KeyChain } from 'avalanche/dist/apis/avm'
import { KeyPair as EVMKeyPair } from 'avalanche/dist/apis/evm'
import { ethers, providers } from 'ethers'
import { privateToAddress } from 'ethereumjs-util'

import { Blockchain } from '@aleph-sdk/core'
import { SignableMessage, BaseProviderWallet } from '@aleph-sdk/account'
import { ChangeRpcParam, RpcId, EVMAccount, JsonRPCWallet } from '@aleph-sdk/evm'
import { ChangeRpcParam, RpcId, EVMAccount, JsonRPCWallet, ChainData } from '@aleph-sdk/evm'
import { digestMessage, verifyAvalanche } from './verify'

/**
Expand Down Expand Up @@ -152,18 +151,21 @@ export async function importAccountFromMnemonic(
/**
* Get an account from a Web3 provider (ex: Metamask)
*
* @param {providers.ExternalProvider} provider from metamask
* @param {providers.ExternalProvider | ethers.providers.Web3Provider} provider
* @param requestedRpc Use this params to change the RPC endpoint;
*/
export async function getAccountFromProvider(
provider: providers.ExternalProvider,
provider: ethers.providers.ExternalProvider | ethers.providers.Web3Provider,
requestedRpc: ChangeRpcParam = RpcId.AVAX,
): Promise<AvalancheAccount> {
const avaxProvider = new providers.Web3Provider(provider)
const jrw = new JsonRPCWallet(avaxProvider)
await jrw.changeNetwork(requestedRpc)
const ETHprovider =
provider instanceof ethers.providers.Web3Provider ? provider : new providers.Web3Provider(provider)
const jrw = new JsonRPCWallet(ETHprovider)

const chainId = Number((typeof requestedRpc === 'number' ? ChainData[requestedRpc] : requestedRpc).chainId)
if (chainId !== (await jrw.provider.getNetwork()).chainId) await jrw.changeNetwork(requestedRpc)
await jrw.connect()

if (jrw.address) {
return new AvalancheAccount(jrw, jrw.address)
}
Expand Down
9 changes: 9 additions & 0 deletions packages/base/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# @aleph-sdk/base

This package provides an implementation for Base blockchain accounts within the Aleph.im ecosystem, enabling Base account management and message signing functionalities.

See [@aleph-sdk/client](https://npmjs.com/package/@aleph-sdk/client) or the [offical docs](https://docs.aleph.im) as the entrypoint for developing with aleph.im.

## Features

As Base Account extends from Ethereum account, see [@aleph-sdk/ethereum](https://www.npmjs.com/package/@aleph-sdk/ethereum)
87 changes: 87 additions & 0 deletions packages/base/__tests__/account.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import * as bip39 from 'bip39'
import { ethers } from 'ethers'

import * as base from '../src'
import { PostMessageBuilder, prepareAlephMessage, ItemType } from '../../message/src'
import { EthereumMockProvider } from '@aleph-sdk/evm'
import { EphAccount } from '@aleph-sdk/account'

async function createEphemeralEth(): Promise<EphAccount> {
const mnemonic = bip39.generateMnemonic()
const { address, publicKey, privateKey } = ethers.Wallet.fromMnemonic(mnemonic)

return {
address,
publicKey,
privateKey: privateKey.substring(2),
mnemonic,
}
}

describe('Ethereum accounts', () => {
let ephemeralAccount: EphAccount

beforeAll(async () => {
ephemeralAccount = await createEphemeralEth()
})

it('should import a base account using a mnemonic', () => {
const { account, mnemonic } = base.newAccount()
const accountFromMnemonic = base.importAccountFromMnemonic(mnemonic)

expect(account.address).toStrictEqual(accountFromMnemonic.address)
})

it('should import a base account using a private key', () => {
const mnemonic = bip39.generateMnemonic()
const wallet = ethers.Wallet.fromMnemonic(mnemonic)
const accountFromPrivate = base.importAccountFromPrivateKey(wallet.privateKey)

expect(wallet.address).toStrictEqual(accountFromPrivate.address)
})

it('should import a base account using a provider', async () => {
const { address, privateKey } = ephemeralAccount
if (!privateKey) throw Error('Can not retrieve privateKey inside ephemeralAccount.json')

const provider = new EthereumMockProvider({
address,
privateKey,
networkVersion: 31,
})

const accountFromProvider = await base.getAccountFromProvider(provider)
const accountFromPrivate = base.importAccountFromPrivateKey(privateKey)

expect(accountFromProvider.address).toStrictEqual(accountFromPrivate.address)
})

it('should get the same signed message for each account', async () => {
const { address, privateKey } = ephemeralAccount
if (!privateKey) throw Error('Can not retrieve privateKey inside ephemeralAccount.json')

const provider = new EthereumMockProvider({
address,
privateKey,
networkVersion: 31,
})
const { account, mnemonic } = base.newAccount()
const accountFromProvider = await base.getAccountFromProvider(provider)
const accountFromPrivate = await base.importAccountFromMnemonic(mnemonic)

const builtMessage = PostMessageBuilder({
account,
channel: 'TEST',
storageEngine: ItemType.inline,
timestamp: Date.now() / 1000,
content: { address: account.address, time: 15, type: '' },
})

const hashedMessage = await prepareAlephMessage({
message: builtMessage,
})

expect(account.sign(hashedMessage)).toStrictEqual(accountFromPrivate.sign(hashedMessage))
expect(account.sign(hashedMessage)).toStrictEqual(accountFromProvider.sign(hashedMessage))
})
})
38 changes: 38 additions & 0 deletions packages/base/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"name": "@aleph-sdk/base",
"version": "1.0.0",
"description": "Base accounts for signing messages on aleph.im",
"main": "dist/index.cjs",
"module": "dist/index.mjs",
"types": "dist/index.d.ts",
"files": [
"dist"
],
"publishConfig": {
"access": "public"
},
"devDependencies": {
"@types/sha.js": "^2.4.0"
},
"dependencies": {
"eciesjs": "^0.4.6",
"sha.js": "^2.4.11"
},
"peerDependencies": {
"@aleph-sdk/account": "^1.x.x",
"@aleph-sdk/core": "^1.0.4",
"@aleph-sdk/evm": "^1.0.4",
"@aleph-sdk/ethereum": "^1.x.x",
"avalanche": "^3.15.3",
"ethers": "^5.x.x"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"rollup": "rollup -c ../../rollup.config.js",
"build": "npm run rollup"
},
"author": "",
"homepage": "https://aleph.im",
"bugs": "https://github.com/aleph-im/aleph-sdk-ts/issues",
"license": "MIT"
}
Loading
Loading