# Getting Started

In this quickstart guide, you will be deploying a Glacis-powered smart contract that sends a string message across chains: from Avalanche Fuji Testnet to Arbitrum Sepolia Testnet.

To begin working with Glacis smart contracts, you can work with a starter client smart contract. You can easily access this on Remix.

[Click Here to Open in Remix](https://remix.ethereum.org/#optimize=false\&runs=200\&evmVersion=null\&version=soljson-v0.8.18+commit.87f61d96.js\&url=https://raw.githubusercontent.com/jboetticher/glacis-alpha-quickstart-remix-template/main/GlacisTextSample.sol\&lang=en)!

Please ensure that you understand how to [use and deploy with Remix](https://remix-ide.readthedocs.io/en/latest/run.html) before starting this guide.

#### Glacis Client

The `GlacisClient` smart contract provides a full interface for your cross-chain smart contract to communicate with the GlacisRouter. You can send messages via [`_route` and its other derivative functions](/glacis-core/references/smart-contracts/glacisclient.md#the-route-function), and receive messages by overriding the `_receiveMessage` function.

In this example, you can send and receive a string across chains:

```solidity
contract GlacisClientTextSample is GlacisClientOwnable {
    string public currentMessage;

    constructor(
        address glacisRouter_,
        address owner_
    ) GlacisClientOwnable(glacisRouter_, 1, owner_) {}

    function sendMessage(
        address to,
        uint256 chainId,
        string memory message,
        uint8[] memory gmps,
        uint256[] memory fees
    ) external payable returns (bytes32) {
        return
            _route(
                chainId,
                to,
                abi.encode(message),
                gmps,
                fees,
                msg.sender,
                false,
                msg.value
            );
    }

    function _receiveMessage(
        uint8[] calldata, // fromGmpId,
        uint256, // fromChainId,
        address, // fromAddress,
        bytes memory payload
    ) internal override {
        (currentMessage) = abi.decode(payload, (string));
    }
}
```

To explain what's happening, let's go step by step.

The constructor includes construction of an ownable version of the GlacisClient:

```solidity
GlacisClientOwnable(glacisRouter_, 1, owner_)
```

It requires an instance of the `GlacisRouter` smart contract so that it can send and receive messages. `1` refers to quorum (a [redundancy](/glacis-core/concepts/features/redundancy.md) feature). Finally, the contract is owned by the designated user, which will be relevant for initialization later.

```solidity
    function sendMessage(
        address to,
        uint256 chainId,
        string memory message,
        uint8[] memory gmps,
        uint256[] memory fees
    ) external payable returns (bytes32) {
        return
            _route(
                chainId,                // destination chain ID
                to,                     // destination address
                abi.encode(message),    // payload
                gmps,                   // gmps
                fees,                   // fees
                msg(sender),            // refundAddress
                msg.value               // payment
            );
    }
```

To send a message across chains, this smart contract includes a `sendMessage` function, which is arbitrarily named. Within it is a call to the `_route` function, which is what sends the message to the `GlacisRouter` smart contract.

Note that there are a couple of inputs within the `sendMessage` function. First is the address of the contract that the message is being sent to, known as your destination address (`to`). The `chainId` is the Glacis Chain ID that the message is being sent to, which is typically the Ethereum chain ID. Then the message string that's being sent. The `gmps` and `fees` arrays should be the same length, and are important if you plan on sending a redundant message (the same message being sent through multiple GMPs).

The `_route` function includes much of these inputs as well as other configurations about the message, which you can learn more about on the [GlacisClient](/glacis-core/references/smart-contracts/glacisclient.md#the-route-function) page.

```solidity
    function _receiveMessage(
        uint8[] calldata, // fromGmpId,
        uint256, // fromChainId,
        address, // fromAddress,
        bytes memory payload
    ) internal override {
        (value) = abi.decode(payload, (string));
    }
```

The receive message function can only be triggered by the GlacisRouter when it receives a cross-chain message. This function will inject information about the origins of the message, but in this case the only information desired is the message itself. Note that all payloads are encoded into bytes and received as bytes, but they can be easily encoded and decoded through `abi.encode` and `abi.decode`.

#### GlacisClient Initialization

You can add this entire smart contract to your project and deploy it to [Avalanche Fuji](https://core.app/en/tools/testnet-faucet/?subnet=c\&token=c) with the following information in the constructor:

```solidity
GlacisClientTextSample(0x1Ce678F0e7834713868877C34F84C2cfaf511aFe, INSERT_YOUR_WALLET_ADDRESS_HERE)
```

Constructing it with the `0x1Ce678F0e7834713868877C34F84C2cfaf511aFe` address works because a GlacisRouter has been pre-deployed to this address on Avalanche Fuji.

<figure><img src="/files/KFbZfQC4xNT1sIu04rFP" alt=""><figcaption><p>Deploy on Avalanche Fuji Testnet</p></figcaption></figure>

After deployment, access control must be initialized. Since this example is using the ownable version of `GlacisClient`, we can use the `addAllowedRoute` function.

```solidity
addAllowedRoute(GlacisCommons.GlacisRoute {
    fromChainId,    // WILDCARD means any chain
    fromAddress,    // WILDCARD means any address
    fromAdapter     // WILDCARD means any official Glacis GMP Adapter
})
```

To allow messages from all smart contracts, chains, and official Glacis adapters, you can pack all parameters with the wildcard value, which is just `type(uint160).max` encoded in different ways:

```
addAllowedRoute([
    "0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF",
    "0x000000000000000000000000ffffffffffffffffffffffffffffffffffffffff",
    "0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF"
])
```

Copy the parameters and execute the `addAllowedRoute` funciton in Remix.

Typically you would only allow smart contracts from a small subset of chains, but this is for demonstration purposes.

Now try deploying and initializing an instance of this smart contract on [Arbitrum Sepolia Testnet](https://bwarelabs.com/faucets/arbitrum-sepolia) too! This way you can send a message from one chain to the other. The constructor would look like the following:

```solidity
GlacisClientTextSample(0x51f4510b1488d03A4c8C699fEa3c0B745a042e45, INSERT_YOUR_WALLET_ADDRESS_HERE)
```

Don't forget to call `addAllowedRoute` on Arbitrum Sepolia Testnet as well!

By the end of this process, you should have two addresses: `AVALANCHE_FUJI_INSTANCE_ADDRESS` and `ARB_TESTNET_INSTANCE_ADDRESS`.

#### Sending a Message

You can now send a cross-chain message by interacting with your deployed instance's `sendMessage` function. Try sending one from Avalanche Fuji to Arbitrum Sepolia with the following call:

```solidity
function sendMessage(
    ARB_TESTNET_INSTANCE_ADDRESS, 
    421614, 
    "Hello World", 
    ["0x0000000000000000000000000000000000000001"], 
    [[0, 500000000000000000]]
) 
```

* Set `to` as the `ARB_TESTNET_INSTANCE_ADDRESS`
* Set `chainId` to Arbitrum Sepolia's chain ID (97)
* Set whatever you like, such as `Hello World`, as the message
* Use `["0x0000000000000000000000000000000000000001"]` as the adapters to indicate Axelar (with a GMP ID of 1)
* Set `[[0, 500000000000000000]]` for the fees. Note that you will have to **send this message with `500000000000000000 wei`** as well to pay for cross-chain gas. This value is artificially high to ensure that the transaction executes

<figure><img src="/files/RfU1pSxRpdKmVJHSPlOe" alt=""><figcaption><p>Send message to Arbitrum Sepolia</p></figcaption></figure>

Invoking this call would send a message from the origin chain, through a GMP, and to the destination Arbitrum Sepolia Testnet.

In this case, since the adapter array has only `1` set, the only GMP used is Axelar. You would be able to see a cross-chain message on [Axelarscan](https://testnet.axelarscan.io/).

<figure><img src="/files/euDEqhiHkqWlmpNammg8" alt=""><figcaption><p>Checking Avalanche Fuji to Arbitrum Sepolia on Axelarscan</p></figcaption></figure>

If you sent the message, congratulations! You have sent your first message with Glacis. You can also try with GMPs of `[2]` or `[3]` to try it out with LayerZero or Wormhole.

The next step would be to get associated with some of the more complex ideas of Glacis and start deploying smart contracts on multiple chains:

* Get up to speed with the [GlacisClient](/glacis-core/references/smart-contracts/glacisclient.md)
* Understand how [Glacis redundancy works](/glacis-core/concepts/features/redundancy.md)
* Use [access control](/glacis-core/concepts/features/access-control.md) to firewall your cross-chain contracts
* Explore [Glacis Cross-Chain Token](/glacis-core/concepts/features/glacis-cross-chain-token.md) to pass your custom token across chains


---

# 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://docs.glacislabs.com/glacis-core/quickstart.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.
