Transaction
C6D097CBC4DE94…132D95EB7C25
Block 77,252 · index 0 · indexed
Summary
- Hash
- C6D097CBC4DE9448C762C1C5AB8BFE24E2550D0CBFBEF7C4FD7F132D95EB7C25
- Block
- 77,252
- Size
- 8965 bytes
- Gas used
- 10,607,305 / 12,728,730
- Fee
- 12729ugnot
- Status
- success
Messages
- Package
- gno.land/r/gnoswap/gov/xgns
Arguments · 11
- #1xgns
- #2README.md
- #3# xGNS Non-transferable receipt token for GNS staked through `gov/staker`. ## Overview xGNS is a GRC20 token that mirrors GNS locked in `gov/staker`. It exists so that governance and the launchpad can read one staked-GNS balance, and it is minted and burned only by `gov/staker` as delegations and launchpad project deposits change. xGNS does not maintain a voting-power ledger. A holder's balance is the staked-GNS receipt of the **delegator**; the delegatee attribution and the timestamped history that governance reads for vote weight live in `gov/staker`. See [gov/staker](../staker) and [governance](../governance). ## Configuration - **Name**: XGNS - **Symbol**: xGNS - **Decimals**: 6, matching GNS - **Backing**: 1:1 with the GNS locked in `gov/staker` - **Transfers**: none. The realm exposes no `Transfer`, `TransferFrom`, `Approve`, or `Allowance` entry point, so a balance can change only through `Mint` and `Burn`. - **Mint/burn authority**: the `gov_staker` role address only - **Token path**: `gno.land/r/gnoswap/gov/xgns` ## Core Functions ### `Mint` Credits xGNS to an address. Only callable by the gov/staker contract. - Reverts while the **xgns** halt scope is active - Reverts on an invalid address, a negative amount, or a total-supply overflow ### `Burn` Debits xGNS from an address. Only callable by the gov/staker contract. - Reverts while the **withdraw** halt scope is active, a different scope from `Mint`, so issuance and redemption can be halted independently - Reverts on an invalid address, a negative amount, or an insufficient balance ### `TotalSupply` Total xGNS issued. Governance reads it at proposal creation to derive that proposal's quorum amount, so the figure includes launchpad-held issuance. ### `BalanceOf` xGNS balance of an address. Read by governance for the proposal-creation threshold, and by the launchpad when a project condition names the xGNS token path. ### `SupplyInfo` Returns `(totalIssued, issuedByDelegate, issuedByDepositGns, err)`. - `issuedByDepositGns` is the balance held by the launchpad role address - `issuedByDelegate` is the remainder, `totalIssued - issuedByDepositGns` - `err` is non-nil when the launchpad address is not registered in access; the three amounts are zero in that case ### `Render` - `""` renders the token home view - `balance/<address>` renders that address's balance - Any other path renders `404` ## Supply Lifecycle Only `gov/staker` moves xGNS, and its mint/burn points are not symmetric with the delegation calls: | gov/staker call | xGNS effect | |---|---| | `Delegate` | mints the delegated amount to the **delegator** (the caller), not to the delegatee | | `Redelegate` | no mint or burn; only the delegatee attribution moves | | `Undelegate` | no burn; voting power is removed immediately while the xGNS balance stays | | `CollectUndelegatedGns` | burns the collected amount from the caller after the lockup | | `SetAmountByProjectWallet` with `add = true` | mints to the launchpad role address | | `SetAmountByProjectWallet` with `add = false` | burns from the launchpad role address | Because `Undelegate` does not burn, a holder keeps the xGNS balance for the duration of the undelegation lockup even though the delegated voting power is already gone. ## Halt Scopes | Function | Halt scope | |---|---| | `Mint` | `xgns` | | `Burn` | `withdraw` | | `TotalSupply`, `BalanceOf`, `SupplyInfo`, `Render` | none; read-only | ## Usage These snippets call the xGNS realm from a realm function with a current `cur` token. Import the package and qualify its function names in integrating code. ```go // Read paths take no realm token supply := TotalSupply() balance := BalanceOf(voterAddress) totalIssued, issuedByDelegate, issuedByDepositGns, err := SupplyInfo() // Write paths are rejected for any caller other than the gov/staker realm Mint(cross(cur), delegator, 1_000_000_000) Burn(cross(cur), delegator, 1_000_000_000) ``` Integrating realms should go through `gov/staker` rather than calling this realm directly. `Delegate` and `CollectUndelegatedGns` keep the GNS ledger, the delegation history, and the xGNS supply consistent, while a direct `Mint` or `Burn` is rejected for any caller other than `gov/staker`. ## Security - `Mint` and `Burn` assert the `gov_staker` role, so no user and no other realm can change a balance - Without transfer entry points, xGNS cannot be traded, lent, or borrowed to inflate a governance reading within a transaction - The two write paths sit in different halt scopes: halting `withdraw` stops burning, and therefore undelegated-GNS collection, without stopping delegation - Quorum is fixed from `TotalSupply` at proposal creation and includes launchpad-held issuance; see [governance](../governance) for how the stored quorum amount is applied
- #4doc.gno
- #5// Package xgns implements the GRC20-compliant xGNS token that represents // staked GNS. It manages balances, total supply, and the gov/staker-authorized // mint and burn operations used by delegation and launchpad accounting. // // xGNS does not maintain a separate voting-power ledger. Governance and // gov/staker read xGNS balances and supply, then apply delegation history and // proposal rules outside this package. package xgns
- #6gnomod.toml
- #7module = "gno.land/r/gnoswap/gov/xgns" gno = "0.9"
- #8xgns.gno
- #9package xgns import ( "chain" "errors" "strings" "gno.land/p/nt/grc20/v0" "gno.land/p/nt/ownable/v0" "gno.land/p/nt/ufmt/v0" "gno.land/r/gnoswap/access/v1" "gno.land/r/gnoswap/halt/v1" prbac "gno.land/p/gnoswap/rbac/v1" ) const tokenID = 0 var ( admin = ownable.NewWithAddress(chain.PackageAddress(prbac.ROLE_GOV_STAKER.String())) token *grc20.Token ledger *grc20.PrivateLedger ) func init(cur realm) { token, ledger = grc20.NewToken("XGNS", "xGNS", 6, tokenID, cur) } // TotalSupply returns the total supply of xGNS tokens. // // Returns: // - supply: total xGNS token supply func TotalSupply() int64 { return token.TotalSupply() } // BalanceOf returns token balance for address. // // Parameters: // - owner: address to check balance for // // Returns: // - balance: token balance amount func BalanceOf(owner address) int64 { return token.BalanceOf(owner) } // Render returns a formatted representation of the token state. // // Parameters: // - path: render path for specific views // // Returns: // - output: formatted token state representation func Render(path string) string { if path == "" { return token.RenderHome() } parts := strings.Split(path, "/") switch parts[0] { case "balance": if len(parts) != 2 { return "404\n" } balance := token.BalanceOf(address(parts[1])) return ufmt.Sprintf("%d\n", balance) default: return "404\n" } } // Mint mints tokens to an address. // // Parameters: // - cur: current realm context; callers use cross(cur) when crossing into this // realm. // - to: recipient address receiving the newly minted tokens. // - amount: number of xGNS token units to mint. // // Only callable by governance staker contract. func Mint(cur realm, to address, amount int64) { halt.AssertIsNotHaltedXGns() caller := cur.Previous().Address() access.AssertIsGovStaker(caller) checkErr(ledger.Mint(to, amount)) } // Burn burns tokens from an address. // // Parameters: // - cur: current realm context; callers use cross(cur) when crossing into this // realm. // - from: address whose xGNS balance is burned. // - amount: number of xGNS token units to burn. // // Only callable by governance staker contract. func Burn(cur realm, from address, amount int64) { halt.AssertIsNotHaltedWithdraw() caller := cur.Previous().Address() access.AssertIsGovStaker(caller) checkErr(ledger.Burn(from, amount)) } // SupplyInfo returns supply breakdown information. // // Returns: // - totalIssued: total xGNS tokens issued // - issuedByDelegate: tokens issued through governance delegation // - issuedByDepositGns: tokens issued through launchpad deposit // - err: nil when the launchpad address is registered; an error when it cannot // be found. func SupplyInfo() (totalIssued, issuedByDelegate, issuedByDepositGns int64, err error) { launchpad, ok := access.GetAddress(prbac.ROLE_LAUNCHPAD.String()) if !ok { return 0, 0, 0, errors.New("launchpad address not found") } totalIssued = token.TotalSupply() issuedByDepositGns = token.BalanceOf(launchpad) issuedByDelegate = totalIssued - issuedByDepositGns return totalIssued, issuedByDelegate, issuedByDepositGns, nil } func checkErr(err error) { if err != nil { panic(err) } }
- #10/gno.MemPackageType
- #11 MPUserAll
Result log
msg:0,success:true,log:,events:[]