@gala-chain/launchpad 1.0.9 → 1.0.11

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.
Files changed (36) hide show
  1. package/CLAUDE.md +279 -0
  2. package/lib/package.json +2 -2
  3. package/lib/src/api/utils/error.js +1 -1
  4. package/lib/src/api/utils/error.js.map +1 -1
  5. package/lib/src/chaincode/launchpad/buyExactToken.js +1 -1
  6. package/lib/src/chaincode/launchpad/buyExactToken.js.map +1 -1
  7. package/lib/src/chaincode/launchpad/buyWithNative.d.ts.map +1 -1
  8. package/lib/src/chaincode/launchpad/buyWithNative.js +12 -5
  9. package/lib/src/chaincode/launchpad/buyWithNative.js.map +1 -1
  10. package/lib/src/chaincode/launchpad/sellExactToken.js +1 -1
  11. package/lib/src/chaincode/launchpad/sellExactToken.js.map +1 -1
  12. package/lib/src/chaincode/launchpad/sellWithNative.d.ts.map +1 -1
  13. package/lib/src/chaincode/launchpad/sellWithNative.js +10 -2
  14. package/lib/src/chaincode/launchpad/sellWithNative.js.map +1 -1
  15. package/lib/src/chaincode/test/launchpadgala.js +1 -1
  16. package/lib/src/chaincode/test/launchpadgala.js.map +1 -1
  17. package/lib/tsconfig.tsbuildinfo +1 -1
  18. package/package.json +2 -2
  19. package/src/api/utils/error.ts +1 -1
  20. package/src/chaincode/launchpad/buyExactToken.spec.ts +90 -20
  21. package/src/chaincode/launchpad/buyExactToken.ts +1 -1
  22. package/src/chaincode/launchpad/buyWithNative.spec.ts +99 -26
  23. package/src/chaincode/launchpad/buyWithNative.ts +21 -6
  24. package/src/chaincode/launchpad/callMemeTokenIn.spec.ts +244 -0
  25. package/src/chaincode/launchpad/callMemeTokenOut.spec.ts +1 -1
  26. package/src/chaincode/launchpad/callNativeTokenIn.spec.ts +269 -0
  27. package/src/chaincode/launchpad/callNativeTokenOut.spec.ts +276 -0
  28. package/src/chaincode/launchpad/configureLaunchpadFeeConfig.spec.ts +202 -0
  29. package/src/chaincode/launchpad/createSale.spec.ts +259 -0
  30. package/src/chaincode/launchpad/fetchSaleDetails.spec.ts +141 -0
  31. package/src/chaincode/launchpad/finalizeTokenAllocation.spec.ts +126 -0
  32. package/src/chaincode/launchpad/sellExactToken.spec.ts +284 -0
  33. package/src/chaincode/launchpad/sellExactToken.ts +1 -1
  34. package/src/chaincode/launchpad/sellWithNative.spec.ts +329 -0
  35. package/src/chaincode/launchpad/sellWithNative.ts +23 -6
  36. package/src/chaincode/test/launchpadgala.ts +1 -1
@@ -0,0 +1,259 @@
1
+ /*
2
+ * Copyright (c) Gala Games Inc. All rights reserved.
3
+ * Licensed under the Apache License, Version 2.0 (the "License");
4
+ * you may not use this file except in compliance with the License.
5
+ * You may obtain a copy of the License at
6
+ *
7
+ * http://www.apache.org/licenses/LICENSE-2.0
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ */
15
+ import { TokenBalance, TokenClass, TokenInstance, randomUniqueKey } from "@gala-chain/api";
16
+ import { fixture, users } from "@gala-chain/test";
17
+ import BigNumber from "bignumber.js";
18
+ import { plainToInstance } from "class-transformer";
19
+
20
+ import { CreateTokenSaleDTO } from "../../api/types";
21
+ import { LaunchpadContract } from "../LaunchpadContract";
22
+
23
+ describe("createSale", () => {
24
+ it("should create a new token sale successfully", async () => {
25
+ // Given
26
+ const { ctx, contract } = fixture(LaunchpadContract).registeredUsers(users.testUser1);
27
+
28
+ const createSaleDto = new CreateTokenSaleDTO(
29
+ "Test Token",
30
+ "TEST",
31
+ "A test token for launchpad",
32
+ "https://example.com/token.png",
33
+ new BigNumber(0),
34
+ "TestCollection",
35
+ "TestCategory"
36
+ );
37
+ createSaleDto.websiteUrl = "https://example.com";
38
+ createSaleDto.uniqueKey = randomUniqueKey();
39
+
40
+ const signedDto = createSaleDto.signed(users.testUser1.privateKey);
41
+
42
+ // When
43
+ const response = await contract.CreateSale(ctx, signedDto);
44
+
45
+ // Then
46
+ expect(response.Status).toBe(1);
47
+ expect(response.Data?.tokenName).toBe("Test Token");
48
+ expect(response.Data?.symbol).toBe("TEST");
49
+ expect(response.Data?.description).toBe("A test token for launchpad");
50
+ expect(response.Data?.collection).toBe("TestCollection");
51
+ expect(response.Data?.category).toBe("TestCategory");
52
+ expect(response.Data?.vaultAddress).toBeDefined();
53
+ expect(response.Data?.creatorAddress).toBe(users.testUser1.identityKey);
54
+ expect(response.Data?.isFinalized).toBe(false);
55
+ });
56
+
57
+ it("should create token sale with telegram URL", async () => {
58
+ // Given
59
+ const { ctx, contract } = fixture(LaunchpadContract).registeredUsers(users.testUser1);
60
+
61
+ const createSaleDto = new CreateTokenSaleDTO(
62
+ "Telegram Token",
63
+ "TG",
64
+ "A token with telegram link",
65
+ "https://example.com/tg.png",
66
+ new BigNumber(0),
67
+ "TelegramCollection",
68
+ "SocialCategory"
69
+ );
70
+ createSaleDto.telegramUrl = "https://t.me/testtoken";
71
+ createSaleDto.uniqueKey = randomUniqueKey();
72
+
73
+ const signedDto = createSaleDto.signed(users.testUser1.privateKey);
74
+
75
+ // When
76
+ const response = await contract.CreateSale(ctx, signedDto);
77
+
78
+ // Then
79
+ expect(response.Status).toBe(1);
80
+ expect(response.Data?.telegramUrl).toBe("https://t.me/testtoken");
81
+ expect(response.Data?.websiteUrl).toBe("");
82
+ expect(response.Data?.twitterUrl).toBe("");
83
+ });
84
+
85
+ it("should create token sale with twitter URL", async () => {
86
+ // Given
87
+ const { ctx, contract } = fixture(LaunchpadContract).registeredUsers(users.testUser1);
88
+
89
+ const createSaleDto = new CreateTokenSaleDTO(
90
+ "Twitter Token",
91
+ "TWT",
92
+ "A token with twitter link",
93
+ "https://example.com/twt.png",
94
+ new BigNumber(0),
95
+ "TwitterCollection",
96
+ "SocialCategory"
97
+ );
98
+ createSaleDto.twitterUrl = "https://twitter.com/testtoken";
99
+ createSaleDto.uniqueKey = randomUniqueKey();
100
+
101
+ const signedDto = createSaleDto.signed(users.testUser1.privateKey);
102
+
103
+ // When
104
+ const response = await contract.CreateSale(ctx, signedDto);
105
+
106
+ // Then
107
+ expect(response.Status).toBe(1);
108
+ expect(response.Data?.twitterUrl).toBe("https://twitter.com/testtoken");
109
+ });
110
+
111
+ it("should create token sale with pre-buy amount", async () => {
112
+ // Given - Setup GALA token for pre-buy (matching LaunchpadSale nativeToken)
113
+ const galaClass = plainToInstance(TokenClass, {
114
+ collection: "GALA",
115
+ category: "Unit",
116
+ type: "none",
117
+ additionalKey: "none",
118
+ decimals: 8,
119
+ name: "GALA",
120
+ symbol: "GALA",
121
+ description: "GALA token",
122
+ image: "",
123
+ maxSupply: new BigNumber("1e+10"),
124
+ maxCapacity: new BigNumber("1e+10"),
125
+ totalMintAllowance: new BigNumber("1e+10"),
126
+ totalSupply: new BigNumber("1e+10"),
127
+ totalBurned: new BigNumber("0"),
128
+ authorities: [users.testUser1.identityKey]
129
+ });
130
+
131
+ const galaInstance = plainToInstance(TokenInstance, {
132
+ collection: "GALA",
133
+ category: "Unit",
134
+ type: "none",
135
+ additionalKey: "none",
136
+ instance: new BigNumber(0),
137
+ isNonFungible: false,
138
+ owner: users.testUser1.identityKey,
139
+ quantity: new BigNumber("1e+10")
140
+ });
141
+
142
+ const userGalaBalance = plainToInstance(TokenBalance, {
143
+ collection: "GALA",
144
+ category: "Unit",
145
+ type: "none",
146
+ additionalKey: "none",
147
+ instance: new BigNumber(0),
148
+ owner: users.testUser1.identityKey,
149
+ quantity: new BigNumber("1000") // User has GALA for pre-buy
150
+ });
151
+
152
+ const { ctx, contract } = fixture(LaunchpadContract)
153
+ .registeredUsers(users.testUser1)
154
+ .savedState(galaClass, galaInstance, userGalaBalance);
155
+
156
+ const createSaleDto = new CreateTokenSaleDTO(
157
+ "Pre-buy Token",
158
+ "PRE",
159
+ "A token with pre-buy",
160
+ "https://example.com/pre.png",
161
+ new BigNumber("10"),
162
+ "PreBuyCollection",
163
+ "PreBuyCategory"
164
+ );
165
+ createSaleDto.websiteUrl = "https://example.com";
166
+ createSaleDto.uniqueKey = randomUniqueKey();
167
+
168
+ const signedDto = createSaleDto.signed(users.testUser1.privateKey);
169
+
170
+ // When
171
+ const response = await contract.CreateSale(ctx, signedDto);
172
+
173
+ // Then
174
+ expect(response.Status).toBe(1);
175
+ expect(response.Data?.initialBuyQuantity).toBe("10");
176
+ });
177
+
178
+ it("should convert token symbol to uppercase", async () => {
179
+ // Given
180
+ const { ctx, contract } = fixture(LaunchpadContract).registeredUsers(users.testUser1);
181
+
182
+ const createSaleDto = new CreateTokenSaleDTO(
183
+ "Lowercase Token",
184
+ "lower", // lowercase symbol
185
+ "A token with lowercase symbol",
186
+ "https://example.com/lower.png",
187
+ new BigNumber(0),
188
+ "LowerCollection",
189
+ "LowerCategory"
190
+ );
191
+ createSaleDto.websiteUrl = "https://example.com";
192
+ createSaleDto.uniqueKey = randomUniqueKey();
193
+
194
+ const signedDto = createSaleDto.signed(users.testUser1.privateKey);
195
+
196
+ // When
197
+ const response = await contract.CreateSale(ctx, signedDto);
198
+
199
+ // Then
200
+ expect(response.Status).toBe(1);
201
+ expect(response.Data?.symbol).toBe("LOWER"); // Should be converted to uppercase
202
+ });
203
+
204
+ it("should create sale with all social media URLs", async () => {
205
+ // Given
206
+ const { ctx, contract } = fixture(LaunchpadContract).registeredUsers(users.testUser1);
207
+
208
+ const createSaleDto = new CreateTokenSaleDTO(
209
+ "Social Token",
210
+ "SOC",
211
+ "A fully connected social token",
212
+ "https://example.com/soc.png",
213
+ new BigNumber(0),
214
+ "SocialCollection",
215
+ "FullSocialCategory"
216
+ );
217
+ createSaleDto.websiteUrl = "https://socialtoken.com";
218
+ createSaleDto.telegramUrl = "https://t.me/socialtoken";
219
+ createSaleDto.twitterUrl = "https://twitter.com/socialtoken";
220
+ createSaleDto.uniqueKey = randomUniqueKey();
221
+
222
+ const signedDto = createSaleDto.signed(users.testUser1.privateKey);
223
+
224
+ // When
225
+ const response = await contract.CreateSale(ctx, signedDto);
226
+
227
+ // Then
228
+ expect(response.Status).toBe(1);
229
+ expect(response.Data?.websiteUrl).toBe("https://socialtoken.com");
230
+ expect(response.Data?.telegramUrl).toBe("https://t.me/socialtoken");
231
+ expect(response.Data?.twitterUrl).toBe("https://twitter.com/socialtoken");
232
+ });
233
+
234
+ it("should create sale with custom token image", async () => {
235
+ // Given
236
+ const { ctx, contract } = fixture(LaunchpadContract).registeredUsers(users.testUser1);
237
+
238
+ const createSaleDto = new CreateTokenSaleDTO(
239
+ "Image Token",
240
+ "IMG",
241
+ "A token with custom image",
242
+ "https://cdn.example.com/token-logo.png",
243
+ new BigNumber(0),
244
+ "ImageCollection",
245
+ "ImageCategory"
246
+ );
247
+ createSaleDto.websiteUrl = "https://example.com";
248
+ createSaleDto.uniqueKey = randomUniqueKey();
249
+
250
+ const signedDto = createSaleDto.signed(users.testUser1.privateKey);
251
+
252
+ // When
253
+ const response = await contract.CreateSale(ctx, signedDto);
254
+
255
+ // Then
256
+ expect(response.Status).toBe(1);
257
+ expect(response.Data?.image).toBe("https://cdn.example.com/token-logo.png");
258
+ });
259
+ });
@@ -0,0 +1,141 @@
1
+ /*
2
+ * Copyright (c) Gala Games Inc. All rights reserved.
3
+ * Licensed under the Apache License, Version 2.0 (the "License");
4
+ * you may not use this file except in compliance with the License.
5
+ * You may obtain a copy of the License at
6
+ *
7
+ * http://www.apache.org/licenses/LICENSE-2.0
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ */
15
+ import {
16
+ TokenInstance,
17
+ TokenInstanceKey,
18
+ UserAlias,
19
+ asValidUserAlias,
20
+ randomUniqueKey
21
+ } from "@gala-chain/api";
22
+ import { fixture, users } from "@gala-chain/test";
23
+ import BigNumber from "bignumber.js";
24
+
25
+ import { FetchSaleDto, LaunchpadSale, ReverseBondingCurveConfigurationChainObject } from "../../api/types";
26
+ import { LaunchpadContract } from "../LaunchpadContract";
27
+ import launchpadgala from "../test/launchpadgala";
28
+
29
+ describe("fetchSaleDetails", () => {
30
+ let launchpadGalaInstance: TokenInstance;
31
+ let vaultAddress: UserAlias;
32
+ let sale: LaunchpadSale;
33
+
34
+ beforeEach(() => {
35
+ launchpadGalaInstance = launchpadgala.tokenInstance();
36
+ vaultAddress = asValidUserAlias(`service|${launchpadgala.tokenClassKey().toStringKey()}$launchpad`);
37
+
38
+ // Initialize sale
39
+ sale = new LaunchpadSale(
40
+ vaultAddress,
41
+ launchpadGalaInstance.instanceKeyObj(),
42
+ undefined,
43
+ users.testUser1.identityKey
44
+ );
45
+ });
46
+
47
+ it("should fetch existing sale details successfully", async () => {
48
+ // Given
49
+ const { ctx, contract } = fixture(LaunchpadContract).registeredUsers(users.testUser1).savedState(sale);
50
+
51
+ const fetchSaleDto = new FetchSaleDto(vaultAddress);
52
+ fetchSaleDto.uniqueKey = randomUniqueKey();
53
+
54
+ const signedDto = fetchSaleDto.signed(users.testUser1.privateKey);
55
+
56
+ // When
57
+ const response = await contract.FetchSaleDetails(ctx, signedDto);
58
+
59
+ // Then
60
+ expect(response.Status).toBe(1);
61
+ expect(response.Data?.vaultAddress).toBe(vaultAddress);
62
+ expect(response.Data?.saleOwner).toBe(users.testUser1.identityKey);
63
+ expect(response.Data?.sellingToken).toEqual(launchpadGalaInstance.instanceKeyObj());
64
+ });
65
+
66
+ it("should handle sale with existing trades", async () => {
67
+ // Given
68
+ sale.buyToken(new BigNumber("100"), new BigNumber("0.01"));
69
+ const { ctx, contract } = fixture(LaunchpadContract).registeredUsers(users.testUser1).savedState(sale);
70
+
71
+ const fetchSaleDto = new FetchSaleDto(vaultAddress);
72
+ fetchSaleDto.uniqueKey = randomUniqueKey();
73
+
74
+ const signedDto = fetchSaleDto.signed(users.testUser1.privateKey);
75
+
76
+ // When
77
+ const response = await contract.FetchSaleDetails(ctx, signedDto);
78
+
79
+ // Then
80
+ expect(response.Status).toBe(1);
81
+ expect(response.Data?.fetchTokensSold()).toBe("100");
82
+ expect(new BigNumber(response.Data?.nativeTokenQuantity || "0").isPositive()).toBe(true);
83
+ });
84
+
85
+ it("should return sale with correct finalization status", async () => {
86
+ // Given - Create finalized sale
87
+ sale.finalizeSale();
88
+ const { ctx, contract } = fixture(LaunchpadContract).registeredUsers(users.testUser1).savedState(sale);
89
+
90
+ const fetchSaleDto = new FetchSaleDto(vaultAddress);
91
+ fetchSaleDto.uniqueKey = randomUniqueKey();
92
+
93
+ const signedDto = fetchSaleDto.signed(users.testUser1.privateKey);
94
+
95
+ // When
96
+ const response = await contract.FetchSaleDetails(ctx, signedDto);
97
+
98
+ // Then
99
+ expect(response.Status).toBe(1);
100
+ expect(response.Data?.saleStatus).toBe("Finished");
101
+ });
102
+
103
+ it("should fetch sale with reverse bonding curve configuration", async () => {
104
+ // Given - Create sale with reverse bonding curve
105
+ const tokenInstanceKey = new TokenInstanceKey();
106
+ tokenInstanceKey.collection = "TestCollection";
107
+ tokenInstanceKey.category = "TestCategory";
108
+ tokenInstanceKey.type = "TEST";
109
+ tokenInstanceKey.additionalKey = "test:key";
110
+ tokenInstanceKey.instance = new BigNumber(0);
111
+
112
+ const reverseBondingCurveConfig = new ReverseBondingCurveConfigurationChainObject(
113
+ new BigNumber(0.02), // minFeePortion
114
+ new BigNumber(0.05) // maxFeePortion
115
+ );
116
+
117
+ const saleWithConfig = new LaunchpadSale(
118
+ vaultAddress,
119
+ tokenInstanceKey,
120
+ reverseBondingCurveConfig,
121
+ users.testUser1.identityKey
122
+ );
123
+
124
+ const { ctx, contract } = fixture(LaunchpadContract)
125
+ .registeredUsers(users.testUser1)
126
+ .savedState(saleWithConfig);
127
+
128
+ const fetchSaleDto = new FetchSaleDto(vaultAddress);
129
+ fetchSaleDto.uniqueKey = randomUniqueKey();
130
+
131
+ const signedDto = fetchSaleDto.signed(users.testUser1.privateKey);
132
+
133
+ // When
134
+ const response = await contract.FetchSaleDetails(ctx, signedDto);
135
+
136
+ // Then
137
+ expect(response.Status).toBe(1);
138
+ expect(response.Data?.reverseBondingCurveConfiguration).toBeDefined();
139
+ expect(response.Data?.reverseBondingCurveConfiguration?.maxFeePortion).toEqual(new BigNumber(0.05));
140
+ });
141
+ });
@@ -0,0 +1,126 @@
1
+ /*
2
+ * Copyright (c) Gala Games Inc. All rights reserved.
3
+ * Licensed under the Apache License, Version 2.0 (the "License");
4
+ * you may not use this file except in compliance with the License.
5
+ * You may obtain a copy of the License at
6
+ *
7
+ * http://www.apache.org/licenses/LICENSE-2.0
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ */
15
+ import { asValidUserAlias, randomUniqueKey } from "@gala-chain/api";
16
+ import { fixture, users } from "@gala-chain/test";
17
+
18
+ import { FinalizeTokenAllocationDto, LaunchpadFeeConfig } from "../../api/types";
19
+ import { LaunchpadContract } from "../LaunchpadContract";
20
+
21
+ describe("finalizeTokenAllocation", () => {
22
+ let feeConfig: LaunchpadFeeConfig;
23
+
24
+ beforeEach(() => {
25
+ feeConfig = new LaunchpadFeeConfig(asValidUserAlias("client|platformFeeAddress"), 0.01, [
26
+ users.admin.identityKey
27
+ ]);
28
+ });
29
+
30
+ it("should create new token allocation successfully", async () => {
31
+ // Given
32
+ const { ctx, contract } = fixture(LaunchpadContract)
33
+ .caClientIdentity("test-admin", "CuratorOrg")
34
+ .registeredUsers(users.admin)
35
+ .savedState(feeConfig);
36
+
37
+ const finalizeDto = new FinalizeTokenAllocationDto();
38
+ finalizeDto.platformFeePercentage = 0.02;
39
+ finalizeDto.ownerFeePercentage = 0.03;
40
+ finalizeDto.uniqueKey = randomUniqueKey();
41
+ const signedDto = finalizeDto.signed(users.admin.privateKey);
42
+
43
+ // When
44
+ const response = await contract.FinalizeTokenAllocation(ctx, signedDto);
45
+
46
+ // Then
47
+ expect(response.Status).toBe(1);
48
+ expect(response.Data?.platformFeePercentage).toBe(0.02);
49
+ expect(response.Data?.ownerAllocationPercentage).toBe(0.03);
50
+ });
51
+
52
+ it("should update existing token allocation", async () => {
53
+ // Given - Create existing allocation first
54
+ const { ctx, contract } = fixture(LaunchpadContract)
55
+ .caClientIdentity("test-admin", "CuratorOrg")
56
+ .registeredUsers(users.admin)
57
+ .savedState(feeConfig);
58
+
59
+ const initialDto = new FinalizeTokenAllocationDto();
60
+ initialDto.platformFeePercentage = 0.01;
61
+ initialDto.ownerFeePercentage = 0.02;
62
+ initialDto.uniqueKey = randomUniqueKey();
63
+ const signedInitialDto = initialDto.signed(users.admin.privateKey);
64
+
65
+ await contract.FinalizeTokenAllocation(ctx, signedInitialDto);
66
+
67
+ // Update with new values
68
+ const updateDto = new FinalizeTokenAllocationDto();
69
+ updateDto.platformFeePercentage = 0.05;
70
+ updateDto.ownerFeePercentage = 0.06;
71
+ updateDto.uniqueKey = randomUniqueKey();
72
+ const signedUpdateDto = updateDto.signed(users.admin.privateKey);
73
+
74
+ // When
75
+ const response = await contract.FinalizeTokenAllocation(ctx, signedUpdateDto);
76
+
77
+ // Then
78
+ expect(response.Status).toBe(1);
79
+ expect(response.Data?.platformFeePercentage).toBe(0.05);
80
+ expect(response.Data?.ownerAllocationPercentage).toBe(0.06);
81
+ });
82
+
83
+ it("should handle zero percentage allocations", async () => {
84
+ // Given
85
+ const { ctx, contract } = fixture(LaunchpadContract)
86
+ .caClientIdentity("test-admin", "CuratorOrg")
87
+ .registeredUsers(users.admin)
88
+ .savedState(feeConfig);
89
+
90
+ const finalizeDto = new FinalizeTokenAllocationDto();
91
+ finalizeDto.platformFeePercentage = 0;
92
+ finalizeDto.ownerFeePercentage = 0;
93
+ finalizeDto.uniqueKey = randomUniqueKey();
94
+ const signedDto = finalizeDto.signed(users.admin.privateKey);
95
+
96
+ // When
97
+ const response = await contract.FinalizeTokenAllocation(ctx, signedDto);
98
+
99
+ // Then
100
+ expect(response.Status).toBe(1);
101
+ expect(response.Data?.platformFeePercentage).toBe(0);
102
+ expect(response.Data?.ownerAllocationPercentage).toBe(0);
103
+ });
104
+
105
+ it("should handle high percentage allocations", async () => {
106
+ // Given
107
+ const { ctx, contract } = fixture(LaunchpadContract)
108
+ .caClientIdentity("test-admin", "CuratorOrg")
109
+ .registeredUsers(users.admin)
110
+ .savedState(feeConfig);
111
+
112
+ const finalizeDto = new FinalizeTokenAllocationDto();
113
+ finalizeDto.platformFeePercentage = 0.1; // 10%
114
+ finalizeDto.ownerFeePercentage = 0.15; // 15%
115
+ finalizeDto.uniqueKey = randomUniqueKey();
116
+ const signedDto = finalizeDto.signed(users.admin.privateKey);
117
+
118
+ // When
119
+ const response = await contract.FinalizeTokenAllocation(ctx, signedDto);
120
+
121
+ // Then
122
+ expect(response.Status).toBe(1);
123
+ expect(response.Data?.platformFeePercentage).toBe(0.1);
124
+ expect(response.Data?.ownerAllocationPercentage).toBe(0.15);
125
+ });
126
+ });