Sui.

Publication

Partagez vos connaissances.

Meaning.Sui.
Jul 09, 2025
Questions et Réponses avec des Experts

Monnaie frappée 2 fois à la même adresse

Si je frappe ma pièce deux fois à la même adresse, les montants ne s'additionnent pas. Seul le montant de la dernière monnaie apparaît lors du test ?

module package_addr::my_coin;
//https://docs.sui.io/guides/developer/coin
use sui::coin::{Self, Coin, TreasuryCap, CoinMetadata};

public struct MY_COIN has drop {}
const TOTAL_SUPPLY: u64 = 1_000_000_000_000_000_000;//includes decimal zeros
const INITIAL_SUPPLY: u64 = 900_000_000_000_000_000;
const REMAINING: u64 = 
100_000_000_000_000_000;

fun init(witness: MY_COIN, ctx: &mut TxContext) {
		let (mut treasury, metadata) = coin::create_currency(
				witness,
				9,
				b"MY_COIN",
				b"",
				b"",
				option::none(),
				ctx,
		);
    mint( &mut treasury, INITIAL_SUPPLY, ctx.sender(), ctx);
		transfer::public_freeze_object(metadata);
		transfer::public_transfer(treasury, ctx.sender())
}

public fun mint(
		treasury_cap: &mut TreasuryCap<MY_COIN>,
		amount: u64,
		recipient: address,
		ctx: &mut TxContext,
) {
		let coin = coin::mint(treasury_cap, amount, ctx);
		transfer::public_transfer(coin, recipient)
}

//----------== Test
#[test_only]use sui::test_scenario;
#[test_only] use sui::coin::value;
#[test_only] use std::debug::print as pp;
#[test_only] use std::string::{utf8};

#[test]
fun test_init() {
let admin = @0xAd;
let bob = @0xb0;
let mut sce = test_scenario::begin(admin);
{
    let otw = MY_COIN{};
    init(otw, sce.ctx());
};

sce.next_tx(admin);
{
  let coin = sce.take_from_sender<Coin<MY_COIN>>();
  pp(&utf8(b"admin balc1"));
  pp(&value(&coin));
  assert!(value(&coin) == INITIAL_SUPPLY, 441);
  sce.return_to_sender(coin);
};

//mint 2nd time
sce.next_tx(admin);
{
  let mut treasury = sce.take_from_sender<TreasuryCap<MY_COIN>>();
      mint(
        &mut treasury,
        2000,
        admin,//sce.ctx().sender(),
        sce.ctx()
    );
  sce.return_to_sender(treasury);
};

sce.next_tx(admin);
{
  let coin = sce.take_from_sender<Coin<MY_COIN>>();
  pp(&utf8(b"admin balc2"));
  pp(&value(&coin));// it shows 2000, instead of INITIAL_SUPPLY+2000  !!??
  assert!(value(&coin) == INITIAL_SUPPLY+2000, 442);// Failed here
  sce.return_to_sender(coin);
};
sce.end();
}
  • Sui
  • SDKs and Developer Tools
0
2
Partager
Commentaires
.

Réponses

2
HaGiang.
Jul 9 2025, 07:51

le problème, c'est qu'il s'agit Coind'objets différents. Dans Sui Move, chaque opération de frappe crée un nouvel <T>objet Coin au lieu de le combiner automatiquement avec des pièces existantes du même type.

Vous devrez donc créer une autre transaction fictive pour obtenir les deux pièces et les rejoindre... comme indiqué ci-dessous

module package_addr::my_coin;
//https://docs.sui.io/guides/developer/coin
use sui::coin::{Self, Coin, TreasuryCap, CoinMetadata};

public struct MY_COIN has drop {}
const TOTAL_SUPPLY: u64 = 1_000_000_000_000_000_000;//includes decimal zeros
const INITIAL_SUPPLY: u64 = 900_000_000_000_000_000;
const REMAINING: u64 = 
100_000_000_000_000_000;

fun init(witness: MY_COIN, ctx: &mut TxContext) {
		let (mut treasury, metadata) = coin::create_currency(
				witness,
				9,
				b"MY_COIN",
				b"",
				b"",
				option::none(),
				ctx,
		);
    mint( &mut treasury, INITIAL_SUPPLY, ctx.sender(), ctx);
		transfer::public_freeze_object(metadata);
		transfer::public_transfer(treasury, ctx.sender())
}

public fun mint(
		treasury_cap: &mut TreasuryCap<MY_COIN>,
		amount: u64,
		recipient: address,
		ctx: &mut TxContext,
) {
		let coin = coin::mint(treasury_cap, amount, ctx);
		transfer::public_transfer(coin, recipient)
}

//----------== Test
#[test_only]use sui::test_scenario;
#[test_only] use sui::coin::value;
#[test_only] use std::debug::print as pp;
#[test_only] use std::string::{utf8};

#[test]
fun test_init() {
    let admin = @0xAd;
    let mut sce = test_scenario::begin(admin);
    {
        let otw = MY_COIN{};
        init(otw, sce.ctx());
    };

    // First transaction - check initial supply
    sce.next_tx(admin);
    {
        let coin = sce.take_from_sender<Coin<MY_COIN>>();
        pp(&utf8(b"admin balc1"));
        pp(&value(&coin));
        assert!(value(&coin) == INITIAL_SUPPLY, 441);
        sce.return_to_sender(coin);
    };

    // Second transaction - mint additional coins
    sce.next_tx(admin);
    {
        let mut treasury = sce.take_from_sender<TreasuryCap<MY_COIN>>();
        mint(
            &mut treasury,
            2000,
            admin,
            sce.ctx()
        );
        sce.return_to_sender(treasury);
    };

    // Third transaction - check combined balance
    sce.next_tx(admin);
    {
        // Take both coins from sender
        let coin1 = sce.take_from_sender<Coin<MY_COIN>>(); // Initial coin
        let coin2 = sce.take_from_sender<Coin<MY_COIN>>(); // Newly minted coin
        
        // Combine them
        let mut combined_coin = coin1;
        coin::join(&mut combined_coin, coin2);
        
        pp(&utf8(b"admin balc2"));
        pp(&value(&combined_coin));
        assert!(value(&combined_coin) == INITIAL_SUPPLY + 2000, 442);
        sce.return_to_sender(combined_coin);
    };
    sce.end();
}

Points clés :

Lors de la première transaction, nous renvoyons la pièce initiale à l'expéditeur au lieu de la renvoyer

Lors de la deuxième transaction, nous frappons de nouvelles pièces, ce qui crée un objet Coin distinct

Lors de la troisième transaction, nous prenons les deux pièces de l'expéditeur

Utilisez coin : :join pour les combiner

Vérifiez la valeur totale

Cela correspond au comportement réel de Sui, où chaque monnaie crée un nouvel objet Coin

Les portefeuilles combinent généralement les pièces automatiquement

Vous devez joindre explicitement des pièces dans les tests car le scénario de test ne les combine pas automatiquement.

0
Commentaires
.
24p30p.
Jul 9 2025, 21:07

Lorsque vous frappez votre pièce personnalisée plusieurs fois à la même adresse sur Sui, chaque monnaie crée un Coin<T>objet distinct au lieu d'en ajouter à un objet existant. Ainsi, lorsque vous vérifiez le solde à l'aide d'une seule pièce, vous ne verrez que la valeur de cette pièce, généralement la dernière frappée. Pour obtenir le solde complet, vous devez fusionner toutes les pièces appartenant à votre adresse. Coin<MY_COIN>Dans les tests, cela signifie qu'il faut saisir chacune des propriétés coin::mergede l'expéditeur et les combiner à l'aide de celles-ci. Sans cela, le test n'indiquera que le montant d'une pièce, et non le total de toutes les pièces frappées. Voici un exemple simple de fusion de deux pièces après plusieurs opérations dans un bloc de transaction :

let coin1 = sce.take_from_sender<Coin<MY_COIN>>();
let coin2 = sce.take_from_sender<Coin<MY_COIN>>();
let merged_coin = coin::merge(coin1, coin2);
pp(&value(&merged_coin));

Si vous avez frappé plusieurs pièces à la même adresse, assurez-vous toujours de les fusionner avant de lire le solde ou d'utiliser les pièces pour d'autres opérations. Pour en savoir plus sur le fonctionnement des pièces en Sui et sur la manière de les gérer correctement, cliquez ici : https://docs.sui.io/build/coin

0
Commentaires
.

Connaissez-vous la réponse ?

Veuillez vous connecter et la partager.

Sui is a Layer 1 protocol blockchain designed as the first internet-scale programmable blockchain platform.

394Publications554Réponses
Sui.X.Peera.

Gagne ta part de 1000 Sui

Gagne des points de réputation et obtiens des récompenses pour avoir aidé la communauté Sui à se développer.

Campagne de RécompensesJuillet