Skip to content

Commit

Permalink
Merge pull request #39 from dcSpark/fix-event-emit
Browse files Browse the repository at this point in the history
Fix event emit on connect
  • Loading branch information
SebastienGllmt authored Jan 13, 2024
2 parents 061ba93 + 2cbc6d8 commit 0f7080f
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 4 deletions.
2 changes: 2 additions & 0 deletions docs/developers.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ The provider customizes few json-rpc methods like `eth_sendTransaction`, `eth_re
```typescript
const oldProvider = window.ethereum;
const provider = await import("provider");
// this is the EIP-1193 compatible provider
// it will internally try to override `window.ethereum` and emit an EIP-6963 event
const injectedProvider = provider.inject(oracleUrl, nodeUrl);
await injectedProvider.setup();
```
Expand Down
12 changes: 12 additions & 0 deletions packages/dapp-example/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const App = () => {
const injectedProvider = provider
.injectCardano("http://localhost:8080", "https://rpc-devnet-cardano-evm.c1.milkomeda.com");
setInjectedProvider(injectedProvider);
injectedProvider.on('connect', (connectInfo) => { console.log(connectInfo); });
await injectedProvider.setup(1);

alert("Injected");
Expand All @@ -23,6 +24,7 @@ const App = () => {
const injectedProvider = provider
.injectAlgorand("http://localhost:8080", "https://rpc-devnet-cardano-evm.c1.milkomeda.com");
setInjectedProvider(injectedProvider);
injectedProvider.on('connect', (connectInfo) => { console.log(connectInfo); });
await injectedProvider.setup();

alert("Injected");
Expand Down Expand Up @@ -57,6 +59,13 @@ const App = () => {
alert(blockNumber);
};

const eth_chainId = async () => {
if (injectedProvider == null) alert("Provider not injected");
const provider = new ethers.providers.Web3Provider(injectedProvider);
const networkInfo = await provider.getNetwork();
alert(networkInfo.chainId);
};

const eth_getBalance = async () => {
if (injectedProvider == null) alert("Provider not injected");
const provider = new ethers.providers.Web3Provider(injectedProvider);
Expand Down Expand Up @@ -128,6 +137,9 @@ const App = () => {
<div>
<button onClick={eth_blockNumber}>eth_blockNumber</button>
</div>
<div>
<button onClick={eth_chainId}>eth_chainId</button>
</div>
<div>
<button onClick={eth_getBalance}>eth_getBalance</button>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const InputSchema = z.union([
]);

/**
* @dev Wraps the eth transaction to the Actor transaction, signs using algorand wallet
* @dev Wraps the eth transaction to the Actor transaction, signs using Algorand wallet
* and sends it to the oracle.
*/
const eth_sendTransaction: CustomMethod = async (
Expand Down
2 changes: 2 additions & 0 deletions packages/milkomeda-wsc-provider/src/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ export class ProviderRpcError extends Error {
}

export const JSON_RPC_ERROR_CODES = {
// error codes below from the EIP-1474 standards
// https://eips.ethereum.org/EIPS/eip-1474
PARSE_ERROR: -32700,
INVALID_REQUEST: -32600,
METHOD_NOT_FOUND: -32601,
Expand Down
31 changes: 28 additions & 3 deletions packages/milkomeda-wsc-provider/src/provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,22 @@ export type ProviderType = (typeof PROVIDER_TYPES)[keyof typeof PROVIDER_TYPES];
* params: [],
* })
* ```
*
* Or listen to events
* ```ts
* provider.on('connect', (connectInfo) => { console.log(connectInfo); });
* ```
*
* *Note*: we extend `EventEmitter` instead of forwarding listeners to the underlying RPC.
* This is because out of all the events defined in EIP-1193,
* the only only relevant to WSCs is the `connect` event emission
* which is native to the WSC and not the underlying provider
*/
class Provider extends EventEmitter implements MilkomedaProvider {
/**
* Events that need to be handled explicitly by the WSC
* Instead of simply being forwarded to the underlying RPC
*/
private readonly methods: { [key: string]: CustomMethod };

public readonly peraWallet: PeraWalletConnect | undefined;
Expand Down Expand Up @@ -59,12 +73,18 @@ class Provider extends EventEmitter implements MilkomedaProvider {
method: "eth_actorFactoryAddress",
params: [actorVersion],
});

this.actorVersion = actorVersion;

// required to emit `connect` as per EIP1193
// https://eips.ethereum.org/EIPS/eip-1193#connect-1
this.emit("connect");
// note: although the spec says this is required, it looks like this isn't well supported:
// 1) Some providers like MetaMask follow the spec (https://github.com/MetaMask/providers/blob/126a8c868785eb088511769cd532a72072662369/src/BaseProvider.ts#L323)
// 2) Some emit the event without a chainID (https://github.com/floating/eth-provider/blob/69184e9b4101e09e39dd391aef5b1c620a63e147/connections/ws.js#L41)
// 3) Some emit no event at all (seemingly HardHat as of Jan 2024)
const chainId = (await this.request({
method: "eth_chainId",
})) as string;
this.emit("connect", { chainId });
}

async changeActorVersion(actorVersion: number): Promise<void> {
Expand All @@ -76,10 +96,11 @@ class Provider extends EventEmitter implements MilkomedaProvider {
* https://eips.ethereum.org/EIPS/eip-1193#request-1
*/
async request(payload: RequestArguments): Promise<unknown> {
// 1) Check if this is a method that requires special support to work with WSC
if (payload.method in this.methods) {
return this.methods[payload.method](this, payload);
}

// 2) Otherwise, just forward it to the underlying provider
return this.providerRequest(payload);
}

Expand All @@ -91,6 +112,10 @@ class Provider extends EventEmitter implements MilkomedaProvider {
return this.jsonRpcRequest<T>(this.jsonRpcProviderUrl, payload);
}

/**
* Implementation of the JSON-RPC API
* See https://eips.ethereum.org/EIPS/eip-1474
*/
private async jsonRpcRequest<T>(url: string, payload: RequestArguments): Promise<T> {
const response = await fetch(url, {
method: "POST",
Expand Down

0 comments on commit 0f7080f

Please sign in to comment.