Skip to content

Commit

Permalink
Merge pull request #130 from gnosisguild/sign-typed-data
Browse files Browse the repository at this point in the history
handle wallet signature requests and improve simulations
  • Loading branch information
jfschwarz authored Aug 14, 2024
2 parents f847d80 + 8ca5de0 commit 700ee8c
Show file tree
Hide file tree
Showing 24 changed files with 558 additions and 455 deletions.
83 changes: 65 additions & 18 deletions extension/.pnp.cjs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
8 changes: 4 additions & 4 deletions extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@
"@eslint/js": "^9.7.0",
"@gnosis.pm/zodiac": "^4.0.3",
"@noble/hashes": "^1.4.0",
"@safe-global/api-kit": "^2.4.2",
"@safe-global/protocol-kit": "^4.0.2",
"@safe-global/api-kit": "^2.4.4",
"@safe-global/protocol-kit": "^4.0.4",
"@safe-global/safe-apps-sdk": "^9.1.0",
"@safe-global/safe-core-sdk-types": "^5.0.2",
"@safe-global/safe-gateway-typescript-sdk": "^3.21.10",
"@safe-global/safe-core-sdk-types": "^5.0.3",
"@safe-global/safe-gateway-typescript-sdk": "^3.22.2",
"@shazow/whatsabi": "^0.13.2",
"@testing-library/dom": "^10.3.1",
"@testing-library/jest-dom": "^6.4.6",
Expand Down
12 changes: 5 additions & 7 deletions extension/src/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import ProvideProvider from './browser/ProvideProvider'
import { ProvideState } from './state'
import ZodiacToastContainer from './components/Toast'
import { pushLocation } from './location'
import { ProvideMetaMask, ProvideTenderly } from './providers'
import { ProvideMetaMask } from './providers'
import { useMatchConnectionsRoute, usePushConnectionsRoute } from './routing'
import { ProvideRoutes } from './routes'
import { useRoutes, useUpdateLastUsedRoute } from './routes/routeHooks'
Expand Down Expand Up @@ -55,12 +55,10 @@ root.render(
<ProvideState>
<ProvideRoutes>
<ProvideMetaMask>
<ProvideTenderly>
<ProvideProvider>
<Routes />
<ZodiacToastContainer />
</ProvideProvider>
</ProvideTenderly>
<ProvideProvider>
<Routes />
<ZodiacToastContainer />
</ProvideProvider>
</ProvideMetaMask>
</ProvideRoutes>
</ProvideState>
Expand Down
59 changes: 52 additions & 7 deletions extension/src/background.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const activeExtensionTabs = new Set<number>()

const startTrackingTab = (tabId: number) => {
activeExtensionTabs.add(tabId)
clearStaleRules()
updateHeadersRule()
console.log('Pilot: started tracking tab', tabId)
}
Expand All @@ -21,6 +22,7 @@ const stopTrackingTab = (tabId: number) => {
removeRpcRedirectRules(tabId)
activeExtensionTabs.delete(tabId)
simulatingExtensionTabs.delete(tabId)
clearStaleRules()
updateHeadersRule()
console.log('Pilot: stopped tracking tab', tabId)
}
Expand Down Expand Up @@ -99,12 +101,10 @@ chrome.action.onClicked.addListener(toggle)
// a fork network.
const simulatingExtensionTabs = new Map<number, Fork>()

// Hash the RPC URL+ tab ID to a number, so we can use it as a declarativeNetRequest rule ID.
// Hash the RPC URL + tab ID to a number, so we can use it as a declarativeNetRequest rule ID.
// Implementation taken from https://github.com/darkskyapp/string-hash (CC0 Public Domain)
function hash(rpcUrl: string, tabId: number) {
const urlComponents = rpcUrl.split('/')
const forkId = urlComponents[urlComponents.length - 1]
const str = `${tabId}:${forkId}`
const str = `${tabId}:${rpcUrl}`
const MAX_RULE_ID = 0xffffff // chrome throws an error if the rule ID is too large ("expected integer, got number")

let hash = 5381,
Expand All @@ -120,6 +120,46 @@ function hash(rpcUrl: string, tabId: number) {
return (hash >>> 0) % MAX_RULE_ID
}

async function clearStaleRules() {
const openTabIds = await new Promise<Set<number>>((resolve) => {
chrome.tabs.query({}, (tabs) => {
resolve(new Set(tabs.map((tab) => tab.id).filter(Boolean) as number[]))
})
})

// clear activeExtensionTabs that are not open anymore
activeExtensionTabs.difference(openTabIds).forEach((tabId) => {
activeExtensionTabs.delete(tabId)
})
console.log({ activeExtensionTabs, openTabIds })

// clear simulatingExtensionTabs that are not active (= extension is activated) anymore
const simulatingTabIds = new Set(simulatingExtensionTabs.keys())
simulatingTabIds.difference(activeExtensionTabs).forEach((tabId) => {
simulatingExtensionTabs.delete(tabId)
})

// remove rules for tabs that are not simulating anymore
const staleRules = await new Promise<chrome.declarativeNetRequest.Rule[]>(
(resolve) => {
chrome.declarativeNetRequest.getSessionRules((rules) => {
resolve(
rules.filter(
(rule) =>
rule.condition.tabIds?.length === 1 &&
!simulatingExtensionTabs.has(rule.condition.tabIds[0])
)
)
})
}
)
chrome.declarativeNetRequest.updateSessionRules({
removeRuleIds: staleRules.map((r) => r.id),
})

console.debug('Cleared stale rules', staleRules)
}

const updateRpcRedirectRules = (tabId: number) => {
const fork = simulatingExtensionTabs.get(tabId)
if (!fork) {
Expand Down Expand Up @@ -156,6 +196,10 @@ const updateRpcRedirectRules = (tabId: number) => {
addRules,
removeRuleIds: ruleIds,
})

chrome.declarativeNetRequest.getSessionRules((rules) => {
console.debug('RPC redirect rules updated', tabId, rules)
})
}

const removeRpcRedirectRules = (tabId: number) => {
Expand All @@ -176,9 +220,6 @@ const removeRpcRedirectRules = (tabId: number) => {
735219801
)
)
chrome.declarativeNetRequest.getSessionRules((rules) =>
console.log('removeRpcRedirectRules getSessionRules', rules)
)
}

chrome.runtime.onMessage.addListener((message, sender) => {
Expand All @@ -202,6 +243,7 @@ chrome.runtime.onMessage.addListener((message, sender) => {
rpcUrl
)
}

if (message.type === 'stopSimulating') {
console.log('stopSimulating', sender.tab.id, { simulatingExtensionTabs })
simulatingExtensionTabs.delete(sender.tab.id)
Expand Down Expand Up @@ -233,6 +275,9 @@ chrome.webRequest.onBeforeRequest.addListener(
// don't consider requests that are already redirected to the fork RPC
if (details.url === simulatingExtensionTabs.get(details.tabId)?.rpcUrl)
return
// ignore requests to fork RPCs
if (details.url.startsWith('https://virtual.mainnet.rpc.tenderly.co/'))
return
// only consider requests with a JSON RPC body
if (!getJsonRpcBody(details)) return

Expand Down
2 changes: 1 addition & 1 deletion extension/src/bridge/SafeAppBridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ export default class SafeAppBridge {
// assume on-chain signature
const safeTxHash = await this.provider.request({
method: 'eth_signTypedData_v4',
params: [typedData],
params: [this.connection.avatarAddress, JSON.stringify(typedData)],
})
return { safeTxHash }
},
Expand Down
38 changes: 18 additions & 20 deletions extension/src/browser/Drawer/DecodedTransaction.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,23 @@ interface Props {
functionFragment: FunctionFragment
data: Result
}
const DecodedTransaction: React.FC<Props> = ({ functionFragment, data }) => {
return (
<div className={classes.transaction}>
{functionFragment.inputs.length > 0 && (
<fieldset>
{functionFragment.inputs.map((input, i) => (
<label key={input.name}>
<span>
{input.name} <i className={classes.inputType}>{input.type}</i>
</span>
<Box p={1} bg>
<input type="text" value={data[i]} readOnly />
</Box>
</label>
))}
</fieldset>
)}
</div>
)
}
const DecodedTransaction: React.FC<Props> = ({ functionFragment, data }) => (
<div className={classes.transaction}>
{functionFragment.inputs.length > 0 && (
<fieldset>
{functionFragment.inputs.map((input, i) => (
<label key={input.name}>
<span>
{input.name} <i className={classes.inputType}>{input.type}</i>
</span>
<Box p={1} bg>
<input type="text" value={data[i].toString()} readOnly />
</Box>
</label>
))}
</fieldset>
)}
</div>
)

export default DecodedTransaction
Loading

0 comments on commit 700ee8c

Please sign in to comment.