Skip to content

Commit 45e429a

Browse files
authored
Merge pull request #15 from anoma/feature/transferable
feat: add non-transferability property
2 parents bbc4d03 + c6c9199 commit 45e429a

File tree

4 files changed

+47
-20
lines changed

4 files changed

+47
-20
lines changed

Token/Error.juvix

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ type TokenError :=
1212
| ErrTokenInsufficientQuantity InsufficientQuantityError
1313
| ErrTokenInvalidLabel InvalidLabelError
1414
| ErrTokenInvalidLogic InvalidLogicError
15+
| ErrNonTransferable NonTransferableError
1516
| ErrTokenInsufficientElements InsufficientElementsError
1617
| ErrTokenDefault Error;
1718

@@ -53,6 +54,12 @@ InvalidLogicThrowable {A} : TokenThrowable InvalidLogicError A :=
5354
throw (e : InvalidLogicError) : Result TokenError A := error {_} {A} (ErrTokenInvalidLogic e)
5455
};
5556

57+
instance
58+
NonTransferableThrowable {A} : TokenThrowable NonTransferableError A :=
59+
mkTokenThrowable@{
60+
throw (e : NonTransferableError) : Result TokenError A := error {_} {A} (ErrNonTransferable e)
61+
};
62+
5663
instance
5764
ErrorThrowable {A} : TokenThrowable Error A :=
5865
mkTokenThrowable@{

Token/Label.juvix

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ type Label :=
1212
symbol : String;
1313
decimals : Nat;
1414
supply : Supply;
15+
transferable : Bool;
1516
originator : PublicKey
1617
};
1718

@@ -41,6 +42,9 @@ Label-Show : Show Label :=
4142
++str "supply : "
4243
++str (l |> Label.supply |> Show.show)
4344
++str ", "
45+
++str "transferable : "
46+
++str (l |> Label.transferable |> Show.show)
47+
++str ", "
4448
++str "originator : "
4549
++str (l |> Label.supply |> Show.show)
4650
++str "}"};
@@ -55,6 +59,8 @@ getDecimals (r : Resource) : Nat := Label.decimals (getLabel r);
5559

5660
getSupply (r : Resource) : Supply := Label.supply (getLabel r);
5761

62+
isTransferable (r : Resource) : Bool := Label.transferable (getLabel r);
63+
5864
getOriginator (r : Resource) : PublicKey := Label.originator (getLabel r);
5965

6066
terminating
@@ -83,3 +89,8 @@ InvalidLabelError-Show : Show InvalidLabelError :=
8389
++str "actual"
8490
++str (e |> InvalidLabelError.actual |> Show.show)
8591
++str "}"};
92+
93+
type NonTransferableError := mkNonTransferableError;
94+
95+
instance
96+
NonTransferableError-Show : Show NonTransferableError := mkShow \ {e := "NonTransferableError"};

Token/Logic.juvix

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,21 @@ tokenLogic (supply : Supply) : Resource -> Transaction -> Bool :=
1818
unboundSupplyLogic (self : Resource) (tx : Transaction) : Bool :=
1919
case lifecycle self tx, ephemerality self of
2020
| Consumed, Ephemeral := isAuthorizedBy (getOriginator self) self tx
21-
| Consumed, NonEphemeral := isAuthorizedBy (getOwner self) self tx
21+
| Consumed, NonEphemeral := transferLogic self tx
2222
| Created, _ := true
2323
| Unknown, _ := false;
2424

2525
fixedSupplyLogic (nf : Nullifier) (self : Resource) (tx : Transaction) : Bool :=
2626
case lifecycle self tx, ephemerality self of
2727
| Consumed, Ephemeral := isAuthorizedBy (getOriginator self) self tx && isNullifierPresent nf tx
28-
| Consumed, NonEphemeral := isAuthorizedBy (getOwner self) self tx
28+
| Consumed, NonEphemeral := transferLogic self tx
2929
| Created, Ephemeral := false
3030
| Created, NonEphemeral := true
3131
| Unknown, _ := false;
3232

3333
axiom cappedSupplyLogic : Resource -> Transaction -> Bool;
34+
35+
transferLogic (self : Resource) (tx : Transaction) : Bool :=
36+
case isTransferable self of
37+
| true := isAuthorizedBy (getOwner self) self tx
38+
| false := false;

Token/Transaction.juvix

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ transfer (self : KeyPair) (token : Resource) (receiver : PublicKey)
9595
mustBeCreated := createdRs
9696
};
9797
in if
98+
| not (isTransferable token) := throw mkNonTransferableError
9899
| owner /= myself := throw mkUnauthorizedError@{expected := myself; actual := owner}
99100
| else := ok (mkTransaction mySecret consumedRs createdRs extraData);
100101

@@ -123,6 +124,7 @@ split (self : KeyPair) (token : Resource) (amountsAndReceivers : List (Pair Nat
123124
mustBeCreated := createdRs
124125
};
125126
in if
127+
| not (isTransferable token) := throw mkNonTransferableError
126128
| owner /= myself := throw mkUnauthorizedError@{expected := myself; actual := owner}
127129
| balance /= sum := throw mkInsufficientQuantityError@{limit := balance; actual := sum}
128130
| else := ok (mkTransaction mySecret consumedRs createdRs extraData);
@@ -139,15 +141,14 @@ send (self : KeyPair) (token : Resource) (amount : Nat) (receiver : PublicKey)
139141
let
140142
myself : PublicKey := KeyPair.pubKey self;
141143
availableAmount : Nat := Resource.quantity token;
142-
in
143-
case (compare availableAmount amount) of
144-
| LT := throw mkInsufficientQuantityError@{limit := availableAmount; actual := amount}
145-
| EQ := transfer self token receiver
146-
| GT :=
147-
let
148-
remainder : Nat := toNat (intSubNat availableAmount amount);
149-
in
150-
split self token [(amount, receiver); (remainder, myself)];
144+
in case (compare availableAmount amount) of
145+
| LT := throw mkInsufficientQuantityError@{limit := availableAmount; actual := amount}
146+
| EQ := transfer self token receiver
147+
| GT :=
148+
let
149+
remainder : Nat := toNat (intSubNat availableAmount amount);
150+
in
151+
split self token [(amount, receiver); (remainder, myself)];
151152

152153
--- Merges token ;Resource;s, if the calling ;KeyPair; is the owner of all
153154
--- of them and the ;Label;s match.
@@ -178,12 +179,15 @@ merge (self : KeyPair) (tokens : List Resource) (receiver : PublicKey)
178179
mustBeConsumed := [];
179180
mustBeCreated := createdRs
180181
};
181-
in case find ((/=) owner) (map getOwner tokens) of
182-
| just wrongOwner := throw mkUnauthorizedError@{expected := myself; actual := wrongOwner}
183-
| nothing :=
184-
case find ((/=) label) (map getLabel tokens) of
185-
| just wrongLabel := throw mkInvalidLabelError@{expected := label; actual := wrongLabel}
186-
| nothing :=
187-
case find ((/=) logic) (map getLogic tokens) of
188-
| just wrongLogic := throw mkInvalidLogicError@{expected := logic; actual := wrongLogic}
189-
| nothing := ok (mkTransaction mySecret consumedRs createdRs extraData);
182+
in if
183+
| not (isTransferable t) := throw mkNonTransferableError
184+
| else :=
185+
case find ((/=) owner) (map getOwner tokens) of
186+
| just wrongOwner := throw mkUnauthorizedError@{expected := myself; actual := wrongOwner}
187+
| nothing :=
188+
case find ((/=) label) (map getLabel tokens) of
189+
| just wrongLabel := throw mkInvalidLabelError@{expected := label; actual := wrongLabel}
190+
| nothing :=
191+
case find ((/=) logic) (map getLogic tokens) of
192+
| just wrongLogic := throw mkInvalidLogicError@{expected := logic; actual := wrongLogic}
193+
| nothing := ok (mkTransaction mySecret consumedRs createdRs extraData);

0 commit comments

Comments
 (0)