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

relay-kit not working in server side nodejs backend #621

Open
francelwebdev opened this issue Nov 27, 2023 · 6 comments
Open

relay-kit not working in server side nodejs backend #621

francelwebdev opened this issue Nov 27, 2023 · 6 comments

Comments

@francelwebdev
Copy link

relay-kit not working in server side nodejs backend

@Gabriel-Mbugua
Copy link

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)```

@Gabriel-Mbugua
Copy link

I figured it out. Seems like the issue was the version. Seems like anything past version 1.3.0 won't work.

@francelwebdev
Copy link
Author

francelwebdev commented Feb 5, 2024

Hi @Gabriel-Mbugua
what did you do in the end? Did it finally work or did you find a solution?

@Gabriel-Mbugua
Copy link

Hi @francelwebdev, below is my integration and package versions.

@safe-global/api-kit@1.3.1
@safe-global/protocol-kit@1.3.0
@safe-global/relay-kit@1.3.0
@safe-global/safe-core-sdk-types@2.3.0
@safe-global/safe-core-sdk@3.3.2

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)
    }
}```

@dasanra
Copy link
Collaborator

dasanra commented Feb 6, 2024

Hi @francelwebdev, below is my integration and package versions.

@safe-global/api-kit@1.3.1 @safe-global/protocol-kit@1.3.0 @safe-global/relay-kit@1.3.0 @safe-global/safe-core-sdk-types@2.3.0 @safe-global/safe-core-sdk@3.3.2

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

relay-kit@2.0.0 will only work with protocol-kit@2.0.0

You should also remove the @safe-global/safe-core-sdk@3.3.2

@Gabriel-Mbugua
Copy link

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)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants