Cryptocurrency bridging

To transfer from bsc to erc20 do you need to make token mintable and burnable to do the bridge function back and forth? Or is that a seperate contract not associated with the original erc20 contract. If so, how do you remove the stigmata that it is mintable at any time?

users have to trust that bridge implementation, for example you can validate that smart contract that does the bridge so that users can see exactly what it can do

2 Likes

yeahh @cryptokid said is mostly right, bridges usually require some level of trust on the implementation, building one is usually difficult too because the blockchains are basically separate system, if one transaction occurs on one chain and it might revert on the other chain you are transferring to, the source blockchain will not even notice it.

But if you’re going with some cross chain functionality, highly recommend you to check the Connext protocol, they have quite decentralized bridge infrastructure to help you make cross-chain transaction and swaps

1 Like

thank you both. the original question was more about the contract for the coin itself. I need to avoid the stigmata that it is mintable. but does the coin need to be mintable and burnable in order to use these bridges? If so then it needs to be mintable regardless. I just dont like what Im seeing with coins like Cake. its way worse than the dollar. its hypocrisy.

I will look into Connext Protocol.

Im not at the bridging step, but I am forseeing this as something necessary in the future and dont want my tokenomics to be done improperly.

Yes I believe so, at least from the bridge level minting and burning feature is used to control the total supply of the coin throughout multiple chains. And yes, this is also to avoid the coin being minted continuously and excessively :raised_hands: of course you need to define you admin/minter access well too so that only certain address will have the authority to do the minting/burning.

Hey everyone, reviving this after some time but I was building on top of the react boilerplate and wanted to integrate bridging. I was looking into Connext but wasn’t entirely sure how I would integrate it with the rest of the boilerplate. They have this sample bridge deployed, should I just attempt to fork over components from this into the boilerplate?
This is a Next project compared to React but things should carry over right?

I would think that you only use that bridge for sending transactions, in case that the bridge already exists as a set of smart contracts.

I’m getting a cloud function error on my server https://5mvwcjt1udmr.usemoralis.com:2053/server. Any way someone can see what’s going on for my cross chain bridge

Can you please make another post with more details - what the error is, what your cloud function is.

> const logger = Moralis.Cloud.getLogger();
> 
> const web3Main = https://speedy-nodes-nyc.moralis.io/602c31f2fce703bb491b08fb/bsc/mainnet
> const web3Side = https://speedy-nodes-nyc.moralis.io/602c31f2fce703bb491b08fb/eth/mainnet
> 
> const MainBridge_address = "";0xd70697B620437Db03c2b0DBE4A1404b8e36bE810n
> const SideBridge_address = "";0x49e7759526092a14016De004a5b3DcEdD912de6Bn
> const mainToken_address = "";0xa701EC6B9C1883fcF727FED7e41FE925A1b1E91Cn
> const childToken_address = "";0xB0b3cF80cAEDdec50f5b803B59B89e4bC4C889FAn
> const gateway_address = "";0x8F1a70DDeb36b715bA8A20b7Dcb021324a821623n
> const gatewayKey = "";646369f30f442aaecfddd2e32410b17ec01cde9888da69df9fb5776a7108e86a
> const MainBridge_abi = '[{"inputs": [{"internalType": "address", "name": "_mainToken", "type": "address"}, {"internalType": "address", "name": "_gateway", "type": "address"}], "stateMutability": "nonpayable", "type": "constructor", "name": "constructor"}, {"anonymous": false, "inputs": [{"indexed": true, "internalType": "address", "name": "requester", "type": "address"}, {"indexed": true, "internalType": "bytes32", "name": "mainDepositHash", "type": "bytes32"}, {"indexed": false, "internalType": "uint256", "name": "amount", "type": "uint256"}, {"indexed": false, "internalType": "uint256", "name": "timestamp", "type": "uint256"}], "name": "TokensLocked", "type": "event"}, {"anonymous": false, "inputs": [{"indexed": true, "internalType": "address", "name": "requester", "type": "address"}, {"indexed": true, "internalType": "bytes32", "name": "sideDepositHash", "type": "bytes32"}, {"indexed": false, "internalType": "uint256", "name": "amount", "type": "uint256"}, {"indexed": false, "internalType": "uint256", "name": "timestamp", "type": "uint256"}], "name": "TokensUnlocked", "type": "event"}, {"inputs": [{"internalType": "address", "name": "_requester", "type": "address"}, {"internalType": "uint256", "name": "_bridgedAmount", "type": "uint256"}, {"internalType": "bytes32", "name": "_mainDepositHash", "type": "bytes32"}], "name": "lockTokens", "outputs": [], "stateMutability": "nonpayable", "type": "function"}, {"inputs": [{"internalType": "address", "name": "_requester", "type": "address"}, {"internalType": "uint256", "name": "_bridgedAmount", "type": "uint256"}, {"internalType": "bytes32", "name": "_sideDepositHash", "type": "bytes32"}], "name": "unlockTokens", "outputs": [], "stateMutability": "nonpayable", "type": "function"}]';
> const SideBridge_abi = '[{"inputs": [{"internalType": "address", "name": "_gateway", "type": "address"}], "stateMutability": "nonpayable", "type": "constructor", "name": "constructor"}, {"anonymous": false, "inputs": [{"indexed": true, "internalType": "uint256", "name": "timestamp", "type": "uint256"}], "name": "BridgeInitialized", "type": "event"}, {"anonymous": false, "inputs": [{"indexed": true, "internalType": "address", "name": "requester", "type": "address"}, {"indexed": true, "internalType": "bytes32", "name": "mainDepositHash", "type": "bytes32"}, {"indexed": false, "internalType": "uint256", "name": "amount", "type": "uint256"}, {"indexed": false, "internalType": "uint256", "name": "timestamp", "type": "uint256"}], "name": "TokensBridged", "type": "event"}, {"anonymous": false, "inputs": [{"indexed": true, "internalType": "address", "name": "requester", "type": "address"}, {"indexed": true, "internalType": "bytes32", "name": "sideDepositHash", "type": "bytes32"}, {"indexed": false, "internalType": "uint256", "name": "amount", "type": "uint256"}, {"indexed": false, "internalType": "uint256", "name": "timestamp", "type": "uint256"}], "name": "TokensReturned", "type": "event"}, {"inputs": [{"internalType": "address", "name": "_requester", "type": "address"}, {"internalType": "uint256", "name": "_bridgedAmount", "type": "uint256"}, {"internalType": "bytes32", "name": "_mainDepositHash", "type": "bytes32"}], "name": "bridgeTokens", "outputs": [], "stateMutability": "nonpayable", "type": "function"}, {"inputs": [{"internalType": "address", "name": "_childTokenAddress", "type": "address"}], "name": "initializeBridge", "outputs": [], "stateMutability": "nonpayable", "type": "function"}, {"inputs": [{"internalType": "address", "name": "_requester", "type": "address"}, {"internalType": "uint256", "name": "_bridgedAmount", "type": "uint256"}, {"internalType": "bytes32", "name": "_sideDepositHash", "type": "bytes32"}], "name": "returnTokens", "outputs": [], "stateMutability": "nonpayable", "type": "function"}]';
> const MainBridge = new web3Main.eth.Contract(JSON.parse(MainBridge_abi),MainBridge_address);
> const SideBridge = new web3Side.eth.Contract(JSON.parse(SideBridge_abi),SideBridge_address);
> 
> Moralis.Cloud.afterSave("EthTokenTransfers", (request) => {
>     const data = JSON.parse(JSON.stringify(request.object, ["token_address", "to_address", "from_address","transaction_hash","value", "confirmed"]));
>     logger.info(data);
>     if (data["token_address"] == mainToken_address.toLocaleLowerCase() && data["to_address"] == MainBridge_address.toLocaleLowerCase() && !data["confirmed"]) {
>         const txlock = processBridgeRequestLock(data);
>         const txbridge = processBridgeRequestBridge(data);
>     }
>     else{
>         logger.info("transaction not related to bridge");
>     }
>     async function processBridgeRequestLock(data) {
>         logger.info("bridging starting locking tokens");
>         const functionCall = MainBridge.methods.lockTokens(data["from_address"],data["value"],data["transaction_hash"]).encodeABI();
>         const gatewayNonce = web3Main.eth.getTransactionCount(gateway_address);
>         const transactionBody = {
>             to: MainBridge_address,
>             nonce:gatewayNonce,
>             data:functionCall,
>             gas:400000,
>             gasPrice:web3Main.utils.toWei("2", "gwei")
>         }
>         signedTransaction = await web3Main.eth.accounts.signTransaction(transactionBody,gatewayKey);
>         logger.info(signedTransaction.transactionHash);
>         fulfillTx = await web3Main.eth.sendSignedTransaction(signedTransaction.rawTransaction);
>         logger.info("fulfillTx: " + JSON.stringify(fulfillTx));
>     }
>     async function processBridgeRequestBridge(data) {
>         logger.info("bridging tokens");
>         const functionCall = SideBridge.methods.bridgeTokens(data["from_address"],data["value"],data["transaction_hash"]).encodeABI();
>         const gatewayNonce = web3Side.eth.getTransactionCount(gateway_address);
>         const transactionBody = {
>             to: SideBridge_address,
>               nonce:gatewayNonce,
>               data:functionCall,
>               gas:400000,
>               gasPrice:web3Side.utils.toWei("2", "gwei")
>         }
>         signedTransaction = await web3Side.eth.accounts.signTransaction(transactionBody,gatewayKey);
>         logger.info(signedTransaction.transactionHash);`Preformatted text`

And I get error this error

2022-05-29T22:43:12.432Z - SyntaxError: Unexpected identifier
at customUserPlugin (/moralis-server/cloud/main.js:157:26)
at /moralis-server/lib/cloud-code/plugins/index.js:144:15
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at async Object.initialize (/moralis-server/lib/cloud-code/plugins/index.js:133:3)

First of all, your addresses and speedy nodes need to be inside the strings. E.g.

const web3Main = "https://speedy-nodes-nyc.moralis.io/602c31f2fce703bb491b08fb/bsc/mainnet";
...
const MainBridge_address = "0xd70697B620437Db03c2b0DBE4A1404b8e36bE810n";
...

Also your MainBridge and SideBridge won’t work, you’re trying to call web3.js methods on strings.

Make sure you’re following your tutorial properly and check that your code matches.

Ok got those fixed no only error I get is undefined is all it says

What have you done so far now and what is the tutorial you’re using?

https://youtu.be/UkWj7rwOGGc Is the tutorial

You can view all of the final code here to compare with your own.

Yes I got the code there my man fixed the address (); with this

const logger = Moralis.Cloud.getLogger();

const web3Main = Moralis.web3ByChain("0x4"); // Rinkeby Testnet
const web3Side = Moralis.web3ByChain("0x13881"); // Mumbai Testnet

const MainBridge_address = "0xd70697B620437Db03c2b0DBE4A1404b8e36bE810";
const SideBridge_address = "0x49e7759526092a14016De004a5b3DcEdD912de6B";
const mainToken_address = "0xa701EC6B9C1883fcF727FED7e41FE925A1b1E91C";
const childToken_address = "0xB0b3cF80cAEDdec50f5b803B59B89e4bC4C889FA";
const gateway_address = "0x8F1a70DDeb36b715bA8A20b7Dcb021324a821623";
const gatewayKey = "646369f30f442aaecfddd2e32410b17ec01cde9888da69df9fb5776a7108e86a";
const MainBridge_abi = '[{"inputs": [{"internalType": "address", "name": "_mainToken", "type": "address"}, {"internalType": "address", "name": "_gateway", "type": "address"}], "stateMutability": "nonpayable", "type": "constructor", "name": "constructor"}, {"anonymous": false, "inputs": [{"indexed": true, "internalType": "address", "name": "requester", "type": "address"}, {"indexed": true, "internalType": "bytes32", "name": "mainDepositHash", "type": "bytes32"}, {"indexed": false, "internalType": "uint256", "name": "amount", "type": "uint256"}, {"indexed": false, "internalType": "uint256", "name": "timestamp", "type": "uint256"}], "name": "TokensLocked", "type": "event"}, {"anonymous": false, "inputs": [{"indexed": true, "internalType": "address", "name": "requester", "type": "address"}, {"indexed": true, "internalType": "bytes32", "name": "sideDepositHash", "type": "bytes32"}, {"indexed": false, "internalType": "uint256", "name": "amount", "type": "uint256"}, {"indexed": false, "internalType": "uint256", "name": "timestamp", "type": "uint256"}], "name": "TokensUnlocked", "type": "event"}, {"inputs": [{"internalType": "address", "name": "_requester", "type": "address"}, {"internalType": "uint256", "name": "_bridgedAmount", "type": "uint256"}, {"internalType": "bytes32", "name": "_mainDepositHash", "type": "bytes32"}], "name": "lockTokens", "outputs": [], "stateMutability": "nonpayable", "type": "function"}, {"inputs": [{"internalType": "address", "name": "_requester", "type": "address"}, {"internalType": "uint256", "name": "_bridgedAmount", "type": "uint256"}, {"internalType": "bytes32", "name": "_sideDepositHash", "type": "bytes32"}], "name": "unlockTokens", "outputs": [], "stateMutability": "nonpayable", "type": "function"}]';
const SideBridge_abi = '[{"inputs": [{"internalType": "address", "name": "_gateway", "type": "address"}], "stateMutability": "nonpayable", "type": "constructor", "name": "constructor"}, {"anonymous": false, "inputs": [{"indexed": true, "internalType": "uint256", "name": "timestamp", "type": "uint256"}], "name": "BridgeInitialized", "type": "event"}, {"anonymous": false, "inputs": [{"indexed": true, "internalType": "address", "name": "requester", "type": "address"}, {"indexed": true, "internalType": "bytes32", "name": "mainDepositHash", "type": "bytes32"}, {"indexed": false, "internalType": "uint256", "name": "amount", "type": "uint256"}, {"indexed": false, "internalType": "uint256", "name": "timestamp", "type": "uint256"}], "name": "TokensBridged", "type": "event"}, {"anonymous": false, "inputs": [{"indexed": true, "internalType": "address", "name": "requester", "type": "address"}, {"indexed": true, "internalType": "bytes32", "name": "sideDepositHash", "type": "bytes32"}, {"indexed": false, "internalType": "uint256", "name": "amount", "type": "uint256"}, {"indexed": false, "internalType": "uint256", "name": "timestamp", "type": "uint256"}], "name": "TokensReturned", "type": "event"}, {"inputs": [{"internalType": "address", "name": "_requester", "type": "address"}, {"internalType": "uint256", "name": "_bridgedAmount", "type": "uint256"}, {"internalType": "bytes32", "name": "_mainDepositHash", "type": "bytes32"}], "name": "bridgeTokens", "outputs": [], "stateMutability": "nonpayable", "type": "function"}, {"inputs": [{"internalType": "address", "name": "_childTokenAddress", "type": "address"}], "name": "initializeBridge", "outputs": [], "stateMutability": "nonpayable", "type": "function"}, {"inputs": [{"internalType": "address", "name": "_requester", "type": "address"}, {"internalType": "uint256", "name": "_bridgedAmount", "type": "uint256"}, {"internalType": "bytes32", "name": "_sideDepositHash", "type": "bytes32"}], "name": "returnTokens", "outputs": [], "stateMutability": "nonpayable", "type": "function"}]';
const MainBridge = new web3Main.eth.Contract(JSON.parse(MainBridge_abi),MainBridge_address);
const SideBridge = new web3Side.eth.Contract(JSON.parse(SideBridge_abi),SideBridge_address);

Moralis.Cloud.afterSave("EthTokenTransfers", (request) => {
    const data = JSON.parse(JSON.stringify(request.object, ["token_address", "to_address", "from_address","transaction_hash","value", "confirmed"]));
    logger.info(data);
    if (data["token_address"] == mainToken_address.toLocaleLowerCase() && data["to_address"] == MainBridge_address.toLocaleLowerCase() && !data["confirmed"]) {
        const txlock = processBridgeRequestLock(data);
        const txbridge = processBridgeRequestBridge(data);
    }
    else{
        logger.info("transaction not related to bridge");
    }
    async function processBridgeRequestLock(data) {
        logger.info("bridging starting locking tokens");
        const functionCall = MainBridge.methods.lockTokens(data["from_address"],data["value"],data["transaction_hash"]).encodeABI();
        const gatewayNonce = web3Main.eth.getTransactionCount(gateway_address);
        const transactionBody = {
            to: MainBridge_address,
            nonce:gatewayNonce,
            data:functionCall,
            gas:400000,
            gasPrice:web3Main.utils.toWei("2", "gwei")
        }
        signedTransaction = await web3Main.eth.accounts.signTransaction(transactionBody,gatewayKey);
        logger.info(signedTransaction.transactionHash);
        fulfillTx = await web3Main.eth.sendSignedTransaction(signedTransaction.rawTransaction);
        logger.info("fulfillTx: " + JSON.stringify(fulfillTx));
    }
    async function processBridgeRequestBridge(data) {
        logger.info("bridging tokens");
        const functionCall = SideBridge.methods.bridgeTokens(data["from_address"],data["value"],data["transaction_hash"]).encodeABI();
        const gatewayNonce = web3Side.eth.getTransactionCount(gateway_address);
        const transactionBody = {
            to: SideBridge_address,
              nonce:gatewayNonce,
              data:functionCall,
              gas:400000,
              gasPrice:web3Side.utils.toWei("2", "gwei")
        }
        signedTransaction = await web3Side.eth.accounts.signTransaction(transactionBody,gatewayKey);
        logger.info(signedTransaction.transactionHash);
        fulfillTx = await web3Side.eth.sendSignedTransaction(signedTransaction.rawTransaction);
        logger.info("fulfillTx: " + JSON.stringify(fulfillTx))
        return fulfillTx;
    }
});


Moralis.Cloud.afterSave("PolygonTokenTransfers", (request) => {
    const data = JSON.parse(JSON.stringify(request.object, ["token_address", "to_address", "from_address","transaction_hash","value", "confirmed"]));
    logger.info(data);
    if (data["token_address"] == childToken_address.toLocaleLowerCase() && data["to_address"] == SideBridge_address.toLocaleLowerCase() && !data["confirmed"]) {
        const txlock = processReturnBurn(data);
        const txbridge = processReturnUnlock(data);
    }
    else{
        logger.info("transaction not related to bridge");
    }
    async function processReturnBurn(data) {
        logger.info("returning tokens burning");
        const functionCall = SideBridge.methods.returnTokens(data["from_address"],data["value"],data["transaction_hash"]).encodeABI();
        const gatewayNonce = web3Side.eth.getTransactionCount(gateway_address);
        const transactionBody = {
            to: SideBridge_address,
              nonce:gatewayNonce,
              data:functionCall,
              gas:400000,
              gasPrice:web3Side.utils.toWei("2", "gwei")
        }
        signedTransaction = await web3Side.eth.accounts.signTransaction(transactionBody,gatewayKey);
        logger.info(signedTransaction.transactionHash);
        fulfillTx = await web3Side.eth.sendSignedTransaction(signedTransaction.rawTransaction);
        logger.info("fulfillTx: " + JSON.stringify(fulfillTx))
        return fulfillTx;
    }
    async function processReturnUnlock(data) {
        logger.info("returning starting unlocking tokens");
        const functionCall = MainBridge.methods.unlockTokens(data["from_address"],data["value"],data["transaction_hash"]).encodeABI();
        const gatewayNonce = web3Main.eth.getTransactionCount(gateway_address);
        const transactionBody = {
            to: MainBridge_address,
              nonce:gatewayNonce,
              data:functionCall,
              gas:400000,
              gasPrice:web3Main.utils.toWei("2", "gwei")
        }
        signedTransaction = await web3Main.eth.accounts.signTransaction(transactionBody,gatewayKey);
        logger.info(signedTransaction.transactionHash);
        fulfillTx = await web3Main.eth.sendSignedTransaction(signedTransaction.rawTransaction);
        logger.info("fulfillTx: " + JSON.stringify(fulfillTx));
    }
});

God makes it look so easy in the video dang only get this error now

  1. 2022-05-30T00:07:51.192Z - undefined
  2. 2022-05-30T00:07:51.191Z - CLOUD FUNCTION ERROR PLEASE CHECK YOUR CLOUD FUNCTION CODE

Is everything in a cloud function?

Moralis.Cloud.define('bridge', async (request) => {

...

});