Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor: move getRemainingRelays to a service #1839

Merged
merged 2 commits into from
Apr 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/build/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,5 @@ runs:
NEXT_PUBLIC_TENDERLY_SIMULATE_ENDPOINT_URL: ${{ fromJSON(inputs.secrets).NEXT_PUBLIC_TENDERLY_SIMULATE_ENDPOINT_URL }}
NEXT_PUBLIC_WC_BRIDGE: ${{ fromJSON(inputs.secrets).NEXT_PUBLIC_WC_BRIDGE }}
NEXT_PUBLIC_CYPRESS_MNEMONIC: ${{ inputs.e2e_mnemonic }}
NEXT_PUBLIC_SAFE_GELATO_RELAY_SERVICE_URL_PRODUCTION: ${{ fromJSON(inputs.secrets).NEXT_PUBLIC_SAFE_GELATO_RELAY_SERVICE_URL_PRODUCTION }}
NEXT_PUBLIC_SAFE_GELATO_RELAY_SERVICE_URL_STAGING: ${{ fromJSON(inputs.secrets).NEXT_PUBLIC_SAFE_GELATO_RELAY_SERVICE_URL_STAGING }}
NEXT_PUBLIC_SAFE_RELAY_SERVICE_URL_PRODUCTION: ${{ fromJSON(inputs.secrets).NEXT_PUBLIC_SAFE_GELATO_RELAY_SERVICE_URL_PRODUCTION }}
NEXT_PUBLIC_SAFE_RELAY_SERVICE_URL_STAGING: ${{ fromJSON(inputs.secrets).NEXT_PUBLIC_SAFE_GELATO_RELAY_SERVICE_URL_STAGING }}
6 changes: 3 additions & 3 deletions src/components/new-safe/create/logic/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { EthersTxReplacedReason } from '@/utils/ethers-utils'
import { SafeCreationStatus } from '@/components/new-safe/create/steps/StatusStep/useSafeCreation'
import { type ChainInfo } from '@safe-global/safe-gateway-typescript-sdk'
import { hexZeroPad } from 'ethers/lib/utils'
import * as sponsoredCall from '@/services/tx/sponsoredCall'
import * as relaying from '@/services/tx/relaying'
import {
Gnosis_safe__factory,
Proxy_factory__factory,
Expand Down Expand Up @@ -226,7 +226,7 @@ describe('createNewSafeViaRelayer', () => {
} as ChainInfo

it('returns taskId if create Safe successfully relayed', async () => {
const sponsoredCallSpy = jest.spyOn(sponsoredCall, 'sponsoredCall').mockResolvedValue({ taskId: '0x123' })
const sponsoredCallSpy = jest.spyOn(relaying, 'sponsoredCall').mockResolvedValue({ taskId: '0x123' })

const expectedSaltNonce = 69
const expectedThreshold = 1
Expand Down Expand Up @@ -265,7 +265,7 @@ describe('createNewSafeViaRelayer', () => {
it('should throw an error if relaying fails', () => {
const relayFailedError = new Error('Relay failed')

jest.spyOn(sponsoredCall, 'sponsoredCall').mockRejectedValue(relayFailedError)
jest.spyOn(relaying, 'sponsoredCall').mockRejectedValue(relayFailedError)

expect(relaySafeCreation(mockChainInfo, [owner1, owner2], 1, 69)).rejects.toEqual(relayFailedError)
})
Expand Down
2 changes: 1 addition & 1 deletion src/components/new-safe/create/logic/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import { backOff } from 'exponential-backoff'
import { LATEST_SAFE_VERSION } from '@/config/constants'
import { EMPTY_DATA, ZERO_ADDRESS } from '@safe-global/safe-core-sdk/dist/src/utils/constants'
import { formatError } from '@/utils/formatters'
import { sponsoredCall } from '@/services/tx/sponsoredCall'
import { sponsoredCall } from '@/services/tx/relaying'

export type SafeCreationProps = {
owners: string[]
Expand Down
8 changes: 4 additions & 4 deletions src/config/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export enum SafeAppsTag {
}

// Safe Gelato relay service
export const SAFE_GELATO_RELAY_SERVICE_URL_PRODUCTION =
process.env.NEXT_PUBLIC_SAFE_GELATO_RELAY_SERVICE_URL_PRODUCTION || 'https://safe-client-nest.safe.global/v1/relay'
export const SAFE_GELATO_RELAY_SERVICE_URL_STAGING =
process.env.NEXT_PUBLIC_SAFE_GELATO_RELAY_SERVICE_URL_STAGING || 'https://safe-client-nest.staging.5afe.dev/v1/relay'
export const SAFE_RELAY_SERVICE_URL_PRODUCTION =
process.env.NEXT_PUBLIC_SAFE_RELAY_SERVICE_URL_PRODUCTION || 'https://safe-client-nest.safe.global/v1/relay'
export const SAFE_RELAY_SERVICE_URL_STAGING =
process.env.NEXT_PUBLIC_SAFE_RELAY_SERVICE_URL_STAGING || 'https://safe-client-nest.staging.5afe.dev/v1/relay'
Comment on lines +65 to +68
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll rename them in the Github secrets after the release.

21 changes: 15 additions & 6 deletions src/hooks/__tests__/useRemainingRelays.test.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
import { renderHook, waitFor } from '@/tests/test-utils'
import {
useLeastRemainingRelays,
useRemainingRelaysBySafe,
SAFE_GELATO_RELAY_SERVICE_URL,
} from '@/hooks/useRemainingRelays'
import { useLeastRemainingRelays, useRemainingRelaysBySafe } from '@/hooks/useRemainingRelays'
import * as useSafeAddress from '@/hooks/useSafeAddress'
import * as useChains from '@/hooks/useChains'
import { type ChainInfo } from '@safe-global/safe-gateway-typescript-sdk'
import { FEATURES } from '@/utils/chains'
import { SAFE_RELAY_SERVICE_URL } from '@/services/tx/relaying'

const SAFE_ADDRESS = '0x0000000000000000000000000000000000000001'

Expand All @@ -34,7 +31,7 @@ describe('fetch remaining relays hooks', () => {
global.fetch = jest.fn()
const mockFetch = jest.spyOn(global, 'fetch')

const url = `${SAFE_GELATO_RELAY_SERVICE_URL}/5/${SAFE_ADDRESS}`
const url = `${SAFE_RELAY_SERVICE_URL}/5/${SAFE_ADDRESS}`

renderHook(() => useRemainingRelaysBySafe())
expect(mockFetch).toHaveBeenCalledTimes(1)
Expand All @@ -59,12 +56,15 @@ describe('fetch remaining relays hooks', () => {
global.fetch = jest
.fn()
.mockResolvedValue({
ok: true,
json: () => Promise.resolve({ remaining: 3 }),
})
.mockResolvedValueOnce({
ok: true,
json: () => Promise.resolve({ remaining: 0 }),
})
.mockResolvedValueOnce({
ok: true,
json: () => Promise.resolve({ remaining: 5 }),
})

Expand All @@ -79,12 +79,15 @@ describe('fetch remaining relays hooks', () => {
global.fetch = jest
.fn()
.mockResolvedValue({
ok: true,
json: () => Promise.resolve({ remaining: 3 }),
})
.mockResolvedValueOnce({
ok: true,
json: () => Promise.resolve({ remaining: 2 }),
})
.mockResolvedValueOnce({
ok: true,
json: () => Promise.resolve({ remaining: 5 }),
})

Expand All @@ -99,12 +102,15 @@ describe('fetch remaining relays hooks', () => {
global.fetch = jest
.fn()
.mockResolvedValue({
ok: true,
json: () => Promise.resolve({ remaining: 3 }),
})
.mockRejectedValueOnce({
ok: false,
json: () => Promise.reject('Failed to fetch'),
})
.mockResolvedValueOnce({
ok: true,
json: () => Promise.resolve({ remaining: 2 }),
})

Expand All @@ -120,12 +126,15 @@ describe('fetch remaining relays hooks', () => {
global.fetch = jest
.fn()
.mockResolvedValue({
ok: true,
json: () => Promise.resolve({ remaining: 3 }),
})
.mockRejectedValueOnce({
ok: false,
json: () => Promise.reject('Failed to fetch'),
})
.mockResolvedValueOnce({
ok: true,
json: () => Promise.resolve({ remaining: 2 }),
})
const mockFetch = jest.spyOn(global, 'fetch')
Expand Down
31 changes: 8 additions & 23 deletions src/hooks/useRemainingRelays.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,25 @@
import type { AsyncResult } from '@/hooks/useAsync'
import useAsync from '@/hooks/useAsync'
import useSafeAddress from '@/hooks/useSafeAddress'
import { Errors, logError } from '@/services/exceptions'
import {
IS_PRODUCTION,
SAFE_GELATO_RELAY_SERVICE_URL_PRODUCTION,
SAFE_GELATO_RELAY_SERVICE_URL_STAGING,
} from '@/config/constants'
import { FEATURES, hasFeature } from '@/utils/chains'
import { useCurrentChain } from '@/hooks/useChains'
import { cgwDebugStorage } from '@/components/sidebar/DebugToggle'

export const SAFE_GELATO_RELAY_SERVICE_URL =
IS_PRODUCTION || cgwDebugStorage.get()
? SAFE_GELATO_RELAY_SERVICE_URL_PRODUCTION
: SAFE_GELATO_RELAY_SERVICE_URL_STAGING
import { getRemainingRelays } from '@/services/tx/relaying'

const fetchRemainingRelays = async (chainId: string, address: string): Promise<number> => {
const url = `${SAFE_GELATO_RELAY_SERVICE_URL}/${chainId}/${address}`

try {
const res = await fetch(url)
const data = await res.json()
return data.remaining
return await getRemainingRelays(chainId, address)
} catch (error) {
logError(Errors._630, (error as Error).message)
return 0
}
}

export const useRemainingRelaysBySafe = () => {
export const useRemainingRelaysBySafe = (): AsyncResult<number> => {
const chain = useCurrentChain()
const safeAddress = useSafeAddress()

return useAsync(() => {
return useAsync<number>(() => {
if (!safeAddress || !chain || !hasFeature(chain, FEATURES.RELAYING)) return

return fetchRemainingRelays(chain.chainId, safeAddress)
Expand All @@ -41,14 +28,12 @@ export const useRemainingRelaysBySafe = () => {

const getMinimum = (result: number[]) => Math.min(...result)

export const useLeastRemainingRelays = (ownerAddresses: string[]) => {
export const useLeastRemainingRelays = (ownerAddresses: string[]): AsyncResult<number> => {
const chain = useCurrentChain()

return useAsync(async () => {
return useAsync<number>(() => {
if (!chain || !hasFeature(chain, FEATURES.RELAYING)) return

const result = await Promise.all(ownerAddresses.map((address) => fetchRemainingRelays(chain.chainId, address)))

return getMinimum(result)
return Promise.all(ownerAddresses.map((address) => fetchRemainingRelays(chain.chainId, address))).then(getMinimum)
}, [chain, ownerAddresses])
}
51 changes: 51 additions & 0 deletions src/services/tx/relaying.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { type SafeTransactionData } from '@safe-global/safe-core-sdk-types'
import { IS_PRODUCTION, SAFE_RELAY_SERVICE_URL_PRODUCTION, SAFE_RELAY_SERVICE_URL_STAGING } from '@/config/constants'
import { cgwDebugStorage } from '@/components/sidebar/DebugToggle'

export const SAFE_RELAY_SERVICE_URL =
IS_PRODUCTION || cgwDebugStorage.get() ? SAFE_RELAY_SERVICE_URL_PRODUCTION : SAFE_RELAY_SERVICE_URL_STAGING

// TODO: import type from relay-service
export type SponsoredCallPayload = {
chainId: string
to: string
data: SafeTransactionData['data']
gasLimit?: string | number
}

export const sponsoredCall = async (tx: SponsoredCallPayload): Promise<{ taskId: string }> => {
const requestObject: RequestInit = {
method: 'POST',
headers: {
'content-type': 'application/JSON',
},
body: JSON.stringify(tx),
}

const res = await fetch(SAFE_RELAY_SERVICE_URL, requestObject)

if (res.ok) {
return res.json()
}

const errorData: { error?: { message: string } } = await res.json()
throw new Error(`${res.status} - ${res.statusText}: ${errorData?.error?.message}`)
}

export const getRemainingRelays = async (chainId: string, address: string): Promise<number> => {
const url = `${SAFE_RELAY_SERVICE_URL}/${chainId}/${address}`

try {
const res = await fetch(url)

if (res.ok) {
const data = await res.json()
return data.remaining
}

const errorData: { error?: { message: string } } = await res.json()
throw new Error(errorData?.error?.message || 'Unknown error')
} catch (error) {
throw new Error(`Error fetching remaining relays: ${error}`)
}
}
31 changes: 0 additions & 31 deletions src/services/tx/sponsoredCall.ts

This file was deleted.

2 changes: 1 addition & 1 deletion src/services/tx/tx-sender/dispatch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import proposeTx from '../proposeTransaction'
import { txDispatch, TxEvent } from '../txEvents'
import { waitForRelayedTx } from '@/services/tx/txMonitor'
import { getSpecificGnosisSafeContractInstance } from '@/services/contracts/safeContracts'
import { sponsoredCall } from '@/services/tx/sponsoredCall'
import { sponsoredCall } from '@/services/tx/relaying'
import {
getAndValidateSafeSDK,
getSafeSDKWithSigner,
Expand Down