Skip to content

Commit 332e5a2

Browse files
committed
Add experimental Archon actor
1 parent cc0741c commit 332e5a2

File tree

6 files changed

+240
-4
lines changed

6 files changed

+240
-4
lines changed

convex-core/src/main/cvx/asset/nft/basic.cvx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,15 @@
1010

1111
;;;;;;;;;; Values
1212

13-
(def counter
13+
(define counter
1414
^{:doc {:description "Used for creating NFT ids."}}
1515
0)
1616

17-
(def offers
17+
(define offers
1818
^{:doc {:description "Map of `owner` -> map of `recipient address` -> `set of NFT ids`"}}
1919
{})
2020

21-
(def meta
21+
(define meta
2222
^{:doc {:description "Map of ID -> NFT metadata. May be nil for no metadata"}}
2323
{})
2424

convex-core/src/main/cvx/convex/core.cvx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,16 @@
191191
(apply m# (next x))
192192
e)))))
193193

194+
(defmacro define
195+
^{:doc {:description "Defines a value in the current environment, like def, but at expand time."
196+
:examples [{:code "(define cols [:red :green])"}]
197+
:signature [{:params [name]}
198+
{:params [name vale]}]}}
199+
([name]
200+
(eval `(def ~name)))
201+
([name value]
202+
(eval `(def ~name ~value))))
203+
194204
(defmacro defn
195205
^{:doc {:description "Defines a function in the current environment."
196206
:examples [{:code "(defn my-square [x] (* x x))"}]
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
'archon
2+
3+
(call *registry*
4+
(register {:description ["Actor for the Archon NFT collection."]
5+
:name "Archon Actor"}))
6+
7+
(declare balance)
8+
9+
;;;;;;;;;; Governance
10+
;; We set a controller with upgrade and access rights. This can be removed / modified later
11+
;; Use the current controller, or the geneses peer account #12 if unspecified
12+
13+
(define guv (or *controller* #12))
14+
(set-controller guv)
15+
16+
;;;;;;;;;; Values
17+
18+
(define offers
19+
^{:doc {:description "Map of `owner` -> map of `recipient address` -> `set of NFT ids`"}}
20+
{})
21+
22+
(define base-url "http://localhost:8080/dlfs/archon")
23+
24+
25+
;;;;;;;;;; Archon specific functionality
26+
27+
28+
;; Determine if an ID is valid
29+
(defn valid-id? [id]
30+
(cond
31+
(and
32+
(blob? id)
33+
(= 2 (count id))
34+
(<= 1 (int id) 1024))
35+
true
36+
false))
37+
38+
;; Archon NFT minting, performed once
39+
(loop [nfts #{} i 1]
40+
(cond
41+
;; looping for each Archon NFT
42+
(<= i 1024)
43+
44+
;; Run this branch for each NFT
45+
(let [;; Generate a 2 byte blob. Small new numeric IDs need an extra byte
46+
nft (blob i)
47+
nft (if (< i 128) (blob (str "00" nft)) nft)]
48+
(if (valid-id? nft)
49+
(recur (conj nfts nft) (inc i))
50+
(fail (str "Somehow created an invalid NFT:" nft))))
51+
52+
;; When done give all NFTs to governance account
53+
(do (set-holding guv nfts)
54+
(or (= (count nfts) 1024) (fail "Unexpected total number of Archons" (count nfts))))))
55+
56+
57+
;;;;;;;;;; Implementation of `convex.asset` interface
58+
59+
(defn -qc
60+
^{:doc {:description "Checks a basic NFT quantity."}
61+
:private? true}
62+
[q]
63+
(cond (set? q) q ;; base case, quantity should always be a Set
64+
(blob? q) #{q}
65+
(nil? q) #{}
66+
(fail :ARGUMENT "Invalid NFT quantity")))
67+
68+
(defn -direct-transfer
69+
^{:private? true}
70+
;; Used internally by [[accept]] and [[direct-transfer]].
71+
[sender receiver quantity]
72+
(let [q (-qc quantity)
73+
receiver (address receiver)
74+
sender-balance (or (get-holding sender)
75+
#{})
76+
_ (or (subset? q sender-balance)
77+
(fail :FUNDS "Cannot transfer non-owned NFT(s)"))
78+
receiver-balance (or (get-holding receiver)
79+
#{})
80+
new-sender-balance (difference sender-balance q)
81+
new-receiver-balance (union receiver-balance q)]
82+
(set-holding sender new-sender-balance)
83+
(set-holding receiver new-receiver-balance)
84+
quantity))
85+
86+
87+
(defn accept
88+
^{:callable true
89+
:private? true}
90+
[sender quantity]
91+
(let [q (-qc quantity)
92+
sender (address sender)
93+
sender-offers (or (get offers
94+
sender)
95+
{})
96+
offer (or (get-in offers
97+
[sender
98+
*caller*])
99+
#{})
100+
_ (or (subset? q offer)
101+
(fail :STATE "Insuffient NFT offer to accept"))
102+
receiver-balance (or (get-holding *caller*)
103+
#{})
104+
new-offer (difference offer q)]
105+
106+
(set! offers
107+
(assoc offers
108+
sender
109+
(assoc sender-offers
110+
*caller*
111+
new-offer)))
112+
113+
(-direct-transfer sender
114+
*caller*
115+
quantity)))
116+
117+
(defn balance
118+
^{:callable true}
119+
[owner]
120+
(or (get-holding owner)
121+
#{}))
122+
123+
(defn direct-transfer
124+
^{:callable true}
125+
[receiver quantity]
126+
(-direct-transfer *caller*
127+
receiver
128+
quantity))
129+
130+
(defn offer
131+
^{:callable true}
132+
[receiver quantity]
133+
(let [q (-qc quantity)
134+
caller-offers (get offers *caller* {})]
135+
(set! offers
136+
(assoc offers
137+
*caller*
138+
(assoc caller-offers
139+
receiver
140+
q)))))
141+
142+
143+
(def quantity-add
144+
^{:callable true}
145+
union)
146+
147+
(def quantity-sub
148+
^{:callable true}
149+
difference)
150+
151+
(def quantity-subset?
152+
^{:callable true}
153+
subset?)
154+
155+
;;;;;;;;;; Callable functions
156+
157+
158+
(defn get-metadata
159+
^{:callable true
160+
:doc {:description "Gets metadata for a given NFT ID."
161+
:signature [{:params []}
162+
{:params [id]}]}}
163+
([] (recur *scope*))
164+
([id]
165+
(or (valid-id? id) nil)
166+
(let [hex (str id)
167+
img (str base-url hex ".png")]
168+
{
169+
"image" img
170+
})))

convex-core/src/main/java/convex/core/Constants.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ public class Constants {
169169
/**
170170
* Default print limit
171171
*/
172-
public static final long PRINT_LIMIT = 4096;
172+
public static final long PRINT_LIMIT = 65536;
173173

174174
public static final String PRINT_EXCEEDED_STRING = "<<Print limit exceeded>>";
175175
public static final AString PRINT_EXCEEDED_MESSAGE = Strings.create(PRINT_EXCEEDED_STRING);

convex-core/src/test/java/convex/core/lang/CoreTest.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4209,6 +4209,7 @@ public void testSetBang() {
42094209
// set! fails on undeclared values
42104210
assertUndeclaredError(step("(set! not-declared 1)"));
42114211
assertUndeclaredError(step("(do (set! a 13) a)"));
4212+
assertUndeclaredError(step("(let [foo 3] (set! a 13) a)"));
42124213

42134214
// set! works in a function body
42144215
assertEquals(35L,evalL("(let [a 13 f (fn [x] (set! a 25) (+ x a))] (f 10))"));
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package lab;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
5+
import java.io.IOException;
6+
7+
import org.junit.jupiter.api.Test;
8+
9+
import convex.core.data.Address;
10+
import convex.core.lang.ACVMTest;
11+
import convex.core.lang.Context;
12+
import convex.core.lang.TestState;
13+
import convex.core.util.Utils;
14+
import convex.lib.AssetTester;
15+
16+
public class ArchonTest extends ACVMTest {
17+
18+
Address ARCHON;
19+
20+
@Override protected Context buildContext(Context ctx) {
21+
ctx=TestState.CONTEXT.fork();
22+
23+
ctx=exec(ctx,"(import convex.asset :as asset)");
24+
ctx=exec(ctx,"(import convex.trust :as trust)");
25+
26+
ctx=exec(ctx,"(def archon (deploy '(set-controller *caller*) *address*))");
27+
ARCHON=ctx.getResult();
28+
29+
try {
30+
String code=Utils.readResourceAsString("lab/archon.cvx");
31+
ctx=exec(ctx,"(eval-as archon '(do "+code+"))");
32+
33+
34+
} catch (IOException e) {
35+
// TODO Auto-generated catch block
36+
e.printStackTrace();
37+
throw new Error(e);
38+
}
39+
return ctx;
40+
}
41+
42+
@Test public void testArchonActor() {
43+
Context ctx=context();
44+
Address archon=eval(ctx,"archon");
45+
assertEquals(ARCHON,archon);
46+
47+
assertEquals(1024,evalL(ctx,"(count (asset/balance archon))"));
48+
}
49+
50+
@Test public void testArchonNFTs() {
51+
Context ctx=context();
52+
ctx=exec(ctx,"(asset/transfer "+VILLAIN+" [archon #{0x0123}])");
53+
AssetTester.doAssetTests(ctx, ARCHON, HERO, VILLAIN);
54+
}
55+
}

0 commit comments

Comments
 (0)