Skip to content
This repository has been archived by the owner on Dec 26, 2024. It is now read-only.

Commit

Permalink
Merge pull request #10 from abstraction-hq/develop
Browse files Browse the repository at this point in the history
Support  EIP-5792, Add RPC Provider.
  • Loading branch information
imduchuyyy authored Jul 25, 2024
2 parents c6fd4ce + 22048df commit 033fda0
Show file tree
Hide file tree
Showing 14 changed files with 339 additions and 79 deletions.
92 changes: 82 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
Abstraction wallet SDK allow developers connect their Dapps to Abstraction Wallet via EIP-6963

## Install Abstraction Wallet SDK

```sh
# yarn
yarn add @abstraction-hq/wallet-skd
Expand All @@ -14,25 +15,96 @@ npm install @abstraction-hq/wallet-sdk
```

## Basic Usage
### Use with EIP-6963
1. Initialize Wallet

### Init provider with EIP-6963

```typescript
import { initAbstractionWallet } from "@abstraction-hq/wallet-sdk"
import { initAbstractionWallet } from "@abstraction-hq/wallet-sdk";

initAbstractionWallet()
initAbstractionWallet();
```

### Use with Provider
1. Create provider
### Create provider

```typescript
import { createAbstractionProvider } from "@abstraction-hq/wallet-sdk"
import { createAbstractionProvider } from "@abstraction-hq/wallet-sdk";

const provider = createAbstractionProvider()
const provider = createAbstractionProvider();
```

2 Use provider
### Use provider
1. Connect Wallet

```typescript
const addresses = provider.request({
method: 'eth_requestAccounts',
method: "eth_requestAccounts",
});
```

2. Send Transaction

```typescript
const txHash = await(window as any).abstraction.request({
method: "eth_sendTransaction",
params: [
{
from: address,
to: address,
value: 0,
data,
},
],
});
```

3. Sending multiple calls
```typescript
const userOpHash = await(window as any).abstraction.request({
method: "wallet_sendCalls",
params: [
{
version: "1.0",
chainId: "0x58",
from: "0xd46e8dd67c5d32be8058bb8eb970870f07244567",
calls: [
{
to: "0xd46e8dd67c5d32be8058bb8eb970870f07244567",
value: "0x9184e72a",
data: "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675"
},
{
to: "0xd46e8dd67c5d32be8058bb8eb970870f07244567",
value: "0x9184e72a",
data: "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675"
},
]
}
],
});
```

4. Get call status
```typescript
const callStatus = await(window as any).abstraction.request({
method: "wallet_getCallsStatus",
params: [
userOpHash
],
});
```


5. Create contract
```typescript
const txHash = await(window as any).abstraction.request({
method: "eth_sendTransaction",
params: [
{
from: address,
value: 0,
data: CONTRACT_BYTECODE,
},
],
salt: // Salt to create contract with create2 - account.nonce() if not provide
});
```
3 changes: 3 additions & 0 deletions constants/address.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { Address } from "viem";

export const FACTORY: Address = "0xbC82703bDbE098773059957837016b8CA7374992"
23 changes: 23 additions & 0 deletions constants/chain.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { defineChain } from "viem";

export const NETWORKS = "mainnet"

export const mainnet = defineChain({
id: 88,
name: "Viction Mainnet",
nativeCurrency: {
decimals: 18,
name: "Viction",
symbol: "VIC",
},
rpcUrls: {
default: {
http: ["https://rpc.viction.xyz"],
webSocket: ["wss://ws.viction.xyz"],
},
},
blockExplorers: {
default: { name: "Explorer", url: "https://vicscan.xyz" },
},
testnet: true,
});
4 changes: 4 additions & 0 deletions constants/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
export * from "./supportedMethod"
export * from "./chain"
export * from "./address"

export const KEY_URL = "https://wallet.abstraction.world"
export const BUNDLER_URL = "https://wallet.abstraction.world/bundler"
3 changes: 2 additions & 1 deletion constants/supportedMethod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ export const supportedMethods: any = {
],
state: [
// internal state
'eth_chainId',
// 'eth_chainId',
'wallet_getCallsStatus',
'eth_accounts',
'eth_coinbase',
'net_version',
Expand Down
14 changes: 8 additions & 6 deletions index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { IProvider } from "./types/provider/provider";
import { IProvider, ProviderInput, EIP6963ProviderInfo } from "./types";
import { AbstractionProvider } from "./provider";
import { EIP6963ProviderInfo } from "./types/provider/eip6963";

const announceProvider: Function = (provider: IProvider) => {
const info: EIP6963ProviderInfo = {
Expand All @@ -19,19 +18,22 @@ const announceProvider: Function = (provider: IProvider) => {
window.removeEventListener("eip6963:requestProvider", () => {})
};

const initAbstractionWallet: Function = (keyUrl?: string) => {
const provider = new AbstractionProvider(keyUrl);
const initAbstractionWallet: Function = (providerInput?: ProviderInput) => {
const provider = new AbstractionProvider(providerInput);
window.addEventListener("eip6963:requestProvider", () => {
announceProvider(provider);
});
};

const createAbstractionProvider: Function = (keyUrl?: string): IProvider => {
const provider = new AbstractionProvider(keyUrl);
const createAbstractionProvider: Function = (providerInput?: ProviderInput): IProvider => {
const provider = new AbstractionProvider(providerInput);
return provider;
};

export { initAbstractionWallet, createAbstractionProvider };

export * from "./communicator"
export * from "./types"
export * from "./constants"
export * from "./provider"
export * from "./utils"
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"dependencies": {
"@types/chai": "^4.3.16",
"@types/mocha": "^10.0.7",
"axios": "^1.7.2",
"chai": "^5.1.1",
"eventemitter3": "^5.0.1",
"mocha": "^10.6.0",
Expand Down
40 changes: 27 additions & 13 deletions provider.ts → provider/index.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
import EventEmitter from "eventemitter3";
import { Address, toHex } from "viem";
import { Communicator } from "./communicator/communicator";
import { supportedMethods } from "./constants/supportedMethod";
import { Communicator } from "../communicator/communicator";
import { supportedMethods } from "../constants/supportedMethod";
import {
MethodCategory,
RequestArguments,
IProvider,
} from "./types/provider/provider";
import { Message } from "./types/communicator/message";
import { getFavicon } from "./utils/getIcon";
ProviderInput,
} from "../types";
import { Message } from "../types";
import { getFavicon } from "../utils/getIcon";
import RPCProvider from "./rpcProvider";
import { BUNDLER_URL } from "../constants";
import axios from "axios";

function determineMethodCategory(method: string): MethodCategory | undefined {
for (const c in supportedMethods) {
Expand All @@ -21,22 +25,23 @@ function determineMethodCategory(method: string): MethodCategory | undefined {
}

export class AbstractionProvider extends EventEmitter implements IProvider {
public rpcProvider: RPCProvider;
communicator: Communicator;
accounts: Address[] = [];
isAbstractionWallet: boolean = true;
chainId: number = 89;

constructor(keyUrl?: string) {
constructor(providerInput?: ProviderInput) {
super();
this.communicator = new Communicator(null, keyUrl);
this.communicator = new Communicator(null, providerInput?.keyUrl);
this.rpcProvider = new RPCProvider(providerInput?.rpcInput);
}

public get connected() {
return this.accounts.length > 0;
}

public async request<T>(args: RequestArguments): Promise<T> {
console.log("request", toHex(this.chainId));
const methodCategory = determineMethodCategory(args.method) ?? "fetch";
return (this.handlers as any)[methodCategory](args) as unknown as T;
}
Expand Down Expand Up @@ -69,7 +74,7 @@ export class AbstractionProvider extends EventEmitter implements IProvider {

if (handshakeResponse.payload == "rejected") {
reject("User rejected the connection");
return
return;
}

this.accounts = handshakeResponse.payload as Address[];
Expand Down Expand Up @@ -100,22 +105,31 @@ export class AbstractionProvider extends EventEmitter implements IProvider {
);
if (signResponse.payload == "rejected") {
reject("User rejected the connection");
return
return;
}
resolve(signResponse.payload);
});
},
fetch: async (args: RequestArguments) => {},
fetch: async (args: RequestArguments) => {
return this.rpcProvider.requestRPC(args);
},
state: async (args: RequestArguments) => {
switch (args.method) {
case "eth_chainId":
return toHex(this.chainId);
case "eth_accounts":
return this.accounts;
case "eth_coinbase":
return this.accounts[0];
case "net_version":
return "0x1";
case "wallet_getCallsStatus":
const data = {
jsonrpc: "2.0",
id: 1,
method: "eth_getUserOperationReceipt",
params: args.params,
};
const response = await axios.post(BUNDLER_URL, data);
return response.data
default:
return undefined;
}
Expand Down
48 changes: 48 additions & 0 deletions provider/rpcProvider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { RPCProviderInput } from "../types";
import { mainnet } from "../constants";
import { Chain, createPublicClient, defineChain, http, PublicClient } from "viem";

export default class RPCProvider {
ethClient: PublicClient;

constructor(input?: RPCProviderInput) {
let chain: Chain;
if (input) {
chain = defineChain({
id: 88,
name: "Viction Mainnet",
nativeCurrency: {
decimals: 18,
name: "Viction",
symbol: "VIC",
},
rpcUrls: {
default: {
http: [input.rpcUrl, "https://rpc.viction.xyz"],
webSocket: [input.wsUrl, "wss://ws.viction.xyz"],
},
},
blockExplorers: {
default: { name: "Explorer", url: "https://vicscan.xyz" },
},
testnet: false,
})
} else {
chain = mainnet
}

// @ts-ignore
this.ethClient = createPublicClient({
chain: chain,
transport: http()
}) as PublicClient
}

public async requestRPC(args: any) {
return this.ethClient.request(args)
}

public async getClient() {
return this.ethClient
}
}
27 changes: 25 additions & 2 deletions tests/provider.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { createAbstractionProvider } from "../index";
import { createAbstractionProvider, IProvider } from "../index";

describe("Provider", () => {
it("Can create provider", async () => {
Expand All @@ -8,7 +8,30 @@ describe("Provider", () => {

it("Should override KeyURL", async() => {
const keyUrl = "https://example.com";
const provider = createAbstractionProvider(keyUrl);
const provider = createAbstractionProvider({
keyUrl
});
console.log(provider)
})

it("Can request rpc", async () => {
const provider: IProvider = createAbstractionProvider();
console.log(provider.rpcProvider)
const transaction = await provider.request({
method: "eth_chainId",
params: []
})

console.log(transaction)
})

it("Get call status", async () => {
const provider: IProvider = createAbstractionProvider();
const callStatus = await provider.request({
method: "wallet_getCallsStatus",
params: ["0x6b4f1165bfee4d6164ab44f52bd9e5bfa40da28491a33960ad9952aa3f202799"]
})

console.log(callStatus)
})
})
Loading

0 comments on commit 033fda0

Please sign in to comment.