safe-core-sdk
safe-core-sdk copied to clipboard
relay-kit not working in server side nodejs backend
relay-kit not working in server side nodejs backend
I'm encountering the same issue as described, where the relay-kit is not functioning correctly in a server-side Node.js environment. Like you, I'm also connected to the Sepolia network.
Here's the code I'm using:
const { ethers } = require('ethers');
/* ---------------------------------- SAFE ---------------------------------- */
const Safe = require('@safe-global/protocol-kit').default
const SafeApiKit = require("@safe-global/api-kit").default
const { EthersAdapter, SafeFactory } = require("@safe-global/protocol-kit")
const {
OperationType,
MetaTransactionData
} = require('@safe-global/safe-core-sdk-types');
/* --------------------------------- Gelato --------------------------------- */
const { GelatoRelayPack } = require('@safe-global/relay-kit'`
const createRelayTransaction = async ({ senderPrivateKey, receiverAddress, amount, safeAddress }) => {
try{
const sender = new ethers.Wallet(senderPrivateKey, provider);
const senderAddress = await sender.getAddress()
const value = ethers.utils.parseUnits(amount , 'ether').toString()
const transactions = [{
to: receiverAddress,
data: '0x',
value
}]
console.log({ transactions })
const ethAdapter = new EthersAdapter({ ethers, signerOrProvider: sender });
const protocolKit = await Safe.create({ ethAdapter, safeAddress });
const relayKit = new GelatoRelayPack({ protocolKit });
const safeTransaction = await relayKit.createRelayedTransaction({ transactions });
console.log({safeTransaction})
// const senderAddress = await sender.getAddress()
const safeTxHash = await protocolKit.getTransactionHash(safeTransaction)
// Sign transaction to verify that the transaction is coming from owner 1
const senderSignature = await protocolKit.signTransactionHash(safeTxHash)
console.log('Safe tx hash: ',safeTxHash)
console.log('senderSignature: ',senderSignature)
console.log({
safeAddress,
safeTransactionData: safeTransaction.data,
safeTxHash,
senderAddress,
senderSignature: senderSignature.data,
})
await safeService.proposeTransaction({
safeAddress,
safeTransactionData: safeTransaction.data,
safeTxHash,
senderAddress,
senderSignature: senderSignature.data,
})
console.log("Proposal made")
return {
safeTxHash,
safeTransaction: safeTransaction.data
}
}catch(err){
console.error(err)
throw new Error(err)
}
}```
Error:
```TypeError: Cannot read properties of undefined (reading 'to')
at standardizeSafeTransactionData (/Users/gabe/Documents/HC/HC-Crypto-Server/node_modules/@safe-global/protocol-kit/dist/src/utils/transactions/utils.js:24:16)
at Safe.createTransaction (/Users/gabe/Documents/HC/HC-Crypto-Server/node_modules/@safe-global/protocol-kit/dist/src/Safe.js:250:90)
at GelatoRelayPack.createTransactionWithHandlePayment (/Users/gabe/Documents/HC/HC-Crypto-Server/node_modules/@safe-global/relay-kit/dist/src/packs/gelato/GelatoRelayPack.js:107:65)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at async createRelayTransaction (/Users/gabe/Documents/HC/HC-Crypto-Server/modules/safe_vault.js:358:33)
/Users/gabe/Documents/HC/HC-Crypto-Server/modules/safe_vault.js:394
throw new Error(err)```
I figured it out. Seems like the issue was the version. Seems like anything past version 1.3.0 won't work.
Hi @Gabriel-Mbugua what did you do in the end? Did it finally work or did you find a solution?
Hi @francelwebdev, below is my integration and package versions.
@safe-global/[email protected]
@safe-global/[email protected]
@safe-global/[email protected]
@safe-global/[email protected]
@safe-global/[email protected]
Ignore the ERC20 flow. Currently broken. Trying to figure it out.
const createRelayTransaction = async ({
senderPrivateKey,
receiverAddress,
amount,
safeAddress,
network,
token,
sandbox = SANDBOX
}) => {
try{
console.log(`Creating relay transaction...`)
const { provider, serviceUrl } = getNetworkDetails({ network, sandbox })
const sender = new ethers.Wallet(senderPrivateKey, provider);
const senderAddress = await sender.getAddress()
const value = ethers.utils.parseUnits(amount , 'ether').toString()
let transaction = {
to: receiverAddress,
data: '0x',
value,
// operation: OperationType.Call
}
let options = {
gasLimit: "80000000",
isSponsored: false
}
if(token){
console.log(`Transfering ${token}`)
const { inputData, contractAddress } = erc20InputData({
token,
network,
sandbox,
amount,
to: receiverAddress
})
transaction.to = contractAddress
transaction.data = inputData
transaction.value = '0'
options.gasToken = contractAddress
}
const ethAdapter = new EthersAdapter({ ethers, signerOrProvider: sender });
const protocolKit = await Safe.create({ ethAdapter, safeAddress });
const relayKit = new GelatoRelayPack({ protocolKit });
// const safeTransaction = await relayKit.createRelayedTransaction({ safe: protocolKit, transactions, options});
const safeTransaction = await relayKit.createRelayedTransaction({
safe: protocolKit,
transactions: [transaction],
options
});
console.log({safeTransaction})
// const senderAddress = await sender.getAddress()
const safeTxHash = await protocolKit.getTransactionHash(safeTransaction)
// Sign transaction to verify that the transaction is coming from the user
const senderSignature = await protocolKit.signTransactionHash(safeTxHash)
console.log('Signed transaction...')
// const senderSignature = await protocolKit.signHash(safeTxHash)
// Create Safe API Kit instance
const safeService = new SafeApiKit({
txServiceUrl: serviceUrl,
ethAdapter
});
await safeService.proposeTransaction({
safeAddress,
safeTransactionData: safeTransaction.data,
// safeTransactionData: confirmTransaction,
safeTxHash,
senderAddress,
senderSignature: senderSignature.data,
})
console.log("Proposal made")
const confirmTransaction = await safeService.confirmTransaction(safeTxHash, senderSignature.data)
console.log(`Transaction confirmed..`,confirmTransaction)
return {
safeTxHash,
safeTransaction: safeTransaction.data
}
}catch(err){
console.error(err)
throw new Error(err)
}
}
senderPrivateKey,
receiverAddress,
amount,
safeAddress,
network,
token,
sandbox = SANDBOX
}) => {
try{
console.log(`Creating relay transaction...`)
const { provider, serviceUrl } = getNetworkDetails({ network, sandbox })
const sender = new ethers.Wallet(senderPrivateKey, provider);
const senderAddress = await sender.getAddress()
const value = ethers.utils.parseUnits(amount , 'ether').toString()
let transaction = {
to: receiverAddress,
data: '0x',
value,
// operation: OperationType.Call
}
let options = { isSponsored: true }
if(token){
console.log(`Transfering ${token}`)
const { inputData, contractAddress } = erc20InputData({
token,
network,
sandbox,
amount,
to: receiverAddress
})
transaction.to = contractAddress
transaction.data = inputData
transaction.value = '0'
options.gasToken = contractAddress
}
const ethAdapter = new EthersAdapter({ ethers, signerOrProvider: sender });
const protocolKit = await Safe.create({ ethAdapter, safeAddress });
// const relayKit = new GelatoRelayPack({ apiKey: GELATO_API_KEY, protocolKit });
const relayKit = new GelatoRelayPack(GELATO_API_KEY);
// const safeTransaction = await relayKit.createRelayedTransaction({ safe: protocolKit, transactions, options});
const safeTransaction = await relayKit.createRelayedTransaction({
safe: protocolKit,
transactions: [transaction],
options
});
console.log({safeTransaction})
// const senderAddress = await sender.getAddress()
const safeTxHash = await protocolKit.getTransactionHash(safeTransaction)
// Sign transaction to verify that the transaction is coming from the user
const senderSignature = await protocolKit.signTransactionHash(safeTxHash)
console.log('Signed transaction...')
// const senderSignature = await protocolKit.signHash(safeTxHash)
// Create Safe API Kit instance
const safeService = new SafeApiKit({
txServiceUrl: serviceUrl,
ethAdapter
});
await safeService.proposeTransaction({
safeAddress,
safeTransactionData: safeTransaction.data,
// safeTransactionData: confirmTransaction,
safeTxHash,
senderAddress,
senderSignature: senderSignature.data,
})
console.log("Proposal made")
const confirmTransaction = await safeService.confirmTransaction(safeTxHash, senderSignature.data)
console.log(`Transaction confirmed..`,confirmTransaction)
return {
safeTxHash,
safeTransaction: safeTransaction.data
}
}catch(err){
console.error(err)
throw new Error(err)
}
}```
Hi @francelwebdev, below is my integration and package versions.
@safe-global/[email protected]@safe-global/[email protected]@safe-global/[email protected]@safe-global/[email protected]@safe-global/[email protected]
Hey @Gabriel-Mbugua thank you for adding more information on your issue
Have you tried to explicitly set the following versions:
api-kit: v2.0.0
protocol-kit: v2.0.0
relay-kit: v2.0.0
safe-core-sdk-types: v3.0.0
[email protected] will only work with [email protected]
You should also remove the @safe-global/[email protected]
Hey @dasanra, thanks for responding. I've made the package changes you suggested above and the signature signing seems to be broken:
const senderSignature = await protocolKit.signTransactionHash(safeTxHash)
Error:
TypeError: __classPrivateFieldGet(...).getBytes is not a function
at EthersAdapter.signMessage (/Users/gabe/Documents/HC/HC-Crypto-Server/node_modules/@safe-global/protocol-kit/dist/src/adapters/ethers/EthersAdapter.js:159:87)
at generateSignature (/Users/gabe/Documents/HC/HC-Crypto-Server/node_modules/@safe-global/protocol-kit/dist/src/utils/signatures/utils.js:76:38)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at async createRelayTransaction (/Users/gabe/Documents/HC/HC-Crypto-Server/modules/safe_vault.js:548:33)
/Users/gabe/Documents/HC/HC-Crypto-Server/modules/safe_vault.js:578
throw new Error(err)
^
Error: TypeError: __classPrivateFieldGet(...).getBytes is not a function
at createRelayTransaction (/Users/gabe/Documents/HC/HC-Crypto-Server/modules/safe_vault.js:578:15)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)