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