Search Apps Documentation Source Content File Folder Download Copy Actions Download

contract.gno

3.71 Kb ยท 152 lines
  1package ghverify
  2
  3import (
  4	"chain"
  5	"chain/runtime"
  6	"errors"
  7
  8	"gno.land/p/demo/gnorkle/feeds/static"
  9	"gno.land/p/demo/gnorkle/gnorkle"
 10	"gno.land/p/demo/gnorkle/message"
 11	"gno.land/p/nt/avl"
 12)
 13
 14const (
 15	// The agent should send this value if it has verified the github handle.
 16	verifiedResult = "OK"
 17)
 18
 19var (
 20	ownerAddress = runtime.OriginCaller()
 21	oracle       *gnorkle.Instance
 22	postHandler  postGnorkleMessageHandler
 23
 24	handleToAddressMap = avl.NewTree()
 25	addressToHandleMap = avl.NewTree()
 26)
 27
 28func init() {
 29	oracle = gnorkle.NewInstance()
 30	oracle.AddToWhitelist("", []string{string(ownerAddress)})
 31}
 32
 33type postGnorkleMessageHandler struct{}
 34
 35// Handle does post processing after a message is ingested by the oracle feed. It extracts the value to realm
 36// storage and removes the feed from the oracle.
 37func (h postGnorkleMessageHandler) Handle(i *gnorkle.Instance, funcType message.FuncType, feed gnorkle.Feed) error {
 38	if funcType != message.FuncTypeIngest {
 39		return nil
 40	}
 41
 42	result, _, consumable := feed.Value()
 43	if !consumable {
 44		return nil
 45	}
 46
 47	// The value is consumable, meaning the ingestion occurred, so we can remove the feed from the oracle
 48	// after saving it to realm storage.
 49	defer oracle.RemoveFeed(feed.ID())
 50
 51	// Couldn't verify; nothing to do.
 52	if result.String != verifiedResult {
 53		return nil
 54	}
 55
 56	feedTasks := feed.Tasks()
 57	if len(feedTasks) != 1 {
 58		return errors.New("expected feed to have exactly one task")
 59	}
 60
 61	task, ok := feedTasks[0].(*verificationTask)
 62	if !ok {
 63		return errors.New("expected ghverify task")
 64	}
 65
 66	handleToAddressMap.Set(task.githubHandle, task.gnoAddress)
 67	addressToHandleMap.Set(task.gnoAddress, task.githubHandle)
 68	return nil
 69}
 70
 71// RequestVerification creates a new static feed with a single task that will
 72// instruct an agent to verify the github handle / gno address pair.
 73func RequestVerification(cur realm, githubHandle string) {
 74	gnoAddress := string(runtime.OriginCaller())
 75	if err := oracle.AddFeeds(
 76		static.NewSingleValueFeed(
 77			gnoAddress,
 78			"string",
 79			&verificationTask{
 80				gnoAddress:   gnoAddress,
 81				githubHandle: githubHandle,
 82			},
 83		),
 84	); err != nil {
 85		panic(err)
 86	}
 87	chain.Emit(
 88		"verification_requested",
 89		"from", gnoAddress,
 90		"handle", githubHandle,
 91	)
 92}
 93
 94// GnorkleEntrypoint is the entrypoint to the gnorkle oracle handler.
 95func GnorkleEntrypoint(cur realm, message string) string {
 96	result, err := oracle.HandleMessage(message, postHandler)
 97	if err != nil {
 98		panic(err)
 99	}
100
101	return result
102}
103
104// SetOwner transfers ownership of the contract to the given address.
105func SetOwner(_ realm, owner address) {
106	if ownerAddress != runtime.OriginCaller() {
107		panic("only the owner can set a new owner")
108	}
109
110	ownerAddress = owner
111
112	// In the context of this contract, the owner is the only one that can
113	// add new feeds to the oracle.
114	oracle.ClearWhitelist("")
115	oracle.AddToWhitelist("", []string{string(ownerAddress)})
116}
117
118// GetHandleByAddress returns the github handle associated with the given gno address.
119func GetHandleByAddress(cur realm, address_XXX string) string {
120	if value, ok := addressToHandleMap.Get(address_XXX); ok {
121		return value.(string)
122	}
123
124	return ""
125}
126
127// GetAddressByHandle returns the gno address associated with the given github handle.
128func GetAddressByHandle(cur realm, handle string) string {
129	if value, ok := handleToAddressMap.Get(handle); ok {
130		return value.(string)
131	}
132
133	return ""
134}
135
136// Render returns a json object string will all verified handle -> address mappings.
137func Render(_ string) string {
138	result := "{"
139	var appendComma bool
140	handleToAddressMap.Iterate("", "", func(handle string, address_XXX any) bool {
141		if appendComma {
142			result += ","
143		}
144
145		result += `"` + handle + `": "` + address_XXX.(string) + `"`
146		appendComma = true
147
148		return false
149	})
150
151	return result + "}"
152}