Skip to content

Commit

Permalink
Integrate MetaMask wallet usage (#91)
Browse files Browse the repository at this point in the history
* Implement use of signer from MetaMask wallet in browser (#87)

* Refactor chain service to use metamask signer

* Update signer before contract eth_call

* Add method to setup chain service with provider

* Remove old methods not required

* Export utilities required in mobymask app (#90)

* Export signEthereumMessage in nitro-client

* Wait on voucher after nitro pay

* Upgrade package versions

---------

Co-authored-by: Nabarun Gogoi <[email protected]>
  • Loading branch information
prathamesh0 and nikugogoi authored Jul 20, 2023
1 parent 2f56f16 commit 4dfb41e
Show file tree
Hide file tree
Showing 15 changed files with 188 additions and 78 deletions.
2 changes: 1 addition & 1 deletion lerna.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"$schema": "node_modules/lerna/schemas/lerna-schema.json",
"useWorkspaces": true,
"version": "0.1.2"
"version": "0.1.3"
}
8 changes: 5 additions & 3 deletions packages/example-web-app/package.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{
"name": "@cerc-io/example-web-app",
"version": "0.1.2",
"version": "0.1.3",
"private": true,
"dependencies": {
"@cerc-io/nitro-client": "^0.1.2",
"@cerc-io/nitro-client": "^0.1.3",
"@libp2p/crypto": "^1.0.4",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
Expand All @@ -20,6 +20,7 @@
"web-vitals": "^2.1.4"
},
"scripts": {
"analyze": "source-map-explorer 'build/static/js/*.js'",
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --watchAll=false",
Expand Down Expand Up @@ -47,6 +48,7 @@
"devDependencies": {
"eslint-config-react-app": "^7.0.1",
"eslint-config-semistandard": "^17.0.0",
"eslint-config-standard": "^17.0.0"
"eslint-config-standard": "^17.0.0",
"source-map-explorer": "^2.5.3"
}
}
4 changes: 2 additions & 2 deletions packages/nitro-client/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@cerc-io/nitro-client",
"version": "0.1.2",
"version": "0.1.3",
"main": "dist/index.js",
"license": "MIT",
"scripts": {
Expand Down Expand Up @@ -48,7 +48,7 @@
},
"dependencies": {
"@cerc-io/libp2p": "0.42.2-laconic-0.1.3",
"@cerc-io/nitro-util": "^0.1.2",
"@cerc-io/nitro-util": "^0.1.3",
"@cerc-io/peer": "^0.2.46",
"@cerc-io/ts-channel": "1.0.3-ts-nitro-0.1.1",
"@libp2p/crypto": "^1.0.4",
Expand Down
4 changes: 4 additions & 0 deletions packages/nitro-client/src/browser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ export { Allocation, AllocationType, Allocations } from './channel/state/outcome
export { Destination } from './types/destination';
export { Metrics, GetMetrics } from './client/engine/metrics';
export { LedgerChannelInfo, PaymentChannelInfo } from './client/query/types';
export { Voucher } from './payments/vouchers';
export {
Signature, recoverEthereumMessageSigner, getSignatureFromEthersSignature, signEthereumMessage,
} from './crypto/signatures';

export * as utils from './utils';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import assert from 'assert';
import { ethers } from 'ethers';
import { ethers, providers } from 'ethers';
import debug from 'debug';

import type { ReadChannel, ReadWriteChannel } from '@cerc-io/ts-channel';
import type { Log } from '@ethersproject/abstract-provider';
import Channel from '@cerc-io/ts-channel';
import { connectToChain, go, hex2Bytes } from '@cerc-io/nitro-util';
import { EthClient, go, hex2Bytes } from '@cerc-io/nitro-util';

import {
ChainService, ChainEvent, DepositedEvent, ConcludedEvent, AllocationUpdatedEvent,
Expand All @@ -20,6 +20,7 @@ import {
import * as NitroAdjudicatorConversions from './adjudicator/typeconversions';

import { getChainHolding } from './eth-chain-helpers';
import { connectToChain } from './utils/utils';

const log = debug('ts-nitro:eth-chain-service');

Expand All @@ -44,7 +45,7 @@ interface EthChain {
// Following Interfaces in Go have been implemented using EthClient.provider (ethers Provider)
// bind.ContractBackend (github.com/ethereum/go-ethereum/accounts/abi/bind)
// ethereum.TransactionReader (github.com/ethereum/go-ethereum)
provider: ethers.providers.JsonRpcProvider
provider: ethers.providers.BaseProvider

chainID (): Promise<bigint>;
}
Expand Down Expand Up @@ -119,6 +120,25 @@ export class EthChainService implements ChainService {
return EthChainService._newEthChainService(ethClient, na, naAddress, caAddress, vpaAddress, txSigner, logDestination);
}

static async newEthChainServiceWithProvider(
provider: providers.JsonRpcProvider,
naAddress: Address,
caAddress: Address,
vpaAddress: Address,
logDestination?: WritableStream,
): Promise<EthChainService> {
if (vpaAddress === caAddress) {
throw new Error(`virtual payment app address and consensus app address cannot be the same: ${vpaAddress}`);
}

const ethClient = new EthClient(provider);
const txSigner = provider.getSigner();

const na = NitroAdjudicator__factory.connect(naAddress, txSigner);

return EthChainService._newEthChainService(ethClient, na, naAddress, caAddress, vpaAddress, txSigner, logDestination);
}

// _newEthChainService constructs a chain service that submits transactions to a NitroAdjudicator
// and listens to events from an eventSource
private static _newEthChainService(
Expand Down Expand Up @@ -160,6 +180,9 @@ export class EthChainService implements ChainService {

// sendTransaction sends the transaction and blocks until it has been submitted.
async sendTransaction(tx: ChainTransaction): Promise<void> {
assert(this.txSigner, 'txSigner not assigned in chainservice');
this.na = this.na.connect(this.txSigner);

switch (tx.constructor) {
case DepositTransaction: {
const depositTx = tx as DepositTransaction;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { ethers } from 'ethers';
import { Buffer } from 'buffer';

import { EthClient } from '@cerc-io/nitro-util';

// connectToChain connects to the chain at the given url and returns a client and a transactor.
export async function connectToChain(chainUrl: string, chainPK: Buffer): Promise<[EthClient, ethers.Signer]> {
const client = await EthClient.dial(chainUrl);

const txSigner = new ethers.Wallet(chainPK, client.provider);

return [client, txSigner];
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ import type { ReadChannel, ReadWriteChannel } from '@cerc-io/ts-channel';
// @ts-expect-error
import type { Libp2p } from '@cerc-io/libp2p';
// @ts-expect-error
import { PeerInitConfig } from '@cerc-io/peer';
// @ts-expect-error
import type { PrivateKey } from '@libp2p/interface-keys';
// @ts-expect-error
import type { Stream, Connection } from '@libp2p/interface-connection';
Expand Down
4 changes: 3 additions & 1 deletion packages/nitro-client/src/node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ export { Destination } from './types/destination';
export { Metrics, GetMetrics } from './client/engine/metrics';
export { LedgerChannelInfo, PaymentChannelInfo } from './client/query/types';
export { Voucher } from './payments/vouchers';
export { Signature, recoverEthereumMessageSigner, getSignatureFromEthersSignature } from './crypto/signatures';
export {
Signature, recoverEthereumMessageSigner, getSignatureFromEthersSignature, signEthereumMessage,
} from './crypto/signatures';

export * as utils from './utils';
22 changes: 2 additions & 20 deletions packages/nitro-client/src/utils/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ import { JSONbigNative, bytes2Hex } from '@cerc-io/nitro-util';
import { P2PMessageService } from '../client/engine/messageservice/p2p-message-service/service';
import { Client } from '../client/client';
import { Store } from '../client/engine/store/store';
import { EthChainService } from '../client/engine/chainservice/eth-chainservice';
import { PermissivePolicy } from '../client/engine/policy-maker';
import { Metrics } from '../client/engine/metrics';
import { SingleAssetExit, Exit } from '../channel/state/outcome/exit';
import { Allocation, AllocationType, Allocations } from '../channel/state/outcome/allocation';
import { Destination } from '../types/destination';
import { Signature } from '../crypto/signatures';
import { ChainService } from '../client/engine/chainservice/chainservice';

const log = debug('ts-nitro:util:helpers');

Expand All @@ -26,27 +26,9 @@ const log = debug('ts-nitro:util:helpers');
export async function setupClient(
messageService: P2PMessageService,
store: Store,
options: {
chainPk: string,
chainURL: string,
contractAddresses: { [key: string]: string },
},
chainService: ChainService,
metricsApi?: Metrics,
): Promise<Client> {
const {
chainPk,
chainURL,
contractAddresses,
} = options;

const chainService = await EthChainService.newEthChainService(
chainURL,
chainPk,
contractAddresses.nitroAdjudicatorAddress,
contractAddresses.consensusAppAddress,
contractAddresses.virtualPaymentAppAddress,
);

const client = await Client.new(
messageService,
chainService,
Expand Down
73 changes: 59 additions & 14 deletions packages/nitro-client/src/utils/nitro.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import debug from 'debug';
import { providers } from 'ethers';

import { hex2Bytes } from '@cerc-io/nitro-util';
// @ts-expect-error
Expand All @@ -11,8 +12,11 @@ import { MemStore } from '../client/engine/store/memstore';
import { DurableStore } from '../client/engine/store/durablestore';
import { Destination } from '../types/destination';
import { LedgerChannelInfo, PaymentChannelInfo } from '../client/query/types';
import { EthChainService } from '../client/engine/chainservice/eth-chainservice';

import { createOutcome, setupClient, subscribeVoucherLogs } from './helpers';
import { ChainService } from '../client/engine/chainservice/chainservice';
import { Voucher } from '../payments/vouchers';

const log = debug('ts-nitro:util:nitro');

Expand All @@ -24,12 +28,16 @@ export class Nitro {

msgService: P2PMessageService;

chainService: ChainService;

constructor(
client: Client,
msgService: P2PMessageService,
chainService: ChainService,
) {
this.client = client;
this.msgService = msgService;
this.chainService = chainService;
}

static async setupClient(
Expand All @@ -40,27 +48,59 @@ export class Nitro {
peer: Peer,
location?: string,
): Promise<Nitro> {
let store: Store;
if (location) {
store = DurableStore.newDurableStore(hex2Bytes(pk), location);
} else {
store = new MemStore(hex2Bytes(pk));
}
const store = this.getStore(pk, location);
const msgService = await P2PMessageService.newMessageService(store.getAddress(), peer);

const chainService = await EthChainService.newEthChainService(
chainURL,
chainPk,
contractAddresses.nitroAdjudicatorAddress,
contractAddresses.consensusAppAddress,
contractAddresses.virtualPaymentAppAddress,
);

const client = await setupClient(
msgService,
store,
chainService,
);

subscribeVoucherLogs(client);
return new Nitro(client, msgService, chainService);
}

static async setupClientWithProvider(
pk: string,
provider: providers.JsonRpcProvider,
contractAddresses: { [key: string]: string },
peer: Peer,
location?: string,
): Promise<Nitro> {
const store = this.getStore(pk, location);
const msgService = await P2PMessageService.newMessageService(store.getAddress(), peer);

const chainService = await EthChainService.newEthChainServiceWithProvider(
provider,
contractAddresses.nitroAdjudicatorAddress,
contractAddresses.consensusAppAddress,
contractAddresses.virtualPaymentAppAddress,
);

const client = await setupClient(
msgService,
store,
{
chainPk,
chainURL,
contractAddresses,
},
chainService,
);

subscribeVoucherLogs(client);
return new Nitro(client, msgService);
return new Nitro(client, msgService, chainService);
}

private static getStore(pk: string, location?: string): Store {
if (location) {
return DurableStore.newDurableStore(hex2Bytes(pk), location);
}
return new MemStore(hex2Bytes(pk));
}

static async clearClientStorage(): Promise<boolean> {
Expand All @@ -84,7 +124,7 @@ export class Nitro {
return [true, `Peer with address ${address} is dialable`];
}

async directFund(counterParty: string, amount: number): Promise<void> {
async directFund(counterParty: string, amount: number): Promise<string> {
const outcome = createOutcome(
ASSET,
this.client.address,
Expand All @@ -100,6 +140,8 @@ export class Nitro {

await this.client.objectiveCompleteChan(response.id).shift();
log(`Ledger channel created with id ${response.channelId.string()}\n`);

return response.channelId.string();
}

async virtualFund(counterParty: string, amount: number): Promise<void> {
Expand All @@ -122,9 +164,12 @@ export class Nitro {
log(`Virtual payment channel created with id ${response.channelId.string()}\n`);
}

async pay(virtualPaymentChannel: string, amount: number): Promise<void> {
async pay(virtualPaymentChannel: string, amount: number): Promise<Voucher> {
const virtualPaymentChannelId = new Destination(virtualPaymentChannel);
await this.client.pay(virtualPaymentChannelId, BigInt(amount));
const sentVoucher = await this.client.sentVouchers().shift();

return sentVoucher;
}

async virtualDefund(virtualPaymentChannel: string): Promise<void> {
Expand Down
2 changes: 1 addition & 1 deletion packages/nitro-util/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@cerc-io/nitro-util",
"version": "0.1.2",
"version": "0.1.3",
"main": "dist/index.js",
"license": "MIT",
"scripts": {
Expand Down
15 changes: 3 additions & 12 deletions packages/nitro-util/src/eth-client.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
import assert from 'assert';
import { ethers, providers, EventFilter } from 'ethers';
import { Buffer } from 'buffer';

export class EthClient {
provider: providers.JsonRpcProvider;
provider: providers.BaseProvider;

constructor(provider: providers.JsonRpcProvider) {
constructor(provider: providers.BaseProvider) {
this.provider = provider;
}

static async dial(chainUrl: string): Promise<EthClient> {
static dial(chainUrl: string): EthClient {
// Connect to the Ethereum provider
const provider = new ethers.providers.JsonRpcProvider(chainUrl);
return new EthClient(provider);
Expand Down Expand Up @@ -44,11 +43,3 @@ export class EthClient {
return listener;
}
}

// connectToChain connects to the chain at the given url and returns a client and a transactor.
export async function connectToChain(chainUrl: string, chainPK: Buffer): Promise<[EthClient, ethers.Signer]> {
const client = await EthClient.dial(chainUrl);
const txSigner = new ethers.Wallet(chainPK, client.provider);

return [client, txSigner];
}
Loading

0 comments on commit 4dfb41e

Please sign in to comment.