Gully Chain

On this page

Gully Chain is the Gully Labs L3. Items, scores, seasons, quests and prizes live on it. Games read it with the SDK's JsonRpcClient and write to it through the player's account (Wallet).

#Network

Field Testnet value SDK constant
Chain ID 485590 GullyChain.TestnetChainId
CAIP-2 eip155:485590 GullyChain.TestnetCaip2
Public RPC https://testnet-rpc.gullychain.xyz GullyChain.TestnetRpc
Explorer https://testnet-explorer.gullychain.xyz GullyChain.TestnetExplorer
WETH 0x26aCCCb2e98ca9e067E58668Aa3B101beF432754 (opens in a new tab) GullyChain.TestnetWeth
GullyArcade 0xe573789b235314661DEdDA08a18Ca261c069c872 (opens in a new tab) GullyChain.TestnetArcadeAddress

Mainnet constants are added to the SDK when the chain launches.

#Which RPC to use

Endpoint Use it for
https://testnet-rpc.gullychain.xyz prototypes, the editor, samples. Free and rate-limited.
https://rpc.gullyrpc.xyz/<project>/evm/485590 shipped games and game servers. Your own Gully RPC project key, with its own limits and metrics.

Create a project key in the Gully RPC portal (opens in a new tab). The SDK builds the URL for you:

C#
var rpc = new JsonRpcClient(GullyChain.GullyRpcUrl("<your-gully-rpc-project>"));
var dev = new JsonRpcClient(); // defaults to the public testnet RPC

Note

A Gully RPC key in a client build is visible to anyone who unpacks it. Treat it as a per-game, rate-limited public key, and keep server-side keys (game servers, backends) separate.

#Reads

C#
using GullyLabs.GameSdk;

var rpc = new JsonRpcClient();
long chainId = await rpc.ChainIdAsync();          // 485590
long block   = await rpc.BlockNumberAsync();
var latest   = await rpc.GetLatestBlockAsync();    // latest.Number, latest.Time, latest.TxCount
var wei      = await rpc.GetBalanceAsync(player);

Errors from the node raise GullyRpcException with the JSON-RPC Code.

#ERC-20

C#
var raw      = await Erc20.BalanceOfAsync(rpc, token, player);
int decimals = await Erc20.DecimalsAsync(rpc, token);
string sym   = await Erc20.SymbolAsync(rpc, token);
Debug.Log($"{Erc20.Format(raw, decimals)} {sym}");

// a transfer: build calldata, send it from the player's account
var tx = new TransactionRequest { To = token, Data = Erc20.TransferCalldata(to, amount) };
string hash = await sender.SendTransactionAsync(tx);

#Any contract: Abi

Abi encodes calls by signature and decodes return words. It covers static types and dynamic bytes; structs with strings are decoded by hand from the words.

C#
// view call: bestScore(uint256 seasonId, address player)
string data = Abi.Call("bestScore(uint256,address)", Abi.Uint(seasonId), Abi.Address(player));
string ret  = await rpc.EthCallAsync(contract, data);
var score   = Abi.DecodeUint(Abi.Words(ret)[0]);

string selector = Abi.Selector("questCount()");   // "0x3970ab43"
string checksum = Abi.ToChecksumAddress(addr);     // EIP-55

Keccak256 is the same hash the chain uses, so selectors and event topics computed in C# match cast sig and cast keccak.

C#
Application.OpenURL(GullyChain.TxUrl(txHash));
Application.OpenURL(GullyChain.AddressUrl(player));

#Next