# Multichain RWA Lending with Axelar GMP

Today, we see many different networks, each with its own strengths and limitations. This has created significant challenges, leading to scattered liquidity and complicated user experiences, especially in Real World Asset (RWA) lending.

To tackle these challenges, Axelar, the leading Web3 interoperability platform, has a feature called [Axelar's General Message Passing (GMP)](https://docs.axelar.dev/dev/general-message-passing/overview), which offers an effective and scalable solution. It enables secure and efficient communication between blockchains beyond simple asset transfers.

To understand how Axelar's GMP can impact real-world scenarios, let's consider an example of how blockchain technology is already changing lives.

A farmer named Amani lives in a small village with acres of fertile land but can't get a loan from local banks because he lacks a traditional credit score. Now, think of Sarah, a tech entrepreneur in New York working on blockchain solutions. Their worlds seem far apart, but blockchain technology could connect them. Consider [Goldfinch](https://goldfinch.finance/), a real-world example in the DeFi space. It allows borrowers from emerging markets to secure loans using real-world assets as collateral, funded by global investors who trust in blockchain's transparency. This system opens doors for people previously excluded from the financial system.

Now, imagine scaling this idea across multiple blockchains, each optimized for different strengths like speed, security, or low fees. A multichain platform could tap into the best of each world, creating a truly global lending ecosystem that operates 24/7, without borders, and with minimal friction.

In this guide, we'll explore how to build a multichain real-world asset lending platform using Axelar GMP. If you want to see the complete code, you can find it on GitHub [**here**](https://gist.github.com/Olanetsoft/1689f5860413478d0f82aaf90051b31a).

## What is a Real-world Asset (RWA)?

A [Real-World Asset (RWA)](https://www.coinbase.com/en-gb/learn/crypto-glossary/what-are-real-world-assets-rwa) is a digital representation of a tangible or intangible asset that exists outside the blockchain ecosystem. These digital tokens symbolize ownership or rights to various types of assets, such as:

1. Real estate.
    
2. Commodities (e.g., gold, oil).
    
3. Fine art.
    
4. Intellectual property.
    
5. Financial instruments (e.g., stocks, bonds).
    

The process of creating these digital representations is called **tokenization**. This involves converting real-world assets into blockchain-based tokens. The following are the advantages of tokenization:

1. Increased liquidity: Assets previously difficult to divide or trade can now be easily bought and sold in smaller fractions.
    
2. Broader accessibility: Investors can access a wider range of assets with lower capital requirements.
    
3. Improved transparency: Blockchain technology provides a clear, immutable record of ownership and transactions.
    
4. Enhanced efficiency: Tokenization can streamline various processes by reducing administrative overhead and costs.
    

## Prerequisites

* A good understanding of [**Solidity**](https://www.tutorialspoint.com/solidity/index.htm)**.**
    
* A [MetaMask wallet](https://metamask.io/) with FTM and Celo funds for testing. If you don’t have these funds, you can get FTM from the [Fantom faucet](https://faucet.fantom.network/) and Celo from the [Celo faucets](https://faucet.celo.org/alfajores).
    
* `aUSDC` [faucet](https://discord.com/invite/aRZ3Ra6f7D).
    
* Familiarity with the [remix.ethereum.org](http://remix.ethereum.org/) portal.
    

Before we get started, let's outline what we'll be doing and why each component is important for our multichain RWA lending platform:

1. `MockRWAToken`: This contract will simulate a tokenized real-world asset. For our demonstration, we'll create a simplified version that allows us to mint and transfer tokens.
    
2. `RWAOracle`: This contract will act as a price feed for our RWA tokens. For our purposes, we'll create a simple oracle that allows us to set and update asset values manually.
    
3. `LendingPool`: This is the core contract of our platform. It will handle the creation of loans, manage collateral, and facilitate cross-chain interactions using Axelar GMP.
    

By creating these contracts, we can simulate a simple RWA lending platform that works across different blockchains. This setup will let users, like our example farmer Amani, use their tokenized real-world assets as collateral, even if the lender is on another blockchain network.

Next, we'll start by creating the `MockRWAToken`. This will serve as the foundation for our platform, representing the tokenized real-world assets that can be used as collateral.

## Create a Mock RWA Token

To begin your implementation, you’ll start by creating a `MockRWAToken` contract. This will serve as a representation of tokenized real-world assets.

* Navigate to [remix.ethereum.org](http://remix.ethereum.org).
    
* Create a new folder named "contracts".
    
* Inside this folder, create a new file called `MockRWAToken.sol`.
    

![Navigate to remix.ethereum.org](https://cdn.hashnode.com/res/hashnode/image/upload/v1728156591878/60b0df53-6543-4f1d-a9e2-3df4c2de0405.png align="center")

Add the following code snippet to the file:

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

contract MockRWAToken is ERC721, Ownable {
    uint256 private _nextTokenId;

    constructor(
        address initialOwner
    ) ERC721("Mock RWA", "MRWA") Ownable(initialOwner) {}

    function safeMint(address to) public onlyOwner {
        uint256 tokenId = _nextTokenId++;
        _safeMint(to, tokenId);
    }
}
```

In the code snippet above, you:

* Created an ERC721 token contract named "Mock RWA" with the symbol "MRWA"
    
* Implemented a `safeMint` function that allows the contract owner to create new tokens
    
* Used OpenZeppelin's ERC721 and Ownable contracts for standard functionality and access control
    

In the next step, you will create the `RWAOracle` contract, which will provide price information for your tokenized assets. This oracle will help determine the value of the assets used as collateral in your lending platform.

## Create a Mock RWA Oracle

In your `contracts` folder, create a new file named `RWAOracle.sol` add the following code snippet:

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/access/Ownable.sol";

// RWA Oracle
contract RWAOracle is Ownable {
    constructor(address initialOwner) Ownable(initialOwner) {}

    mapping(uint256 => uint256) private rwaValues;

    event RWAValueUpdated(uint256 indexed tokenId, uint256 value);

    function updateRWAValue(
        uint256 _tokenId,
        uint256 _value
    ) external onlyOwner {
        rwaValues[_tokenId] = _value;
        emit RWAValueUpdated(_tokenId, _value);
    }

    function getRWAValue(uint256 _tokenId) external view returns (uint256) {
        return rwaValues[_tokenId];
    }
}
```

This contract provides two key functions:

* `updateRWAValue`: Allows the contract owner to set or update the value of an RWA token.
    
* `getRWAValue`: Retrieves the current value of a specific RWA token
    

> In a production environment, this oracle would connect with real-world data sources to provide accurate, up-to-date asset valuations. For our demonstration, this simplified version is enough to show the main features of our lending platform.

Next, you'll create the `LendingPool` contract, which will connect the `MockRWAToken` and `RWAOracle` to enable cross-chain lending operations.

## Create the Lending Pool Contract

Now that you have your `MockRWAToken` and `RWAOracle` ready, you can move on to creating the `LendingPool` contract. In your `contracts` folder, create a new file named `LendingPool.sol`.

### Import Necessary Contracts

Add the following code snippet to import the necessary contracts.

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Import required OpenZeppelin contracts
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";

// Import Axelar contracts for cross-chain functionality
import "@axelar-network/axelar-gmp-sdk-solidity/contracts/executable/AxelarExecutable.sol";
import "@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IAxelarGasService.sol";

// Import our custom RWAOracle contract
import "./RWAOracle.sol";

contract LendingPool is AxelarExecutable, ReentrancyGuard, Ownable {

	// Contract code here
	
}
```

### Add State Variables, Structs, and Events

```solidity
//...

contract LendingPool is AxelarExecutable, ReentrancyGuard, Ownable {

		// Main contract interfaces
		IERC20Metadata public lendingToken;
		ERC721 public rwaToken;
		RWAOracle public rwaOracle;
		IAxelarGasService public immutable gasService;
		
		// Constants for loan parameters
		uint256 public constant LIQUIDATION_THRESHOLD = 150;
		uint256 public constant INTEREST_RATE = 5;
		
		// Cross-chain source information
		string public sourceAddress;
		string public sourceChain;
		
		// Loan struct to store loan information
		struct Loan {
		    uint256 amount;
		    uint256 collateralId;
		    uint256 startTime;
		    uint256 duration;
		    address borrower;
		    bool isActive;
		}
		
		// Mapping to store loans by ID
		mapping(uint256 => Loan) public loans;
		uint256 public nextLoanId;
		
		// Events for various loan actions
		event LoanCreated(uint256 loanId, address borrower, uint256 amount, uint256 collateralId);
		event LoanRepaid(uint256 loanId);
		event LoanLiquidated(uint256 loanId, address liquidator);
		event CrossChainLoanRepaid(uint256 loanId);
		event CollateralReleased(uint256 loanId, uint256 collateralId, address borrower);
}
```

In the code above, you:

* Defined key contract components: tokens, oracle, loan parameters
    
* Created Loan `struct` to store loan information
    
* Created events for contract actions like `LoanCreated`, `LoanRepaid`, `LoanLiquidated`, `CrossChainLoanRepaid`, `CollateralReleased`
    

Ignore the red lines showing on your remix right now; you will fix it in a bit.

### Implement the Constructor

```solidity
//...
contract LendingPool is AxelarExecutable, ReentrancyGuard, Ownable {

	//...

	constructor(
	    address _initialOwner,
	    address _gateway,
	    address _gasService,
	    address _lendingToken,
	    address _rwaToken,
	    address _rwaOracle
	) AxelarExecutable(_gateway) Ownable(_initialOwner) {
	    // Initialize contract components
	    gasService = IAxelarGasService(_gasService);
	    lendingToken = IERC20Metadata(_lendingToken);
	    rwaToken = ERC721(_rwaToken);
	    rwaOracle = RWAOracle(_rwaOracle);
	}

}
```

In the code above, you implemented the constructor, set up the contract with the necessary addresses, and initialized the inherited contracts.

Next, you will proceed to implement the main functions, starting with a function to initiate a multichain loan.

### Create a Multichain Loan Function

This function allows users to initiate a loan on a different blockchain using their RWA token as collateral. To do this, add the following code to your `LendingPool` contract:

```solidity
//...
contract LendingPool is AxelarExecutable, ReentrancyGuard, Ownable {

	//...

    function initiateCrossChainLoan(
        string memory destinationChain,
        string memory destinationAddress,
        uint256 _amount,
        uint256 _collateralId,
        uint256 _duration
    ) external payable {
        // Ensure gas payment is provided
        require(msg.value > 0, "Gas payment is required");
    
        // Check if the sender owns the RWA token
        require(
            rwaToken.ownerOf(_collateralId) == msg.sender,
            "Not the owner of the RWA"
        );
    
        // Verify collateral value is sufficient
        uint256 collateralValue = rwaOracle.getRWAValue(_collateralId);
        require(
            (collateralValue * 100) / _amount >= LIQUIDATION_THRESHOLD,
            "Insufficient collateral"
        );
    
        // Prepare payload for cross-chain message
        bytes memory payload = abi.encode(
            msg.sender,
            _amount,
            _collateralId,
            _duration
        );
    
        // Pay for gas on the source/destination chain
        gasService.payNativeGasForContractCallWithToken{value: msg.value}(
            address(this),
            destinationChain,
            destinationAddress,
            payload,
            lendingToken.symbol(),
            _amount,
            msg.sender
        );
    
        // Transfer collateral to this contract
        rwaToken.transferFrom(msg.sender, address(this), _collateralId);
    
        // Transfer lending tokens to this contract
        lendingToken.transferFrom(msg.sender, address(this), _amount);
    
        // Approve gateway to spend lending tokens
        lendingToken.approve(address(gateway), _amount);
    
        // Initiate cross-chain call with token transfer
        gateway().callContractWithToken(
            destinationChain,
            destinationAddress,
            payload,
            lendingToken.symbol(),
            _amount
        );
    }
}
```

In the code snippet above, you:

* Implemented verification of gas payment for cross-chain operation
    
* Check ownership of the RWA token and ensure collateral value meets the liquidation threshold
    
* Prepared the payload for cross-chain messages and paid for gas on the source/destination chain
    
* Transferred RWA token (collateral) to the contract using the `transferFrom`
    
* Transferred lending tokens to the contract with the `transferFrom` method and approved the gateway to spending lending tokens by calling the `approve` method
    
* Finally, Initiated the cross-chain call using `callContractWithToken`
    

### Create Repay Cross-Chain Loan Function

When a cross-chain loan is initiated and collateral is received, users need to repay the loan when they are ready. To achieve this, you will implement the loan repayment function.

In the contract, create a function named `repayCrossChainLoan` that accepts `_loanId`, `destinationChain`, and `destinationAddress` to repay the loan.

To do this, add the following code snippet below:

```solidity
//...

contract LendingPool is AxelarExecutable, ReentrancyGuard, Ownable {

	//...
    function repayCrossChainLoan(
        uint256 _loanId,
        string memory destinationChain,
        string memory destinationAddress
    ) external payable nonReentrant {
        // Ensure gas payment is provided
        require(msg.value > 0, "Gas payment is required");
    
        // Retrieve loan details
        Loan storage loan = loans[_loanId];
    
        // Verify loan status and borrower
        require(loan.isActive, "Loan is not active");
        require(loan.borrower == msg.sender, "Not the borrower");
    
        // Calculate total repayment amount
        uint256 interest = calculateInterest(
            loan.amount,
            loan.startTime,
            loan.duration
        );
        uint256 totalRepayment = loan.amount + interest;
    
        // Transfer repayment amount from borrower
        require(
            lendingToken.transferFrom(
                msg.sender,
                address(this),
                totalRepayment
            ),
            "Transfer failed"
        );
    
        // Mark loan as inactive
        loan.isActive = false;
    
        // Prepare payload for cross-chain message
        bytes memory payload = abi.encode(
            _loanId,
            loan.collateralId,
            loan.borrower
        );
    
        // Pay for gas on the destination chain
        gasService.payNativeGasForContractCallWithToken{value: msg.value}(
            address(this),
            destinationChain,
            destinationAddress,
            payload,
            lendingToken.symbol(),
            loan.amount,
            msg.sender
        );
    
        // Initiate cross-chain call to release collateral
        gateway().callContract(sourceChain, sourceAddress, payload);
    
        // Emit event for cross-chain loan repayment
        emit CrossChainLoanRepaid(_loanId);
    }
}
```

In the code snippet above, you:

* Implemented a check for gas payment to cover cross-chain operation costs
    
* Retrieved and verified the loan details, ensuring the loan is active, and the caller is the borrower
    
* Calculated the total repayment amount, including interest, using the `calculateInterest` function
    
* Transferred the repayment amount from the borrower to the contract using `transferFrom`
    
* Marked the loan as inactive after successful repayment
    
* Prepared a payload for the cross-chain message, including loan ID, collateral ID, and borrower address
    
* Utilized the `gasService` to pay for gas on the source/destination chain, ensuring smooth cross-chain operation
    
* Initiated a cross-chain call using `gateway.callContract` to trigger collateral release on the source chain
    
* Emitted a `CrossChainLoanRepaid` event to log the successful repayment
    

In the step above, you called the `calculateInterest` function, but it hasn't been implemented yet. Let’s do that in the following step.

### Implement Interest Calculation Function

This function calculates the interest for a loan based on the loan amount, start time, and duration.

```solidity
//...

contract LendingPool is AxelarExecutable, ReentrancyGuard, Ownable {

	//...

    function repayCrossChainLoan(){
    //...
    }

    function calculateInterest(
        uint256 _amount,
        uint256 _startTime,
        uint256 _duration
    ) public view returns (uint256) {
        uint256 timeElapsed = block.timestamp - _startTime;
    
        // Cap the time elapsed to the loan duration
        if (timeElapsed > _duration) {
            timeElapsed = _duration;
        }
    
        // Calculate interest: (amount * rate * time) / (365 days * 100 * 10^decimals)
        // For a 5% annual rate
        uint256 interest = (_amount * 5 * timeElapsed) / (365 days * 100);
    
        // Adjust for token decimals (assuming 6 decimals for USDC)
        return interest / 1e6;
    }
}
```

In the code snippet above, you:

* Calculated the time elapsed since the loan started using `block.timestamp`
    
* Implemented a cap on the elapsed time to ensure it doesn't exceed the loan duration
    
* Computed the interest using a formula that accounts for a 5% annual rate: `(amount * rate * time) / (365 days * 100)`
    
* Adjusted the calculated interest for token decimals, assuming 6 decimal places for USDC
    
* Returned the final interest amount
    

Next, you will implement the `_executeWithToken` to handle transferring the loan amount to the borrower.

### Create the `_executeWithToken` Function

In this step, you'll implement the `_executeWithToken` function that manages cross-chain token transfers and loan creation on the destination chain. This function is essential for completing the cross-chain loan process.

```solidity
//...

contract LendingPool is AxelarExecutable, ReentrancyGuard, Ownable {

	//...
    function _executeWithToken(
        bytes32 commandId, 
        string calldata _sourceChain,
        string calldata _sourceAddress,
        bytes calldata payload,
        string calldata tokenSymbol,
        uint256
    ) internal override {
        // Verify that the received token matches the lending token
        require(
            keccak256(bytes(tokenSymbol)) ==
                keccak256(bytes(lendingToken.symbol())),
            "Invalid token"
        );
    
        // Store the source chain and address
        sourceAddress = _sourceAddress;
        sourceChain = _sourceChain;
    
        // Decode the payload to extract loan details
        (
            address borrower,
            uint256 _amount,
            uint256 _collateralId,
            uint256 _duration
        ) = abi.decode(payload, (address, uint256, uint256, uint256));
    
        // Create a new loan internally
        uint256 loanId = _createLoanInternal(
            borrower,
            _amount,
            _collateralId,
            _duration
        );
    
        // Transfer the loan amount to the borrower
        require(lendingToken.transfer(borrower, _amount), "Transfer failed");
    
        // Emit an event for the created loan
        emit LoanCreated(loanId, borrower, _amount, _collateralId);
    }
}
```

In the code snippet above, you:

* Verified that the received token symbol matches the lending token symbol using `keccak256` hash comparison
    
* Stored the source chain and address for future reference
    
* Decoded the payload to extract loan details, including borrower address, loan amount, collateral ID, and loan duration
    
* Created a new loan internally by calling the `_createLoanInternal` function with the extracted details
    
* Transferred the loan amount to the borrower using the `transfer` method of the lending token
    
* Emitted a `LoanCreated` event with the new loan's details
    

In the implementation above, you called the `_createLoanInternal` function, but it hasn't been implemented yet. Let’s do that in the following step.

### Implement `_createLoanInternal` Function

The `_createLoanInternal` function is a helper function used to create a new loan with the internal type that returns the loan ID.

```solidity
//...

contract LendingPool is AxelarExecutable, ReentrancyGuard, Ownable {

	//...
    function _createLoanInternal(
        address borrower,
        uint256 _amount,
        uint256 _collateralId,
        uint256 _duration
        ) internal returns (uint256) {
            // Generate a new unique loan ID
            uint256 loanId = nextLoanId++;
        
            // Create a new Loan struct and store it in the loans mapping
            loans[loanId] = Loan({
                amount: _amount,          // The amount of the loan
                collateralId: _collateralId,  // ID of the collateral RWA token
                startTime: block.timestamp,   // Current time as the loan start time
                duration: _duration,      // Duration of the loan
                borrower: borrower,       // Address of the borrower
                isActive: true            // Mark the loan as active
            });
        
            // Return the newly created loan ID
            return loanId;
    }
}
```

In the code snippet above, you:

* Generated a new loan ID by incrementing the `nextLoanId` counter
    
* Created a new `Loan` Struct with the provided parameters and additional details:
    
    * Set the loan amount, collateral ID, and duration as provided
        
    * Recorded the current timestamp as the loan's start time
        
    * Set the borrower's address
        
    * Marked the loan as active
        
* Stored the new loan in the `loans` mapping using the generated loan ID
    
* Returned the new loan ID
    

You're almost done! It's great to see you've made it this far in the tutorial.

### Implement `_execute` Function for Incoming Cross-chain Message

This `_execute` function is automatically called by the [Axelar relayers](https://docs.axelar.dev/dev/evm-relayer/). It decodes the incoming payload and releases the collateral to the borrower on the source chain. Add the following code snippet to your contract.

```solidity
//...

contract LendingPool is AxelarExecutable, ReentrancyGuard, Ownable {

	//...
    function _execute(
        bytes32,
        string calldata,
        string calldata,
        bytes calldata payload
    ) internal override {
        (uint256 loanId, uint256 collateralId, address borrower) = abi.decode(
            payload,
            (uint256, uint256, address)
        );
    
        // Release the collateral
        rwaToken.transferFrom(address(this), borrower, collateralId);
    
        emit CollateralReleased(loanId, collateralId, borrower);
    }
}
```

In the next step, you will test the contract using Fantom and Celo in this tutorial. However, feel free to use any network you prefer.

## Testing the Lending Pool Contract

You will test all the contracts you have built during this tutorial. To proceed, deploy and mint mock RWA tokens to the specified address.

### Deploy Mock RWA Token

You will deploy the mock RWA Token on the Fantom network. Click on the `MockRWAToken.sol` file and go to the deploy section, as shown below.

![Deploy Mock RWA Token](https://cdn.hashnode.com/res/hashnode/image/upload/v1728318354282/eaeec873-0c9e-44c7-8fb0-1a4b9a14ba0d.png align="center")

Next, click `Transact` and specify your address.

![Next, click Transact and specify your address](https://cdn.hashnode.com/res/hashnode/image/upload/v1728318741272/52fcb11d-f0d9-440c-9af8-6face742b8f5.png align="center")

After deployment, you should be able to see the transaction chain similar to [this](https://testnet.ftmscan.com/tx/0xcba609b0ee304fb77dc66117f7088070650966594049caa5cee95a41ec608c96). in the next step you will mint tokens to your preferred address.

### Mint RWA tokens

Scroll down to the deploy section on Remix, as shown below, to use the `safeMint` method. Mint the token to the specified address and click on `transact`.

![Mint RWA tokens](https://cdn.hashnode.com/res/hashnode/image/upload/v1728319242378/f6092895-6a4e-47c0-b2f8-2824a22a7805.png align="center")

Check out the transaction [here](https://testnet.ftmscan.com/tx/0x363f22e28dbe0b496957f4cf95dea6ec2a0236fc03753aad2a82ae9228702892). Your transaction should look similar. To confirm, you can use the `balanceOf` method to verify, as shown below, where you can see the specified address has a balance of `1`.

![Check out the transaction here](https://cdn.hashnode.com/res/hashnode/image/upload/v1728319545132/22b64815-e35e-413b-b0c3-3178e4d90e40.png align="center")

Next, you will deploy the RWAOracle contract, which simulates the Oracle price feed flow.

### Deploy RWAOracle Contract

To deploy the `RWAOracle` contract, navigate to the `RWAOracle.sol` file on the Fantom network and deploy the contract as shown below.

![Deploy RWAOracle Contract](https://cdn.hashnode.com/res/hashnode/image/upload/v1728320092689/96a80d29-2ca0-43ea-a348-91c5d1bcbaf2.png align="center")

After deploying, you should have a transaction on-chain similar to [this](https://testnet.ftmscan.com/tx/0xffa082cf3277c5e552e0f6d65de92f4314cdc11f8599b4ff70d4448f16d020de) on the Fantom network.

### Set RWA Token Value

Next, set the RWA token value of the token you minted in the previous step. as shown below. The `_tokenId` is 0 (this is the first token minted), `_value` should be set to `20000000` which is 20×10^6.

![Set RWA Token Value](https://cdn.hashnode.com/res/hashnode/image/upload/v1728321425002/50ff5572-3c58-4b5a-8490-f13d17fe902c.png align="center")

After updating the RWA token value, you should have a transaction on-chain similar to [this](https://testnet.ftmscan.com/tx/0x652a02d3c7983765a1edd66cfd063d4e0c64c1b21a831e5eb12b99495199af21).

### Deploy the Lending Pool Contract on the Fantom Testnet

Deploying the `LendingPool` contract is similar to how you deployed the other contracts earlier in this tutorial. Go to the lending pool contract file, click on the deploy section, and enter the following details as arguments for the contract. Then, click `transact` to deploy the contract on the Fantom testnet.

```bash
_initialOwner: 0x510e5EA32386B7C48C4DEEAC80e86859b5e2416C // Replace with your address
_gateway: 0x97837985Ec0494E7b9C71f5D3f9250188477ae14
_gasService: 0xbE406F0189A0B4cf3A05C286473D23791Dd44Cc6
_lendingToken: 0x75Cc4fDf1ee3E781C1A3Ee9151D5c6Ce34Cf5C61
_rwaToken: 0x1C84e5556301202e6f6d4826Be5e13265E48ee17
_rwaOracle: 0x57d6A23A9cD2A719A8da3e47b402c0E88AB6036E
```

The `_initialOwner` is the address of the account that minted the token. You can find the `_gateway` and `_gasService` addresses in the Axelar documentation [here](https://docs.axelar.dev/resources/contract-addresses/testnet/). This `lendingToken` is the `aUSDC` asset that the user will lend. For the Fantom network, scroll down on this [page](https://docs.axelar.dev/resources/contract-addresses/testnet/) to the `Assets` section and copy the [aUSDC contract](https://testnet.ftmscan.com/address/0x75Cc4fDf1ee3E781C1A3Ee9151D5c6Ce34Cf5C61) address on Fantom.

![Transaction info](https://cdn.hashnode.com/res/hashnode/image/upload/v1728322716138/83b238ac-dcbf-4c45-a0f1-4913af739e0e.png align="center")

You can find the transaction link [here](https://testnet.ftmscan.com/tx/0xfb7d684279a293a220db636ff2a79579025b845ddf012d92491be4e856e9eb13).

### Deploy the Lending Pool Contract on the Celo Testnet

Since this tutorial focuses on multichain lending, you will work with contracts on both the Fantom Testnet and the Celo Testnet. You will also deploy the contract on Celo before testing the cross-chain lending feature. Follow the same steps you used to deploy on the Fantom Testnet.

```bash
_initialOwner: 0x510e5EA32386B7C48C4DEEAC80e86859b5e2416C // Replace with your address
_gateway: 0xe432150cce91c13a887f7D836923d5597adD8E31
_gasService: 0xbE406F0189A0B4cf3A05C286473D23791Dd44Cc6
_lendingToken: 0x254d06f33bDc5b8ee05b2ea472107E300226659A
_rwaToken: 0x1C84e5556301202e6f6d4826Be5e13265E48ee17
_rwaOracle: 0x57d6A23A9cD2A719A8da3e47b402c0E88AB6036E
```

The `_initialOwner` is the address of the account that minted the token. You can find the `_gateway` and `_gasService` addresses in the Axelar documentation [here](https://docs.axelar.dev/resources/contract-addresses/testnet/). This `lendingToken` is the `aUSDC` asset that the user will lend. For the Celo test network, scroll down on this [page](https://docs.axelar.dev/resources/contract-addresses/testnet/) to the `Assets` section and copy the [aUSDC contract](https://alfajores.celoscan.io//address/0x254d06f33bDc5b8ee05b2ea472107E300226659A) address on Celo.

![Transaction details](https://cdn.hashnode.com/res/hashnode/image/upload/v1728322716138/83b238ac-dcbf-4c45-a0f1-4913af739e0e.png align="center")

You can find the transaction link [here](https://alfajores.celoscan.io/tx/0xf43e724fc70e186cbdadc2732fa7fe752647bb736dfe097d22b0b824bb16ffb3).

The next step is to initiate the cross-chain loan. Before doing that, you need to approve the lending pool contract address on the `MockRWAToken` contract on the Fantom testnet to allow the transfer of the asset from the user.

### Approve the Lending Pool Contract Address on MockRWAToken on the Fantom Testnet

Navigate to the MockRWAToken Deployment as shown below and click on approve, then specify the contract address.

![Approve the Lending Pool Contract Address on MockRWAToken on the Fantom Testnet](https://cdn.hashnode.com/res/hashnode/image/upload/v1728390800305/d5e31e7f-7bb2-4116-8aa6-e019b0cf3267.png align="center")

Please switch your network back to the Fantom testnet from Celo and then click the “transact” button.

![Switch your network back to the Fantom testnet](https://cdn.hashnode.com/res/hashnode/image/upload/v1728390815913/5e1aab16-f91d-4870-8051-4f6ae566e1cd.png align="center")

After approval is successful, you should have the transaction onchain similar to [this](https://testnet.ftmscan.com/tx/0x20f845beccafa2d56ee31de48a97cdb616545417afded7e71719e23f77cf4dfb).

### Approve Lending Pool Contract to Spend the Asset to Be Borrowed

In the lending pool contract, there is an implementation inside the `initiateCrosschainLoan` function. You must approve the `LendingPool` contract address on the lending token contract (the asset you want to lend out).

> The asset you are using is aUSDC. If you don't have it, please request it on our Discord channel [here](https://discord.com/invite/aRZ3Ra6f7D) by going to the faucet channel and asking for it for free.

```solidity
//...

// Transfer lending tokens to this contract
lendingToken.transferFrom(msg.sender, address(this), _amount);
```

Go to the Axelar documentation [here](https://docs.axelar.dev/resources/contract-addresses/testnet/), scroll down to the asset section, and click on the aUSDC contract address on Fantom.

![Go to the Axelar documentation here, scroll down to the asset section, and click on the aUSDC contract address on Fantom.](https://cdn.hashnode.com/res/hashnode/image/upload/v1728391963433/a25ee28d-ac03-414e-9562-8ff20c75f29c.png align="center")

Go to the "Contract" tab, click on "Write Contract," and then connect your wallet by clicking on "Connect to Web3," as shown below.

![Go to the "Contract" tab, click on "Write Contract," and then connect your wallet by clicking on "Connect to Web3,"](https://cdn.hashnode.com/res/hashnode/image/upload/v1728392248846/d871eb68-c6a8-4d6b-8504-089b04b728e8.png align="center")

Enter the lending pool contract address and the amount to be approved; for example, `0xE9D662dd2E4A479C2559bec1685b1BA4C4Ee24E1` and 50000000, which equals 50 × 10^6 since it is in aUSDC.

![Enter the lending pool contract address and the amount to be approved](https://cdn.hashnode.com/res/hashnode/image/upload/v1728392555773/a72132eb-d9bd-461b-b46e-9d98096345d2.png align="center")

Link to the approval transaction [here](https://testnet.ftmscan.com/tx/0x6616c28ebac7bd12f161c56096c25a17afe2c1b9abf541ce23dc757ea67a2e54).

One last thing before you call the `initiateCrosschain` function, you need to fund the destination contract so it can loan the user the required asset.

Here's how it works: If the user triggers the initiate cross-chain loan function from the source chain (Fantom) and reaches the destination chain (Celo), the `_executeWithToken` function in the contract will be triggered automatically. This is where you implement sending the asset the user wants to lend and fund the contract with the asset in the following step.

### Fund the Destination Contract with the Asset to be Borrowed

To fund the contract on the destination chain (Celo), you can either request the asset on Axelar Discord to be sent directly to the contract address or transfer it from your account. Let's transfer it from an account as shown below.

![Fund the Destination Contract with the Asset to be Borrowed](https://cdn.hashnode.com/res/hashnode/image/upload/v1728394057352/eead5ef7-1215-4fea-b9b8-0db1b803eb23.png align="center")

Next, proceed to initiate the cross-chain loan. Here is the [transaction link](https://testnet.ftmscan.com/tx/0x73604bfec32361ff1d02ff4a4cac3f7bf98fd18d2da0fd180e546a8a8806734d).

### Call initiateCrossChainLoan on the Lending Pool Contract on Fantom Network

To initiate the cross-chain loan request, navigate to the lending pool deployment on Remix as shown below and enter the following details.

```bash
destinationChain: celo
destinationAddress: 0x36365FbCB839E309226d4f488310CcA3feDB91f4
_amount: 5000000 // 5 aUSDC
_collateralId: 0
_duration: 3600
```

Next, click “transact”.

![Call initiateCrossChainLoan on the Lending Pool Contract on Fantom Network](https://cdn.hashnode.com/res/hashnode/image/upload/v1728394563697/6187e26f-c293-4f84-b49d-b2649af6f2f4.png align="center")

Next, add gas value.

![add gas value](https://cdn.hashnode.com/res/hashnode/image/upload/v1728395779005/35dc4f14-c964-42ec-8b5a-0485006a3513.png align="center")

Transaction hash on the Fantom testnet is available [here](https://testnet.ftmscan.com/tx/0x2ec0ee1f39499ec0163ccb9840e6b03cf9ec3f2906509616a3cebf32e95e1c4c). You can also view it on Axelarscan [here](https://testnet.axelarscan.io/gmp/0x2ec0ee1f39499ec0163ccb9840e6b03cf9ec3f2906509616a3cebf32e95e1c4c).

![Transaction details](https://cdn.hashnode.com/res/hashnode/image/upload/v1728396483014/407c74fd-1dd9-499b-909d-92038bada5a9.png align="center")

Congratulations! You have successfully initiated a cross-chain loan from the Fantom testnet to Celo. How does that feel? Great, right?

Next, you need to repay the loan, which is the typical process of lending.

### Call `repayCrossChainLoan` on Lending Pool Contract on Celo Tesnet

One of the most interesting things about cross-chain activities or processes with Axelar GMP is that you can implement any custom functionality, like initiating a loan from one chain, repaying the loan from that same chain, or repaying the loan on the destination chain where the asset was used, and vice versa.

You must approve the `LendingPool` contract address to be able to transfer the amount the user wants to repay from the user's account to the address.

Go to the Axelar documentation [here](https://docs.axelar.dev/resources/contract-addresses/testnet/), scroll down to the asset section, and click on the aUSDC contract address on Celo.

![Go to the Axelar documentation here, scroll down to the asset section, and click on the aUSDC contract address on Celo.](https://cdn.hashnode.com/res/hashnode/image/upload/v1728398299793/9f943f00-c940-416e-b8d5-d43b66ee0ab3.png align="center")

Go to the "Contract" tab, click on "Write Contract," and then connect your wallet by clicking on "Connect to Web3," as shown below.

![Go to the "Contract" tab, click on "Write Contract,"](https://cdn.hashnode.com/res/hashnode/image/upload/v1728398481389/becc1784-f468-4197-8976-e0ee3ea535aa.png align="center")

![connect your wallet by clicking on "Connect to Web3](https://cdn.hashnode.com/res/hashnode/image/upload/v1728398626794/879d1aff-41aa-48b0-a7f7-fdfd89fd06d7.png align="center")

Link to the [approval transaction](https://alfajores.celoscan.io/tx/0x3ef1edaf88d04732e0641e657d2c93d249650242a9682facc6dcddcd22ee31a2).

To repay the loan, navigate to the lending pool deployment contract section on Celo Remix and add the following details.

![Select Lending pool contract deployed Celo](https://cdn.hashnode.com/res/hashnode/image/upload/v1728397378503/e8653e45-2bc4-4096-8520-408ebb5419bd.png align="center")

```bash
_loadId: 0
destinationChain: Fantom
destinationAddress: 0xE9D662dd2E4A479C2559bec1685b1BA4C4Ee24E1
```

Next, add gas value.

![Add gas value](https://cdn.hashnode.com/res/hashnode/image/upload/v1728395779005/35dc4f14-c964-42ec-8b5a-0485006a3513.png align="center")

Please switch your network back to the Fantom testnet from Celo and then click the “transact” button.

![Please switch your network back to the Fantom testnet from Celo and then click the “transact” button.](https://cdn.hashnode.com/res/hashnode/image/upload/v1728397817650/d267b8f0-f7b8-4537-a77a-525a13dcc2c1.png align="center")

Transaction hash on the Celo testnet is available [here](https://alfajores.celoscan.io/tx/0xa9fba813e94b0cce486f34dccf84772d6e2e19d750ba32f5d571a4603506595d). You can also view it on Axelarscan [here](https://testnet.axelarscan.io/gmp/0xa9fba813e94b0cce486f34dccf84772d6e2e19d750ba32f5d571a4603506595d).

![Transaction details](https://cdn.hashnode.com/res/hashnode/image/upload/v1728399402743/af628243-183d-4a01-940d-902e4595c398.png align="center")

Woohoo! You have successfully repaid the loan and completed the entire process. If you check the transaction details page, you will notice the collateral has been released, as shown below.

![You have successfully repaid the loan and completed the entire process. If you check the transaction details page, you will notice the collateral has been released](https://cdn.hashnode.com/res/hashnode/image/upload/v1728399563369/a66dfe74-b4a0-4abe-81f4-13b3d5266f29.png align="center")

## Conclusion

In conclusion, integrating Axelar's General Message Passing (GMP) into a multichain Real-World Asset (RWA) lending platform offers a transformative approach to decentralized finance. The practical implementation of tokenized real-world assets, as demonstrated through the creation of smart contracts like `MockRWAToken`, `RWAOracle`, and `LendingPool`, showcases the potential for a more inclusive financial ecosystem.

This system empowers individuals, such as our hypothetical farmer Amani, to leverage their assets for financial growth, regardless of geographical or traditional banking limitations.

## References

* [**Axelar General Message Passing (GMP**](https://docs.axelar.dev/dev/axelarjs/send-message)**)**
    
* [Real-World Asset (RWA)](https://www.coinbase.com/en-gb/learn/crypto-glossary/what-are-real-world-assets-rwa)
    
* [Testnet Asset](https://docs.axelar.dev/resources/contract-addresses/testnet/)
