@gala-chain/launchpad 1.0.9 → 1.0.10

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 (27) hide show
  1. package/CLAUDE.md +279 -0
  2. package/lib/package.json +2 -2
  3. package/lib/src/chaincode/launchpad/buyWithNative.d.ts.map +1 -1
  4. package/lib/src/chaincode/launchpad/buyWithNative.js +11 -4
  5. package/lib/src/chaincode/launchpad/buyWithNative.js.map +1 -1
  6. package/lib/src/chaincode/launchpad/sellWithNative.d.ts.map +1 -1
  7. package/lib/src/chaincode/launchpad/sellWithNative.js +9 -1
  8. package/lib/src/chaincode/launchpad/sellWithNative.js.map +1 -1
  9. package/lib/src/chaincode/test/launchpadgala.js +1 -1
  10. package/lib/src/chaincode/test/launchpadgala.js.map +1 -1
  11. package/lib/tsconfig.tsbuildinfo +1 -1
  12. package/package.json +2 -2
  13. package/src/chaincode/launchpad/buyExactToken.spec.ts +90 -20
  14. package/src/chaincode/launchpad/buyWithNative.spec.ts +99 -25
  15. package/src/chaincode/launchpad/buyWithNative.ts +20 -5
  16. package/src/chaincode/launchpad/callMemeTokenIn.spec.ts +244 -0
  17. package/src/chaincode/launchpad/callMemeTokenOut.spec.ts +1 -1
  18. package/src/chaincode/launchpad/callNativeTokenIn.spec.ts +269 -0
  19. package/src/chaincode/launchpad/callNativeTokenOut.spec.ts +276 -0
  20. package/src/chaincode/launchpad/configureLaunchpadFeeConfig.spec.ts +202 -0
  21. package/src/chaincode/launchpad/createSale.spec.ts +259 -0
  22. package/src/chaincode/launchpad/fetchSaleDetails.spec.ts +141 -0
  23. package/src/chaincode/launchpad/finalizeTokenAllocation.spec.ts +126 -0
  24. package/src/chaincode/launchpad/sellExactToken.spec.ts +284 -0
  25. package/src/chaincode/launchpad/sellWithNative.spec.ts +329 -0
  26. package/src/chaincode/launchpad/sellWithNative.ts +22 -5
  27. package/src/chaincode/test/launchpadgala.ts +1 -1
@@ -0,0 +1,202 @@
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 { ConfigureLaunchpadFeeAddressDto } from "../../api/types";
19
+ import { LaunchpadContract } from "../LaunchpadContract";
20
+
21
+ describe("configureLaunchpadFeeAddress", () => {
22
+ it("should create initial fee configuration with valid inputs", async () => {
23
+ // Given
24
+ const { ctx, contract } = fixture(LaunchpadContract)
25
+ .caClientIdentity("test-admin", "CuratorOrg")
26
+ .registeredUsers(users.admin);
27
+
28
+ const configDto = new ConfigureLaunchpadFeeAddressDto();
29
+ configDto.newPlatformFeeAddress = asValidUserAlias("client|feeAddress");
30
+ configDto.newFeeAmount = 0.01;
31
+ configDto.newAuthorities = [users.admin.identityKey];
32
+ configDto.uniqueKey = randomUniqueKey();
33
+ const signedDto = configDto.signed(users.admin.privateKey);
34
+
35
+ // When
36
+ const response = await contract.ConfigureLaunchpadFeeAddress(ctx, signedDto);
37
+
38
+ // Then
39
+ expect(response.Status).toBe(1);
40
+ expect(response.Data?.feeAddress).toBe("client|feeAddress");
41
+ expect(response.Data?.feeAmount).toBe(0.01);
42
+ expect(response.Data?.authorities).toContain(users.admin.identityKey);
43
+ });
44
+
45
+ it("should update existing fee configuration", async () => {
46
+ // Given
47
+ const existingConfig = new ConfigureLaunchpadFeeAddressDto();
48
+ existingConfig.newPlatformFeeAddress = asValidUserAlias("client|oldFeeAddress");
49
+ existingConfig.newFeeAmount = 0.01;
50
+ existingConfig.newAuthorities = [users.admin.identityKey];
51
+ existingConfig.uniqueKey = randomUniqueKey();
52
+ const signedExistingDto = existingConfig.signed(users.admin.privateKey);
53
+
54
+ const { ctx, contract } = fixture(LaunchpadContract)
55
+ .caClientIdentity("test-admin", "CuratorOrg")
56
+ .registeredUsers(users.admin);
57
+
58
+ // Create initial config
59
+ await contract.ConfigureLaunchpadFeeAddress(ctx, signedExistingDto);
60
+
61
+ // Update with new values
62
+ const updateDto = new ConfigureLaunchpadFeeAddressDto();
63
+ updateDto.newPlatformFeeAddress = asValidUserAlias("client|newFeeAddress");
64
+ updateDto.newFeeAmount = 0.02;
65
+ updateDto.newAuthorities = [users.admin.identityKey, users.testUser2.identityKey];
66
+ updateDto.uniqueKey = randomUniqueKey();
67
+ const signedUpdateDto = updateDto.signed(users.admin.privateKey);
68
+
69
+ // When
70
+ const response = await contract.ConfigureLaunchpadFeeAddress(ctx, signedUpdateDto);
71
+
72
+ // Then
73
+ expect(response.Status).toBe(1);
74
+ expect(response.Data?.feeAddress).toBe("client|newFeeAddress");
75
+ expect(response.Data?.feeAmount).toBe(0.02);
76
+ expect(response.Data?.authorities).toContain(users.testUser2.identityKey);
77
+ });
78
+
79
+ it("should update only fee address when other fields are not provided", async () => {
80
+ // Given
81
+ const existingConfig = new ConfigureLaunchpadFeeAddressDto();
82
+ existingConfig.newPlatformFeeAddress = asValidUserAlias("client|oldFeeAddress");
83
+ existingConfig.newFeeAmount = 0.01;
84
+ existingConfig.newAuthorities = [users.admin.identityKey];
85
+ existingConfig.uniqueKey = randomUniqueKey();
86
+ const signedExistingDto = existingConfig.signed(users.admin.privateKey);
87
+
88
+ const { ctx, contract } = fixture(LaunchpadContract)
89
+ .caClientIdentity("test-admin", "CuratorOrg")
90
+ .registeredUsers(users.admin);
91
+
92
+ // Create initial config
93
+ await contract.ConfigureLaunchpadFeeAddress(ctx, signedExistingDto);
94
+
95
+ // Update only fee address
96
+ const updateDto = new ConfigureLaunchpadFeeAddressDto();
97
+ updateDto.newPlatformFeeAddress = asValidUserAlias("client|newOnlyAddress");
98
+ updateDto.uniqueKey = randomUniqueKey();
99
+ const signedUpdateDto = updateDto.signed(users.admin.privateKey);
100
+
101
+ // When
102
+ const response = await contract.ConfigureLaunchpadFeeAddress(ctx, signedUpdateDto);
103
+
104
+ // Then
105
+ expect(response.Status).toBe(1);
106
+ expect(response.Data?.feeAddress).toBe("client|newOnlyAddress");
107
+ expect(response.Data?.feeAmount).toBe(0.01); // Should remain the same
108
+ });
109
+
110
+ it("should update only fee amount when other fields are not provided", async () => {
111
+ // Given
112
+ const existingConfig = new ConfigureLaunchpadFeeAddressDto();
113
+ existingConfig.newPlatformFeeAddress = asValidUserAlias("client|feeAddress");
114
+ existingConfig.newFeeAmount = 0.01;
115
+ existingConfig.newAuthorities = [users.admin.identityKey];
116
+ existingConfig.uniqueKey = randomUniqueKey();
117
+ const signedExistingDto = existingConfig.signed(users.admin.privateKey);
118
+
119
+ const { ctx, contract } = fixture(LaunchpadContract)
120
+ .caClientIdentity("test-admin", "CuratorOrg")
121
+ .registeredUsers(users.admin);
122
+
123
+ // Create initial config
124
+ await contract.ConfigureLaunchpadFeeAddress(ctx, signedExistingDto);
125
+
126
+ // Update only fee amount
127
+ const updateDto = new ConfigureLaunchpadFeeAddressDto();
128
+ updateDto.newFeeAmount = 0.05;
129
+ updateDto.uniqueKey = randomUniqueKey();
130
+ const signedUpdateDto = updateDto.signed(users.admin.privateKey);
131
+
132
+ // When
133
+ const response = await contract.ConfigureLaunchpadFeeAddress(ctx, signedUpdateDto);
134
+
135
+ // Then
136
+ expect(response.Status).toBe(1);
137
+ expect(response.Data?.feeAddress).toBe("client|feeAddress"); // Should remain the same
138
+ expect(response.Data?.feeAmount).toBe(0.05);
139
+ });
140
+
141
+ it("should handle zero fee amount configuration after initial setup", async () => {
142
+ // Given - Create initial config with non-zero fee first
143
+ const { ctx, contract } = fixture(LaunchpadContract)
144
+ .caClientIdentity("test-admin", "CuratorOrg")
145
+ .registeredUsers(users.admin);
146
+
147
+ const initialConfigDto = new ConfigureLaunchpadFeeAddressDto();
148
+ initialConfigDto.newPlatformFeeAddress = asValidUserAlias("client|feeAddress");
149
+ initialConfigDto.newFeeAmount = 0.01;
150
+ initialConfigDto.newAuthorities = [users.admin.identityKey];
151
+ initialConfigDto.uniqueKey = randomUniqueKey();
152
+ const signedInitialDto = initialConfigDto.signed(users.admin.privateKey);
153
+
154
+ await contract.ConfigureLaunchpadFeeAddress(ctx, signedInitialDto);
155
+
156
+ // Update with zero fee amount
157
+ const configDto = new ConfigureLaunchpadFeeAddressDto();
158
+ configDto.newPlatformFeeAddress = asValidUserAlias("client|feeAddress"); // Keep same address
159
+ configDto.newFeeAmount = 0;
160
+ configDto.uniqueKey = randomUniqueKey();
161
+ const signedDto = configDto.signed(users.admin.privateKey);
162
+
163
+ // When
164
+ const response = await contract.ConfigureLaunchpadFeeAddress(ctx, signedDto);
165
+
166
+ // Then
167
+ expect(response.Status).toBe(1);
168
+ expect(response.Data?.feeAmount).toBe(0);
169
+ });
170
+
171
+ it("should handle multiple authorities in configuration", async () => {
172
+ // Given
173
+ const { ctx, contract } = fixture(LaunchpadContract)
174
+ .caClientIdentity("test-admin", "CuratorOrg")
175
+ .registeredUsers(users.admin, users.testUser1, users.testUser2, users.testUser3);
176
+
177
+ const authorities = [
178
+ users.admin.identityKey,
179
+ users.testUser1.identityKey,
180
+ users.testUser2.identityKey,
181
+ users.testUser3.identityKey
182
+ ];
183
+
184
+ const configDto = new ConfigureLaunchpadFeeAddressDto();
185
+ configDto.newPlatformFeeAddress = asValidUserAlias("client|feeAddress");
186
+ configDto.newFeeAmount = 0.01;
187
+ configDto.newAuthorities = authorities;
188
+ configDto.uniqueKey = randomUniqueKey();
189
+ const signedDto = configDto.signed(users.admin.privateKey);
190
+
191
+ // When
192
+ const response = await contract.ConfigureLaunchpadFeeAddress(ctx, signedDto);
193
+
194
+ // Then
195
+ expect(response.Status).toBe(1);
196
+ expect(response.Data?.authorities).toHaveLength(4);
197
+ expect(response.Data?.authorities).toContain(users.admin.identityKey);
198
+ expect(response.Data?.authorities).toContain(users.testUser1.identityKey);
199
+ expect(response.Data?.authorities).toContain(users.testUser2.identityKey);
200
+ expect(response.Data?.authorities).toContain(users.testUser3.identityKey);
201
+ });
202
+ });
@@ -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 { currency, 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
+ });