Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(grc): remake of grc721 nft standard #3973

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
Open
1 change: 1 addition & 0 deletions examples/gno.land/p/demo/grc/grc721remake/gno.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module gno.land/p/demo/grc/grc721remake
188 changes: 188 additions & 0 deletions examples/gno.land/p/demo/grc/grc721remake/hooks.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
package grc721remake

import (
"std"

"gno.land/p/demo/avl"
)

// HookType represents the type of operation a hook is associated with
type HookType string

const (
HookTransfer HookType = "transfer"
HookApproval HookType = "approval"
HookApprovalForAll HookType = "approvalForAll"
HookMint HookType = "mint"
HookBurn HookType = "burn"
)

// HookTime represents when a hook should be executed
type HookTime string

const (
HookBefore HookTime = "before"
HookAfter HookTime = "after"
)

// Hook is the base interface that all hooks must implement
type Hook interface {
GetHookType() HookType
GetHookTime() HookTime
}

// TransferHook is implemented by hooks that want to intercept transfer operations
type TransferHook interface {
Hook
OnTransfer(nft *NFT, from, to std.Address, tid TokenID) error
}

// ApprovalHook is implemented by hooks that want to intercept approval operations
type ApprovalHook interface {
Hook
OnApproval(nft *NFT, owner, approved std.Address, tid TokenID) error
}

// ApprovalForAllHook is implemented by hooks that want to intercept approvalForAll operations
type ApprovalForAllHook interface {
Hook
OnApprovalForAll(nft *NFT, owner, operator std.Address, approved bool) error
}

// MintHook is implemented by hooks that want to intercept mint operations
type MintHook interface {
Hook
OnMint(nft *NFT, to std.Address, tid TokenID) error
}

// BurnHook is implemented by hooks that want to intercept burn operations
type BurnHook interface {
Hook
OnBurn(nft *NFT, tid TokenID) error
}

// HookRegistry manages a collection of hooks using a tree structure
type HookRegistry struct {
hooks *avl.Tree
}

// NewHookRegistry creates a new hook registry
func NewHookRegistry() *HookRegistry {
return &HookRegistry{
hooks: avl.NewTree(),
}
}

// RegisterHookWithKey adds a hook to the registry with a specified key
func (reg *HookRegistry) RegisterHook(key string, hook Hook) {
reg.hooks.Set(key, hook)
}

// GetHook retrieves a hook by its key
func (reg *HookRegistry) GetHook(key string) (Hook, bool) {
value, exists := reg.hooks.Get(key)
if !exists {
return nil, false
}
return value.(Hook), true
}

// TriggerTransferHooks executes all transfer hooks of the specified time
func (reg *HookRegistry) TriggerTransferHooks(nft *NFT, time HookTime, from, to std.Address, tid TokenID) error {
var foundError error = nil

reg.hooks.Iterate("", "", func(key string, value any) bool {
hook := value.(Hook)
if hook.GetHookType() == HookTransfer && hook.GetHookTime() == time {
if transferHook, ok := hook.(TransferHook); ok {
if err := transferHook.OnTransfer(nft, from, to, tid); err != nil {
foundError = err
return true
}
}
}
return false
})

return foundError
}

// TriggerApprovalHooks executes all approval hooks of the specified time
func (reg *HookRegistry) TriggerApprovalHooks(nft *NFT, time HookTime, owner, approved std.Address, tid TokenID) error {
var foundError error = nil

reg.hooks.Iterate("", "", func(key string, value any) bool {
hook := value.(Hook)
if hook.GetHookType() == HookApproval && hook.GetHookTime() == time {
if approvalHook, ok := hook.(ApprovalHook); ok {
if err := approvalHook.OnApproval(nft, owner, approved, tid); err != nil {
foundError = err
return true
}
}
}
return false
})

return foundError
}

// TriggerApprovalForAllHooks executes all approvalForAll hooks of the specified time
func (reg *HookRegistry) TriggerApprovalForAllHooks(nft *NFT, time HookTime, owner, operator std.Address, approved bool) error {
var foundError error = nil

reg.hooks.Iterate("", "", func(key string, value any) bool {
hook := value.(Hook)
if hook.GetHookType() == HookApprovalForAll && hook.GetHookTime() == time {
if approvalForAllHook, ok := hook.(ApprovalForAllHook); ok {
if err := approvalForAllHook.OnApprovalForAll(nft, owner, operator, approved); err != nil {
foundError = err
return true
}
}
}
return false
})

return foundError
}

// TriggerMintHooks executes all mint hooks of the specified time
func (reg *HookRegistry) TriggerMintHooks(nft *NFT, time HookTime, to std.Address, tid TokenID) error {
var foundError error = nil

reg.hooks.Iterate("", "", func(key string, value any) bool {
hook := value.(Hook)
if hook.GetHookType() == HookMint && hook.GetHookTime() == time {
if mintHook, ok := hook.(MintHook); ok {
if err := mintHook.OnMint(nft, to, tid); err != nil {
foundError = err
return true
}
}
}
return false
})

return foundError
}

// TriggerBurnHooks executes all burn hooks of the specified time
func (reg *HookRegistry) TriggerBurnHooks(nft *NFT, time HookTime, tid TokenID) error {
var foundError error = nil

reg.hooks.Iterate("", "", func(key string, value any) bool {
hook := value.(Hook)
if hook.GetHookType() == HookBurn && hook.GetHookTime() == time {
if burnHook, ok := hook.(BurnHook); ok {
if err := burnHook.OnBurn(nft, tid); err != nil {
foundError = err
return true
}
}
}
return false
})

return foundError
}
Loading
Loading