PathrockNetwork Gno Explorer
HomeBlocksTransactionsTokensRealmsPackagesValidatorsAnalytics

PathrockNetwork Gno Explorer — an independent explorer for Gno.land Mainnet (gnoland-1), operated by PathrockNetwork. Not an official Gno.land service.

gnowebarchive RPC

gno.land/r/gnoswap/gns

Realm
Open in gnoweb ↗

Overview

Kind
Realm (renderable)
Name
gns
Namespace
gnoswap
Files
12 (README)(gnomod.toml)
Exported functions
43
Module
gno.land/r/gnoswap/gns
gno
0.9
This realm implements a recognized token.GNS →

Files (12)

  • README.mdmarkdown
  • gnomod.tomltoml
  • consts.gnogno
  • doc.gnogno
  • emission_state.gnogno
  • emission.gnogno
  • errors.gnogno
  • getter.gnogno
  • gns.gnogno
  • halving.gnogno
  • setup.gnogno
  • utils.gnogno
  • gns.gnogno
    1package gns23import (4	"chain"5	"strings"6	"time"78

    Functions

    • Allowance(owner string, spender string) int64

    • Approve(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, spender string, amount int64)

    • BalanceOf(owner string) int64

    • CalculateMintGnsAmount(fromTimestamp int64, toTimestamp int64) int64

    • Decimals() int

    • GetAmountPerSecondPerHalvingYear(year int64) int64

    • GetCurrentYear() int64

    • GetEmissionAccumulatedAmountByTimestamp(timestamp int64) int64

    • GetEmissionAmountPerSecondByTimestamp(timestamp int64) int64

    • GetEmissionAmountPerSecondInRange(fromTime int64, toTime int64) ([]int64, []int64)

    • GetEmissionCreatedHeight() int64

    • GetEmissionEndTimestamp() int64

    • GetEmissionLeftAmountByTimestamp(timestamp int64) int64

    • GetEmissionStartTimestamp() int64

    • GetHalvingAmountsPerYear(year int64) int64

    • GetHalvingInfo() *gno.land/r/gnoswap/gns.HalvingData

    • GetHalvingYear(timestamp int64) int64

    • GetHalvingYearEndTimestamp(year int64) int64

    • GetHalvingYearInfo(timestamp int64) (int64, int64, int64)

    • GetHalvingYearLeftAmount(year int64) int64

    • GetHalvingYearMaxAmount(year int64) int64

    • GetHalvingYearMintedAmount(year int64) int64

    • GetHalvingYearStartTimestamp(year int64) int64

    • GetInitialMintAmount() int64

    • GetMaxEmissionAmount() int64

    • GetMaximumSupply() int64

    • InitEmissionState(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, createdHeight int64, startTimestamp int64)

    • IsEmissionActive() bool

    • IsEmissionEnded() bool

    • IsEmissionInitialized() bool

    • KnownAccounts() int

    • LastMintedTimestamp() int64

    • LeftEmissionAmount() int64

    • MintedEmissionAmount() int64

    • MintGns(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, address string) int64

    • Name() string

    • NewEmissionState(createdHeight int64, startTimestamp int64) *gno.land/r/gnoswap/gns.EmissionState

    • NewHalvingData(startTimestamp int64) *gno.land/r/gnoswap/gns.HalvingData

    • Render(path string) string

    • Symbol() string

    • TotalSupply() int64

    • Transfer(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, to string, amount int64)

    • TransferFrom(cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, from string, to string, amount int64)

    Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.

    Rendered

    RenderedRawgnoweb ↗

    vm/qrender output, sanitized (docs/render-security.md) and displayed in an empty-sandbox iframe — scripts, forms and popups cannot run. Links stay inert in-preview; right-click to open.

    "gno.land/p/nt/grc20/v0"
    9 "gno.land/p/nt/ufmt/v0"
    10
    11 "gno.land/r/gnoswap/access/v1"
    12 "gno.land/r/nt/grc20reg/v0"
    13
    14 "gno.land/p/gnoswap/gnsmath/v1"
    15 "gno.land/p/gnoswap/utils/v1"
    16 _ "gno.land/r/gnoswap/rbac/v1"
    17)
    18
    19const (
    20 tokenID = 0
    21 MAXIMUM_SUPPLY = int64(1_000_000_000_000_000)
    22 INITIAL_MINT_AMOUNT = int64(100_000_000_000_000)
    23 MAX_EMISSION_AMOUNT = int64(900_000_000_000_000) // MAXIMUM_SUPPLY - INITIAL_MINT_AMOUNT
    24)
    25
    26var (
    27 token *grc20.Token
    28 privateLedger *grc20.PrivateLedger
    29 userTeller grc20.Teller
    30
    31 leftEmissionAmount int64 // amount of GNS can be minted for emission
    32 mintedEmissionAmount int64 // amount of GNS that has been minted for emission
    33 lastMintedTimestamp int64 // last block time that gns was minted for emission
    34)
    35
    36func init(cur realm) {
    37 token, privateLedger = grc20.NewToken("Gnoswap", "GNS", 6, tokenID, cur)
    38 userTeller = privateLedger.CallerTeller()
    39
    40 grc20reg.Register(cross(cur), token, "")
    41
    42 // Initial amount set to 900_000_000_000_000 (MAXIMUM_SUPPLY - INITIAL_MINT_AMOUNT).
    43 // leftEmissionAmount will decrease as tokens are minted.
    44 setLeftEmissionAmount(MAX_EMISSION_AMOUNT)
    45 setMintedEmissionAmount(0)
    46 setLastMintedTimestamp(0)
    47
    48 // Pre-mint the initial GNS supply.
    49 setupPreMint(cur)
    50}
    51
    52// Name returns the name of the GNS token.
    53//
    54// Returns:
    55// - name: token name
    56func Name() string { return token.GetName() }
    57
    58// Symbol returns the symbol of the GNS token.
    59//
    60// Returns:
    61// - symbol: token symbol
    62func Symbol() string { return token.GetSymbol() }
    63
    64// Decimals returns the number of decimal places for GNS token.
    65//
    66// Returns:
    67// - decimals: number of decimal places
    68func Decimals() int { return token.GetDecimals() }
    69
    70// TotalSupply returns the total supply of GNS tokens in circulation.
    71//
    72// Returns:
    73// - supply: total token supply
    74func TotalSupply() int64 { return token.TotalSupply() }
    75
    76// KnownAccounts returns the number of addresses that have held GNS.
    77//
    78// Returns:
    79// - count: number of known accounts
    80func KnownAccounts() int { return token.KnownAccounts() }
    81
    82// BalanceOf returns the GNS balance of a specific address.
    83//
    84// Parameters:
    85// - owner: address to check balance for
    86//
    87// Returns:
    88// - balance: token balance
    89func BalanceOf(owner address) int64 { return token.BalanceOf(owner) }
    90
    91// Allowance returns the amount of GNS that a spender is allowed to transfer from an owner.
    92//
    93// Parameters:
    94// - owner: token owner address
    95// - spender: spender address
    96//
    97// Returns:
    98// - allowance: approved amount
    99func Allowance(owner, spender address) int64 { return token.Allowance(owner, spender) }
    100
    101// MintGns mints new GNS tokens according to the emission schedule.
    102//
    103// Parameters:
    104// - cur: Current realm context; callers use cross(cur) when crossing into this realm.
    105// - address: recipient address for minted tokens
    106//
    107// Returns:
    108// - amount: GNS minted for the current timestamp; zero when emission is
    109// already processed for that timestamp or the schedule has ended
    110//
    111// Only callable by emission contract.
    112//
    113// Note: Halt check is performed by the caller (emission.MintAndDistributeGns)
    114// to allow graceful handling. This function assumes caller has already verified
    115// halt status before invoking.
    116func MintGns(cur realm, address address) int64 {
    117 previousRealm := cur.Previous()
    118 caller := previousRealm.Address()
    119 access.AssertIsEmission(caller)
    120
    121 lastGNSMintedTimestamp := LastMintedTimestamp()
    122 currentTime := time.Now().Unix()
    123
    124 // Skip if already minted this timestamp or emission ended.
    125 if lastGNSMintedTimestamp == currentTime || lastGNSMintedTimestamp >= GetEmissionEndTimestamp() {
    126 return 0
    127 }
    128
    129 amountToMint, err := calculateAmountToMint(getEmissionState(), lastGNSMintedTimestamp+1, currentTime)
    130 if err != nil {
    131 panic(err)
    132 }
    133
    134 err = validEmissionAmount(amountToMint)
    135 if err != nil {
    136 panic(err)
    137 }
    138
    139 setLastMintedTimestamp(currentTime)
    140 setMintedEmissionAmount(gnsmath.SafeAddInt64(MintedEmissionAmount(), amountToMint))
    141 setLeftEmissionAmount(gnsmath.SafeSubInt64(LeftEmissionAmount(), amountToMint))
    142
    143 err = privateLedger.Mint(address, amountToMint)
    144 if err != nil {
    145 panic(err.Error())
    146 }
    147
    148 chain.Emit(
    149 "MintGNS",
    150 "prevAddr", caller.String(),
    151 "prevRealm", previousRealm.PkgPath(),
    152 "mintedBlockTime", utils.FormatInt(currentTime),
    153 "mintedGNSAmount", utils.FormatInt(amountToMint),
    154 "accumMintedGNSAmount", utils.FormatInt(MintedEmissionAmount()),
    155 "accumLeftMintGNSAmount", utils.FormatInt(LeftEmissionAmount()),
    156 )
    157
    158 return amountToMint
    159}
    160
    161// Transfer transfers GNS tokens from caller to recipient.
    162//
    163// Parameters:
    164// - cur: Current realm context; callers use cross(cur) when crossing into this realm.
    165// - to: recipient address
    166// - amount: number of GNS base units to transfer
    167func Transfer(cur realm, to address, amount int64) {
    168 checkErr(userTeller.Transfer(0, cur, to, amount))
    169}
    170
    171// Approve allows spender to transfer GNS tokens from caller's account.
    172//
    173// Parameters:
    174// - cur: Current realm context; callers use cross(cur) when crossing into this realm.
    175// - spender: address authorized to spend
    176// - amount: maximum number of GNS base units spender can transfer
    177func Approve(cur realm, spender address, amount int64) {
    178 checkErr(userTeller.Approve(0, cur, spender, amount))
    179}
    180
    181// TransferFrom transfers GNS tokens on behalf of owner.
    182//
    183// Parameters:
    184// - cur: Current realm context; callers use cross(cur) when crossing into this realm.
    185// - from: token owner address
    186// - to: recipient address
    187// - amount: number of GNS base units to transfer
    188func TransferFrom(cur realm, from, to address, amount int64) {
    189 checkErr(userTeller.TransferFrom(0, cur, from, to, amount))
    190}
    191
    192// Render returns token information for web interface.
    193//
    194// Parameters:
    195// - path: render path for specific views
    196//
    197// Returns:
    198// - output: formatted token information
    199func Render(path string) string {
    200 parts := strings.Split(path, "/")
    201 c := len(parts)
    202
    203 switch {
    204 case path == "":
    205 return token.RenderHome()
    206 case c == 2 && parts[0] == "balance":
    207 owner := address(parts[1])
    208 balance := token.BalanceOf(owner)
    209 return ufmt.Sprintf("%d\n", balance)
    210 default:
    211 return "404\n"
    212 }
    213}
    214
    215// checkErr panics if error is not nil.
    216func checkErr(err error) {
    217 if err != nil {
    218 panic(err.Error())
    219 }
    220}
    221
    222// calculateAmountToMint calculates and allocates GNS tokens to mint for given timestamp range.
    223// This function has side effects: it updates the accumulated and remaining amounts
    224// for each halving year in the emission state.
    225func calculateAmountToMint(state *EmissionState, fromTimestamp, toTimestamp int64) (int64, error) {
    226 // Cache state to avoid repeated lookups
    227 endTimestamp := state.getEndTimestamp()
    228 if toTimestamp > endTimestamp {
    229 toTimestamp = endTimestamp
    230 }
    231
    232 if fromTimestamp > toTimestamp {
    233 return 0, nil
    234 }
    235
    236 startTimestamp := state.getStartTimestamp()
    237 if fromTimestamp < startTimestamp {
    238 fromTimestamp = startTimestamp
    239 }
    240
    241 if toTimestamp < startTimestamp {
    242 return 0, nil
    243 }
    244
    245 fromYear := state.getCurrentYear(fromTimestamp)
    246 toYear := state.getCurrentYear(toTimestamp)
    247
    248 if fromYear == 0 || toYear == 0 {
    249 return 0, nil
    250 }
    251
    252 totalAmountToMint := int64(0)
    253
    254 for year := fromYear; year <= toYear; year++ {
    255 yearEndTimestamp := state.getHalvingYearEndTimestamp(year)
    256 currentToTimestamp := i64Min(toTimestamp, yearEndTimestamp)
    257
    258 seconds := currentToTimestamp - fromTimestamp + 1
    259 if seconds <= 0 {
    260 break
    261 }
    262
    263 amountPerSecond := state.getHalvingYearAmountPerSecond(year)
    264 yearAmountToMint := gnsmath.SafeMulInt64(amountPerSecond, seconds)
    265
    266 if currentToTimestamp >= yearEndTimestamp {
    267 leftover := gnsmath.SafeSubInt64(state.getHalvingYearLeftAmount(year), yearAmountToMint)
    268 yearAmountToMint = gnsmath.SafeAddInt64(yearAmountToMint, leftover)
    269 }
    270
    271 totalAmountToMint = gnsmath.SafeAddInt64(totalAmountToMint, yearAmountToMint)
    272
    273 err := state.addHalvingYearMintedAmount(year, yearAmountToMint)
    274 if err != nil {
    275 return 0, err
    276 }
    277
    278 err = state.subHalvingYearLeftAmount(year, yearAmountToMint)
    279 if err != nil {
    280 return 0, err
    281 }
    282
    283 fromTimestamp = currentToTimestamp + 1
    284
    285 if fromTimestamp > toTimestamp {
    286 break
    287 }
    288 }
    289
    290 return totalAmountToMint, nil
    291}
    292
    293// LastMintedTimestamp returns the timestamp of the last GNS emission mint.
    294//
    295// Returns:
    296// - timestamp: last minted timestamp
    297func LastMintedTimestamp() int64 { return lastMintedTimestamp }
    298
    299// LeftEmissionAmount returns the remaining GNS tokens available for emission.
    300//
    301// Returns:
    302// - amount: remaining emission amount
    303func LeftEmissionAmount() int64 { return leftEmissionAmount }
    304
    305// MintedEmissionAmount returns the total GNS tokens minted through emission,
    306// excluding the initial mint amount.
    307//
    308// Returns:
    309// - amount: total minted emission amount
    310func MintedEmissionAmount() int64 { return mintedEmissionAmount }
    311
    312// setLastMintedTimestamp sets the timestamp of the last emission mint.
    313func setLastMintedTimestamp(timestamp int64) { lastMintedTimestamp = timestamp }
    314
    315// setLeftEmissionAmount sets the remaining emission amount.
    316func setLeftEmissionAmount(amount int64) { leftEmissionAmount = amount }
    317
    318// setMintedEmissionAmount sets the total minted emission amount.
    319func setMintedEmissionAmount(amount int64) { mintedEmissionAmount = amount }
    320