# Back end

* Example of relaying a transaction
* Reading a player structure (simple GET API endpoit)

## The role of the back-end in a wallet-less dApp

In the previous section (Build a gas-less transaction), we learned how to use Moonbeam's callPermit in order to relay a transaction and make it gassless. In order to go one step further and removing the need to sign a transaction, the transaction is going to be generated by the mirror wallet and dispatched by the contract's owner (or any authorized address defined in a particular modifier).

The backend is going to generate the data to sign and execute it on behalf of the user, following for instance a web2 POST call.

### Example of a simple Express POST function

```javascript
app.post('/doTx', async (req, res) => {
  let infos = await req.body
  let sendTxn = await prepareCall(infos)
    if (await sendTxn == true) {
      await res.status(200).json({ 'ok': true, 'message': 'Tx successfully sent!' })
    }
    else {
      await res.status(200).json({ 'ok': false, 'message': 'There was a problem during the tx' })
    }
})
```

### Example of a function that encodes, sign, relay/executes a transaction

```javascript
// dependencies
let ethers = require('ethers');
let {
    signTypedData,
    SignTypedDataVersion
} = require('@metamask/eth-sig-util');

async function prepareCall(userData) {
    let dataFct
    let messageData
    let finalCall
    let formattedSignature = {}

    // first we use the real EOA address received in the post
    let wallet = userData.userWallet
    // we then get its mirror's wallet private key
    let key = await getPvKey(wallet) // here you need to create a function able to get the mirror wallet private key using your own security standard
    let userSigner = new ethers.Wallet(await key, provider); // internal wallet signer
    let publicAddy = await userSigner.getAddress() // internal wallet address
    let currentNonce = await getNonces(publicAddy) // useful function made by Moonbeam to get the current Nonces for an address (see helpers below)

    // here we're encoding the function using the required arguments
    let iface = new ethers.utils.Interface(yourABI);
    dataFct = iface.encodeFunctionData("yourSolidityFunction",
        [
            arg1,
            arg2,
            arg3
        ])
    userData.encoded = dataFct

    // function to generate compliant message for callPermit
    const createPermitMessageData = async function() {
        const message = {
            from: publicAddy,
            to: yourContractAddress,
            value: 0,
            data: userData.encoded,
            gaslimit: 300000,
            nonce: currentNonce.toNumber(),
            deadline: Date.now() + (5 * 60 * 1000),
        };
        const typedData = {
            types: {
                EIP712Domain: [{
                    name: 'name',
                    type: 'string'
                }, {
                    name: 'version',
                    type: 'string'
                }, {
                    name: 'chainId',
                    type: 'uint256'
                }, {
                    name: 'verifyingContract',
                    type: 'address'
                }, ],
                CallPermit: [{
                    name: 'from',
                    type: 'address'
                }, {
                    name: 'to',
                    type: 'address'
                }, {
                    name: 'value',
                    type: 'uint256'
                }, {
                    name: 'data',
                    type: 'bytes'
                }, {
                    name: 'gaslimit',
                    type: 'uint64'
                }, {
                    name: 'nonce',
                    type: 'uint256'
                }, {
                    name: 'deadline',
                    type: 'uint256'
                }, ],
            },
            primaryType: 'CallPermit',
            domain: {
                name: 'Call Permit Precompile',
                version: '1',
                chainId: 1284,
                verifyingContract: '0x000000000000000000000000000000000000080a',
            },
            message: message,
        };
        return {
            typedData,
            message,
        };
    };

    try {
        messageData = await createPermitMessageData();
    } catch (errMd) {
        console.log(errMd)
    }
    
    // sign the message
    let signature
    try {
        signature = signTypedData({
            privateKey: Buffer.from(key, 'hex'),
            data: await messageData.typedData,
            version: SignTypedDataVersion.V4,
        });
        console.log(`Signature successful with hash: ${signature}`);
    } catch (signErr) {
        console.log(signErr, 'signErr')
    }

    try {
        // validate the message
        let {
            r,
            s,
            v
        } = await getSignatureParameters(signature); // see helpers below
        formattedSignature = {
            r: r,
            s: s,
            v: v,
        };

    } catch (sigError) {
        console.log(sigError)
    }

    try {
        finalCall = await {
            'message': await messageData.message,
            'signature': await formattedSignature,
            'config': await userData
        }
    } catch (err) {
        console.log(err)
    }

    try {
        let deployerKey = "yourPrivateKey" // only for development purpose, don't do that on production
        let deployerSigner = new ethers.Wallet(deployerKey, provider);
        const preCompileContract = new ethers.Contract(callPermitAddress, callPermitABI, deployerSigner)
        let tx = await preCompileContract.dispatch(
            finalCall.message.from,
            finalCall.message.to,
            finalCall.message.value,
            finalCall.message.data,
            finalCall.message.gaslimit,
            finalCall.message.deadline,
            finalCall.signature.v,
            finalCall.signature.r,
            finalCall.signature.s)
        let result = await tx.wait()
        await console.log('Tx succesfull!')
        return true
    } catch (err) {
        console.log(err)
        return false
    }
}

// useful helpers made by Moonbeam team
async function getSignatureParameters(signature) {
    if (!ethers.utils.isHexString(signature)) {
        throw new Error(
            'Given value "'.concat(signature, '" is not a valid hex string.')
        );
    }
    var r = signature.slice(0, 66);
    var s = "0x".concat(signature.slice(66, 130));
    var v = "0x".concat(signature.slice(130, 132));
    v = ethers.BigNumber.from(v).toNumber();
    if (![27, 28].includes(v)) v += 27;
    return {
        r: r,
        s: s,
        v: v
    };
};

async function getNonces(wallet) {
    const preCompileContract = new ethers.Contract(callPermitAddress, callPermitABI, provider)
    let nonce
    try {
        nonce = await preCompileContract.nonces(wallet);
    } catch (nonceErr) {
        console.log(nonceErr, 'nonce error')
    }
    return await nonce
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://jungle-toolkit.gitbook.io/evm-xcm-jungle-toolkit/build-a-custodial-solution-to-make-your-dapp-wallet-less-and-gas-less-using-eip-712/back-end.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
