Skip to content

Commit

Permalink
feat: burner wallet connector (#49)
Browse files Browse the repository at this point in the history
  • Loading branch information
pedropereiradev authored Apr 16, 2024
1 parent 495d7d3 commit fe8fe45
Show file tree
Hide file tree
Showing 19 changed files with 1,316 additions and 16 deletions.
6 changes: 6 additions & 0 deletions .changeset/khaki-seas-scream.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@fuels/connectors": minor
"@fuel-connectors/burner-wallet-connector": patch
---

burner wallet connector implemented
1 change: 1 addition & 0 deletions .github/workflows/pr-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ jobs:
uses: FuelLabs/github-actions/setups/node@master
with:
node-version: 20.11.0
pnpm-version: 8.9.0

- uses: FuelLabs/github-actions/setups/docker@master
with:
Expand Down
7 changes: 7 additions & 0 deletions .github/workflows/pr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ jobs:

- name: CI Setup
uses: FuelLabs/github-actions/setups/node@master
with:
pnpm-version: 8.9.0

- name: Validate Changeset
run: pnpm changeset status --since=origin/${{ github.base_ref }}
Expand All @@ -54,6 +56,9 @@ jobs:
steps:
- uses: actions/checkout@v3
- uses: FuelLabs/github-actions/setups/node@master
with:
pnpm-version: 8.9.0

- run: pnpm audit --prod

lint:
Expand All @@ -69,6 +74,8 @@ jobs:

- name: Setup Node
uses: FuelLabs/github-actions/setups/node@master
with:
pnpm-version: 8.9.0

- name: Run lint & ts:check
run: |
Expand Down
30 changes: 30 additions & 0 deletions packages/burner-wallet-connector/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"name": "@fuel-connectors/burner-wallet-connector",
"version": "0.0.0",
"private": true,
"type": "module",
"types": "./dist/index.d.ts",
"exports": {
".": "./src/index.ts"
},
"scripts": {
"build": "tsup --dts-only",
"build:watch": "tsup --watch --dts-only",
"ts:check": "tsc --noEmit",
"test": "vitest"
},
"peerDependencies": {
"fuels": ">=0.77.0"
},
"devDependencies": {
"@fuel-ts/account": "^0.79.0",
"@fuel-ts/fuel-core": "^0.79.0",
"fuels": "^0.79.0",
"jsdom": "24.0.0",
"tsup": "8.0.2",
"typescript": "5.4.3",
"vite": "^5.0.10",
"vite-plugin-dts": "^3.6.4",
"vitest": "^1.4.0"
}
}
279 changes: 279 additions & 0 deletions packages/burner-wallet-connector/src/BurnerWalletConnector.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,279 @@
import {
type AbiMap,
type Asset,
type ConnectorMetadata,
FuelConnector,
FuelConnectorEventTypes,
type JsonAbi,
type Network,
Provider,
type StorageAbstract,
type TransactionRequestLike,
type Version,
Wallet,
type WalletUnlocked,
} from 'fuels';
import {
BETA_5_URL,
BURNER_WALLET_CONNECTED,
BURNER_WALLET_ICON,
BURNER_WALLET_PRIVATE_KEY,
WINDOW,
} from './constants';
import type { BurnerWalletConfig } from './types';

export class BurnerWalletConnector extends FuelConnector {
name = 'Burner Wallet';

connected = false;
installed = false;

events = FuelConnectorEventTypes;

metadata: ConnectorMetadata = {
image: BURNER_WALLET_ICON,
install: {
action: '',
description: 'Burner Wallet to connect to Fuel',
link: '',
},
};

burnerWallet: WalletUnlocked | null = null;
burnerWalletProvider: Provider | null = null;
burnerWalletPrivateKey: string | null = null;

private config: BurnerWalletConfig = {};
private storage: StorageAbstract;

constructor(config: BurnerWalletConfig = {}) {
super();

this.config = config;
this.storage = this.getStorage(config.storage);

this.configFuelProvider(config);
this.setupBurnerWallet();
}

private async configFuelProvider(config: BurnerWalletConfig = {}) {
this.config.fuelProvider =
config.fuelProvider || Provider.create(BETA_5_URL);
}

private async setupBurnerWallet() {
const privateKey = await this.storage.getItem(BURNER_WALLET_PRIVATE_KEY);

if (privateKey) {
this.storage.setItem(BURNER_WALLET_ICON, privateKey);
}

if (!privateKey) {
this.burnerWallet = Wallet.generate({
provider: await this.config.fuelProvider,
});

this.burnerWalletProvider = this.burnerWallet.provider;
this.burnerWalletPrivateKey = this.burnerWallet.privateKey;

this.storage.setItem(
BURNER_WALLET_PRIVATE_KEY,
this.burnerWalletPrivateKey,
);

return this.burnerWallet;
}

this.burnerWallet = Wallet.fromPrivateKey(
privateKey,
await this.config.fuelProvider,
);

this.burnerWalletProvider = this.burnerWallet.provider;
this.burnerWalletPrivateKey = this.burnerWallet.privateKey;

return this.burnerWallet;
}

private getStorage(storage?: StorageAbstract) {
const _storage =
storage ?? (WINDOW.sessionStorage as unknown as StorageAbstract);
if (!_storage) {
throw new Error('No storage provided');
}

return _storage;
}

/**
* ============================================================
* Connector methods
* ============================================================
*/
async ping(): Promise<boolean> {
await this.configFuelProvider();
await this.setupBurnerWallet();

return true;
}

async version(): Promise<Version> {
return { app: '0.0.0', network: '0.0.0' };
}

async isConnected(): Promise<boolean> {
const connected =
(await this.storage.getItem(BURNER_WALLET_CONNECTED)) === 'true';

if (!connected) {
return false;
}

const account = this.burnerWallet?.address.toString();

return !!account && account.length > 0;
}

async connect(): Promise<boolean> {
if (!(await this.isConnected())) {
if (!this.burnerWalletProvider) {
throw Error('Burner Wallet Provider not found');
}

await this.setupBurnerWallet();

this.burnerWalletProvider = this.burnerWallet?.connect(
this.burnerWalletProvider,
) as Provider;

this.storage.setItem(BURNER_WALLET_CONNECTED, 'true');
}

this.emit(this.events.connection, true);
this.emit(
this.events.currentAccount,
this.burnerWallet?.address.toAddress(),
);
this.emit(this.events.accounts, [this.burnerWallet?.address.toAddress()]);

return this.connected;
}

async accounts(): Promise<string[]> {
if (!this.burnerWallet) {
throw Error('Wallet not connected');
}

const account = this.burnerWallet.address.toAddress();

if (!account) {
return [];
}

return [account as `fuel${string}`];
}

async disconnect(): Promise<boolean> {
if (await this.isConnected()) {
this.burnerWalletPrivateKey = null;
this.burnerWalletProvider = null;
this.burnerWallet = null;
}

this.storage.setItem(BURNER_WALLET_CONNECTED, 'false');
this.storage.removeItem(BURNER_WALLET_PRIVATE_KEY);

this.emit(this.events.connection, false);
this.emit(this.events.currentAccount, null);
this.emit(this.events.accounts, []);

return this.connected;
}

async signMessage(_address: string, _message: string): Promise<string> {
if (!this.burnerWallet) {
throw Error('Wallet not connected');
}

if (_address !== this.burnerWallet.address.toString()) {
throw Error('Address not found for the connector');
}

const signMessage = await this.burnerWallet.signMessage(_message);

return signMessage;
}

async sendTransaction(
_address: string,
transaction: TransactionRequestLike,
): Promise<string> {
if (!this.burnerWallet) {
throw Error('Wallet not connected');
}

if (_address !== this.burnerWallet.address.toString()) {
throw Error('Address not found for the connector');
}

const transactionRequest = await this.burnerWallet.sendTransaction(
transaction,
{ awaitExecution: true },
);

return transactionRequest.id;
}

async currentAccount(): Promise<string | null> {
if (!this.burnerWallet) {
throw Error('Wallet not connected');
}

return this.burnerWallet.address.toString() || null;
}

async addAssets(_assets: Asset[]): Promise<boolean> {
throw new Error('Method not implemented.');
}

async addAsset(_asset: Asset): Promise<boolean> {
throw new Error('Method not implemented.');
}

async assets(): Promise<Array<Asset>> {
return [];
}

async addNetwork(_networkUrl: string): Promise<boolean> {
throw new Error('Method not implemented.');
}

async selectNetwork(_network: Network): Promise<boolean> {
throw new Error('Method not implemented.');
}

async networks(): Promise<Network[]> {
return [await this.currentNetwork()];
}

async currentNetwork(): Promise<Network> {
const network = await this.burnerWalletProvider?.getNetwork();

return {
chainId: Number(network?.chainId),
url: this.burnerWalletProvider?.url ?? '',
};
}

async addAbi(_abiMap: AbiMap): Promise<boolean> {
throw new Error('Method not implemented.');
}

async getAbi(_contractId: string): Promise<JsonAbi> {
throw Error('Method not implemented.');
}

async hasAbi(_contractId: string): Promise<boolean> {
throw Error('Method not implemented.');
}
}
11 changes: 11 additions & 0 deletions packages/burner-wallet-connector/src/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export const BURNER_WALLET_ICON =
'data:image/svg+xml;utf8;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0Ny41IDQ3LjUiPjxkZWZzPjxjbGlwUGF0aCBpZD0iYSI+PHBhdGggZD0iTTAgMzhoMzhWMEgwdjM4WiIvPjwvY2xpcFBhdGg+PGNsaXBQYXRoIGlkPSJiIj48cGF0aCBkPSJNMTguNTgzIDI3LjgzM2MtMi45NTctLjIzMS01LjY2NiAyLjU0Mi00LjY2NiA3LjA0Mi0zLjIzOS0yLjM4Ni0zLjMzMi02LjQwMy0yLjMzMy05IDEuMDQxLTIuNzA4LS4wNDItNC45NTgtMi41ODQtNS4yMDgtMi44MzktLjI4LTQuNDE2IDMuMDQyLTIuOTYyIDguMzMzQTE2LjkzNiAxNi45MzYgMCAwIDEgMiAxOEMyIDguNjExIDkuNjExIDEgMTkgMXMxNyA3LjYxMSAxNyAxN2MwIDIuMDYzLS4zNjcgNC4wMzktMS4wNCA1Ljg2OC0uNDYtNS4zODgtMy4zMzMtOC4xNTctNi4zMzUtNi44NjgtMi44MTIgMS4yMDgtLjkxNyA1LjkxNy0uNzc3IDguMTY0LjIzNiAzLjgwOS0uMDEyIDguMTY5LTYuOTMxIDExLjc5NCAyLjg3NS01LjQ5OS4zMzMtOC45MTctMi4zMzQtOS4xMjUiLz48L2NsaXBQYXRoPjwvZGVmcz48ZyBjbGlwLXBhdGg9InVybCgjYSkiIHRyYW5zZm9ybT0ibWF0cml4KDEuMjUgMCAwIC0xLjI1IDAgNDcuNSkiPjxwYXRoIGZpbGw9IiNmNDkwMGMiIGQ9Ik0zNiAxOGMwIDIuMDYzLS4zNjcgNC4wMzktMS4wNCA1Ljg2OC0uNDYtNS4zODktMy4zMzMtOC4xNTctNi4zMzUtNi44NjgtMi44MTMgMS4yMDgtLjkxNyA1LjkxNy0uNzc3IDguMTY0LjIzNiAzLjgwOS0uMDEyIDguMTY5LTYuOTMxIDExLjc5NCAyLjg3NS01LjUuMzMzLTguOTE2LTIuMzM0LTkuMTI1LTIuOTU4LS4yMy01LjY2NiAyLjU0Mi00LjY2NiA3LjA0Mi0zLjIzOC0yLjM4Ni0zLjMzMy02LjQwMi0yLjMzNC05IDEuMDQyLTIuNzA4LS4wNDEtNC45NTgtMi41ODMtNS4yMDgtMi44MzktLjI4LTQuNDE3IDMuMDQxLTIuOTYyIDguMzMzQTE2LjkzNiAxNi45MzYgMCAwIDEgMiAxOEMyIDguNjExIDkuNjExIDEgMTkgMXMxNyA3LjYxMSAxNyAxNyIvPjwvZz48ZyBjbGlwLXBhdGg9InVybCgjYikiIHRyYW5zZm9ybT0ibWF0cml4KDEuMjUgMCAwIC0xLjI1IDAgNDcuNSkiPjxwYXRoIGZpbGw9IiNmZmNjNGQiIGQ9Ik0zMSA3YzAgMi4xODctLjU4NCA0LjIzNi0xLjYwNSA2LjAwMS4xNDctMy4wODQtMi41NjItNC4yOTMtNC4wMi0zLjcwOS0yLjEwNS44NDMtMS41NDEgMi4yOTEtMi4wODMgNS4yOTEtLjU0MiAzLTIuNjI1IDUuMDg0LTUuNzA5IDYgMi4yNS02LjMzMy0xLjI0Ny04LjY2Ny0zLjA4LTkuMDg0LTEuODcyLS40MjYtMy43NTMuMDAxLTMuOTY4IDQuMDA3QTExLjk2NyAxMS45NjcgMCAwIDEgNyA3QzcgLjM3MyAxMi4zNzMtNSAxOS01UzMxIC4zNzMgMzEgNyIvPjwvZz48L3N2Zz4=';

export const BETA_5_URL = 'https://beta-5.fuel.network/graphql';

export const HAS_WINDOW = typeof window !== 'undefined';
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
export const WINDOW: any = HAS_WINDOW ? window : {};

export const BURNER_WALLET_CONNECTED = 'burner-wallet-connected';
export const BURNER_WALLET_PRIVATE_KEY = 'burner-wallet-private-key';
1 change: 1 addition & 0 deletions packages/burner-wallet-connector/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './BurnerWalletConnector';
Loading

0 comments on commit fe8fe45

Please sign in to comment.