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

[Refactor] Accounts for Node.js/Webpack #159

Merged
merged 20 commits into from
Jan 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
e707d96
Add @superfluid-finance/sdk-core and graphql dependencies, update eth…
MHHukiewitz Jan 6, 2024
50300e9
Refactor EVM Wallet connection, because it was too complicated and ma…
MHHukiewitz Jan 8, 2024
21d25f4
Add superfluid connector
MHHukiewitz Jan 8, 2024
bfac50e
Update SuperfluidAccount to use WrapperSuperToken instead of SuperTok…
MHHukiewitz Jan 8, 2024
5915367
Remove unused methods and update flow rate calculations in superfluid…
MHHukiewitz Jan 9, 2024
ee48ce7
Add docstrings, improve error messages
MHHukiewitz Jan 10, 2024
fe90a2c
Use 0x hex representation instead of decimals for chainId
MHHukiewitz Jan 10, 2024
14cc0af
Add number as valid type
MHHukiewitz Jan 10, 2024
2288723
Add autoconvert of wallet to provider
MHHukiewitz Jan 10, 2024
0047eef
WIP switch network functionality for EVM
MHHukiewitz Jan 10, 2024
3999284
WIP switch network functionality for EVM
MHHukiewitz Jan 10, 2024
ba48ab2
Rename RpcChainType to RpcId
MHHukiewitz Jan 17, 2024
9212113
Add `getRpcId` and fix `changeNetwork`
MHHukiewitz Jan 17, 2024
64a633c
Remove wrapping functions as ALEPHx is a Pure SuperToken
MHHukiewitz Jan 17, 2024
753a0d6
change AVAX block explorer back to snowtrace because of better latenc…
MHHukiewitz Jan 22, 2024
0c56ffb
fix conversion rate in `alephPerHourToFlowRate`
MHHukiewitz Jan 22, 2024
6cea33b
add payment parameter to Instance & Program
MHHukiewitz Jan 22, 2024
a542c60
fix exported types; clean up comments
MHHukiewitz Jan 22, 2024
f27e921
fix instance publish with updated type
MHHukiewitz Jan 22, 2024
c3a867a
Simplify GetChain()
MHHukiewitz Jan 22, 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
14 changes: 7 additions & 7 deletions examples/toolshed/src/components/WalletConfig.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { solana, ethereum, avalanche, substrate } from '../../../../src/accounts
import { WalletChains } from '../model/chains'
import { dispatchAndConsume } from '../model/componentProps'
import { Actions } from '../reducer'
import { RpcChainType } from "../../../../src/accounts/providers/JsonRPCWallet";
import { RpcId } from "../../../../src/accounts/providers/JsonRPCWallet";
import Select, { SingleValue } from "react-select";
import { useState } from "react";

Expand All @@ -13,15 +13,15 @@ type Option = {
}

const availableChains: Option[] = [
{ label: 'Ethereum Mainnet', value: RpcChainType.ETH },
{ label: 'Ethereum Mainnet (FLASHBOT)', value: RpcChainType.ETH_FLASHBOTS },
{ label: 'Avalanche Mainnet', value: RpcChainType.AVAX },
{ label: 'Polygon Mainnet', value: RpcChainType.POLYGON },
{ label: 'BSC Mainnet', value: RpcChainType.BSC },
{ label: 'Ethereum Mainnet', value: RpcId.ETH },
{ label: 'Ethereum Mainnet (FLASHBOT)', value: RpcId.ETH_FLASHBOTS },
{ label: 'Avalanche Mainnet', value: RpcId.AVAX },
{ label: 'Polygon Mainnet', value: RpcId.POLYGON },
{ label: 'BSC Mainnet', value: RpcId.BSC },
]

function WalletConfig({ dispatch, state } : dispatchAndConsume) {
const [customEndpoint, setCustomEndpoint] = useState<RpcChainType>(availableChains[0].value)
const [customEndpoint, setCustomEndpoint] = useState<RpcId>(availableChains[0].value)
const getAccountClass = () => (
state.selectedChain === WalletChains.Avalanche ? [avalanche, window.ethereum]
: state.selectedChain === WalletChains.Substrate ? [substrate, null]
Expand Down
25,116 changes: 18,065 additions & 7,051 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@
"@polkadot/util-crypto": "^7.7.1",
"@solana/wallet-adapter-base": "^0.9.15",
"@solana/web3.js": "^1.39.1",
"@superfluid-finance/sdk-core": "^0.6.12",
"@taquito/beacon-wallet": "^14.0.0",
"@taquito/signer": "^13.0.1",
"avalanche": "^3.15.3",
Expand All @@ -93,8 +94,9 @@
"bip39": "^3.0.4",
"eciesjs": "^0.3.14",
"ethereumjs-util": "^7.1.5",
"ethers": "^5.6.4",
"ethers": "^5.7.2",
"form-data": "^4.0.0",
"graphql": "^16.8.1",
"semver": "^7.3.8",
"sha.js": "^2.4.11",
"tweetnacl": "^1.0.3",
Expand Down
42 changes: 42 additions & 0 deletions src/accounts/account.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { BaseMessage, Chain } from "../messages/types";
import { ProviderEncryptionLabel } from "./providers/ProviderEncryptionLib";
import { getRpcId, JsonRPCWallet, RpcId, RpcType } from "./providers/JsonRPCWallet";
import { ethers } from "ethers";

/**
* The Account class is used to implement protocols related accounts - Ethereum, Solana, ...
Expand Down Expand Up @@ -40,3 +42,43 @@ export abstract class ECIESAccount extends Account {
): Promise<Buffer | string>;
abstract decrypt(content: Buffer | string): Promise<Buffer>;
}

export abstract class EVMAccount extends ECIESAccount {
public wallet?: ethers.Wallet | JsonRPCWallet;

public async getChainId(): Promise<number> {
if (this.wallet instanceof JsonRPCWallet) {
return this.wallet.provider.network.chainId;
}
if (this.wallet instanceof ethers.Wallet) {
return (await this.wallet.provider.getNetwork()).chainId;
}
throw new Error("EVMAccount has no connected wallet");
}

public getRpcUrl(): string {
if (this.wallet instanceof JsonRPCWallet) {
return this.wallet.provider.connection.url;
}
if (this.wallet instanceof ethers.Wallet) {
throw new Error("Wallet has no connected provider");
}
throw new Error("EVMAccount has no connected wallet");
}

public async getRpcId(): Promise<RpcId> {
const chainId = await this.getChainId();
const rpcUrl = this.getRpcUrl();
return getRpcId({ chainId, rpcUrl });
}

public async changeNetwork(chainOrRpc: RpcType | RpcId = RpcId.ETH): Promise<void> {
if (this.wallet instanceof JsonRPCWallet) {
await this.wallet.changeNetwork(chainOrRpc);
}
if (this.wallet instanceof ethers.Wallet) {
//await this.wallet.provider.send("wallet_switchEthereumChain", [{ chainId: chainId.toString(16) }]);
throw new Error("Not implemented for ethers.Wallet");
}
}
}
56 changes: 29 additions & 27 deletions src/accounts/avalanche.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import shajs from "sha.js";
import { ECIESAccount } from "./account";
import { ECIESAccount, EVMAccount } from "./account";
import { GetVerificationBuffer } from "../messages";
import { BaseMessage, Chain } from "../messages/types";
import { decrypt as secp256k1_decrypt, encrypt as secp256k1_encrypt } from "eciesjs";
import { KeyPair, KeyChain } from "avalanche/dist/apis/avm";
import { KeyPair as EVMKeyPair } from "avalanche/dist/apis/evm";
import { Avalanche, BinTools, Buffer as AvaBuff } from "avalanche";
import { ChangeRpcParam, JsonRPCWallet, RpcChainType } from "./providers/JsonRPCWallet";
import { BaseProviderWallet } from "./providers/BaseProviderWallet";
import { providers } from "ethers";
import { ChangeRpcParam, JsonRPCWallet, RpcId } from "./providers/JsonRPCWallet";
import { ethers, providers } from "ethers";
import { privateToAddress } from "ethereumjs-util";
import { ProviderEncryptionLabel, ProviderEncryptionLib } from "./providers/ProviderEncryptionLib";
import verifyAvalanche from "../utils/signature/verifyAvalanche";
Expand All @@ -17,19 +16,23 @@ import verifyAvalanche from "../utils/signature/verifyAvalanche";
* AvalancheAccount implements the Account class for the Avalanche protocol.
* It is used to represent an Avalanche account when publishing a message on the Aleph network.
*/
export class AvalancheAccount extends ECIESAccount {
private signer?: KeyPair | EVMKeyPair;
private provider?: BaseProviderWallet;
constructor(signerOrProvider: KeyPair | EVMKeyPair | BaseProviderWallet, address: string, publicKey?: string) {
export class AvalancheAccount extends EVMAccount {
public override readonly wallet?: JsonRPCWallet;
public readonly keyPair?: KeyPair | EVMKeyPair;
constructor(
signerOrWallet: KeyPair | EVMKeyPair | JsonRPCWallet | ethers.providers.JsonRpcProvider,
address: string,
publicKey?: string,
) {
super(address, publicKey);
if (signerOrProvider instanceof KeyPair || signerOrProvider instanceof EVMKeyPair)
this.signer = signerOrProvider;
if (signerOrProvider instanceof BaseProviderWallet) this.provider = signerOrProvider;
if (signerOrWallet instanceof ethers.providers.JsonRpcProvider) this.wallet = new JsonRPCWallet(signerOrWallet);
else if (signerOrWallet instanceof KeyPair || signerOrWallet instanceof EVMKeyPair)
this.keyPair = signerOrWallet;
else this.wallet = signerOrWallet;
}

override GetChain(): Chain {
if (this.signer) return Chain.AVAX;
if (this.provider) return Chain.AVAX;
if (this.keyPair || this.wallet) return Chain.AVAX;

throw new Error("Cannot determine chain");
}
Expand All @@ -44,9 +47,8 @@ export class AvalancheAccount extends ECIESAccount {
*/
override async askPubKey(): Promise<void> {
if (!!this.publicKey) return;
if (!this.provider) throw Error("PublicKey Error: No providers are setup");

this.publicKey = await this.provider.getPublicKey();
if (!this.wallet) throw Error("PublicKey Error: No providers are setup");
this.publicKey = await this.wallet.getPublicKey();
return;
}

Expand Down Expand Up @@ -78,7 +80,7 @@ export class AvalancheAccount extends ECIESAccount {
}

if (!publicKey) throw new Error("Cannot encrypt content");
if (!this.provider) {
if (!this.wallet) {
// Wallet encryption method or non-metamask provider
return secp256k1_encrypt(publicKey, content);
} else {
Expand All @@ -93,12 +95,12 @@ export class AvalancheAccount extends ECIESAccount {
* @param encryptedContent The encrypted content to decrypt.
*/
async decrypt(encryptedContent: Buffer | string): Promise<Buffer> {
if (this.signer) {
const secret = this.signer.getPrivateKey().toString("hex");
if (this.keyPair) {
const secret = this.keyPair.getPrivateKey().toString("hex");
return secp256k1_decrypt(secret, Buffer.from(encryptedContent));
}
if (this.provider) {
const decrypted = await this.provider.decrypt(encryptedContent);
if (this.wallet) {
const decrypted = await this.wallet.decrypt(encryptedContent);
return Buffer.from(decrypted);
}
throw new Error("Cannot encrypt content");
Expand All @@ -125,18 +127,18 @@ export class AvalancheAccount extends ECIESAccount {
const buffer = GetVerificationBuffer(message);
const digest = await this.digestMessage(buffer);

if (this.signer) {
if (this.keyPair) {
const digestHex = digest.toString("hex");
const digestBuff = AvaBuff.from(digestHex, "hex");
const signatureBuffer = this.signer?.sign(digestBuff);
const signatureBuffer = this.keyPair?.sign(digestBuff);

const bintools = BinTools.getInstance();
const signature = bintools.cb58Encode(signatureBuffer);
if (await verifyAvalanche(buffer, signature, this.signer.getPublicKey().toString("hex"))) return signature;
if (await verifyAvalanche(buffer, signature, this.keyPair.getPublicKey().toString("hex"))) return signature;

throw new Error("Cannot proof the integrity of the signature");
} else if (this.provider) {
return await this.provider.signMessage(buffer);
} else if (this.wallet) {
return await this.wallet.signMessage(buffer);
}

throw new Error("Cannot sign message");
Expand Down Expand Up @@ -199,7 +201,7 @@ export async function ImportAccountFromPrivateKey(
*/
export async function GetAccountFromProvider(
provider: providers.ExternalProvider,
requestedRpc: ChangeRpcParam = RpcChainType.AVAX,
requestedRpc: ChangeRpcParam = RpcId.AVAX,
): Promise<AvalancheAccount> {
const avaxProvider = new providers.Web3Provider(provider);
const jrw = new JsonRPCWallet(avaxProvider);
Expand Down
42 changes: 18 additions & 24 deletions src/accounts/ethereum.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,23 @@
import * as bip39 from "bip39";
import { ethers } from "ethers";
import { ECIESAccount } from "./account";
import { ECIESAccount, EVMAccount } from "./account";
import { GetVerificationBuffer } from "../messages";
import { BaseMessage, Chain } from "../messages/types";
import verifyEthereum from "../utils/signature/verifyEthereum";
import { BaseProviderWallet } from "./providers/BaseProviderWallet";
import { decrypt as secp256k1_decrypt, encrypt as secp256k1_encrypt } from "eciesjs";
import { ChangeRpcParam, JsonRPCWallet, RpcChainType } from "./providers/JsonRPCWallet";
import { ChangeRpcParam, JsonRPCWallet, RpcId } from "./providers/JsonRPCWallet";
import { ProviderEncryptionLabel, ProviderEncryptionLib } from "./providers/ProviderEncryptionLib";

/**
* ETHAccount implements the Account class for the Ethereum protocol.
* It is used to represent an ethereum account when publishing a message on the Aleph network.
*/
export class ETHAccount extends ECIESAccount {
private wallet?: ethers.Wallet;
private provider?: BaseProviderWallet;
export class ETHAccount extends EVMAccount {
public override readonly wallet: ethers.Wallet | JsonRPCWallet;

constructor(walletOrProvider: ethers.Wallet | BaseProviderWallet, address: string, publicKey?: string) {
public constructor(wallet: ethers.Wallet | JsonRPCWallet, address: string, publicKey?: string) {
super(address, publicKey);

if (walletOrProvider instanceof ethers.Wallet) this.wallet = walletOrProvider;
else this.provider = walletOrProvider;
this.wallet = wallet;
}

override GetChain(): Chain {
Expand All @@ -38,9 +34,13 @@ export class ETHAccount extends ECIESAccount {
*/
override async askPubKey(): Promise<void> {
if (!!this.publicKey) return;
if (!this.provider) throw Error("PublicKey Error: No providers are setup");
if (!this.wallet) throw Error("PublicKey Error: No providers are setup");

this.publicKey = await this.provider.getPublicKey();
if (this.wallet instanceof ethers.Wallet) {
this.publicKey = this.wallet.publicKey;
return;
}
this.publicKey = await this.wallet.getPublicKey();
return;
}

Expand Down Expand Up @@ -72,7 +72,7 @@ export class ETHAccount extends ECIESAccount {
}

if (!publicKey) throw new Error("Cannot encrypt content");
if (!this.provider) {
if (this.wallet instanceof ethers.Wallet) {
// Wallet encryption method or non-metamask provider
return secp256k1_encrypt(publicKey, content);
} else {
Expand All @@ -87,15 +87,13 @@ export class ETHAccount extends ECIESAccount {
* @param encryptedContent The encrypted content to decrypt.
*/
async decrypt(encryptedContent: Buffer | string): Promise<Buffer> {
if (this.wallet) {
if (this.wallet instanceof ethers.Wallet) {
const secret = this.wallet.privateKey;
return secp256k1_decrypt(secret, Buffer.from(encryptedContent));
}
if (this.provider) {
const decrypted = await this.provider.decrypt(encryptedContent);
} else {
const decrypted = await this.wallet.decrypt(encryptedContent);
return Buffer.from(decrypted);
}
throw new Error("Cannot encrypt content");
}

/**
Expand All @@ -108,11 +106,7 @@ export class ETHAccount extends ECIESAccount {
*/
async Sign(message: BaseMessage): Promise<string> {
const buffer = GetVerificationBuffer(message);
const signMethod = this.wallet || this.provider;

if (!signMethod) throw new Error("Cannot sign message");

const signature = await signMethod.signMessage(buffer.toString());
const signature = await this.wallet.signMessage(buffer.toString());
if (verifyEthereum(buffer, signature, this.address)) return signature;

throw new Error("Cannot proof the integrity of the signature");
Expand Down Expand Up @@ -165,7 +159,7 @@ export function NewAccount(derivationPath = "m/44'/60'/0'/0/0"): { account: ETHA
*/
export async function GetAccountFromProvider(
provider: ethers.providers.ExternalProvider,
requestedRpc: ChangeRpcParam = RpcChainType.ETH,
requestedRpc: ChangeRpcParam = RpcId.ETH,
): Promise<ETHAccount> {
const ETHprovider = new ethers.providers.Web3Provider(provider);
const jrw = new JsonRPCWallet(ETHprovider);
Expand Down
4 changes: 3 additions & 1 deletion src/accounts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@ import * as solana from "./solana";
import * as substrate from "./substrate";
import * as tezos from "./tezos";

export { base, avalanche, cosmos, ethereum, solana, substrate, nuls2, tezos };
import * as superfluid from "./superfluid";

export { base, avalanche, cosmos, ethereum, solana, substrate, nuls2, tezos, superfluid };
31 changes: 0 additions & 31 deletions src/accounts/providers/BaseProviderWallet.ts

This file was deleted.

Loading
Loading