Skip to content

Commit

Permalink
Merge pull request #104 from DarkFlorist/undefined-for-missing-rpc
Browse files Browse the repository at this point in the history
use undefined for missing rpcs
  • Loading branch information
KillariDev authored Dec 18, 2024
2 parents a458f0e + e7d9b24 commit 12ca2c5
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 29 deletions.
9 changes: 4 additions & 5 deletions app/ts/components/ConfigureFunding.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ const WithdrawModal = ({ display, blockInfo, signers, provider, bouquetNetwork }

// Default check if we know the network, can also switch to true if sending to known RPC fails
const useBrowserProvider = useSignal<boolean>(false)
useSignalEffect(() => { useBrowserProvider.value = Boolean(provider.value && bouquetNetwork.value.rpcUrl) })
useSignalEffect(() => { useBrowserProvider.value = Boolean(provider.value && bouquetNetwork.value.mempoolSubmitRpcEndpoint === undefined) })

function withdraw() {
waitFor(async () => {
Expand All @@ -150,7 +150,6 @@ const WithdrawModal = ({ display, blockInfo, signers, provider, bouquetNetwork }
if (!provider.value) throw 'User not connected'
if (!recipientAddress.value.address) throw 'No recipient provided'

// Worst case scenario, attempt to send via browser wallet if no NETWORK config for chainId or previous error sending to known RPC
if (useBrowserProvider.value === true) {
try {
const burnerWithBrowserProvider = signers.value.burner.connect(provider.value.provider)
Expand All @@ -162,14 +161,14 @@ const WithdrawModal = ({ display, blockInfo, signers, provider, bouquetNetwork }
throw error
}
}
if (bouquetNetwork.value.rpcUrl === undefined) throw new Error('No RPC URL set and not connected to wallet')
const fundingWithProvider = signers.value.burner.connect(new JsonRpcProvider(bouquetNetwork.value.rpcUrl))
if (bouquetNetwork.value.mempoolSubmitRpcEndpoint === undefined) throw new Error('No RPC URL set and not connected to wallet')
const fundingWithProvider = signers.value.burner.connect(new JsonRpcProvider(bouquetNetwork.value.mempoolSubmitRpcEndpoint))
try {
const tx = await fundingWithProvider.sendTransaction({ chainId: provider.value.chainId, from: signers.value.burner.address, to: addressString(recipientAddress.value.address), gasLimit: 21000, type: 2, value: withdrawAmount.value.amount, maxFeePerGas: withdrawAmount.value.maxFeePerGas })
fundingWithProvider.provider?.destroy()
return tx.hash
} catch (error) {
console.warn('Error sending burner withdraw tx to known RPC:', error)
console.warn('Error sending burner withdraw tx to known RPC:', bouquetNetwork.value.mempoolSubmitRpcEndpoint, ' error:', error)
fundingWithProvider.provider?.destroy()
useBrowserProvider.value = true
throw 'Unknown network! If you have Interceptor installed and simulation mode on please switch to signing mode and try again.'
Expand Down
14 changes: 11 additions & 3 deletions app/ts/components/Settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,20 +31,20 @@ export const SettingsIcon = () => {

export const SettingsModal = ({ display, bouquetNetwork, bouquetSettings }: { display: Signal<boolean>, bouquetNetwork: ReadonlySignal<BouquetNetwork>, bouquetSettings: Signal<BouquetSettings>}) => {
const chainId = useSignal({ value: bouquetNetwork.peek().chainId, valid: true })
const rpcUrl = useSignal({ value: bouquetNetwork.peek().rpcUrl, valid: true })
const simulationRelayEndpointInput = useSignal({ value: bouquetNetwork.peek().simulationRelayEndpoint, valid: true })
const submissionRelayEndpointInput = useSignal({ value: bouquetNetwork.peek().submissionRelayEndpoint, valid: true })
const priorityFeeInput = useSignal({ value: formatUnits(bouquetNetwork.peek().priorityFee, 'gwei'), valid: true })
const blocksInFutureInput = useSignal({ value: bouquetNetwork.peek().blocksInFuture.toString(10), valid: true })
const mempoolSubmitRpcEndpoint = useSignal({ value: bouquetNetwork.peek().mempoolSubmitRpcEndpoint, valid: true })
const mempoolSimulationRpcEndpoint = useSignal({ value: bouquetNetwork.peek().mempoolSimulationRpcEndpoint, valid: true })
const relayMode = useSignal({ value: bouquetNetwork.peek().relayMode, valid: true })
const loaded = useSignal(false)

useEffect(() => {
bringSettingsValues()
loaded.value = display.value
}, [display.value])
const allValidInputs = useComputed(() => submissionRelayEndpointInput.value.valid && simulationRelayEndpointInput.value.valid && priorityFeeInput.value.valid && blocksInFutureInput.value.valid)
const allValidInputs = useComputed(() => submissionRelayEndpointInput.value.valid && simulationRelayEndpointInput.value.valid && priorityFeeInput.value.valid && blocksInFutureInput.value.valid && mempoolSimulationRpcEndpoint.value.valid && mempoolSubmitRpcEndpoint.value.valid && mempoolSubmitRpcEndpoint.value.valid)

// https://urlregex.com/
const uriMatcher = new RegExp(
Expand All @@ -62,6 +62,9 @@ export const SettingsModal = ({ display, bouquetNetwork, bouquetSettings }: { di
function validateMempoolSubmitRpcEndpoint(value: string) {
mempoolSubmitRpcEndpoint.value = { value, valid: uriMatcher.test(value) }
}
function validateMempoolSimulationRpcEndpointInput(value: string) {
mempoolSimulationRpcEndpoint.value = { value, valid: uriMatcher.test(value) }
}
function validateAndSetSubmissionRelayEndpointInput(value: string) {
submissionRelayEndpointInput.value = { value, valid: uriMatcher.test(value) }
}
Expand All @@ -87,12 +90,12 @@ export const SettingsModal = ({ display, bouquetNetwork, bouquetSettings }: { di
function saveSettings() {
if (!allValidInputs.value) return
const newSettings = {
rpcUrl: rpcUrl.value.value,
submissionRelayEndpoint: submissionRelayEndpointInput.value.value,
simulationRelayEndpoint: simulationRelayEndpointInput.value.value,
priorityFee: parseUnits(String(Number(priorityFeeInput.value.value)), 'gwei'),
blocksInFuture: BigInt(blocksInFutureInput.value.value),
mempoolSubmitRpcEndpoint: mempoolSubmitRpcEndpoint.value.value,
mempoolSimulationRpcEndpoint: mempoolSimulationRpcEndpoint.value.value,
relayMode: relayMode.value.value,
}
const oldSettings = fetchSettingsFromStorage()
Expand Down Expand Up @@ -125,6 +128,7 @@ export const SettingsModal = ({ display, bouquetNetwork, bouquetSettings }: { di
submissionRelayEndpointInput.value = { value: bouquetNetwork.peek().submissionRelayEndpoint, valid: true }
priorityFeeInput.value = { value: formatUnits(bouquetNetwork.peek().priorityFee, 'gwei'), valid: true }
blocksInFutureInput.value = { value: bouquetNetwork.peek().blocksInFuture.toString(10), valid: true }
mempoolSimulationRpcEndpoint.value = { value: bouquetNetwork.peek().mempoolSimulationRpcEndpoint, valid: true }
mempoolSubmitRpcEndpoint.value = { value: bouquetNetwork.peek().mempoolSubmitRpcEndpoint, valid: true }
relayMode.value = { value: bouquetNetwork.peek().relayMode, valid: true }
})
Expand Down Expand Up @@ -152,6 +156,10 @@ export const SettingsModal = ({ display, bouquetNetwork, bouquetSettings }: { di
</label>
{ relayMode.value.value === 'mempool' ? <>
<SingleNotice variant = 'warn' title = 'Mempool mode is dangerous' description = { `When mempool mode is enabled. The transactions are sent as individual transactions to the below RPC URL. This means it's possible that only one of the transactions might end up on the chain. Use this mode only if a relay is not available for the network.`} />
<div className={`flex flex-col justify-center border h-16 outline-none px-4 focus-within:bg-white/5 bg-transparent ${!mempoolSimulationRpcEndpoint.value.valid ? 'border-red-400' : 'border-white/50 focus-within:border-white/80'}`}>
<span className='text-sm text-gray-500'>Simulation RPC URL</span>
<input onInput={(e: JSX.TargetedEvent<HTMLInputElement>) => validateMempoolSimulationRpcEndpointInput(e.currentTarget.value)} value={mempoolSimulationRpcEndpoint.value.value} type='text' className='bg-transparent outline-none placeholder:text-gray-600' placeholder='https://' />
</div>
<div className={`flex flex-col justify-center border h-16 outline-none px-4 focus-within:bg-white/5 bg-transparent ${!mempoolSubmitRpcEndpoint.value.valid ? 'border-red-400' : 'border-white/50 focus-within:border-white/80'}`}>
<span className='text-sm text-gray-500'>Mempool Submit RPC URL</span>
<input onInput={(e: JSX.TargetedEvent<HTMLInputElement>) => validateMempoolSubmitRpcEndpoint(e.currentTarget.value)} value={mempoolSubmitRpcEndpoint.value.value} type='text' className='bg-transparent outline-none placeholder:text-gray-600' placeholder='https://' />
Expand Down
28 changes: 14 additions & 14 deletions app/ts/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ export const MAINNET = {
simulationRelayEndpoint: 'https://flashbots-cors-proxy.dark-florist.workers.dev/',
submissionRelayEndpoint: 'https://rpc.titanbuilder.xyz',
blockExplorer: 'https://etherscan.io/',
rpcUrl: 'https://rpc.dark.florist/flipcardtrustone',
chainId: 1n,
blockExplorerApi: 'https://api.etherscan.io',
relayMode: 'relay',
mempoolSubmitRpcEndpoint: '', // don't set default for Mainnet as its not advisable to use it
mempoolSubmitRpcEndpoint: undefined, // don't set default for Mainnet as its not advisable to use it
mempoolSimulationRpcEndpoint: undefined,
blocksInFuture: 3n,
priorityFee: 10n ** 9n * 3n,
} as const
Expand All @@ -21,24 +21,24 @@ export const DEFAULT_NETWORKS: BouquetNetwork[] = [
simulationRelayEndpoint: 'https://flashbots-sepolia-cors-proxy.dark-florist.workers.dev/',
submissionRelayEndpoint: 'https://flashbots-sepolia-cors-proxy.dark-florist.workers.dev/',
blockExplorer: 'https://sepolia.etherscan.io/',
rpcUrl: 'https://rpc-sepolia.dark.florist/flipcardtrustone',
chainId: 11155111n,
blockExplorerApi: 'https://sepolia.api.etherscan.io',
relayMode: 'relay',
mempoolSubmitRpcEndpoint: '', // don't set default for Sepolia as its not advisable to use it
mempoolSubmitRpcEndpoint: undefined, // don't set default for Sepolia as its not advisable to use it
mempoolSimulationRpcEndpoint: undefined,
blocksInFuture: 3n,
priorityFee: 10n ** 9n * 3n,
},
{
networkName: 'Holesky',
simulationRelayEndpoint: '',
submissionRelayEndpoint: '',
simulationRelayEndpoint: undefined,
submissionRelayEndpoint: undefined,
blockExplorer: 'https://holesky.etherscan.io/',
rpcUrl: 'https://holesky.dark.florist',
chainId: 17000n,
blockExplorerApi: 'https://holesky.api.etherscan.io',
relayMode: 'mempool',
mempoolSubmitRpcEndpoint: 'https://holesky.dark.florist',
mempoolSimulationRpcEndpoint: 'https://holesky.dark.florist',
blocksInFuture: 3n,
priorityFee: 10n ** 9n * 3n,
}
Expand All @@ -49,14 +49,14 @@ export const getNetwork = (networks: BouquetSettings, chainId: bigint): BouquetN
if (network !== undefined) return network
return {
networkName: `Custom ChainId: ${ chainId }`,
simulationRelayEndpoint: '',
submissionRelayEndpoint: '',
blockExplorer: '',
rpcUrl: '',
chainId: chainId,
blockExplorerApi: '',
simulationRelayEndpoint: undefined,
submissionRelayEndpoint: undefined,
blockExplorer: undefined,
chainId,
blockExplorerApi: undefined,
relayMode: 'mempool',
mempoolSubmitRpcEndpoint: '',
mempoolSubmitRpcEndpoint: undefined,
mempoolSimulationRpcEndpoint: undefined,
blocksInFuture: 3n,
priorityFee: 10n ** 9n * 3n,
}
Expand Down
12 changes: 7 additions & 5 deletions app/ts/library/flashbots.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ export async function simulateBundle(

switch(network.relayMode) {
case 'mempool': {
if (network.rpcUrl === undefined) throw new Error('simulationRelayEndpoint is not defined')
if (network.mempoolSimulationRpcEndpoint === undefined) throw new Error('mempoolSimulationRpcEndpoint is not defined')
const data: EthSimulateV1Params = {
method: 'eth_simulateV1',
params: [ { 'blockStateCalls': [ { calls: txs.map((tx) => ({
Expand All @@ -94,7 +94,7 @@ export async function simulateBundle(
})) } ], traceTransfers: false, validation: true }, 'latest' ]
} as const
const serialized = serialize(EthSimulateV1Params, data)
const request = await fetch(network.rpcUrl, { method: 'POST', body: JSON.stringify({ jsonrpc: '2.0', id: 0, ...serialized }), headers: { 'Content-Type': 'application/json' } })
const request = await fetch(network.mempoolSimulationRpcEndpoint, { method: 'POST', body: JSON.stringify({ jsonrpc: '2.0', id: 0, ...serialized }), headers: { 'Content-Type': 'application/json' } })
const response = JsonRpcResponse.parse(await request.json())
if ('error' in response) {
console.log(response)
Expand Down Expand Up @@ -175,9 +175,11 @@ export async function sendBundle(bundle: Bundle, targetBlock: bigint, fundingAmo
id: index,
params: [transaction]
}))
const requests = await Promise.all(payloads.map(async (payload) => await fetch(network.mempoolSubmitRpcEndpoint,
{ method: 'POST', body: payload, headers: { 'Content-Type': 'application/json' } }
)))
if (network.mempoolSubmitRpcEndpoint === undefined) throw new Error('MemPool Submit Rpc Endpoint is not set')
const requests = await Promise.all(payloads.map(async (payload) => {
if (network.mempoolSubmitRpcEndpoint === undefined) throw new Error('MemPool Submit Rpc Endpoint is not set')
return await fetch(network.mempoolSubmitRpcEndpoint, { method: 'POST', body: payload, headers: { 'Content-Type': 'application/json' } })
}))
for (const request of requests) {
const response = await request.json()
if (response.error !== undefined && response.error !== null) {
Expand Down
4 changes: 2 additions & 2 deletions app/ts/types/bouquetTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,12 @@ export const BouquetNetwork = funtypes.Object({
chainId: EthereumQuantity,
networkName: funtypes.String,
relayMode: funtypes.Union(funtypes.Literal('relay'), funtypes.Literal('mempool')),
mempoolSubmitRpcEndpoint: funtypes.String,
mempoolSubmitRpcEndpoint: funtypes.Union(funtypes.String, funtypes.Undefined),
mempoolSimulationRpcEndpoint: funtypes.Union(funtypes.String, funtypes.Undefined),
blocksInFuture: EthereumQuantity,
priorityFee: EthereumQuantity,
blockExplorerApi: funtypes.Union(funtypes.String, funtypes.Undefined),
blockExplorer: funtypes.Union(funtypes.String, funtypes.Undefined),
rpcUrl: funtypes.Union(funtypes.String, funtypes.Undefined),
simulationRelayEndpoint: funtypes.Union(funtypes.String, funtypes.Undefined),
submissionRelayEndpoint: funtypes.Union(funtypes.String, funtypes.Undefined)
})
Expand Down

0 comments on commit 12ca2c5

Please sign in to comment.