Guides

Soar (Solana On-Chain Achievements and Rankings)

👑 Solana On-chain Achievements & Rankings 👑

Soar

SOAR is a program that provides a seamless solution for managing leaderboards, achievements, players' profiles and automatic rewards distribution on the Solana blockchain. Currently supporting invocation from a TypeScript client and with the Solana.Unity-SDK. The program IDL is public and other clients can be easily auto-generated.


Create a player profile

  • Register a new player profile on Soar for a given player:
var tx = new Transaction()
{
    FeePayer = Web3.Account,
    Instructions = new List<TransactionInstruction>(),
    RecentBlockHash = await Web3.BlockHash()
};


var playerAccount = SoarPda.PlayerPda(Web3.Account.PublicKey);
var accountsInitUser = new InitializePlayerAccounts()
{
    Payer = Web3.Account,
    User = Web3.Account,
    PlayerAccount = playerAccount,
    SystemProgram = SystemProgram.ProgramIdKey
};
var initPlayerIx = SoarProgram.InitializePlayer(
    accounts: accountsInitUser,
    username: "Peak",
    nftMeta: new PublicKey("BaxBPhbNxqR13QcYPvoTzE9LQZGs71Mu6euywyKHoprc"),
    SoarProgram.ProgramIdKey
);
tx.Add(initPlayerIx);
await Web3.Wallet.SignAndSendTransaction(tx, commitment: Commitment.Confirmed);

Example of a transaction that creates a new profile on Soar: tx


Register a new Game on Soar

var tx = new Transaction()
{
    FeePayer = Web3.Account,
    Instructions = new List<TransactionInstruction>(),
    RecentBlockHash = await Web3.BlockHash()
};
var game = new Account();
var gameMeta = new GameAttributes()
{
    Title = "My Game",
    Description = "My Game Description",
    Genre = 0,
    GameType = 0,
    NftMeta = new PublicKey("8PyfKjB46ih1NHdNQLGhEGRDNRPTnFf94bwnQxa9Veux")
};


var initializeGameAccounts = new InitializeGameAccounts()
{
    Creator = Web3.Account,
    Game = game,
    SystemProgram = SystemProgram.ProgramIdKey
};
var initializeGameIx = SoarProgram.InitializeGame(
    accounts: initializeGameAccounts,
    gameMeta: gameMeta,
    gameAuth: new[] { Web3.Account.PublicKey }, // Add other authorities or PDAs which can sign for CPI
    SoarProgram.ProgramIdKey
);
tx.Add(initializeGameIx);


tx.PartialSign(Web3.Account);
tx.PartialSign(game);


var res = await Web3.Wallet.SignAndSendTransaction(tx, commitment: Commitment.Confirmed);
Debug.Log($"Tx initialize game: {res.Result}");

Example of a transaction that creates a new game on Soar: tx


Register a new Leaderboard on Soar

var tx = new Transaction()
{
    FeePayer = Web3.Account,
    Instructions = new List<TransactionInstruction>(),
    RecentBlockHash = await Web3.BlockHash()
};
var game = new PublicKey("EFf4gsG44gaWUMd6HsEW7pvcRXXGfLxBC5mMeQD4RGDU");
var soarClient = new SoarClient(Web3.Rpc, Web3.WsRpc);
var gameAccount = (await soarClient.GetGameAsync(game)).ParsedResult;
var id = gameAccount.LeaderboardCount + 1;


var leaderboard = SoarPda.LeaderboardPda(game, id);
var topEntries = SoarPda.LeaderboardTopEntriesPda(leaderboard);
var leaderboardMeta = new RegisterLeaderBoardInput()
{
    Description = "A new leaderboard",
    NftMeta = new PublicKey("8PyfKjB46ih1NHdNQLGhEGRDNRPTnFf94bwnQxa9Veux"),
    ScoresToRetain = 10,
    IsAscending = false, // From highest to lowest
    AllowMultipleScores = false // Only one score per player in the global leaderboard
};


var addLeaderboardAccounts = new AddLeaderboardAccounts()
{
    Authority = Web3.Account,
    Payer = Web3.Account,
    Game = game,
    Leaderboard = leaderboard,
    TopEntries = topEntries,
    SystemProgram = SystemProgram.ProgramIdKey
};
var createLeaderboardIx = SoarProgram.AddLeaderboard(
    accounts: addLeaderboardAccounts,
    input: leaderboardMeta,
    SoarProgram.ProgramIdKey
);
tx.Add(createLeaderboardIx);
var res = await Web3.Wallet.SignAndSendTransaction(tx, commitment: Commitment.Confirmed);
Debug.Log($"Create leaderboard: {res.Result}");

Example of a transaction that creates a new leaderboard on Soar: tx

Submit a score to a leaderboard

var tx = new Transaction()
{
    FeePayer = Web3.Account,
    Instructions = new List<TransactionInstruction>(),
    RecentBlockHash = await Web3.BlockHash()
};
var game = new PublicKey("EFf4gsG44gaWUMd6HsEW7pvcRXXGfLxBC5mMeQD4RGDU");
var leaderboard = new PublicKey("4nta83xKooFQDz6tLnJjkCTyuNiReBKBYYw5qXMp1me6");
var playerAccount = SoarPda.PlayerPda(Web3.Account);
var playerScores = SoarPda.PlayerScoresPda(playerAccount, leaderboard);


if (!await IsPdaInitialized(playerScores))
{
    var registerPlayerAccounts = new RegisterPlayerAccounts()
    {
        Payer = Web3.Account,
        User = Web3.Account,
        PlayerAccount = playerAccount,
        Game = game,
        Leaderboard = leaderboard,
        NewList = playerScores,
        SystemProgram = SystemProgram.ProgramIdKey
    };
    var registerPlayerIx = SoarProgram.RegisterPlayer(
        registerPlayerAccounts,
        SoarProgram.ProgramIdKey
    );
    tx.Add(registerPlayerIx);
}


var addLeaderboardAccounts = new SubmitScoreAccounts()
{
    Authority = Web3.Account,
    Payer = Web3.Account,
    PlayerAccount = playerAccount,
    Game = game,
    Leaderboard = leaderboard,
    PlayerScores = playerScores,
    TopEntries = SoarPda.LeaderboardTopEntriesPda(leaderboard),
    SystemProgram = SystemProgram.ProgramIdKey
};
var submitScoreIx = SoarProgram.SubmitScore(
    accounts: addLeaderboardAccounts,
    score: 10,
    SoarProgram.ProgramIdKey
);
tx.Add(submitScoreIx);
var res = await Web3.Wallet.SignAndSendTransaction(tx, commitment: Commitment.Confirmed);
Debug.Log($"Tx Score submission: {res.Result}");

where IsPdaInitialized is a helper function that checks if the playerScores account is initialized:

private async UniTask<bool> IsPdaInitialized(PublicKey pda)
{
    var accountInfoAsync = await Web3.Rpc.GetAccountInfoAsync(pda);
    return accountInfoAsync.WasSuccessful && accountInfoAsync.Result?.Value != null;
}

Example of a transaction that submit a score to a leaderboard on Soar: tx

Previous
Publishing a game as Xnft