Skip to content
This repository has been archived by the owner on Mar 16, 2023. It is now read-only.

Commit

Permalink
feat(sdk): check apiKey quota to render view of proper steps
Browse files Browse the repository at this point in the history
  • Loading branch information
LeilaWang committed Feb 1, 2020
1 parent 9e30e67 commit 1ee399f
Show file tree
Hide file tree
Showing 20 changed files with 276 additions and 240 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import {
} from '@openzeppelin/gsn-provider';
import Web3Service from '~/helpers/Web3Service';
import retrieveSigningInfo from '~/utils/retrieveSigningInfo';
import approveFunction from '~/utils/approveGSNFunction';
import { getProviderUrl } from '~/utils/network';
import makeApproveFunction from './makeApproveFunction';

const sendTransaction = async (query, connection) => {
const {
Expand All @@ -25,7 +25,7 @@ const sendTransaction = async (query, connection) => {
const gsnProvider = new GSNProvider(providerUrl, {
pollInterval: 1 * 1000,
signKey: signingInfo.privateKey,
approveFunction: approveFunction(query, connection),
approveFunction: makeApproveFunction(query, connection),
});
const receipt = await Web3Service
.useContract(contract)
Expand Down Expand Up @@ -53,8 +53,6 @@ const sendTransaction = async (query, connection) => {
}
};

// TODO change this to use the gas station network

export default {
sendTransaction,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import ClientActionService from '~/background/services/ClientActionService';
import {
actionRequestEvent,
} from '~/config/event';

export default function makeApproveFunction(query, connection) {
return async ({
from,
to,
encodedFunctionCall,
txFee,
gasPrice,
gas,
nonce,
relayerAddress,
relayHubAddress,
}) => {
const params = {
from,
to,
encodedFunctionCall,
txFee,
gasPrice,
gas,
nonce,
relayerAddress,
relayHubAddress,
};

const response = await ClientActionService.triggerClientAction({
...query,
data: {
type: actionRequestEvent,
action: 'apiKeyApproval',
params,
},
}, connection);

return response.data.approvalData;
};
}
70 changes: 50 additions & 20 deletions packages/extension/src/client/services/ConnectionService/index.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import {
mergeMap,
filter,
tap,
take,
} from 'rxjs/operators';
import {
Subject,
fromEvent,
from,
} from 'rxjs';
import {
randomId,
Expand All @@ -33,6 +31,8 @@ import {
import MetaMaskService from '~/client/services/MetaMaskService';
import ApiError from '~/client/utils/ApiError';
import getSiteData from '~/client/utils/getSiteData';
import getApiKeyQuota from '~/client/utils/getApiKeyQuota';
import getApiKeyApproval from '~/client/utils/getApiKeyApproval';
import backgroundFrame from './backgroundFrame';

class ConnectionService {
Expand All @@ -42,6 +42,7 @@ class ConnectionService {
}

setInitialVars() {
this.apiKey = '';
this.port = null;
this.MessageSubject = null;
this.messages$ = null;
Expand Down Expand Up @@ -71,6 +72,11 @@ class ConnectionService {
}

async openConnection(clientProfile) {
const {
apiKey,
} = clientProfile;
this.apiKey = apiKey;

const frame = await backgroundFrame.init();

const backgroundResponse = fromEvent(window, 'message')
Expand Down Expand Up @@ -116,28 +122,52 @@ class ConnectionService {
case subscriptionResponseEvent:
this.handleReceiveSubscription(data.response);
break;
case actionRequestEvent:
this.handleClientActionRequest(data);
break;
case clientResponseEvent:
this.handleReceiveResponse(data);
break;
default:
this.MessageSubject.next(data);
}
};
}

this.messages$.pipe(
filter(({ type }) => type === actionRequestEvent),
mergeMap(data => from(MetaMaskService(data))),
tap(({
requestId,
responseId,
response,
}) => this.port.postMessage({
type: actionResponseEvent,
origin: window.location.origin,
clientId: this.clientId,
sender: 'WEB_CLIENT',
requestId,
responseId,
data: response,
})),
).subscribe();
handleReceiveResponse(data) {
this.MessageSubject.next(data);
}

async handleClientActionRequest(data) {
const {
requestId,
responseId,
data: {
action,
params,
},
} = data;
let response;

switch (action) {
case 'apiKeyQuota':
response = await getApiKeyQuota(this.apiKey);
break;
case 'apiKeyApproval':
response = await getApiKeyApproval(this.apiKey, params);
break;
default:
response = await MetaMaskService(action, params);
}

this.port.postMessage({
type: actionResponseEvent,
origin: window.location.origin,
clientId: this.clientId,
sender: 'WEB_CLIENT',
requestId,
responseId,
data: response,
});
}

async postToBackground({
Expand Down
45 changes: 4 additions & 41 deletions packages/extension/src/client/services/MetaMaskService/index.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
import ethSigUtil from 'eth-sig-util';
import * as ethUtil from 'ethereumjs-util';
import Web3Service from '~/client/services/Web3Service';
import {
SIGNING_PROVIDER,
} from '~/config/constants';
import registerExtension, { generateTypedData } from './registerExtension';
import signNote from './signNote';
import signProof from './signProof';


const handleAction = async (action, params) => {
let response = {};
const { address } = Web3Service.account;
Expand All @@ -30,32 +26,6 @@ const handleAction = async (action, params) => {
.send(...data);
break;
}
case 'gsn.sign.transaction': {
const {
apiKey,
networkId,
...data
} = params;
const result = await window.fetch(`${SIGNING_PROVIDER}/Stage/${networkId}/${apiKey}`, {
method: 'POST', // *GET, POST, PUT, DELETE, etc.
mode: 'cors', // no-cors, *cors, same-origin
cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
credentials: 'same-origin', // include, *same-origin, omit
headers: {
'Content-Type': 'application/json',
// 'Content-Type': 'application/x-www-form-urlencoded',
},
body: JSON.stringify({ data }), // body data type must match "Content-Type" header
});
const {
data: {
approvalData,
},
} = await result.json();

response = { approvalData };
break;
}
case 'metamask.register.extension': {
const eip712Data = registerExtension(params);
const method = 'eth_signTypedData_v4';
Expand Down Expand Up @@ -137,14 +107,10 @@ const handleAction = async (action, params) => {
return response;
};

export default async function MetaMaskService(query) {
export default async function MetaMaskService(action, params) {
let response;
let error;
try {
const {
action,
params,
} = query.data;
response = await handleAction(action, params);
({
error,
Expand All @@ -154,11 +120,8 @@ export default async function MetaMaskService(query) {
}

return {
...query,
response: {
...response,
error,
success: !error,
},
...response,
error,
success: !error,
};
}
44 changes: 44 additions & 0 deletions packages/extension/src/client/utils/getApiKeyApproval.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import urls from '~/config/urls';
import {
warnLog,
} from '~/utils/log';
import {
formatStrPattern,
} from '~/utils/format';
import Web3Service from '~/client/services/Web3Service';

const urlPattern = urls.apiKeyQuota;

export default async function getApiKeyApproval(apiKey, data) {
const {
networkId,
} = Web3Service;
const url = formatStrPattern(urlPattern, {
apiKey,
networkId,
});

let approvalData = null;
try {
const result = await fetch(url, {
method: 'POST',
mode: 'cors',
cache: 'no-cache',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ data }),
});
({
data: {
approvalData,
},
} = await result.json());
} catch (e) {
warnLog('Failed to get apiKey approval.', e);
}

return {
approvalData,
};
}
40 changes: 40 additions & 0 deletions packages/extension/src/client/utils/getApiKeyQuota.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import urls from '~/config/urls';
import {
warnLog,
} from '~/utils/log';
import {
formatStrPattern,
} from '~/utils/format';
import Web3Service from '~/client/services/Web3Service';

const urlPattern = urls.apiKeyQuota;

export default async function getApiKeyQuota(apiKey) {
const {
networkId,
} = Web3Service;
const url = formatStrPattern(urlPattern, {
apiKey,
networkId,
});

let hasFreeTransactions = false;
try {
const result = await fetch(url, {
method: 'GET',
mode: 'cors',
cache: 'no-cache',
});
({
data: {
hasFreeTransactions,
},
} = await result.json());
} catch (e) {
warnLog('Failed to get apiKey quota.', e);
}

return {
hasFreeTransactions: hasFreeTransactions || false,
};
}
1 change: 0 additions & 1 deletion packages/extension/src/config/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ export const AZTEC_JS_METADATA_PREFIX_LENGTH = 130;
export const START_EVENTS_SYNCING_BLOCK = 0;

export const INFURA_API_KEY = '09c4eed231c840d5ace14ba5389a1a7c';
export const SIGNING_PROVIDER = 'https://bv9t4hwozi.execute-api.us-east-1.amazonaws.com';

export const NOTE_STATUS = {
CREATED: 'CREATED',
Expand Down
4 changes: 4 additions & 0 deletions packages/extension/src/config/urls.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
const apiKeyQuota = 'https://bv9t4hwozi.execute-api.us-east-1.amazonaws.com/Stage/{networkId}/{apiKey}';

const production = {
origin: 'https://sdk.aztecprotocol.com',
public: 'https://sdk.aztecprotocol.com/{version}/sdk/public',
background: 'https://sdk.aztecprotocol.com/{version}/sdk/background.html',
ui: 'https://sdk.aztecprotocol.com/{version}/sdk/ui.html',
apiKeyQuota,
};

const development = {
origin: 'http://localhost:5555',
public: 'http://localhost:5555/sdk/public',
background: 'http://localhost:5555/sdk/public/background.html',
ui: 'http://localhost:5555/sdk/public/ui.html',
apiKeyQuota,
};

const config = process.env.NODE_ENV === 'production'
Expand Down
Loading

0 comments on commit 1ee399f

Please sign in to comment.