-
Notifications
You must be signed in to change notification settings - Fork 166
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' into feat/gas-estimation
- Loading branch information
Showing
18 changed files
with
730 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,28 +2,33 @@ | |
|
||
This repo provides the code for interacting with the Amplifier Relayer API to relay transactions to the Axelar network and listen to Axelar events. | ||
|
||
For a visual of the flow of an outgoing message see [outgoing msg](/images/Outgoing-Relayer.png) | ||
For a visual of the flow of an inbound message see [inbound msg](/images/Inbound-Relayer.png) | ||
For a visual of the flow of an outgoing message see [outgoing msg](images/Outgoing-Relayer.png) | ||
For a visual of the flow of an inbound message see [inbound msg](images/Inbound-Relayer.png) | ||
|
||
## Setup | ||
|
||
1. Clone this repo. | ||
1. Install dependencies: | ||
2. Install dependencies: | ||
```bash | ||
npm install | ||
``` | ||
1. Copy `.env.example` into `.env` and set up the following environment variables: | ||
3. Go to amplifier examples directory | ||
``` | ||
cd examples/amplifier | ||
``` | ||
4. Copy `.env.example` into `.env` and set up the following environment variables: | ||
```bash | ||
HOST=... | ||
PORT=... | ||
``` | ||
|
||
## Generic endpoints | ||
|
||
There are two endpoints that can be used for generic commands and events: | ||
There are three endpoints that can be used for generic commands and events: | ||
|
||
1. `broadcast` -- Sends a command to get executed as a wasm message on the network | ||
1. `subscribe-to-wasm-events` -- Subscribes to all wasm events emitted on the network | ||
2. `get-receipt` -- Returns the receipt given a receipt-id for a sent message | ||
3. `subscribe-to-wasm-events` -- Subscribes to all wasm events emitted on the network | ||
|
||
### `broadcast` | ||
|
||
|
@@ -43,7 +48,51 @@ $ node amplifier broadcast \ | |
Broadcasting message: | ||
axelar1wkwy0xh89ksdgj9hr347dyd2dw7zesmtrue6kfzyml4vdtz6e5ws2pvc5e {"distribute_rewards":{"pool_id":{"chain_name":"fantom","contract":"axelar1ufs3tlq4umljk0qfe8k5ya0x6hpavn897u2cnf9k0en9jr7qarqqa9263g"},"epoch_count":1000}} | ||
Connecting to server at localhost:50051 | ||
Message sent for broadcast | ||
Message sent for broadcast { published: true, receiptId: '862592eaadbcdb08ccd2edffd647153e' } | ||
``` | ||
### `get-receipt` | ||
Each broadcast returns a `receiptId`, which is a unique key generated by the API to identify every broadcast request attempt. This id can be used to poll for the broadcast response. After a receipt id is returned, you can query the corresponding receipt for 24 hours. | ||
```bash | ||
node amplifier get-receipt --receipt-id <receipt id> | ||
``` | ||
This is going to return either | ||
* the transaction hash, if the transaction is included in a block | ||
* a message indicating that the transaction has not been published yet (this usually takes up to 5-10 seconds) | ||
* an error indicating the transaction failed to publish, or execute | ||
For example: | ||
```bash | ||
# succesful broadcast | ||
$ node amplifier get-receipt -r 53992509aa3267cc7b2bb8a1bfb21d03 | ||
Getting receipt with id: 53992509aa3267cc7b2bb8a1bfb21d03 | ||
Connecting to server at localhost:50051 | ||
Receipt: | ||
87AECB2151F80616DA2CD237E9EE38DC9558FFBBC93A51DF3B3BE8BB89F0A5EF | ||
``` | ||
```bash | ||
# unknown receipt id | ||
Getting receipt with id: random-id | ||
Connecting to server at localhost:50051 | ||
Error Error: ... | ||
code: 2, | ||
details: 'receipt id not found', | ||
} | ||
``` | ||
```bash | ||
# transaction failed to execute | ||
$ node amplifier get-receipt -r 5b0726f7cc6504626023328f62a7454d | ||
Getting receipt with id: 5b0726f7cc6504626023328f62a7454d | ||
Connecting to server at localhost:50051 | ||
Error Error: ... | ||
code: 2, | ||
details: "transaction failed: broadcast tx failed: rpc error: code = Unknown desc = rpc error: code = Unknown desc = failed to execute message; message index: 0: rewards pool balance insufficient: execute wasm contract failed [CosmWasm/[email protected]/x/wasm/keeper/keeper.go:371] With gas wanted: '0' and gas used: '1506569' : unknown request", | ||
} | ||
``` | ||
### `subscribe-to-wasm-events` | ||
|
@@ -125,7 +174,7 @@ where | |
- `destination-address` -- the address of the recipient | ||
- `payload` -- the transaction payload of `ContractCall` event, in bytes. The `0x` can be omitted: | ||
![Payload](/images/payload.png) | ||
![Payload](images/payload.png) | ||
After a few seconds, the `verify` command will exit displaying the `id`, and or an error if any: | ||
|
@@ -150,7 +199,7 @@ Success verification for 0x02293467b9d6e1ce51d8ac0fa24e9a30fb95b5e1e1e18c26c8fd7 | |
After a verification is initiated and once all internal processes (verifying, routing messages to the destination gateway, and constructing proof) are done on the Axelar network, a `signing-completed` event is emitted which contains a `session-id`. This `session-id` can be used to query the proof from the Axelar chain and return the execute data that need to be relayed on the destination chain. Do this by running `subscribe-to-approvals`: | ||
```bash | ||
node amplifer subscribe-to-approvals \ | ||
node amplifier subscribe-to-approvals \ | ||
--chain fantom \ | ||
--start-height <start-height> # optional | ||
``` | ||
|
@@ -184,4 +233,4 @@ Payload: | |
- `hash` -- the payload hash | ||
![Payload hash](/images/payload-hash.png) | ||
![Payload hash](images/payload-hash.png) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
const newClient = require('../grpc/client'); | ||
|
||
function getReceipt(receiptId) { | ||
console.log("Getting receipt with id:", receiptId); | ||
|
||
const client = newClient(); | ||
const getReceiptRequest = { receiptId: receiptId }; | ||
response = client.GetReceipt(getReceiptRequest, (err, response) => { | ||
if (err) { | ||
console.error("Error", err); | ||
process.exit(1) | ||
} | ||
|
||
if (response) { | ||
console.log("Receipt:\n" + response.txHash); | ||
process.exit(0) | ||
} | ||
}); | ||
} | ||
|
||
module.exports = { | ||
getReceipt, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.0; | ||
|
||
import { IERC20 } from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; | ||
|
||
import { AxelarExecutable } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/executable/AxelarExecutable.sol'; | ||
import { IAxelarGateway } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IAxelarGateway.sol'; | ||
import { IAxelarGasService } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IAxelarGasService.sol'; | ||
import '@openzeppelin/contracts/utils/Strings.sol'; | ||
import { AddressToString, StringToAddress } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/libs/AddressString.sol'; | ||
|
||
import { MultichainGameReceiver } from './MultichainGameReceiver.sol'; | ||
|
||
contract MultichainGame is AxelarExecutable { | ||
using AddressToString for address; | ||
using StringToAddress for string; | ||
|
||
IAxelarGasService public immutable gasService; | ||
|
||
constructor(address _gateway, address _gasService) AxelarExecutable(_gateway) { | ||
gasService = IAxelarGasService(_gasService); | ||
} | ||
|
||
function guessNumber( | ||
string memory _destChain, //"" if not cross chain bet | ||
string calldata _gameReceiver, | ||
uint256 _guess, | ||
string memory _symbol, | ||
uint256 _amount | ||
) external payable { | ||
require(_guess >= 1 && _guess <= 6, 'Invalid guess'); | ||
|
||
address tokenAddress = gateway.tokenAddresses(_symbol); | ||
|
||
require(tokenAddress != address(0), 'Invalid token'); | ||
|
||
if (bytes(_destChain).length == 0) { | ||
//NO MULTICHAIN TX PLAYING ON SAME CHAIN | ||
IERC20(tokenAddress).transferFrom(msg.sender, _gameReceiver.toAddress(), _amount); | ||
_checkIfWinner(msg.sender, _guess, _gameReceiver.toAddress()); | ||
} else { | ||
//MULTICHAIN TX FROM CHAIN A TO CHAIN B | ||
require(msg.value > 0, 'Insufficient gas'); | ||
|
||
bytes memory encodedGuess = abi.encode(msg.sender, _guess); | ||
|
||
IERC20(tokenAddress).transferFrom(msg.sender, address(this), _amount); | ||
IERC20(tokenAddress).approve(address(gateway), _amount); | ||
|
||
gasService.payNativeGasForContractCallWithToken{ value: msg.value }( | ||
address(this), | ||
_destChain, | ||
_gameReceiver, | ||
encodedGuess, | ||
_symbol, | ||
_amount, | ||
msg.sender | ||
); | ||
|
||
gateway.callContractWithToken(_destChain, _gameReceiver, encodedGuess, _symbol, _amount); | ||
} | ||
} | ||
|
||
function _executeWithToken( | ||
string calldata, | ||
string calldata, | ||
bytes calldata _payload, | ||
string calldata _symbol, | ||
uint256 _amount | ||
) internal override { | ||
address player = abi.decode(_payload, (address)); | ||
address tokenAddress = gateway.tokenAddresses(_symbol); | ||
IERC20(tokenAddress).transfer(player, _amount); | ||
} | ||
|
||
function _checkIfWinner(address _player, uint256 _guess, address _gameReceiver) internal { | ||
uint256 diceResult = 5; //for testing | ||
// uint256 diceResult = (block.timestamp % 6) + 1; | ||
|
||
bool won = _guess == diceResult; | ||
|
||
if (won) _payoutWinner(_player, _gameReceiver); | ||
} | ||
|
||
function _payoutWinner(address _player, address _gameReceiver) internal { | ||
MultichainGameReceiver(_gameReceiver).payOutAllTokensToWinnerSameChain(_player, address(this).toString(), Strings.toString(block.chainid)); | ||
} | ||
} |
Oops, something went wrong.