@silvana-one/nft 0.2.0 → 0.2.1
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/dist/tsconfig.web.tsbuildinfo +1 -0
- package/dist/web/admin/advanced.js.map +1 -0
- package/dist/web/admin/index.js.map +1 -0
- package/dist/web/contracts/admin.js.map +1 -0
- package/dist/web/contracts/collection.js.map +1 -0
- package/dist/web/contracts/index.js.map +1 -0
- package/dist/web/contracts/nft.js.map +1 -0
- package/dist/web/contracts.js.map +1 -0
- package/dist/web/index.js.map +1 -0
- package/dist/web/{src/interfaces → interfaces}/admin.js.map +1 -1
- package/dist/web/interfaces/approval.js.map +1 -0
- package/dist/web/interfaces/collection.js.map +1 -0
- package/dist/web/interfaces/encoding.js.map +1 -0
- package/dist/web/interfaces/events.js.map +1 -0
- package/dist/web/interfaces/index.js.map +1 -0
- package/dist/web/interfaces/ownable.js.map +1 -0
- package/dist/web/interfaces/owner.js.map +1 -0
- package/dist/web/interfaces/pausable.js.map +1 -0
- package/dist/web/interfaces/types.js.map +1 -0
- package/dist/web/interfaces/update.js.map +1 -0
- package/dist/web/marketplace/auction.js.map +1 -0
- package/dist/web/marketplace/bb.js.map +1 -0
- package/dist/web/marketplace/bid.js.map +1 -0
- package/dist/web/marketplace/index.js.map +1 -0
- package/dist/web/marketplace/nft-shares.js.map +1 -0
- package/dist/web/marketplace/offer.js.map +1 -0
- package/dist/web/marketplace/types.js.map +1 -0
- package/dist/web/metadata/address.js.map +1 -0
- package/dist/web/metadata/index.js.map +1 -0
- package/dist/web/metadata/metadata.js.map +1 -0
- package/dist/web/metadata/pin.js.map +1 -0
- package/dist/web/metadata/text.js.map +1 -0
- package/dist/web/metadata/tree.js.map +1 -0
- package/dist/web/util/div.js.map +1 -0
- package/dist/web/util/index.js.map +1 -0
- package/dist/web/vk.js.map +1 -0
- package/dist/web/zkprogram-example/game.js.map +1 -0
- package/dist/web/zkprogram-example/index.js.map +1 -0
- package/dist/web/zkprogram-example/update.js.map +1 -0
- package/package.json +8 -8
- package/dist/web/src/admin/advanced.js.map +0 -1
- package/dist/web/src/admin/index.js.map +0 -1
- package/dist/web/src/contracts/admin.js.map +0 -1
- package/dist/web/src/contracts/collection.js.map +0 -1
- package/dist/web/src/contracts/index.js.map +0 -1
- package/dist/web/src/contracts/nft.js.map +0 -1
- package/dist/web/src/contracts.js.map +0 -1
- package/dist/web/src/index.js.map +0 -1
- package/dist/web/src/interfaces/approval.js.map +0 -1
- package/dist/web/src/interfaces/collection.js.map +0 -1
- package/dist/web/src/interfaces/encoding.js.map +0 -1
- package/dist/web/src/interfaces/events.js.map +0 -1
- package/dist/web/src/interfaces/index.js.map +0 -1
- package/dist/web/src/interfaces/ownable.js.map +0 -1
- package/dist/web/src/interfaces/owner.js.map +0 -1
- package/dist/web/src/interfaces/pausable.js.map +0 -1
- package/dist/web/src/interfaces/types.js.map +0 -1
- package/dist/web/src/interfaces/update.js.map +0 -1
- package/dist/web/src/marketplace/auction.js.map +0 -1
- package/dist/web/src/marketplace/bb.js.map +0 -1
- package/dist/web/src/marketplace/bid.js.map +0 -1
- package/dist/web/src/marketplace/index.js.map +0 -1
- package/dist/web/src/marketplace/nft-shares.js.map +0 -1
- package/dist/web/src/marketplace/offer.js.map +0 -1
- package/dist/web/src/marketplace/types.js.map +0 -1
- package/dist/web/src/metadata/address.js.map +0 -1
- package/dist/web/src/metadata/index.js.map +0 -1
- package/dist/web/src/metadata/metadata.js.map +0 -1
- package/dist/web/src/metadata/pin.js.map +0 -1
- package/dist/web/src/metadata/text.js.map +0 -1
- package/dist/web/src/metadata/tree.js.map +0 -1
- package/dist/web/src/util/div.js.map +0 -1
- package/dist/web/src/util/index.js.map +0 -1
- package/dist/web/src/vk.js.map +0 -1
- package/dist/web/src/zkprogram-example/game.js.map +0 -1
- package/dist/web/src/zkprogram-example/index.js.map +0 -1
- package/dist/web/src/zkprogram-example/update.js.map +0 -1
- package/dist/web/test/auction.test.d.ts +0 -1212
- package/dist/web/test/auction.test.js +0 -1248
- package/dist/web/test/auction.test.js.map +0 -1
- package/dist/web/test/bb.test.d.ts +0 -1
- package/dist/web/test/bb.test.js +0 -159
- package/dist/web/test/bb.test.js.map +0 -1
- package/dist/web/test/contract.test.d.ts +0 -1
- package/dist/web/test/contract.test.js +0 -1333
- package/dist/web/test/contract.test.js.map +0 -1
- package/dist/web/test/div.test.d.ts +0 -1
- package/dist/web/test/div.test.js +0 -55
- package/dist/web/test/div.test.js.map +0 -1
- package/dist/web/test/helpers/config.d.ts +0 -4
- package/dist/web/test/helpers/config.js +0 -103
- package/dist/web/test/helpers/config.js.map +0 -1
- package/dist/web/test/helpers/metadata.d.ts +0 -30
- package/dist/web/test/helpers/metadata.js +0 -155
- package/dist/web/test/helpers/metadata.js.map +0 -1
- package/dist/web/test/helpers/utils.d.ts +0 -16
- package/dist/web/test/helpers/utils.js +0 -36
- package/dist/web/test/helpers/utils.js.map +0 -1
- package/dist/web/test/helpers/validators.d.ts +0 -15
- package/dist/web/test/helpers/validators.js +0 -46
- package/dist/web/test/helpers/validators.js.map +0 -1
- package/dist/web/test/metadata.test.d.ts +0 -1
- package/dist/web/test/metadata.test.js +0 -66
- package/dist/web/test/metadata.test.js.map +0 -1
- package/dist/web/test/mint.test.d.ts +0 -1
- package/dist/web/test/mint.test.js +0 -262
- package/dist/web/test/mint.test.js.map +0 -1
- package/dist/web/test/pack.test.d.ts +0 -1
- package/dist/web/test/pack.test.js +0 -141
- package/dist/web/test/pack.test.js.map +0 -1
- package/dist/web/test/zkprogram.test.d.ts +0 -1
- package/dist/web/test/zkprogram.test.js +0 -728
- package/dist/web/test/zkprogram.test.js.map +0 -1
- package/dist/web/tsconfig.web.tsbuildinfo +0 -1
- /package/dist/web/{src/admin → admin}/advanced.d.ts +0 -0
- /package/dist/web/{src/admin → admin}/advanced.js +0 -0
- /package/dist/web/{src/admin → admin}/index.d.ts +0 -0
- /package/dist/web/{src/admin → admin}/index.js +0 -0
- /package/dist/web/{src/contracts → contracts}/admin.d.ts +0 -0
- /package/dist/web/{src/contracts → contracts}/admin.js +0 -0
- /package/dist/web/{src/contracts → contracts}/collection.d.ts +0 -0
- /package/dist/web/{src/contracts → contracts}/collection.js +0 -0
- /package/dist/web/{src/contracts → contracts}/index.d.ts +0 -0
- /package/dist/web/{src/contracts → contracts}/index.js +0 -0
- /package/dist/web/{src/contracts → contracts}/nft.d.ts +0 -0
- /package/dist/web/{src/contracts → contracts}/nft.js +0 -0
- /package/dist/web/{src/contracts.d.ts → contracts.d.ts} +0 -0
- /package/dist/web/{src/contracts.js → contracts.js} +0 -0
- /package/dist/web/{src/index.d.ts → index.d.ts} +0 -0
- /package/dist/web/{src/index.js → index.js} +0 -0
- /package/dist/web/{src/interfaces → interfaces}/admin.d.ts +0 -0
- /package/dist/web/{src/interfaces → interfaces}/admin.js +0 -0
- /package/dist/web/{src/interfaces → interfaces}/approval.d.ts +0 -0
- /package/dist/web/{src/interfaces → interfaces}/approval.js +0 -0
- /package/dist/web/{src/interfaces → interfaces}/collection.d.ts +0 -0
- /package/dist/web/{src/interfaces → interfaces}/collection.js +0 -0
- /package/dist/web/{src/interfaces → interfaces}/encoding.d.ts +0 -0
- /package/dist/web/{src/interfaces → interfaces}/encoding.js +0 -0
- /package/dist/web/{src/interfaces → interfaces}/events.d.ts +0 -0
- /package/dist/web/{src/interfaces → interfaces}/events.js +0 -0
- /package/dist/web/{src/interfaces → interfaces}/index.d.ts +0 -0
- /package/dist/web/{src/interfaces → interfaces}/index.js +0 -0
- /package/dist/web/{src/interfaces → interfaces}/ownable.d.ts +0 -0
- /package/dist/web/{src/interfaces → interfaces}/ownable.js +0 -0
- /package/dist/web/{src/interfaces → interfaces}/owner.d.ts +0 -0
- /package/dist/web/{src/interfaces → interfaces}/owner.js +0 -0
- /package/dist/web/{src/interfaces → interfaces}/pausable.d.ts +0 -0
- /package/dist/web/{src/interfaces → interfaces}/pausable.js +0 -0
- /package/dist/web/{src/interfaces → interfaces}/types.d.ts +0 -0
- /package/dist/web/{src/interfaces → interfaces}/types.js +0 -0
- /package/dist/web/{src/interfaces → interfaces}/update.d.ts +0 -0
- /package/dist/web/{src/interfaces → interfaces}/update.js +0 -0
- /package/dist/web/{src/marketplace → marketplace}/auction.d.ts +0 -0
- /package/dist/web/{src/marketplace → marketplace}/auction.js +0 -0
- /package/dist/web/{src/marketplace → marketplace}/bb.d.ts +0 -0
- /package/dist/web/{src/marketplace → marketplace}/bb.js +0 -0
- /package/dist/web/{src/marketplace → marketplace}/bid.d.ts +0 -0
- /package/dist/web/{src/marketplace → marketplace}/bid.js +0 -0
- /package/dist/web/{src/marketplace → marketplace}/index.d.ts +0 -0
- /package/dist/web/{src/marketplace → marketplace}/index.js +0 -0
- /package/dist/web/{src/marketplace → marketplace}/nft-shares.d.ts +0 -0
- /package/dist/web/{src/marketplace → marketplace}/nft-shares.js +0 -0
- /package/dist/web/{src/marketplace → marketplace}/offer.d.ts +0 -0
- /package/dist/web/{src/marketplace → marketplace}/offer.js +0 -0
- /package/dist/web/{src/marketplace → marketplace}/types.d.ts +0 -0
- /package/dist/web/{src/marketplace → marketplace}/types.js +0 -0
- /package/dist/web/{src/metadata → metadata}/address.d.ts +0 -0
- /package/dist/web/{src/metadata → metadata}/address.js +0 -0
- /package/dist/web/{src/metadata → metadata}/index.d.ts +0 -0
- /package/dist/web/{src/metadata → metadata}/index.js +0 -0
- /package/dist/web/{src/metadata → metadata}/metadata.d.ts +0 -0
- /package/dist/web/{src/metadata → metadata}/metadata.js +0 -0
- /package/dist/web/{src/metadata → metadata}/pin.d.ts +0 -0
- /package/dist/web/{src/metadata → metadata}/pin.js +0 -0
- /package/dist/web/{src/metadata → metadata}/text.d.ts +0 -0
- /package/dist/web/{src/metadata → metadata}/text.js +0 -0
- /package/dist/web/{src/metadata → metadata}/tree.d.ts +0 -0
- /package/dist/web/{src/metadata → metadata}/tree.js +0 -0
- /package/dist/web/{src/util → util}/div.d.ts +0 -0
- /package/dist/web/{src/util → util}/div.js +0 -0
- /package/dist/web/{src/util → util}/index.d.ts +0 -0
- /package/dist/web/{src/util → util}/index.js +0 -0
- /package/dist/web/{src/vk.d.ts → vk.d.ts} +0 -0
- /package/dist/web/{src/vk.js → vk.js} +0 -0
- /package/dist/web/{src/zkprogram-example → zkprogram-example}/game.d.ts +0 -0
- /package/dist/web/{src/zkprogram-example → zkprogram-example}/game.js +0 -0
- /package/dist/web/{src/zkprogram-example → zkprogram-example}/index.d.ts +0 -0
- /package/dist/web/{src/zkprogram-example → zkprogram-example}/index.js +0 -0
- /package/dist/web/{src/zkprogram-example → zkprogram-example}/update.d.ts +0 -0
- /package/dist/web/{src/zkprogram-example → zkprogram-example}/update.js +0 -0
|
@@ -1,728 +0,0 @@
|
|
|
1
|
-
import { __decorate, __metadata } from "tslib";
|
|
2
|
-
import { afterEach, beforeEach, describe, it } from "node:test";
|
|
3
|
-
import assert from "node:assert";
|
|
4
|
-
import { Mina, Field, AccountUpdate, UInt32, Cache, UInt64, fetchLastBlock, PublicKey, Struct, state, State, SmartContract, method, Provable, Bool, } from "o1js";
|
|
5
|
-
import { fetchMinaAccount, initBlockchain, accountBalanceMina, Memory, sendTx, pinJSON, } from "@silvana-one/mina-utils";
|
|
6
|
-
import { TEST_ACCOUNTS } from "./helpers/config.js";
|
|
7
|
-
import { NFT, NFTAdmin, CollectionData, fieldFromString, NFTData, NFTState, NFTUpdateProof, NFTStateStruct, MintParams, NFTGameProgram, nftVerificationKeys, Metadata, NonFungibleTokenContractsFactory, NFTTransactionContext, TransferParams, MetadataValue, } from "../src/index.js";
|
|
8
|
-
import { processArguments } from "./helpers/utils.js";
|
|
9
|
-
import { randomMetadata } from "./helpers/metadata.js";
|
|
10
|
-
import { Storage, UInt64Option, createIpfsURL } from "@silvana-one/storage";
|
|
11
|
-
let { chain, readOnly, noLog } = processArguments();
|
|
12
|
-
const networkId = chain === "mainnet" ? "mainnet" : "devnet";
|
|
13
|
-
const expectedTxStatus = chain === "zeko" ? "pending" : "included";
|
|
14
|
-
const vk = nftVerificationKeys[networkId].vk;
|
|
15
|
-
const { TestPublicKey } = Mina;
|
|
16
|
-
/*
|
|
17
|
-
“Richard Of York Gave Battle In Vain”:
|
|
18
|
-
1. Richard – Red
|
|
19
|
-
Hex: #FF0000
|
|
20
|
-
2. Of – Orange
|
|
21
|
-
Hex: #FFA500
|
|
22
|
-
3. York – Yellow
|
|
23
|
-
Hex: #FFFF00
|
|
24
|
-
4. Gave – Green
|
|
25
|
-
Hex: #008000
|
|
26
|
-
5. Battle – Blue
|
|
27
|
-
Hex: #0000FF
|
|
28
|
-
6. In – Indigo
|
|
29
|
-
Hex: #4B0082
|
|
30
|
-
7. Vain – Violet
|
|
31
|
-
Hex: #EE82EE
|
|
32
|
-
*/
|
|
33
|
-
const colors = [
|
|
34
|
-
0xff0000, 0xffa500, 0xffff00, 0x008000, 0x0000ff, 0x4b0082, 0xee82ee,
|
|
35
|
-
];
|
|
36
|
-
const black = 0x000000;
|
|
37
|
-
class Colors extends Struct({
|
|
38
|
-
Richard: Field,
|
|
39
|
-
Of: Field,
|
|
40
|
-
York: Field,
|
|
41
|
-
Gave: Field,
|
|
42
|
-
Battle: Field,
|
|
43
|
-
In: Field,
|
|
44
|
-
Vain: Field,
|
|
45
|
-
}) {
|
|
46
|
-
}
|
|
47
|
-
const rightAnswers = new Colors({
|
|
48
|
-
Richard: Field(colors[0]),
|
|
49
|
-
Of: Field(colors[1]),
|
|
50
|
-
York: Field(colors[2]),
|
|
51
|
-
Gave: Field(colors[3]),
|
|
52
|
-
Battle: Field(colors[4]),
|
|
53
|
-
In: Field(colors[5]),
|
|
54
|
-
Vain: Field(colors[6]),
|
|
55
|
-
});
|
|
56
|
-
class ColorGame extends SmartContract {
|
|
57
|
-
constructor() {
|
|
58
|
-
super(...arguments);
|
|
59
|
-
this.score = State(Field(0));
|
|
60
|
-
this.color = State(Field(black));
|
|
61
|
-
this.user = State(PublicKey.empty());
|
|
62
|
-
this.maxScore = State(Field(0));
|
|
63
|
-
}
|
|
64
|
-
async play(answers) {
|
|
65
|
-
const Richard = answers.Richard.equals(rightAnswers.Richard);
|
|
66
|
-
const Of = answers.Of.equals(rightAnswers.Of);
|
|
67
|
-
const York = answers.York.equals(rightAnswers.York);
|
|
68
|
-
const Gave = answers.Gave.equals(rightAnswers.Gave);
|
|
69
|
-
const Battle = answers.Battle.equals(rightAnswers.Battle);
|
|
70
|
-
const In = answers.In.equals(rightAnswers.In);
|
|
71
|
-
const Vain = answers.Vain.equals(rightAnswers.Vain);
|
|
72
|
-
const isCorrectArray = [Richard, Of, York, Gave, Battle, In, Vain];
|
|
73
|
-
let score = Field(0);
|
|
74
|
-
for (let i = 0; i < 7; i++) {
|
|
75
|
-
score = score.add(Provable.if(isCorrectArray[i], Field(1), Field(0)));
|
|
76
|
-
}
|
|
77
|
-
this.score.set(score);
|
|
78
|
-
const maxScore = this.maxScore.getAndRequireEquals();
|
|
79
|
-
maxScore
|
|
80
|
-
.equals(Field(7))
|
|
81
|
-
.assertFalse("Game is over, the winner is already known");
|
|
82
|
-
this.maxScore.set(Provable.if(score.greaterThan(maxScore), score, maxScore));
|
|
83
|
-
const color = Provable.if(Vain, rightAnswers.Vain, Provable.if(In, rightAnswers.In, Provable.if(Battle, rightAnswers.Battle, Provable.if(Gave, rightAnswers.Gave, Provable.if(York, rightAnswers.York, Provable.if(Of, rightAnswers.Of, Provable.if(Richard, rightAnswers.Richard, Field(black))))))));
|
|
84
|
-
this.color.set(color);
|
|
85
|
-
const sender = this.sender.getAndRequireSignature();
|
|
86
|
-
this.user.set(sender);
|
|
87
|
-
}
|
|
88
|
-
async canUpdate(collectionAddress, nftAddress, input, output) {
|
|
89
|
-
const user = this.user.getAndRequireEquals();
|
|
90
|
-
const score = this.score.getAndRequireEquals();
|
|
91
|
-
const color = this.color.getAndRequireEquals();
|
|
92
|
-
input.context.custom[0].assertEquals(score);
|
|
93
|
-
input.context.custom[1].assertEquals(color);
|
|
94
|
-
input.owner
|
|
95
|
-
.equals(user)
|
|
96
|
-
.or(score.equals(Field(7)))
|
|
97
|
-
.assertTrue("Only the winner can change the NFT owner");
|
|
98
|
-
output.owner.assertEquals(user);
|
|
99
|
-
return Bool(true);
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
__decorate([
|
|
103
|
-
state(Field),
|
|
104
|
-
__metadata("design:type", Object)
|
|
105
|
-
], ColorGame.prototype, "score", void 0);
|
|
106
|
-
__decorate([
|
|
107
|
-
state(Field),
|
|
108
|
-
__metadata("design:type", Object)
|
|
109
|
-
], ColorGame.prototype, "color", void 0);
|
|
110
|
-
__decorate([
|
|
111
|
-
state(PublicKey),
|
|
112
|
-
__metadata("design:type", Object)
|
|
113
|
-
], ColorGame.prototype, "user", void 0);
|
|
114
|
-
__decorate([
|
|
115
|
-
state(Field),
|
|
116
|
-
__metadata("design:type", Object)
|
|
117
|
-
], ColorGame.prototype, "maxScore", void 0);
|
|
118
|
-
__decorate([
|
|
119
|
-
method,
|
|
120
|
-
__metadata("design:type", Function),
|
|
121
|
-
__metadata("design:paramtypes", [Colors]),
|
|
122
|
-
__metadata("design:returntype", Promise)
|
|
123
|
-
], ColorGame.prototype, "play", null);
|
|
124
|
-
__decorate([
|
|
125
|
-
method.returns(Bool),
|
|
126
|
-
__metadata("design:type", Function),
|
|
127
|
-
__metadata("design:paramtypes", [PublicKey,
|
|
128
|
-
PublicKey,
|
|
129
|
-
NFTState,
|
|
130
|
-
NFTState]),
|
|
131
|
-
__metadata("design:returntype", Promise)
|
|
132
|
-
], ColorGame.prototype, "canUpdate", null);
|
|
133
|
-
let nftContractVk;
|
|
134
|
-
let nftProgramVk;
|
|
135
|
-
let collectionVk;
|
|
136
|
-
let adminVk;
|
|
137
|
-
const cache = Cache.FileSystem("./cache");
|
|
138
|
-
const zkNFTKey = TestPublicKey.random();
|
|
139
|
-
const zkCollectionKey = TestPublicKey.random();
|
|
140
|
-
const zkAdminKey = TestPublicKey.random();
|
|
141
|
-
const zkColorGameKey = TestPublicKey.random();
|
|
142
|
-
const { Collection } = NonFungibleTokenContractsFactory({
|
|
143
|
-
adminContract: NFTAdmin,
|
|
144
|
-
updateFactory: () => ColorGame,
|
|
145
|
-
});
|
|
146
|
-
const collectionContract = new Collection(zkCollectionKey);
|
|
147
|
-
const tokenId = collectionContract.deriveTokenId();
|
|
148
|
-
const adminContract = new NFTAdmin(zkAdminKey);
|
|
149
|
-
const colorGameContract = new ColorGame(zkColorGameKey);
|
|
150
|
-
const NUMBER_OF_USERS = 6;
|
|
151
|
-
let admin;
|
|
152
|
-
let users = [];
|
|
153
|
-
let creator;
|
|
154
|
-
let owner;
|
|
155
|
-
const nftParams = [];
|
|
156
|
-
describe(`NFT ZkProgram tests: ${chain} ${readOnly ? "read-only " : ""}${noLog ? "noLog" : ""} `, () => {
|
|
157
|
-
const originalConsoleLog = console.log;
|
|
158
|
-
if (noLog) {
|
|
159
|
-
beforeEach(() => {
|
|
160
|
-
console.log = () => { };
|
|
161
|
-
});
|
|
162
|
-
afterEach(() => {
|
|
163
|
-
console.log = originalConsoleLog;
|
|
164
|
-
});
|
|
165
|
-
}
|
|
166
|
-
it("should initialize a blockchain", async () => {
|
|
167
|
-
if (chain === "devnet" || chain === "zeko" || chain === "mainnet") {
|
|
168
|
-
await initBlockchain(chain);
|
|
169
|
-
admin = TestPublicKey.fromBase58(TEST_ACCOUNTS[0].privateKey);
|
|
170
|
-
users = TEST_ACCOUNTS.slice(1).map((account) => TestPublicKey.fromBase58(account.privateKey));
|
|
171
|
-
}
|
|
172
|
-
else if (chain === "local") {
|
|
173
|
-
const { keys } = await initBlockchain(chain, NUMBER_OF_USERS + 2);
|
|
174
|
-
admin = TestPublicKey(keys[1].key);
|
|
175
|
-
users = keys.slice(2);
|
|
176
|
-
}
|
|
177
|
-
else if (chain === "lightnet") {
|
|
178
|
-
const { keys } = await initBlockchain(chain, NUMBER_OF_USERS + 2);
|
|
179
|
-
admin = TestPublicKey(keys[1].key);
|
|
180
|
-
users = keys.slice(2);
|
|
181
|
-
}
|
|
182
|
-
creator = users[0];
|
|
183
|
-
owner = creator;
|
|
184
|
-
assert(users.length >= NUMBER_OF_USERS);
|
|
185
|
-
console.log("chain:", chain);
|
|
186
|
-
console.log("networkId:", Mina.getNetworkId());
|
|
187
|
-
console.log("Collection contract address:", zkCollectionKey.toBase58());
|
|
188
|
-
console.log("Admin contract address:", zkAdminKey.toBase58());
|
|
189
|
-
console.log("NFT contract address:", zkNFTKey.toBase58());
|
|
190
|
-
console.log("Color Game contract address:", zkColorGameKey.toBase58());
|
|
191
|
-
console.log("Creator", creator.toBase58(), "balance:", await accountBalanceMina(creator));
|
|
192
|
-
console.log("Admin ", admin.toBase58(), "balance:", await accountBalanceMina(admin));
|
|
193
|
-
for (let i = 0; i < NUMBER_OF_USERS; i++) {
|
|
194
|
-
console.log(`User ${i} `, users[i].toBase58(), "balance:", await accountBalanceMina(users[i]));
|
|
195
|
-
}
|
|
196
|
-
Memory.info("before compiling");
|
|
197
|
-
});
|
|
198
|
-
it("should compile NFT Contract", async () => {
|
|
199
|
-
console.log("compiling...");
|
|
200
|
-
console.time("compiled NFTContract");
|
|
201
|
-
const { verificationKey } = await NFT.compile({ cache });
|
|
202
|
-
nftContractVk = verificationKey;
|
|
203
|
-
console.timeEnd("compiled NFTContract");
|
|
204
|
-
assert.strictEqual(nftContractVk.hash.toJSON(), vk.NFT.hash);
|
|
205
|
-
assert.strictEqual(nftContractVk.data, vk.NFT.data);
|
|
206
|
-
});
|
|
207
|
-
it("should compile Color Game", async () => {
|
|
208
|
-
console.log("compiling...");
|
|
209
|
-
console.time("compiled Color Game");
|
|
210
|
-
await ColorGame.compile({ cache });
|
|
211
|
-
console.timeEnd("compiled Color Game");
|
|
212
|
-
});
|
|
213
|
-
it("should compile Admin", async () => {
|
|
214
|
-
console.time("compiled Admin");
|
|
215
|
-
const { verificationKey } = await NFTAdmin.compile({ cache });
|
|
216
|
-
adminVk = verificationKey;
|
|
217
|
-
console.timeEnd("compiled Admin");
|
|
218
|
-
console.log("Admin vk hash:", adminVk.hash.toJSON());
|
|
219
|
-
});
|
|
220
|
-
it("should compile Collection", async () => {
|
|
221
|
-
console.time("compiled Collection");
|
|
222
|
-
const { verificationKey } = await Collection.compile({ cache });
|
|
223
|
-
collectionVk = verificationKey;
|
|
224
|
-
console.timeEnd("compiled Collection");
|
|
225
|
-
console.log("Collection vk hash:", collectionVk.hash.toJSON());
|
|
226
|
-
});
|
|
227
|
-
it("should compile nft ZkProgram", async () => {
|
|
228
|
-
console.time("compiled NFTProgram");
|
|
229
|
-
nftProgramVk = (await NFTGameProgram.compile({ cache })).verificationKey;
|
|
230
|
-
console.timeEnd("compiled NFTProgram");
|
|
231
|
-
console.log("NFTProgram vk hash:", nftProgramVk.hash.toJSON());
|
|
232
|
-
});
|
|
233
|
-
it("should deploy a Collection", async () => {
|
|
234
|
-
console.time("deployed Collection");
|
|
235
|
-
const { metadataRoot, ipfsHash, serializedMap, name, privateMetadata } = await randomMetadata({
|
|
236
|
-
includePrivateTraits: false,
|
|
237
|
-
includeBanner: true,
|
|
238
|
-
});
|
|
239
|
-
if (!ipfsHash) {
|
|
240
|
-
throw new Error("IPFS hash is undefined");
|
|
241
|
-
}
|
|
242
|
-
const slot = chain === "local"
|
|
243
|
-
? Mina.currentSlot()
|
|
244
|
-
: chain === "zeko"
|
|
245
|
-
? UInt32.zero
|
|
246
|
-
: (await fetchLastBlock()).globalSlotSinceGenesis;
|
|
247
|
-
const expiry = slot.add(UInt32.from(100000));
|
|
248
|
-
const masterNFT = new MintParams({
|
|
249
|
-
name: fieldFromString(name),
|
|
250
|
-
address: zkCollectionKey,
|
|
251
|
-
tokenId,
|
|
252
|
-
data: NFTData.new({
|
|
253
|
-
owner: creator,
|
|
254
|
-
}),
|
|
255
|
-
fee: UInt64.zero,
|
|
256
|
-
metadata: metadataRoot,
|
|
257
|
-
storage: Storage.fromString(ipfsHash),
|
|
258
|
-
metadataVerificationKeyHash: Field(0),
|
|
259
|
-
expiry,
|
|
260
|
-
});
|
|
261
|
-
await fetchMinaAccount({ publicKey: creator, force: true });
|
|
262
|
-
const tx = await Mina.transaction({
|
|
263
|
-
sender: creator,
|
|
264
|
-
fee: 100_000_000,
|
|
265
|
-
memo: `Deploy Collection ${name}`.substring(0, 30),
|
|
266
|
-
}, async () => {
|
|
267
|
-
AccountUpdate.fundNewAccount(creator, 3);
|
|
268
|
-
await adminContract.deploy({
|
|
269
|
-
admin: creator,
|
|
270
|
-
uri: `AdminContract`,
|
|
271
|
-
});
|
|
272
|
-
// deploy() and initialize() create 2 account updates for the same publicKey, it is intended
|
|
273
|
-
await collectionContract.deploy({
|
|
274
|
-
creator,
|
|
275
|
-
collectionName: fieldFromString(name),
|
|
276
|
-
baseURL: fieldFromString("ipfs"),
|
|
277
|
-
admin: zkAdminKey,
|
|
278
|
-
symbol: "NFT",
|
|
279
|
-
url: `https://${chain}.minanft.io`,
|
|
280
|
-
});
|
|
281
|
-
await collectionContract.initialize(masterNFT, CollectionData.new({
|
|
282
|
-
requireTransferApproval: false,
|
|
283
|
-
royaltyFee: 10, // 10%
|
|
284
|
-
transferFee: 1_000_000_000, // 1 MINA
|
|
285
|
-
}));
|
|
286
|
-
});
|
|
287
|
-
await tx.prove();
|
|
288
|
-
assert.strictEqual((await sendTx({
|
|
289
|
-
tx: tx.sign([creator.key, zkCollectionKey.key, zkAdminKey.key]),
|
|
290
|
-
description: "deploy Collection",
|
|
291
|
-
}))?.status, expectedTxStatus);
|
|
292
|
-
console.timeEnd("deployed Collection");
|
|
293
|
-
});
|
|
294
|
-
it("should mint NFT", async () => {
|
|
295
|
-
Memory.info("before mint");
|
|
296
|
-
console.time("minted NFT");
|
|
297
|
-
const { name, metadata } = await randomMetadata({
|
|
298
|
-
includePrivateTraits: false,
|
|
299
|
-
pin: false,
|
|
300
|
-
});
|
|
301
|
-
// add color game contract address to metadata to be checked by the Zkprogram
|
|
302
|
-
metadata.addTrait({
|
|
303
|
-
key: "contractX",
|
|
304
|
-
type: "field",
|
|
305
|
-
value: zkColorGameKey.x,
|
|
306
|
-
});
|
|
307
|
-
metadata.addTrait({
|
|
308
|
-
key: "contractIsOdd",
|
|
309
|
-
type: "field",
|
|
310
|
-
value: zkColorGameKey.isOdd.toField(),
|
|
311
|
-
});
|
|
312
|
-
const contractX = metadata.map.get(fieldFromString("contractX"));
|
|
313
|
-
const isOdd = metadata.map.get(fieldFromString("contractIsOdd"));
|
|
314
|
-
assert.strictEqual(MetadataValue.new({ value: zkColorGameKey.x, type: "field" })
|
|
315
|
-
.hash()
|
|
316
|
-
.equals(contractX)
|
|
317
|
-
.toBoolean(), true);
|
|
318
|
-
assert.strictEqual(MetadataValue.new({
|
|
319
|
-
value: zkColorGameKey.isOdd.toField(),
|
|
320
|
-
type: "field",
|
|
321
|
-
})
|
|
322
|
-
.hash()
|
|
323
|
-
.equals(isOdd)
|
|
324
|
-
.toBoolean(), true);
|
|
325
|
-
const ipfsHash = await pinJSON({
|
|
326
|
-
data: metadata.toJSON(true),
|
|
327
|
-
name: "metadata",
|
|
328
|
-
});
|
|
329
|
-
if (!ipfsHash)
|
|
330
|
-
throw new Error("Failed to pin metadata");
|
|
331
|
-
nftParams.push({
|
|
332
|
-
name,
|
|
333
|
-
address: zkNFTKey,
|
|
334
|
-
collection: zkCollectionKey,
|
|
335
|
-
});
|
|
336
|
-
await fetchMinaAccount({ publicKey: creator, force: true });
|
|
337
|
-
await fetchMinaAccount({ publicKey: zkCollectionKey, force: true });
|
|
338
|
-
await fetchMinaAccount({ publicKey: zkAdminKey, force: true });
|
|
339
|
-
owner = users[1];
|
|
340
|
-
const slot = chain === "local"
|
|
341
|
-
? Mina.currentSlot()
|
|
342
|
-
: chain === "zeko"
|
|
343
|
-
? UInt32.zero
|
|
344
|
-
: (await fetchLastBlock()).globalSlotSinceGenesis;
|
|
345
|
-
const expiry = slot.add(UInt32.from(100000));
|
|
346
|
-
const tx = await Mina.transaction({
|
|
347
|
-
sender: creator,
|
|
348
|
-
fee: 100_000_000,
|
|
349
|
-
memo: `Mint NFT ${name}`.substring(0, 30),
|
|
350
|
-
}, async () => {
|
|
351
|
-
await collectionContract.mintByCreator({
|
|
352
|
-
name: fieldFromString(name),
|
|
353
|
-
address: zkNFTKey,
|
|
354
|
-
tokenId,
|
|
355
|
-
metadata: metadata.map.root,
|
|
356
|
-
data: NFTData.new({
|
|
357
|
-
owner,
|
|
358
|
-
canChangeMetadata: !readOnly,
|
|
359
|
-
canChangeStorage: !readOnly,
|
|
360
|
-
canPause: true,
|
|
361
|
-
canChangeName: false,
|
|
362
|
-
canChangeOwnerByProof: !readOnly,
|
|
363
|
-
canTransfer: !readOnly,
|
|
364
|
-
}),
|
|
365
|
-
metadataVerificationKeyHash: nftProgramVk.hash,
|
|
366
|
-
expiry,
|
|
367
|
-
fee: UInt64.from(10_000_000_000),
|
|
368
|
-
storage: Storage.fromString(ipfsHash),
|
|
369
|
-
});
|
|
370
|
-
AccountUpdate.fundNewAccount(creator, 1);
|
|
371
|
-
await colorGameContract.deploy({});
|
|
372
|
-
});
|
|
373
|
-
await tx.prove();
|
|
374
|
-
assert.strictEqual((await sendTx({
|
|
375
|
-
tx: tx.sign([creator.key, zkNFTKey.key, zkColorGameKey.key]),
|
|
376
|
-
description: "mint",
|
|
377
|
-
}))?.status, expectedTxStatus);
|
|
378
|
-
await fetchMinaAccount({ publicKey: zkNFTKey, tokenId, force: true });
|
|
379
|
-
const nft = new NFT(zkNFTKey, tokenId);
|
|
380
|
-
const dataCheck = NFTData.unpack(nft.packedData.get());
|
|
381
|
-
console.log("owner", owner.toBase58());
|
|
382
|
-
console.log("ownerCheck", dataCheck.owner.toBase58());
|
|
383
|
-
console.log("approvalCheck", dataCheck.approved.toBase58());
|
|
384
|
-
assert.strictEqual(dataCheck.owner.equals(owner).toBoolean(), true);
|
|
385
|
-
assert.strictEqual(dataCheck.approved.equals(PublicKey.empty()).toBoolean(), true);
|
|
386
|
-
console.timeEnd("minted NFT");
|
|
387
|
-
});
|
|
388
|
-
it("should play game", async () => {
|
|
389
|
-
Memory.info("before play");
|
|
390
|
-
console.time("played game");
|
|
391
|
-
const player = owner;
|
|
392
|
-
await fetchMinaAccount({ publicKey: player, force: true });
|
|
393
|
-
await fetchMinaAccount({ publicKey: zkCollectionKey, force: true });
|
|
394
|
-
await fetchMinaAccount({ publicKey: zkAdminKey, force: true });
|
|
395
|
-
await fetchMinaAccount({ publicKey: zkNFTKey, tokenId, force: true });
|
|
396
|
-
await fetchMinaAccount({ publicKey: zkColorGameKey, force: true });
|
|
397
|
-
const answers = new Colors({
|
|
398
|
-
Richard: Field(colors[0]),
|
|
399
|
-
Of: Field(75843),
|
|
400
|
-
York: Field(colors[2]),
|
|
401
|
-
Gave: Field(colors[3]),
|
|
402
|
-
Battle: Field(65943),
|
|
403
|
-
In: Field(colors[5]),
|
|
404
|
-
Vain: Field(67483),
|
|
405
|
-
});
|
|
406
|
-
const tx = await Mina.transaction({
|
|
407
|
-
sender: player,
|
|
408
|
-
fee: 100_000_000,
|
|
409
|
-
memo: `Play game`.substring(0, 30),
|
|
410
|
-
}, async () => {
|
|
411
|
-
await colorGameContract.play(answers);
|
|
412
|
-
});
|
|
413
|
-
await tx.prove();
|
|
414
|
-
assert.strictEqual((await sendTx({
|
|
415
|
-
tx: tx.sign([player.key]),
|
|
416
|
-
description: "play",
|
|
417
|
-
}))?.status, expectedTxStatus);
|
|
418
|
-
console.timeEnd("played game");
|
|
419
|
-
await fetchMinaAccount({ publicKey: zkColorGameKey, force: true });
|
|
420
|
-
const score = colorGameContract.score.get();
|
|
421
|
-
const color = colorGameContract.color.get();
|
|
422
|
-
const user = colorGameContract.user.get();
|
|
423
|
-
console.log("score:", score.toJSON());
|
|
424
|
-
console.log("color:", "#" + color.toBigInt().toString(16).toUpperCase());
|
|
425
|
-
console.log("user", user.toBase58());
|
|
426
|
-
assert.strictEqual(user.equals(player).toBoolean(), true);
|
|
427
|
-
assert.strictEqual(score.equals(Field(4)).toBoolean(), true);
|
|
428
|
-
});
|
|
429
|
-
it("should update NFT metadata", async () => {
|
|
430
|
-
Memory.info("before update");
|
|
431
|
-
console.time("updated NFT");
|
|
432
|
-
await fetchMinaAccount({ publicKey: owner, force: true });
|
|
433
|
-
await fetchMinaAccount({ publicKey: zkCollectionKey, force: true });
|
|
434
|
-
await fetchMinaAccount({ publicKey: zkAdminKey, force: true });
|
|
435
|
-
await fetchMinaAccount({ publicKey: zkNFTKey, tokenId, force: true });
|
|
436
|
-
await fetchMinaAccount({ publicKey: zkColorGameKey, force: true });
|
|
437
|
-
const score = colorGameContract.score.get();
|
|
438
|
-
const color = colorGameContract.color.get();
|
|
439
|
-
const user = colorGameContract.user.get();
|
|
440
|
-
assert.strictEqual(user.equals(owner).toBoolean(), true);
|
|
441
|
-
assert.strictEqual(score.equals(Field(4)).toBoolean(), true);
|
|
442
|
-
assert.strictEqual(color.equals(Field(colors[5])).toBoolean(), true);
|
|
443
|
-
const nftAccount = Mina.getAccount(zkNFTKey, tokenId);
|
|
444
|
-
const nftContract = new NFT(zkNFTKey, tokenId);
|
|
445
|
-
const nftStateStruct = NFTStateStruct.fromAccount(nftAccount);
|
|
446
|
-
assert.strictEqual(nftAccount.zkapp?.verificationKey?.hash.toJSON(), nftContractVk.hash.toJSON());
|
|
447
|
-
const nftState = NFTState.fromNFTState({
|
|
448
|
-
nftState: nftStateStruct,
|
|
449
|
-
creator: creator,
|
|
450
|
-
address: zkNFTKey,
|
|
451
|
-
tokenId,
|
|
452
|
-
oracleAddress: zkColorGameKey,
|
|
453
|
-
context: new NFTTransactionContext({
|
|
454
|
-
custom: [score, color, Field(0)],
|
|
455
|
-
}),
|
|
456
|
-
});
|
|
457
|
-
const index = nftParams.findIndex((p) => p.address.equals(zkNFTKey).toBoolean() &&
|
|
458
|
-
p.collection.equals(zkCollectionKey).toBoolean());
|
|
459
|
-
if (index === -1) {
|
|
460
|
-
throw new Error("NFT not found");
|
|
461
|
-
}
|
|
462
|
-
const nft = nftParams[index];
|
|
463
|
-
const { name } = nft;
|
|
464
|
-
const fetchResult = await fetch(createIpfsURL({ hash: nftContract.storage.get().toString() }));
|
|
465
|
-
if (!fetchResult.ok) {
|
|
466
|
-
throw new Error("Failed to fetch metadata");
|
|
467
|
-
}
|
|
468
|
-
const json = await fetchResult.json();
|
|
469
|
-
if (!json) {
|
|
470
|
-
throw new Error("Failed to fetch metadata");
|
|
471
|
-
}
|
|
472
|
-
const metadata = Metadata.fromJSON({
|
|
473
|
-
json,
|
|
474
|
-
checkRoot: true,
|
|
475
|
-
});
|
|
476
|
-
assert.strictEqual(nftState.metadata.toJSON(), metadata.map.root.toJSON());
|
|
477
|
-
if (nftState.metadata.toJSON() !== metadata.map.root.toJSON()) {
|
|
478
|
-
throw new Error("NFT metadata is not the same as the one in the collection");
|
|
479
|
-
}
|
|
480
|
-
const map = metadata.map.clone(); // we need to pass original metadata to the zkprogram
|
|
481
|
-
metadata.addTrait({
|
|
482
|
-
key: "color",
|
|
483
|
-
type: "field",
|
|
484
|
-
value: color,
|
|
485
|
-
});
|
|
486
|
-
metadata.addTrait({
|
|
487
|
-
key: "score",
|
|
488
|
-
type: "field",
|
|
489
|
-
value: score,
|
|
490
|
-
});
|
|
491
|
-
const ipfsHash = await pinJSON({
|
|
492
|
-
data: metadata.toJSON(true),
|
|
493
|
-
name: "metadata",
|
|
494
|
-
});
|
|
495
|
-
if (!ipfsHash)
|
|
496
|
-
throw new Error("Failed to pin new metadata");
|
|
497
|
-
console.time("proved update");
|
|
498
|
-
const update = await NFTGameProgram.updateMetadataAndOwner(nftState, map, zkColorGameKey, score, color, Storage.fromString(ipfsHash), owner);
|
|
499
|
-
const dynamicProof = NFTUpdateProof.fromProof(update.proof);
|
|
500
|
-
console.timeEnd("proved update");
|
|
501
|
-
let success = true;
|
|
502
|
-
try {
|
|
503
|
-
const tx = await Mina.transaction({
|
|
504
|
-
sender: users[2],
|
|
505
|
-
fee: 100_000_000,
|
|
506
|
-
memo: `Update NFT ${name}`.substring(0, 30),
|
|
507
|
-
}, async () => {
|
|
508
|
-
await collectionContract.updateWithOracle(dynamicProof, nftProgramVk);
|
|
509
|
-
});
|
|
510
|
-
await tx.prove();
|
|
511
|
-
const txSigned = tx.sign([users[2].key]);
|
|
512
|
-
assert.strictEqual((await sendTx({
|
|
513
|
-
tx: txSigned,
|
|
514
|
-
description: "update",
|
|
515
|
-
}))?.status, expectedTxStatus);
|
|
516
|
-
await fetchMinaAccount({ publicKey: zkNFTKey, tokenId, force: true });
|
|
517
|
-
const nftCheck = new NFT(zkNFTKey, tokenId);
|
|
518
|
-
const storageCheck = nftCheck.storage.get().toString();
|
|
519
|
-
assert.strictEqual(storageCheck, ipfsHash);
|
|
520
|
-
const metadataCheck = nftCheck.metadata.get();
|
|
521
|
-
assert.strictEqual(metadataCheck.toJSON(), metadata.map.root.toJSON());
|
|
522
|
-
}
|
|
523
|
-
catch (error) {
|
|
524
|
-
console.log("Failed to update read-only NFT:", error?.message ?? "");
|
|
525
|
-
success = false;
|
|
526
|
-
}
|
|
527
|
-
assert.strictEqual(success, !readOnly);
|
|
528
|
-
console.timeEnd("updated NFT");
|
|
529
|
-
});
|
|
530
|
-
it("should win game", { skip: readOnly }, async () => {
|
|
531
|
-
Memory.info("before win");
|
|
532
|
-
console.time("win game");
|
|
533
|
-
const player = users[3];
|
|
534
|
-
await fetchMinaAccount({ publicKey: player, force: true });
|
|
535
|
-
await fetchMinaAccount({ publicKey: zkCollectionKey, force: true });
|
|
536
|
-
await fetchMinaAccount({ publicKey: zkAdminKey, force: true });
|
|
537
|
-
await fetchMinaAccount({ publicKey: zkNFTKey, tokenId, force: true });
|
|
538
|
-
await fetchMinaAccount({ publicKey: zkColorGameKey, force: true });
|
|
539
|
-
const answers = new Colors({
|
|
540
|
-
Richard: Field(colors[0]),
|
|
541
|
-
Of: Field(colors[1]),
|
|
542
|
-
York: Field(colors[2]),
|
|
543
|
-
Gave: Field(colors[3]),
|
|
544
|
-
Battle: Field(colors[4]),
|
|
545
|
-
In: Field(colors[5]),
|
|
546
|
-
Vain: Field(colors[6]),
|
|
547
|
-
});
|
|
548
|
-
const tx = await Mina.transaction({
|
|
549
|
-
sender: player,
|
|
550
|
-
fee: 100_000_000,
|
|
551
|
-
memo: `Win game`.substring(0, 30),
|
|
552
|
-
}, async () => {
|
|
553
|
-
await colorGameContract.play(answers);
|
|
554
|
-
});
|
|
555
|
-
await tx.prove();
|
|
556
|
-
assert.strictEqual((await sendTx({
|
|
557
|
-
tx: tx.sign([player.key]),
|
|
558
|
-
description: "win game",
|
|
559
|
-
}))?.status, expectedTxStatus);
|
|
560
|
-
console.timeEnd("win game");
|
|
561
|
-
await fetchMinaAccount({ publicKey: zkColorGameKey, force: true });
|
|
562
|
-
const score = colorGameContract.score.get();
|
|
563
|
-
const color = colorGameContract.color.get();
|
|
564
|
-
const user = colorGameContract.user.get();
|
|
565
|
-
console.log("score:", score.toJSON());
|
|
566
|
-
console.log("color:", "#" + color.toBigInt().toString(16).toUpperCase());
|
|
567
|
-
console.log("user", user.toBase58());
|
|
568
|
-
assert.strictEqual(user.equals(player).toBoolean(), true);
|
|
569
|
-
assert.strictEqual(score.equals(Field(7)).toBoolean(), true);
|
|
570
|
-
});
|
|
571
|
-
it("should update NFT owner to the game winner", {
|
|
572
|
-
skip: readOnly,
|
|
573
|
-
}, async () => {
|
|
574
|
-
Memory.info("before update");
|
|
575
|
-
console.time("updated NFT");
|
|
576
|
-
const winner = users[3];
|
|
577
|
-
await fetchMinaAccount({ publicKey: winner, force: true });
|
|
578
|
-
await fetchMinaAccount({ publicKey: zkCollectionKey, force: true });
|
|
579
|
-
await fetchMinaAccount({ publicKey: zkAdminKey, force: true });
|
|
580
|
-
await fetchMinaAccount({ publicKey: zkNFTKey, tokenId, force: true });
|
|
581
|
-
await fetchMinaAccount({ publicKey: zkColorGameKey, force: true });
|
|
582
|
-
const score = colorGameContract.score.get();
|
|
583
|
-
const color = colorGameContract.color.get();
|
|
584
|
-
const user = colorGameContract.user.get();
|
|
585
|
-
assert.strictEqual(user.equals(winner).toBoolean(), true);
|
|
586
|
-
assert.strictEqual(score.equals(Field(7)).toBoolean(), true);
|
|
587
|
-
assert.strictEqual(color.equals(Field(colors[6])).toBoolean(), true);
|
|
588
|
-
const nftAccount = Mina.getAccount(zkNFTKey, tokenId);
|
|
589
|
-
const nftContract = new NFT(zkNFTKey, tokenId);
|
|
590
|
-
const nftStateStruct = NFTStateStruct.fromAccount(nftAccount);
|
|
591
|
-
assert.strictEqual(nftAccount.zkapp?.verificationKey?.hash.toJSON(), nftContractVk.hash.toJSON());
|
|
592
|
-
const nftState = NFTState.fromNFTState({
|
|
593
|
-
nftState: nftStateStruct,
|
|
594
|
-
creator: creator,
|
|
595
|
-
address: zkNFTKey,
|
|
596
|
-
tokenId,
|
|
597
|
-
oracleAddress: zkColorGameKey,
|
|
598
|
-
context: new NFTTransactionContext({
|
|
599
|
-
custom: [score, color, Field(0)],
|
|
600
|
-
}),
|
|
601
|
-
});
|
|
602
|
-
const index = nftParams.findIndex((p) => p.address.equals(zkNFTKey).toBoolean() &&
|
|
603
|
-
p.collection.equals(zkCollectionKey).toBoolean());
|
|
604
|
-
if (index === -1) {
|
|
605
|
-
throw new Error("NFT not found");
|
|
606
|
-
}
|
|
607
|
-
const nft = nftParams[index];
|
|
608
|
-
const { name } = nft;
|
|
609
|
-
const fetchResult = await fetch(createIpfsURL({ hash: nftContract.storage.get().toString() }));
|
|
610
|
-
if (!fetchResult.ok) {
|
|
611
|
-
throw new Error("Failed to fetch metadata");
|
|
612
|
-
}
|
|
613
|
-
const json = await fetchResult.json();
|
|
614
|
-
if (!json) {
|
|
615
|
-
throw new Error("Failed to fetch metadata");
|
|
616
|
-
}
|
|
617
|
-
const metadata = Metadata.fromJSON({
|
|
618
|
-
json,
|
|
619
|
-
checkRoot: true,
|
|
620
|
-
});
|
|
621
|
-
assert.strictEqual(nftState.metadata.toJSON(), metadata.map.root.toJSON());
|
|
622
|
-
if (nftState.metadata.toJSON() !== metadata.map.root.toJSON()) {
|
|
623
|
-
throw new Error("NFT metadata is not the same as the one in the collection");
|
|
624
|
-
}
|
|
625
|
-
const map = metadata.map.clone(); // we need to pass original metadata to the zkprogram
|
|
626
|
-
metadata.addTrait({
|
|
627
|
-
key: "color",
|
|
628
|
-
type: "field",
|
|
629
|
-
value: color,
|
|
630
|
-
});
|
|
631
|
-
metadata.addTrait({
|
|
632
|
-
key: "score",
|
|
633
|
-
type: "field",
|
|
634
|
-
value: score,
|
|
635
|
-
});
|
|
636
|
-
const ipfsHash = await pinJSON({
|
|
637
|
-
data: metadata.toJSON(true),
|
|
638
|
-
name: "metadata",
|
|
639
|
-
});
|
|
640
|
-
if (!ipfsHash)
|
|
641
|
-
throw new Error("Failed to pin new metadata");
|
|
642
|
-
console.time("proved update");
|
|
643
|
-
const update = await NFTGameProgram.updateMetadataAndOwner(nftState, map, zkColorGameKey, score, color, Storage.fromString(ipfsHash), winner);
|
|
644
|
-
const dynamicProof = NFTUpdateProof.fromProof(update.proof);
|
|
645
|
-
console.timeEnd("proved update");
|
|
646
|
-
let success = true;
|
|
647
|
-
try {
|
|
648
|
-
const tx = await Mina.transaction({
|
|
649
|
-
sender: winner,
|
|
650
|
-
fee: 100_000_000,
|
|
651
|
-
memo: `Change owner to the game winner for NFT ${name}`.substring(0, 30),
|
|
652
|
-
}, async () => {
|
|
653
|
-
await collectionContract.updateWithOracle(dynamicProof, nftProgramVk);
|
|
654
|
-
});
|
|
655
|
-
await tx.prove();
|
|
656
|
-
const txSigned = tx.sign([winner.key]);
|
|
657
|
-
assert.strictEqual((await sendTx({
|
|
658
|
-
tx: txSigned,
|
|
659
|
-
description: "change owner to the game winner",
|
|
660
|
-
}))?.status, expectedTxStatus);
|
|
661
|
-
await fetchMinaAccount({ publicKey: zkNFTKey, tokenId, force: true });
|
|
662
|
-
const nftCheck = new NFT(zkNFTKey, tokenId);
|
|
663
|
-
const storageCheck = nftCheck.storage.get().toString();
|
|
664
|
-
const ownerCheck = NFTData.unpack(nftCheck.packedData.get()).owner;
|
|
665
|
-
const metadataCheck = nftCheck.metadata.get();
|
|
666
|
-
assert.strictEqual(storageCheck, ipfsHash);
|
|
667
|
-
assert.strictEqual(metadataCheck.toJSON(), metadata.map.root.toJSON());
|
|
668
|
-
assert.strictEqual(ownerCheck.equals(winner).toBoolean(), true);
|
|
669
|
-
owner = winner;
|
|
670
|
-
}
|
|
671
|
-
catch (error) {
|
|
672
|
-
console.log("Failed to update read-only NFT:", error?.message ?? "");
|
|
673
|
-
success = false;
|
|
674
|
-
}
|
|
675
|
-
assert.strictEqual(success, !readOnly);
|
|
676
|
-
console.timeEnd("updated NFT");
|
|
677
|
-
});
|
|
678
|
-
it("should fail to transfer soulbound NFT", { skip: !readOnly }, async () => {
|
|
679
|
-
Memory.info("before transfer");
|
|
680
|
-
await fetchMinaAccount({ publicKey: owner, force: true });
|
|
681
|
-
await fetchMinaAccount({ publicKey: zkCollectionKey, force: true });
|
|
682
|
-
await fetchMinaAccount({ publicKey: zkAdminKey, force: true });
|
|
683
|
-
await fetchMinaAccount({ publicKey: zkNFTKey, tokenId, force: true });
|
|
684
|
-
const requireTransferApproval = CollectionData.unpack(collectionContract.packedData.get()).requireTransferApproval.toBoolean();
|
|
685
|
-
console.log("requireTransferApproval", requireTransferApproval);
|
|
686
|
-
const to = users[2];
|
|
687
|
-
const nft = nftParams.find((p) => p.address.equals(zkNFTKey).toBoolean() &&
|
|
688
|
-
p.collection.equals(zkCollectionKey).toBoolean());
|
|
689
|
-
if (!nft) {
|
|
690
|
-
throw new Error("NFT not found");
|
|
691
|
-
}
|
|
692
|
-
const { name } = nft;
|
|
693
|
-
let success = true;
|
|
694
|
-
try {
|
|
695
|
-
const tx = await Mina.transaction({
|
|
696
|
-
sender: owner,
|
|
697
|
-
fee: 100_000_000,
|
|
698
|
-
memo: `Transfer NFT ${name}`.substring(0, 30),
|
|
699
|
-
}, async () => {
|
|
700
|
-
if (requireTransferApproval) {
|
|
701
|
-
await collectionContract.approvedTransferBySignature(new TransferParams({
|
|
702
|
-
address: zkNFTKey,
|
|
703
|
-
from: owner,
|
|
704
|
-
to,
|
|
705
|
-
price: UInt64Option.none(),
|
|
706
|
-
context: NFTTransactionContext.empty(),
|
|
707
|
-
}));
|
|
708
|
-
}
|
|
709
|
-
else {
|
|
710
|
-
await collectionContract.transferBySignature(new TransferParams({
|
|
711
|
-
address: zkNFTKey,
|
|
712
|
-
from: owner,
|
|
713
|
-
to,
|
|
714
|
-
price: UInt64Option.none(),
|
|
715
|
-
context: NFTTransactionContext.empty(),
|
|
716
|
-
}));
|
|
717
|
-
}
|
|
718
|
-
});
|
|
719
|
-
await tx.prove();
|
|
720
|
-
}
|
|
721
|
-
catch (e) {
|
|
722
|
-
console.log("Failed to transfer soulbound NFT:", e?.message ?? "");
|
|
723
|
-
success = false;
|
|
724
|
-
}
|
|
725
|
-
assert.strictEqual(success, false);
|
|
726
|
-
});
|
|
727
|
-
});
|
|
728
|
-
//# sourceMappingURL=zkprogram.test.js.map
|