Last active
August 15, 2023 16:45
-
-
Save ankushswar1/4dea5adc1cd253e38c2efbe7ad32b8af to your computer and use it in GitHub Desktop.
ReservoirWallet adapter using Gelato relay for gasless transactions
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import type { ReservoirWallet } from '@reservoir0x/reservoir-sdk'; | |
import { GelatoRelay } from '@gelatonetwork/relay-sdk'; | |
import type { Signer } from 'ethers/lib/ethers'; | |
import { arrayify } from 'ethers/lib/utils'; | |
import type { TypedDataSigner } from '@ethersproject/abstract-signer/lib/index'; | |
import { getTaskStatus } from './poll'; | |
const sleep = (time: number) => new Promise((resolve) => setTimeout(resolve, time)); | |
// Helper function to poll the status of a Gelato relay task given the taskId | |
const getTaskStatus = async (taskId: string) => { | |
let taskState; | |
const terminalStates = ['ExecReverted', 'Cancelled', 'ExecSuccess']; | |
do { | |
const response = await fetch(`https://api.gelato.digital/tasks/status/${taskId}`); | |
const status = await response.json(); | |
taskState = status.task.taskState; | |
if (taskState === 'ExecSuccess') { | |
// Success case - return transaction hash | |
return status.task.transactionHash; | |
} else if (taskState === 'ExecReverted' || taskState === 'Cancelled') { | |
// Error case - return undefined | |
throw new Error(`Transaction failed in taskId ${taskId} with error: ${status.task.lastCheckMessage}`); | |
} else { | |
await sleep(3000); | |
} | |
} while (!terminalStates.includes(taskState)); | |
}; | |
// Returns a ReservoirWallet adapter that sends gasless transactions using Gelato | |
// Make sure the wallet has been switched to your desired network, before calling | |
// this function. | |
export const adaptGelatoRelayer = (signer: Signer, gelatoApiKey: string): ReservoirWallet => { | |
return { | |
// https://github.com/reservoirprotocol/reservoir-kit/blob/main/packages/ethers-wallet-adapter/src/adapter.ts | |
address: async () => { | |
return signer.getAddress(); | |
}, | |
// https://github.com/reservoirprotocol/reservoir-kit/blob/main/packages/ethers-wallet-adapter/src/adapter.ts | |
handleSignMessageStep: async (stepItem) => { | |
const signData = stepItem.data?.sign; | |
let signature: string | undefined; | |
if (signData) { | |
// Request user signature | |
if (signData.signatureKind === 'eip191') { | |
if (signData.message.match(/0x[0-9a-fA-F]{64}/)) { | |
// If the message represents a hash, we need to convert it to raw bytes first | |
signature = await signer.signMessage(arrayify(signData.message)); | |
} else { | |
signature = await signer.signMessage(signData.message); | |
} | |
} else if (signData.signatureKind === 'eip712') { | |
signature = await (signer as unknown as TypedDataSigner)._signTypedData( | |
signData.domain, | |
signData.types, | |
signData.value, | |
); | |
} | |
} | |
return signature; | |
}, | |
handleSendTransactionStep: async (chainId, stepItem) => { | |
const { ...stepData } = stepItem.data; | |
const address = await signer.getAddress(); | |
const relay = new GelatoRelay(); | |
const request = { | |
chainId: chainId, | |
target: stepData.to, | |
data: stepData.data, | |
user: address, | |
}; | |
try { | |
const relayResponse = await relay.sponsoredCallERC2771(request, signer, gelatoApiKey); | |
const { taskId } = relayResponse; | |
const txHash = await getTaskStatus(taskId); | |
return txHash; | |
} catch (error) { | |
throw new Error(`Gelato sponsored call failed with error: ${error}`); | |
} | |
}, | |
}; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment