Skip to content

OwnedObject Input #123

@viol3

Description

@viol3

Describe the feature or improvement you're requesting

Hey. Is this SDK supporting OwnedObjects as an argument? I am getting Unknow Call Arg Type error after I send owned object's id. Here Unity and Move codes :

module lucky_game::lucky_game
{
    use sui::object::{Self, UID};
    use sui::balance::{Self, Balance};
    use sui::tx_context::{Self, TxContext};
    use sui::transfer;
    use sui::coin::{Self, Coin};
    use sui::sui::SUI;
    use sui::random::{Self, Random};
    use std::hash;
    use sui::event;
    use std::vector;

    public struct DiceValue has copy, drop
    {
        value: u8,
    }

    public struct Commit has key
    {
        id: UID,
        player: address,
        commit_hash: vector<u8>,
        amount: u64,
        input: u8,
    }

    public struct CHEST has key
    {
        id: UID,
        chestBalance: Balance<SUI>,
        owner: address,
    }

    const PUBLISHER: address = @0x0d9b5ca4ebae5f4a7bd3f17e4e36cd6f868d8f0c5a7f977f94f836631fe0288d;

    public fun create(ctx: &mut TxContext)
    {
        assert!(tx_context::sender(ctx) == PUBLISHER, 100);
        let chest = CHEST
        {
            id: object::new(ctx),
            chestBalance: balance::zero(),
            owner: ctx.sender(),
        };
        transfer::share_object(chest);
    }

    public fun topup(chest: &mut CHEST, mut coins: Coin<SUI>)
    {
        coin::put(&mut chest.chestBalance, coins);
    }

    public fun withdraw(chest: &mut CHEST, amount: u64, ctx: &mut TxContext)
    {
        assert!(tx_context::sender(ctx) == chest.owner, 1);
        assert!(amount > 0, 6); // Sıfırdan büyük miktar kontrolü
        assert!(chest.chestBalance.value() >= amount, 7); // Yeterli bakiye kontrolü

        // Chest'ten belirtilen miktarı çek
        let coin = coin::take(&mut chest.chestBalance, amount, ctx);

        // Kullanıcıya gönder
        transfer::public_transfer(coin, chest.owner);
    }

    /// Kullanıcı commit gönderir
    public entry fun commit( chest: &mut CHEST, mut user_coin: Coin<SUI>, commit_hash: vector<u8>, input: u8, ctx: &mut TxContext)
    {
        let amount = coin::value(&user_coin);
        assert!(amount >= 100_000_000, 2);
        assert!(input >= 2 && input <= 8, 3);

        // Coin'i chest'e koy
        coin::put(&mut chest.chestBalance, user_coin);

        let commit = Commit
        {
            id: object::new(ctx),
            player: tx_context::sender(ctx),
            commit_hash,
            amount,
            input,
        };
        transfer::transfer(commit, tx_context::sender(ctx));
    }

    /// Kullanıcı secret'ı reveal eder ve random sonucu hesaplanır
    public entry fun reveal(r: &Random, chest: &mut CHEST, commit: Commit, secret: vector<u8>, ctx: &mut TxContext)
    {
        assert!(commit.player == tx_context::sender(ctx), 10);

        // Hash doğrulama (SHA3-256 std::hash altındadır)
        let expected_hash = hash::sha3_256(secret);
        assert!(expected_hash == commit.commit_hash, 11);

        // Random üretim: mix yok; doğrudan generator kullan
        let mut generator = random::new_generator(r, ctx);
        let result = random::generate_u8_in_range(&mut generator, 1, commit.input);

        if (result != 1)
        {
            let input_u64 = commit.input as u64;
            let mut factor = ((100000000 / (10000 - (10000 / input_u64))) - 10000) / 100;
            factor = factor - 3;
            let bonus = (commit.amount * factor) / 100;

            // Balance kontrolü (doğru kullanım)
            assert!(balance::value(&chest.chestBalance) >= bonus, 4);

            // Ödeme
            let pay_bonus = coin::take(&mut chest.chestBalance, bonus, ctx);
            let mut refund = coin::take(&mut chest.chestBalance, commit.amount, ctx);
            coin::join(&mut refund, pay_bonus);
            transfer::public_transfer(refund, commit.player);
            event::emit(DiceValue { value:result });
        }
        else
        {
            event::emit(DiceValue { value:result });
        };
        let Commit { id, player: _, commit_hash: _, amount: _, input: _ } = commit;
        object::delete(id);

    }
}
using Ali.Helper;
using NBitcoin;
using OpenDive.BCS;
using Org.BouncyCastle.Ocsp;
using SHA3.Net;
using Sui.Accounts;
using Sui.Rpc;
using Sui.Rpc.Client;
using Sui.Rpc.Models;
using Sui.Transactions;
using Sui.Types;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Net.Sockets;
using System.Numerics;
using System.Security.Cryptography;
using System.Threading.Tasks;
using Unity.Mathematics;
using Unity.VisualScripting;
using UnityEditor.PackageManager;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UIElements;

public class SuiManager : GenericSingleton<SuiManager>
{
    SuiClient _client;
    Account _account;

    [SerializeField] private string _deathCardPackageId = "";
    [SerializeField] private string _deathCardChestId = "";
    private string _deathCardModuleFunc = "::lucky_game::play";
    private string _deathCardCommitFunc = "::lucky_game::commit";
    private string _deathCardRevealFunc = "::lucky_game::reveal";
    private string _randomPackageId = "0x8";

    SuiStructTag _sui_coin = new SuiStructTag("0x2::sui::SUI");
    SuiStructTag _coin = new SuiStructTag("0x2::coin::Coin");

    [HideInInspector]
    public UnityEvent OnDeathCardStarted = new UnityEvent();
    [HideInInspector]
    public UnityEvent<int> OnDeathCardEnded = new UnityEvent<int>();
    [HideInInspector]
    public UnityEvent<float> OnBalanceUpdated = new UnityEvent<float>();
    [HideInInspector]
    public UnityEvent<float> OnBalanceChanged = new UnityEvent<float>();
    private void Start()
    {
        _client = new SuiClient(Constants.TestnetConnection);
        _account = new Account("****");
        //Debug.Log(_account.PrivateKey.KeyHex);
        //Debug.Log(_account.SuiAddress().KeyHex);
        CheckBalance();
        Test();
    }

    async void Test()
    {
        //System.Guid guid = System.Guid.NewGuid();
        //byte[] secret = guid.ToByteArray();
        //HashAlgorithm halg = Sha3.Create();
        //byte[] computedHash = halg.ComputeHash(secret);
        //Debug.Log("Ok => " + guid.ToString());
        //string commitAddress = await Commit(0.1m, 8, computedHash);
        //await Reveal(commitAddress, secret);

        System.Guid guid = new System.Guid("a8eb7e10-a909-4962-a69f-6d977646a1fa");
        HashAlgorithm halg = Sha3.Create();
        byte[] secret = guid.ToByteArray();
        byte[] computedHash = halg.ComputeHash(secret);
        await Reveal("0xe7bb117a7ab3f4091c1c12ac20b6961a788f43a0687e8ef0da8b0fc893834d0d", secret);
    }

    float GetFloatFromBigInteger(BigInteger value)
    {
        decimal suiValue = (decimal)value / 1_000_000_000m;
        return (float)suiValue;
    }

    async Task CheckBalance()
    {
        RpcResult<Balance> result = await _client.GetBalanceAsync(_account);
        BigInteger balance = result.Result.TotalBalance;
        decimal suiBalance = (decimal)balance / 1_000_000_000m;
        OnBalanceUpdated?.Invoke((float)suiBalance);
    }

    public async void DeathCard(float betAmount, byte cardCount)
    {
        OnDeathCardStarted?.Invoke();
       
        
        int diceValue = await PlayDeathCard((decimal)betAmount, cardCount);
        OnDeathCardEnded?.Invoke(diceValue);
        //await CheckBalance();
    }

    async Task<List<CoinDetails>> GetSUICoins()
    {
        List<CoinDetails> result = new List<CoinDetails>();
        RpcResult<CoinPage> alice_sui_coins = await _client.GetCoinsAsync(_account, _sui_coin);
        for (int i = 0; i < alice_sui_coins.Result.Data.Length; i++)
        {
            result.Add(alice_sui_coins.Result.Data[i]);
        }
        return result;
    }

    async Task<string> Commit(decimal amount, byte cardCount, byte[] commitHash)
    {
        Debug.Log("Bet Amount => " + amount);
        TransactionBlock tx_block = new TransactionBlock();
        ulong requestedAmountLong = (ulong)(amount * 1_000_000_000m);
        List<TransactionArgument> splitArgs = tx_block.AddMoveCallTx
        (
            SuiMoveNormalizedStructType.FromStr("0x2::coin::split"),
            new SerializableTypeTag[] { new SerializableTypeTag("0x2::sui::SUI") },
            new TransactionArgument[]
            {
                tx_block.gas,  // Insert coin object ID here
                tx_block.AddPure(new U64(requestedAmountLong)) // Insert split amount here
            }
        );
        tx_block.AddMoveCallTx
        (
            SuiMoveNormalizedStructType.FromStr($"{_deathCardPackageId}{_deathCardCommitFunc}"),
            new SerializableTypeTag[] { },
            new TransactionArgument[]
            {
                    tx_block.AddObjectInput(_deathCardChestId),
                    splitArgs[0],
                    tx_block.AddPure(new Bytes(commitHash)),
                    tx_block.AddPure(new U8(cardCount))
            }
        );
        TransactionBlockResponseOptions transactionBlockResponseOptions = new TransactionBlockResponseOptions();
        transactionBlockResponseOptions.ShowEvents = true;
        transactionBlockResponseOptions.ShowBalanceChanges = true;
        transactionBlockResponseOptions.ShowEffects = true;
        transactionBlockResponseOptions.ShowObjectChanges = true;
        RpcResult<TransactionBlockResponse> result_task = await _client.SignAndExecuteTransactionBlockAsync
        (
            tx_block,
            _account,
            transactionBlockResponseOptions
        );
        

        if (result_task.Error != null)
        {
            Debug.Log("PlayDeathCard Error => " + result_task.Error.Message);
            return "";
        }
        else if(result_task.Result != null && result_task.Result.ObjectChanges != null)
        {
            for (int i = 0; i < result_task.Result.ObjectChanges.Length; i++) 
            {
                ObjectChange oc = result_task.Result.ObjectChanges[i];
                if(oc.Type == ObjectChangeType.Created)
                {
                    Debug.Log(oc.Change.ToString());
                    return oc.Change.ToString();
                }
            }
        }
            
        return "";

    }

    async Task<int> Reveal(string commitAddress, byte[] secret)
    {
        TransactionBlock tx_block = new TransactionBlock();
        tx_block.AddMoveCallTx
        (
            SuiMoveNormalizedStructType.FromStr($"{_deathCardPackageId}{_deathCardRevealFunc}"),
            new SerializableTypeTag[] { new SerializableTypeTag("0xd83656ac7864ec1581b1cc2b0ee37f0e6e7b95a27a2edfe7fe2d6d14927b1f51::lucky_game::Commit") },
            new TransactionArgument[]
            {
                    tx_block.AddObjectInput(_randomPackageId),
                    tx_block.AddObjectInput(_deathCardChestId),
                    tx_block.AddObjectInput(commitAddress),
                    tx_block.AddPure(new Bytes(secret))
            }
        );

        TransactionBlockResponseOptions transactionBlockResponseOptions = new TransactionBlockResponseOptions();
        transactionBlockResponseOptions.ShowEvents = true;
        transactionBlockResponseOptions.ShowBalanceChanges = true;
        transactionBlockResponseOptions.ShowEffects = true;
        transactionBlockResponseOptions.ShowObjectChanges = true;
        Debug.Log(tx_block.Serialize().ToString());
        RpcResult<TransactionBlockResponse> result_task = await _client.SignAndExecuteTransactionBlockAsync
        (
            tx_block,
            _account,
            transactionBlockResponseOptions
        );

        if (result_task.Error != null)
        {
            Debug.Log("Reveal Error => " + result_task.Error.Message);
            return -1;
        }

        if (result_task.Result != null && result_task.Result.BalanceChanges != null && result_task.Result.BalanceChanges.Length > 0)
        {
            BigInteger changeAmountBig = result_task.Result.BalanceChanges[0].Amount;
            float changeAmount = GetFloatFromBigInteger(changeAmountBig);
            OnBalanceChanged?.Invoke(GetFloatFromBigInteger(result_task.Result.BalanceChanges[0].Amount));
        }

        try
        {
            foreach (var m_event in result_task.Result.Events)
            {
                if (m_event.Type.Contains("DiceValue"))
                {
                    string value = m_event.ParsedJson.GetValue("value").ToString();
                    return int.Parse(value);
                }
            }
            return -1;
        }
        catch (System.Exception ex)
        {
            Debug.LogError(ex.StackTrace);
            return -1;
        }


    }

    async Task<int> PlayDeathCard(decimal amount, byte cardCount)
    {
        Debug.Log("Bet Amount => " + amount);
        TransactionBlock tx_block = new TransactionBlock();
        ulong requestedAmountLong = (ulong)(amount * 1_000_000_000m);
        List<TransactionArgument> splitArgs = tx_block.AddMoveCallTx
        (
            SuiMoveNormalizedStructType.FromStr("0x2::coin::split"),
            new SerializableTypeTag[] { new SerializableTypeTag("0x2::sui::SUI") },
            new TransactionArgument[]
            {
                tx_block.gas,  // Insert coin object ID here
                tx_block.AddPure(new U64(requestedAmountLong)) // Insert split amount here
            }
        );
        tx_block.AddMoveCallTx
        (
            SuiMoveNormalizedStructType.FromStr($"{_deathCardPackageId}{_deathCardModuleFunc}"),
            new SerializableTypeTag[] {  },
            new TransactionArgument[]
            {
                    tx_block.AddObjectInput(_randomPackageId),
                    tx_block.AddObjectInput(_deathCardChestId),
                    splitArgs[0],
                    tx_block.AddPure(new U8(cardCount))
            }
        );
        TransactionBlockResponseOptions transactionBlockResponseOptions = new TransactionBlockResponseOptions();
        transactionBlockResponseOptions.ShowEvents = true;
        transactionBlockResponseOptions.ShowBalanceChanges = true;
        transactionBlockResponseOptions.ShowEffects = true;
        transactionBlockResponseOptions.ShowObjectChanges = true;
        RpcResult<TransactionBlockResponse> result_task = await _client.SignAndExecuteTransactionBlockAsync
        (
            tx_block,
            _account,
            transactionBlockResponseOptions
        );

        if (result_task.Error != null)
        {
            Debug.Log("PlayDeathCard Error => " + result_task.Error.Message);
            return -1;
        }

        if (result_task.Result != null && result_task.Result.BalanceChanges != null && result_task.Result.BalanceChanges.Length > 0)
        {
            BigInteger changeAmountBig = result_task.Result.BalanceChanges[0].Amount;
            float changeAmount = GetFloatFromBigInteger(changeAmountBig);
            OnBalanceChanged?.Invoke(GetFloatFromBigInteger(result_task.Result.BalanceChanges[0].Amount));
        }

        try
        {
            foreach (var m_event in result_task.Result.Events)
            {
                if(m_event.Type.Contains("DiceValue"))
                {
                    string value = m_event.ParsedJson.GetValue("value").ToString();
                    return int.Parse(value);
                }
            }
            return -1;
        }
        catch (System.Exception ex)
        {
            Debug.LogError(ex.StackTrace);
            return -1;
        }
        
        
    }

}

Additional context

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions