@silvana-one/token 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/node/BondingCurveAdmin.d.ts +690 -0
- package/dist/node/BondingCurveAdmin.js +504 -0
- package/dist/node/BondingCurveAdmin.js.map +1 -0
- package/dist/node/FungibleToken.d.ts +414 -0
- package/dist/node/FungibleToken.js +7 -0
- package/dist/node/FungibleToken.js.map +1 -0
- package/dist/node/FungibleTokenAdvancedAdmin.d.ts +124 -0
- package/dist/node/FungibleTokenAdvancedAdmin.js +226 -0
- package/dist/node/FungibleTokenAdvancedAdmin.js.map +1 -0
- package/dist/node/FungibleTokenContract.d.ts +526 -0
- package/dist/node/FungibleTokenContract.js +295 -0
- package/dist/node/FungibleTokenContract.js.map +1 -0
- package/dist/node/FungibleTokenStandardAdmin.d.ts +27 -0
- package/dist/node/FungibleTokenStandardAdmin.js +101 -0
- package/dist/node/FungibleTokenStandardAdmin.js.map +1 -0
- package/dist/node/bid.d.ts +86 -0
- package/dist/node/bid.js +168 -0
- package/dist/node/bid.js.map +1 -0
- package/dist/node/claim.d.ts +89 -0
- package/dist/node/claim.js +156 -0
- package/dist/node/claim.js.map +1 -0
- package/dist/node/index.cjs +1576 -0
- package/dist/node/index.d.ts +8 -0
- package/dist/node/index.js +9 -0
- package/dist/node/index.js.map +1 -0
- package/dist/node/offer.d.ts +87 -0
- package/dist/node/offer.js +169 -0
- package/dist/node/offer.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/tsconfig.web.tsbuildinfo +1 -0
- package/dist/web/BondingCurveAdmin.d.ts +690 -0
- package/dist/web/BondingCurveAdmin.js +504 -0
- package/dist/web/BondingCurveAdmin.js.map +1 -0
- package/dist/web/FungibleToken.d.ts +414 -0
- package/dist/web/FungibleToken.js +7 -0
- package/dist/web/FungibleToken.js.map +1 -0
- package/dist/web/FungibleTokenAdvancedAdmin.d.ts +124 -0
- package/dist/web/FungibleTokenAdvancedAdmin.js +226 -0
- package/dist/web/FungibleTokenAdvancedAdmin.js.map +1 -0
- package/dist/web/FungibleTokenContract.d.ts +526 -0
- package/dist/web/FungibleTokenContract.js +295 -0
- package/dist/web/FungibleTokenContract.js.map +1 -0
- package/dist/web/FungibleTokenStandardAdmin.d.ts +27 -0
- package/dist/web/FungibleTokenStandardAdmin.js +101 -0
- package/dist/web/FungibleTokenStandardAdmin.js.map +1 -0
- package/dist/web/bid.d.ts +86 -0
- package/dist/web/bid.js +168 -0
- package/dist/web/bid.js.map +1 -0
- package/dist/web/claim.d.ts +89 -0
- package/dist/web/claim.js +156 -0
- package/dist/web/claim.js.map +1 -0
- package/dist/web/index.d.ts +8 -0
- package/dist/web/index.js +9 -0
- package/dist/web/index.js.map +1 -0
- package/dist/web/offer.d.ts +87 -0
- package/dist/web/offer.js +169 -0
- package/dist/web/offer.js.map +1 -0
- package/package.json +64 -0
- package/src/BondingCurveAdmin.ts +590 -0
- package/src/FungibleToken.ts +11 -0
- package/src/FungibleTokenAdvancedAdmin.ts +260 -0
- package/src/FungibleTokenContract.ts +337 -0
- package/src/FungibleTokenStandardAdmin.ts +95 -0
- package/src/bid.ts +170 -0
- package/src/claim.ts +151 -0
- package/src/index.ts +8 -0
- package/src/offer.ts +164 -0
package/src/bid.ts
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AccountUpdate,
|
|
3
|
+
DeployArgs,
|
|
4
|
+
method,
|
|
5
|
+
Permissions,
|
|
6
|
+
PublicKey,
|
|
7
|
+
State,
|
|
8
|
+
state,
|
|
9
|
+
UInt64,
|
|
10
|
+
SmartContract,
|
|
11
|
+
Bool,
|
|
12
|
+
Field,
|
|
13
|
+
Struct,
|
|
14
|
+
} from "o1js";
|
|
15
|
+
import { Whitelist } from "@silvana-one/storage";
|
|
16
|
+
import { FungibleToken } from "./FungibleToken.js";
|
|
17
|
+
|
|
18
|
+
export interface FungibleTokenBidContractDeployProps
|
|
19
|
+
extends Exclude<DeployArgs, undefined> {
|
|
20
|
+
/** The whitelist. */
|
|
21
|
+
whitelist: Whitelist;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export class BidEvent extends Struct({
|
|
25
|
+
amount: UInt64,
|
|
26
|
+
address: PublicKey,
|
|
27
|
+
}) {}
|
|
28
|
+
|
|
29
|
+
export class FungibleTokenBidContract extends SmartContract {
|
|
30
|
+
@state(UInt64) price = State<UInt64>();
|
|
31
|
+
@state(PublicKey) buyer = State<PublicKey>();
|
|
32
|
+
@state(PublicKey) token = State<PublicKey>();
|
|
33
|
+
@state(Whitelist) whitelist = State<Whitelist>();
|
|
34
|
+
|
|
35
|
+
async deploy(args: FungibleTokenBidContractDeployProps) {
|
|
36
|
+
await super.deploy(args);
|
|
37
|
+
this.whitelist.set(args.whitelist);
|
|
38
|
+
this.account.permissions.set({
|
|
39
|
+
...Permissions.default(),
|
|
40
|
+
send: Permissions.proof(),
|
|
41
|
+
setVerificationKey:
|
|
42
|
+
Permissions.VerificationKey.impossibleDuringCurrentVersion(),
|
|
43
|
+
setPermissions: Permissions.impossible(),
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
events = {
|
|
48
|
+
bid: BidEvent,
|
|
49
|
+
withdraw: BidEvent,
|
|
50
|
+
sell: BidEvent,
|
|
51
|
+
updateWhitelist: Whitelist,
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
@method async initialize(token: PublicKey, amount: UInt64, price: UInt64) {
|
|
55
|
+
this.account.provedState.requireEquals(Bool(false));
|
|
56
|
+
amount.equals(UInt64.from(0)).assertFalse();
|
|
57
|
+
|
|
58
|
+
const totalPriceField = price.value
|
|
59
|
+
.mul(amount.value)
|
|
60
|
+
.div(Field(1_000_000_000));
|
|
61
|
+
totalPriceField.assertLessThan(
|
|
62
|
+
UInt64.MAXINT().value,
|
|
63
|
+
"totalPrice overflow"
|
|
64
|
+
);
|
|
65
|
+
const totalPrice = UInt64.Unsafe.fromField(totalPriceField);
|
|
66
|
+
|
|
67
|
+
const buyer = this.sender.getUnconstrained();
|
|
68
|
+
const buyerUpdate = AccountUpdate.createSigned(buyer);
|
|
69
|
+
buyerUpdate.send({ to: this.address, amount: totalPrice });
|
|
70
|
+
buyerUpdate.body.useFullCommitment = Bool(true);
|
|
71
|
+
|
|
72
|
+
this.buyer.set(buyer);
|
|
73
|
+
this.price.set(price);
|
|
74
|
+
this.token.set(token);
|
|
75
|
+
this.emitEvent("bid", { amount, address: buyer } as BidEvent);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
@method async bid(amount: UInt64, price: UInt64) {
|
|
79
|
+
amount.equals(UInt64.from(0)).assertFalse();
|
|
80
|
+
|
|
81
|
+
const balance = this.account.balance.getAndRequireEquals();
|
|
82
|
+
const oldPrice = this.price.getAndRequireEquals();
|
|
83
|
+
// Price can be changed only when the balance is 0
|
|
84
|
+
price
|
|
85
|
+
.equals(oldPrice)
|
|
86
|
+
.or(balance.equals(UInt64.from(0)))
|
|
87
|
+
.assertTrue();
|
|
88
|
+
this.price.set(price);
|
|
89
|
+
|
|
90
|
+
const totalPriceField = price.value
|
|
91
|
+
.mul(amount.value)
|
|
92
|
+
.div(Field(1_000_000_000));
|
|
93
|
+
totalPriceField.assertLessThan(
|
|
94
|
+
UInt64.MAXINT().value,
|
|
95
|
+
"totalPrice overflow"
|
|
96
|
+
);
|
|
97
|
+
const totalPrice = UInt64.Unsafe.fromField(totalPriceField);
|
|
98
|
+
|
|
99
|
+
const sender = this.sender.getUnconstrained();
|
|
100
|
+
const buyer = this.buyer.getAndRequireEquals();
|
|
101
|
+
sender.assertEquals(buyer);
|
|
102
|
+
const buyerUpdate = AccountUpdate.createSigned(buyer);
|
|
103
|
+
buyerUpdate.send({ to: this.address, amount: totalPrice });
|
|
104
|
+
buyerUpdate.body.useFullCommitment = Bool(true);
|
|
105
|
+
|
|
106
|
+
this.price.set(price);
|
|
107
|
+
this.emitEvent("bid", { amount, address: buyer } as BidEvent);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
@method async withdraw(amountInMina: UInt64) {
|
|
111
|
+
amountInMina.equals(UInt64.from(0)).assertFalse();
|
|
112
|
+
this.account.balance.requireBetween(amountInMina, UInt64.MAXINT());
|
|
113
|
+
|
|
114
|
+
const buyer = this.buyer.getAndRequireEquals();
|
|
115
|
+
const sender = this.sender.getUnconstrained();
|
|
116
|
+
const senderUpdate = AccountUpdate.createSigned(sender);
|
|
117
|
+
senderUpdate.body.useFullCommitment = Bool(true);
|
|
118
|
+
sender.assertEquals(buyer);
|
|
119
|
+
|
|
120
|
+
let bidUpdate = this.send({ to: senderUpdate, amount: amountInMina });
|
|
121
|
+
bidUpdate.body.useFullCommitment = Bool(true);
|
|
122
|
+
this.emitEvent("withdraw", {
|
|
123
|
+
amount: amountInMina,
|
|
124
|
+
address: buyer,
|
|
125
|
+
} as BidEvent);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
@method async sell(amount: UInt64) {
|
|
129
|
+
amount.equals(UInt64.from(0)).assertFalse();
|
|
130
|
+
const price = this.price.getAndRequireEquals();
|
|
131
|
+
const totalPriceField = price.value
|
|
132
|
+
.mul(amount.value)
|
|
133
|
+
.div(Field(1_000_000_000));
|
|
134
|
+
totalPriceField.assertLessThan(
|
|
135
|
+
UInt64.MAXINT().value,
|
|
136
|
+
"totalPrice overflow"
|
|
137
|
+
);
|
|
138
|
+
const totalPrice = UInt64.Unsafe.fromField(totalPriceField);
|
|
139
|
+
|
|
140
|
+
this.account.balance.requireBetween(totalPrice, UInt64.MAXINT());
|
|
141
|
+
const buyer = this.buyer.getAndRequireEquals();
|
|
142
|
+
const token = this.token.getAndRequireEquals();
|
|
143
|
+
|
|
144
|
+
const seller = this.sender.getUnconstrained();
|
|
145
|
+
const sellerUpdate = this.send({ to: seller, amount: totalPrice });
|
|
146
|
+
sellerUpdate.body.useFullCommitment = Bool(true);
|
|
147
|
+
sellerUpdate.requireSignature();
|
|
148
|
+
|
|
149
|
+
const tokenContract = new FungibleToken(token);
|
|
150
|
+
await tokenContract.transfer(seller, buyer, amount);
|
|
151
|
+
|
|
152
|
+
const whitelist = this.whitelist.getAndRequireEquals();
|
|
153
|
+
const whitelistedAmount = await whitelist.getWhitelistedAmount(seller);
|
|
154
|
+
amount.assertLessThanOrEqual(
|
|
155
|
+
whitelistedAmount.assertSome("Cannot sell more than whitelisted amount")
|
|
156
|
+
);
|
|
157
|
+
this.emitEvent("sell", { amount, address: seller } as BidEvent);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
@method async updateWhitelist(whitelist: Whitelist) {
|
|
161
|
+
const buyer = this.buyer.getAndRequireEquals();
|
|
162
|
+
const sender = this.sender.getUnconstrained();
|
|
163
|
+
const senderUpdate = AccountUpdate.createSigned(sender);
|
|
164
|
+
senderUpdate.body.useFullCommitment = Bool(true);
|
|
165
|
+
sender.assertEquals(buyer);
|
|
166
|
+
|
|
167
|
+
this.whitelist.set(whitelist);
|
|
168
|
+
this.emitEvent("updateWhitelist", whitelist);
|
|
169
|
+
}
|
|
170
|
+
}
|
package/src/claim.ts
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AccountUpdate,
|
|
3
|
+
DeployArgs,
|
|
4
|
+
method,
|
|
5
|
+
Permissions,
|
|
6
|
+
PublicKey,
|
|
7
|
+
State,
|
|
8
|
+
state,
|
|
9
|
+
UInt64,
|
|
10
|
+
SmartContract,
|
|
11
|
+
Bool,
|
|
12
|
+
Field,
|
|
13
|
+
Struct,
|
|
14
|
+
Provable,
|
|
15
|
+
} from "o1js";
|
|
16
|
+
import { Whitelist } from "@silvana-one/storage";
|
|
17
|
+
import { FungibleToken } from "./FungibleToken.js";
|
|
18
|
+
|
|
19
|
+
class ClaimEvent extends Struct({
|
|
20
|
+
amount: UInt64,
|
|
21
|
+
address: PublicKey,
|
|
22
|
+
}) {}
|
|
23
|
+
|
|
24
|
+
export interface FungibleTokenClaimContractDeployProps
|
|
25
|
+
extends Exclude<DeployArgs, undefined> {
|
|
26
|
+
/** The whitelist. */
|
|
27
|
+
whitelist: Whitelist;
|
|
28
|
+
/** The maximum amount of tokens to claim in case the whitelist is empty. */
|
|
29
|
+
maxAmount?: UInt64;
|
|
30
|
+
}
|
|
31
|
+
export class FungibleTokenClaimContract extends SmartContract {
|
|
32
|
+
@state(PublicKey) owner = State<PublicKey>();
|
|
33
|
+
@state(PublicKey) token = State<PublicKey>();
|
|
34
|
+
@state(Whitelist) whitelist = State<Whitelist>();
|
|
35
|
+
@state(UInt64) maxAmount = State<UInt64>();
|
|
36
|
+
|
|
37
|
+
async deploy(args: FungibleTokenClaimContractDeployProps) {
|
|
38
|
+
await super.deploy(args);
|
|
39
|
+
this.whitelist.set(args.whitelist);
|
|
40
|
+
this.maxAmount.set(args.maxAmount ?? UInt64.MAXINT());
|
|
41
|
+
this.account.permissions.set({
|
|
42
|
+
...Permissions.default(),
|
|
43
|
+
send: Permissions.proof(),
|
|
44
|
+
setVerificationKey:
|
|
45
|
+
Permissions.VerificationKey.impossibleDuringCurrentVersion(),
|
|
46
|
+
setPermissions: Permissions.impossible(),
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
events = {
|
|
51
|
+
offer: ClaimEvent,
|
|
52
|
+
withdraw: ClaimEvent,
|
|
53
|
+
claim: ClaimEvent,
|
|
54
|
+
updateWhitelist: Whitelist,
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
@method async initialize(
|
|
58
|
+
owner: PublicKey, // we are short of AccountUpdates here, so we use this parameter instead of this.sender.getUnconstrained()
|
|
59
|
+
token: PublicKey,
|
|
60
|
+
amount: UInt64
|
|
61
|
+
) {
|
|
62
|
+
this.account.provedState.requireEquals(Bool(false));
|
|
63
|
+
const tokenContract = new FungibleToken(token);
|
|
64
|
+
const tokenId = tokenContract.deriveTokenId();
|
|
65
|
+
tokenId.assertEquals(this.tokenId);
|
|
66
|
+
await tokenContract.transfer(owner, this.address, amount);
|
|
67
|
+
|
|
68
|
+
this.owner.set(owner);
|
|
69
|
+
this.token.set(token);
|
|
70
|
+
this.emitEvent("offer", { amount, address: owner } as ClaimEvent);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
@method async offer(amount: UInt64) {
|
|
74
|
+
const owner = this.owner.getAndRequireEquals();
|
|
75
|
+
const token = this.token.getAndRequireEquals();
|
|
76
|
+
const tokenContract = new FungibleToken(token);
|
|
77
|
+
const tokenId = tokenContract.deriveTokenId();
|
|
78
|
+
tokenId.assertEquals(this.tokenId);
|
|
79
|
+
|
|
80
|
+
const sender = this.sender.getUnconstrained();
|
|
81
|
+
const senderUpdate = AccountUpdate.createSigned(sender);
|
|
82
|
+
senderUpdate.body.useFullCommitment = Bool(true);
|
|
83
|
+
sender.assertEquals(owner);
|
|
84
|
+
|
|
85
|
+
await tokenContract.transfer(sender, this.address, amount);
|
|
86
|
+
this.emitEvent("offer", { amount, address: sender } as ClaimEvent);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
@method async withdraw(amount: UInt64) {
|
|
90
|
+
amount.equals(UInt64.from(0)).assertFalse();
|
|
91
|
+
this.account.balance.requireBetween(amount, UInt64.MAXINT());
|
|
92
|
+
|
|
93
|
+
const owner = this.owner.getAndRequireEquals();
|
|
94
|
+
const token = this.token.getAndRequireEquals();
|
|
95
|
+
const tokenContract = new FungibleToken(token);
|
|
96
|
+
const tokenId = tokenContract.deriveTokenId();
|
|
97
|
+
tokenId.assertEquals(this.tokenId);
|
|
98
|
+
|
|
99
|
+
const sender = this.sender.getUnconstrained();
|
|
100
|
+
const senderUpdate = AccountUpdate.createSigned(sender, tokenId);
|
|
101
|
+
senderUpdate.body.useFullCommitment = Bool(true);
|
|
102
|
+
sender.assertEquals(owner);
|
|
103
|
+
|
|
104
|
+
let offerUpdate = this.send({ to: senderUpdate, amount });
|
|
105
|
+
offerUpdate.body.mayUseToken = AccountUpdate.MayUseToken.InheritFromParent;
|
|
106
|
+
offerUpdate.body.useFullCommitment = Bool(true);
|
|
107
|
+
this.emitEvent("withdraw", { amount, address: sender } as ClaimEvent);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
@method async claim(amount: UInt64) {
|
|
111
|
+
const maxAmount = this.maxAmount.getAndRequireEquals();
|
|
112
|
+
const token = this.token.getAndRequireEquals();
|
|
113
|
+
const tokenContract = new FungibleToken(token);
|
|
114
|
+
const tokenId = tokenContract.deriveTokenId();
|
|
115
|
+
tokenId.assertEquals(this.tokenId);
|
|
116
|
+
|
|
117
|
+
const sender = this.sender.getUnconstrained();
|
|
118
|
+
const senderUpdate = AccountUpdate.createSigned(sender, tokenId);
|
|
119
|
+
senderUpdate.body.useFullCommitment = Bool(true);
|
|
120
|
+
|
|
121
|
+
const whitelist = this.whitelist.getAndRequireEquals();
|
|
122
|
+
const whiteListedAmount = await whitelist.getWhitelistedAmount(sender);
|
|
123
|
+
const maxClaimAmount = Provable.if(
|
|
124
|
+
whitelist.isSome(),
|
|
125
|
+
whiteListedAmount.assertSome("No tokens to claim"),
|
|
126
|
+
maxAmount
|
|
127
|
+
);
|
|
128
|
+
amount.assertLessThanOrEqual(maxClaimAmount);
|
|
129
|
+
this.account.balance.requireBetween(amount, UInt64.MAXINT());
|
|
130
|
+
|
|
131
|
+
let offerUpdate = this.send({ to: senderUpdate, amount });
|
|
132
|
+
offerUpdate.body.mayUseToken = AccountUpdate.MayUseToken.InheritFromParent;
|
|
133
|
+
offerUpdate.body.useFullCommitment = Bool(true);
|
|
134
|
+
|
|
135
|
+
this.emitEvent("claim", {
|
|
136
|
+
amount,
|
|
137
|
+
address: sender,
|
|
138
|
+
} as ClaimEvent);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
@method async updateWhitelist(whitelist: Whitelist) {
|
|
142
|
+
const owner = this.owner.getAndRequireEquals();
|
|
143
|
+
const sender = this.sender.getUnconstrained();
|
|
144
|
+
const senderUpdate = AccountUpdate.createSigned(sender);
|
|
145
|
+
senderUpdate.body.useFullCommitment = Bool(true);
|
|
146
|
+
sender.assertEquals(owner);
|
|
147
|
+
|
|
148
|
+
this.whitelist.set(whitelist);
|
|
149
|
+
this.emitEvent("updateWhitelist", whitelist);
|
|
150
|
+
}
|
|
151
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export * from "./bid.js";
|
|
2
|
+
export * from "./claim.js";
|
|
3
|
+
export * from "./offer.js";
|
|
4
|
+
export * from "./FungibleToken.js";
|
|
5
|
+
export * from "./FungibleTokenStandardAdmin.js";
|
|
6
|
+
export * from "./FungibleTokenAdvancedAdmin.js";
|
|
7
|
+
export * from "./FungibleTokenContract.js";
|
|
8
|
+
export * from "./BondingCurveAdmin.js";
|
package/src/offer.ts
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AccountUpdate,
|
|
3
|
+
DeployArgs,
|
|
4
|
+
method,
|
|
5
|
+
Permissions,
|
|
6
|
+
PublicKey,
|
|
7
|
+
State,
|
|
8
|
+
state,
|
|
9
|
+
UInt64,
|
|
10
|
+
SmartContract,
|
|
11
|
+
Bool,
|
|
12
|
+
Field,
|
|
13
|
+
Struct,
|
|
14
|
+
} from "o1js";
|
|
15
|
+
import { Whitelist } from "@silvana-one/storage";
|
|
16
|
+
import { FungibleToken } from "./FungibleToken.js";
|
|
17
|
+
|
|
18
|
+
export interface FungibleTokenOfferContractDeployProps
|
|
19
|
+
extends Exclude<DeployArgs, undefined> {
|
|
20
|
+
/** The whitelist. */
|
|
21
|
+
whitelist: Whitelist;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export class OfferEvent extends Struct({
|
|
25
|
+
amount: UInt64,
|
|
26
|
+
address: PublicKey,
|
|
27
|
+
}) {}
|
|
28
|
+
|
|
29
|
+
export class FungibleTokenOfferContract extends SmartContract {
|
|
30
|
+
@state(UInt64) price = State<UInt64>();
|
|
31
|
+
@state(PublicKey) seller = State<PublicKey>();
|
|
32
|
+
@state(PublicKey) token = State<PublicKey>();
|
|
33
|
+
@state(Whitelist) whitelist = State<Whitelist>();
|
|
34
|
+
|
|
35
|
+
async deploy(args: FungibleTokenOfferContractDeployProps) {
|
|
36
|
+
await super.deploy(args);
|
|
37
|
+
this.whitelist.set(args.whitelist);
|
|
38
|
+
this.account.permissions.set({
|
|
39
|
+
...Permissions.default(),
|
|
40
|
+
send: Permissions.proof(),
|
|
41
|
+
setVerificationKey:
|
|
42
|
+
Permissions.VerificationKey.impossibleDuringCurrentVersion(),
|
|
43
|
+
setPermissions: Permissions.impossible(),
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
events = {
|
|
48
|
+
offer: OfferEvent,
|
|
49
|
+
withdraw: OfferEvent,
|
|
50
|
+
buy: OfferEvent,
|
|
51
|
+
updateWhitelist: Whitelist,
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
@method async initialize(
|
|
55
|
+
seller: PublicKey, // we are short of AccountUpdates here, so we use this parameter instead of this.sender.getUnconstrained()
|
|
56
|
+
token: PublicKey,
|
|
57
|
+
amount: UInt64,
|
|
58
|
+
price: UInt64
|
|
59
|
+
) {
|
|
60
|
+
this.account.provedState.requireEquals(Bool(false));
|
|
61
|
+
const tokenContract = new FungibleToken(token);
|
|
62
|
+
const tokenId = tokenContract.deriveTokenId();
|
|
63
|
+
tokenId.assertEquals(this.tokenId);
|
|
64
|
+
await tokenContract.transfer(seller, this.address, amount);
|
|
65
|
+
|
|
66
|
+
this.seller.set(seller);
|
|
67
|
+
this.price.set(price);
|
|
68
|
+
this.token.set(token);
|
|
69
|
+
this.emitEvent("offer", { amount, address: seller } as OfferEvent);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
@method async offer(amount: UInt64, price: UInt64) {
|
|
73
|
+
const seller = this.seller.getAndRequireEquals();
|
|
74
|
+
const token = this.token.getAndRequireEquals();
|
|
75
|
+
const tokenContract = new FungibleToken(token);
|
|
76
|
+
const tokenId = tokenContract.deriveTokenId();
|
|
77
|
+
tokenId.assertEquals(this.tokenId);
|
|
78
|
+
|
|
79
|
+
const balance = this.account.balance.getAndRequireEquals();
|
|
80
|
+
const oldPrice = this.price.getAndRequireEquals();
|
|
81
|
+
// Price can be changed only when the balance is 0
|
|
82
|
+
price
|
|
83
|
+
.equals(oldPrice)
|
|
84
|
+
.or(balance.equals(UInt64.from(0)))
|
|
85
|
+
.assertTrue();
|
|
86
|
+
this.price.set(price);
|
|
87
|
+
|
|
88
|
+
const sender = this.sender.getUnconstrained();
|
|
89
|
+
const senderUpdate = AccountUpdate.createSigned(sender);
|
|
90
|
+
senderUpdate.body.useFullCommitment = Bool(true);
|
|
91
|
+
sender.assertEquals(seller);
|
|
92
|
+
|
|
93
|
+
await tokenContract.transfer(sender, this.address, amount);
|
|
94
|
+
this.emitEvent("offer", { amount, address: sender } as OfferEvent);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
@method async withdraw(amount: UInt64) {
|
|
98
|
+
amount.equals(UInt64.from(0)).assertFalse();
|
|
99
|
+
this.account.balance.requireBetween(amount, UInt64.MAXINT());
|
|
100
|
+
|
|
101
|
+
const seller = this.seller.getAndRequireEquals();
|
|
102
|
+
const token = this.token.getAndRequireEquals();
|
|
103
|
+
const tokenContract = new FungibleToken(token);
|
|
104
|
+
const tokenId = tokenContract.deriveTokenId();
|
|
105
|
+
tokenId.assertEquals(this.tokenId);
|
|
106
|
+
|
|
107
|
+
const sender = this.sender.getUnconstrained();
|
|
108
|
+
const senderUpdate = AccountUpdate.createSigned(sender, tokenId);
|
|
109
|
+
senderUpdate.body.useFullCommitment = Bool(true);
|
|
110
|
+
sender.assertEquals(seller);
|
|
111
|
+
|
|
112
|
+
let offerUpdate = this.send({ to: senderUpdate, amount });
|
|
113
|
+
offerUpdate.body.mayUseToken = AccountUpdate.MayUseToken.InheritFromParent;
|
|
114
|
+
offerUpdate.body.useFullCommitment = Bool(true);
|
|
115
|
+
this.emitEvent("withdraw", { amount, address: sender } as OfferEvent);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
@method async buy(amount: UInt64) {
|
|
119
|
+
amount.equals(UInt64.from(0)).assertFalse();
|
|
120
|
+
this.account.balance.requireBetween(amount, UInt64.MAXINT());
|
|
121
|
+
const seller = this.seller.getAndRequireEquals();
|
|
122
|
+
const token = this.token.getAndRequireEquals();
|
|
123
|
+
const tokenContract = new FungibleToken(token);
|
|
124
|
+
const tokenId = tokenContract.deriveTokenId();
|
|
125
|
+
tokenId.assertEquals(this.tokenId);
|
|
126
|
+
const price = this.price.getAndRequireEquals();
|
|
127
|
+
const totalPriceField = price.value
|
|
128
|
+
.mul(amount.value)
|
|
129
|
+
.div(Field(1_000_000_000));
|
|
130
|
+
totalPriceField.assertLessThan(
|
|
131
|
+
UInt64.MAXINT().value,
|
|
132
|
+
"totalPrice overflow"
|
|
133
|
+
);
|
|
134
|
+
const totalPrice = UInt64.Unsafe.fromField(totalPriceField);
|
|
135
|
+
|
|
136
|
+
const buyer = this.sender.getUnconstrained();
|
|
137
|
+
const buyerUpdate = AccountUpdate.createSigned(buyer);
|
|
138
|
+
buyerUpdate.send({ to: seller, amount: totalPrice });
|
|
139
|
+
buyerUpdate.body.useFullCommitment = Bool(true);
|
|
140
|
+
|
|
141
|
+
let offerUpdate = this.send({ to: buyer, amount });
|
|
142
|
+
offerUpdate.body.mayUseToken = AccountUpdate.MayUseToken.InheritFromParent;
|
|
143
|
+
offerUpdate.body.useFullCommitment = Bool(true);
|
|
144
|
+
|
|
145
|
+
const whitelist = this.whitelist.getAndRequireEquals();
|
|
146
|
+
const whitelistedAmount = await whitelist.getWhitelistedAmount(buyer);
|
|
147
|
+
amount.assertLessThanOrEqual(
|
|
148
|
+
whitelistedAmount.assertSome("Cannot buy more than whitelisted amount")
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
this.emitEvent("buy", { amount, address: buyer } as OfferEvent);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
@method async updateWhitelist(whitelist: Whitelist) {
|
|
155
|
+
const seller = this.seller.getAndRequireEquals();
|
|
156
|
+
const sender = this.sender.getUnconstrained();
|
|
157
|
+
const senderUpdate = AccountUpdate.createSigned(sender);
|
|
158
|
+
senderUpdate.body.useFullCommitment = Bool(true);
|
|
159
|
+
sender.assertEquals(seller);
|
|
160
|
+
|
|
161
|
+
this.whitelist.set(whitelist);
|
|
162
|
+
this.emitEvent("updateWhitelist", whitelist);
|
|
163
|
+
}
|
|
164
|
+
}
|