@gala-chain/launchpad 1.0.5 → 1.0.7
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/lib/package.json +1 -1
- package/lib/src/api/types/LaunchpadDtos.d.ts +5 -4
- package/lib/src/api/types/LaunchpadDtos.d.ts.map +1 -1
- package/lib/src/api/types/LaunchpadDtos.js +17 -15
- package/lib/src/api/types/LaunchpadDtos.js.map +1 -1
- package/lib/src/chaincode/LaunchpadContract.d.ts +4 -4
- package/lib/src/chaincode/LaunchpadContract.d.ts.map +1 -1
- package/lib/src/chaincode/LaunchpadContract.js +22 -16
- package/lib/src/chaincode/LaunchpadContract.js.map +1 -1
- package/lib/src/chaincode/launchpad/buyExactToken.d.ts.map +1 -1
- package/lib/src/chaincode/launchpad/buyExactToken.js +8 -1
- package/lib/src/chaincode/launchpad/buyExactToken.js.map +1 -1
- package/lib/src/chaincode/launchpad/buyWithNative.d.ts.map +1 -1
- package/lib/src/chaincode/launchpad/buyWithNative.js +9 -2
- package/lib/src/chaincode/launchpad/buyWithNative.js.map +1 -1
- package/lib/src/chaincode/launchpad/callMemeTokenOut.d.ts.map +1 -1
- package/lib/src/chaincode/launchpad/callMemeTokenOut.js +20 -7
- package/lib/src/chaincode/launchpad/callMemeTokenOut.js.map +1 -1
- package/lib/src/chaincode/launchpad/callNativeTokenIn.d.ts.map +1 -1
- package/lib/src/chaincode/launchpad/callNativeTokenIn.js.map +1 -1
- package/lib/src/chaincode/launchpad/callNativeTokenOut.d.ts.map +1 -1
- package/lib/src/chaincode/launchpad/callNativeTokenOut.js.map +1 -1
- package/lib/src/chaincode/launchpad/fetchLaunchpadAdressConfig.d.ts +2 -1
- package/lib/src/chaincode/launchpad/fetchLaunchpadAdressConfig.d.ts.map +1 -1
- package/lib/src/chaincode/launchpad/fetchLaunchpadAdressConfig.js +1 -1
- package/lib/src/chaincode/launchpad/fetchLaunchpadAdressConfig.js.map +1 -1
- package/lib/src/chaincode/launchpad/fetchLaunchpadFeeAmount.d.ts +12 -0
- package/lib/src/chaincode/launchpad/fetchLaunchpadFeeAmount.d.ts.map +1 -0
- package/lib/src/chaincode/launchpad/fetchLaunchpadFeeAmount.js +37 -0
- package/lib/src/chaincode/launchpad/fetchLaunchpadFeeAmount.js.map +1 -0
- package/lib/src/chaincode/launchpad/index.d.ts +0 -1
- package/lib/src/chaincode/launchpad/index.d.ts.map +1 -1
- package/lib/src/chaincode/launchpad/index.js +0 -1
- package/lib/src/chaincode/launchpad/index.js.map +1 -1
- package/lib/src/chaincode/launchpad/sellExactToken.d.ts.map +1 -1
- package/lib/src/chaincode/launchpad/sellExactToken.js +2 -1
- package/lib/src/chaincode/launchpad/sellExactToken.js.map +1 -1
- package/lib/src/chaincode/launchpad/sellWithNative.d.ts.map +1 -1
- package/lib/src/chaincode/launchpad/sellWithNative.js +2 -1
- package/lib/src/chaincode/launchpad/sellWithNative.js.map +1 -1
- package/lib/src/chaincode/test/launchpadgala.d.ts +154 -0
- package/lib/src/chaincode/test/launchpadgala.d.ts.map +1 -0
- package/lib/src/chaincode/test/launchpadgala.js +152 -0
- package/lib/src/chaincode/test/launchpadgala.js.map +1 -0
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/api/types/LaunchpadDtos.ts +12 -14
- package/src/chaincode/LaunchpadContract.ts +25 -16
- package/src/chaincode/launchpad/buyExactToken.spec.ts +222 -0
- package/src/chaincode/launchpad/buyExactToken.ts +18 -2
- package/src/chaincode/launchpad/buyWithNative.spec.ts +221 -0
- package/src/chaincode/launchpad/buyWithNative.ts +20 -3
- package/src/chaincode/launchpad/callMemeTokenOut.spec.ts +150 -0
- package/src/chaincode/launchpad/callMemeTokenOut.ts +26 -15
- package/src/chaincode/launchpad/callNativeTokenIn.ts +1 -0
- package/src/chaincode/launchpad/callNativeTokenOut.ts +1 -0
- package/src/chaincode/launchpad/fetchLaunchpadAdressConfig.ts +5 -2
- package/src/chaincode/launchpad/fetchLaunchpadFeeAmount.spec.ts +67 -0
- package/src/chaincode/launchpad/fetchLaunchpadFeeAmount.ts +40 -0
- package/src/chaincode/launchpad/index.ts +0 -1
- package/src/chaincode/launchpad/sellExactToken.ts +2 -1
- package/src/chaincode/launchpad/sellWithNative.ts +2 -1
- package/src/chaincode/test/launchpadgala.ts +174 -0
- package/lib/src/chaincode/launchpad/preMintCalculation.d.ts +0 -17
- package/lib/src/chaincode/launchpad/preMintCalculation.d.ts.map +0 -1
- package/lib/src/chaincode/launchpad/preMintCalculation.js +0 -52
- package/lib/src/chaincode/launchpad/preMintCalculation.js.map +0 -1
- package/src/chaincode/launchpad/preMintCalculation.ts +0 -56
package/package.json
CHANGED
|
@@ -36,7 +36,6 @@ import {
|
|
|
36
36
|
ValidateNested
|
|
37
37
|
} from "class-validator";
|
|
38
38
|
|
|
39
|
-
// TODO: Move to @gala-chain/api
|
|
40
39
|
import { BigNumberIsNotNegative, BigNumberLessThanOrEqualOther, BigNumberMax } from "../validators";
|
|
41
40
|
import { IsNonZeroBigNumber } from "../validators";
|
|
42
41
|
|
|
@@ -254,6 +253,10 @@ export class NativeTokenQuantityDto extends SubmitCallDTO {
|
|
|
254
253
|
@IsOptional()
|
|
255
254
|
public extraFees?: TokenExtraFeesDto;
|
|
256
255
|
|
|
256
|
+
@IsOptional()
|
|
257
|
+
@IsBoolean()
|
|
258
|
+
public IsPreMint?: boolean;
|
|
259
|
+
|
|
257
260
|
constructor(vaultAddress: UserAlias, nativeTokenQuantity: BigNumber = new BigNumber(0)) {
|
|
258
261
|
super();
|
|
259
262
|
this.vaultAddress = vaultAddress;
|
|
@@ -303,10 +306,12 @@ export class TradeResDto {
|
|
|
303
306
|
|
|
304
307
|
@IsNotEmpty()
|
|
305
308
|
public functionName: string;
|
|
309
|
+
|
|
310
|
+
@IsString()
|
|
311
|
+
public uniqueKey: string;
|
|
306
312
|
}
|
|
307
313
|
|
|
308
314
|
export class FetchSaleDto extends ChainCallDTO {
|
|
309
|
-
// TODO: UserAlias?
|
|
310
315
|
@IsUserAlias()
|
|
311
316
|
@IsNotEmpty()
|
|
312
317
|
public vaultAddress: UserAlias;
|
|
@@ -316,18 +321,6 @@ export class FetchSaleDto extends ChainCallDTO {
|
|
|
316
321
|
}
|
|
317
322
|
}
|
|
318
323
|
|
|
319
|
-
export class PreMintCalculationDto extends ChainCallDTO {
|
|
320
|
-
@BigNumberProperty()
|
|
321
|
-
@IsNonZeroBigNumber()
|
|
322
|
-
@IsNotEmpty()
|
|
323
|
-
public nativeTokenQuantity: BigNumber;
|
|
324
|
-
|
|
325
|
-
constructor(nativeTokenQuantity: BigNumber = new BigNumber(0)) {
|
|
326
|
-
super();
|
|
327
|
-
this.nativeTokenQuantity = nativeTokenQuantity;
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
|
|
331
324
|
export class ConfigureLaunchpadFeeAddressDto extends SubmitCallDTO {
|
|
332
325
|
@IsOptional()
|
|
333
326
|
@IsUserAlias()
|
|
@@ -404,3 +397,8 @@ export class BatchSubmitAuthoritiesResDto extends ChainCallDTO {
|
|
|
404
397
|
@IsString({ each: true })
|
|
405
398
|
authorities: string[];
|
|
406
399
|
}
|
|
400
|
+
|
|
401
|
+
export class TransactionFeeResDto {
|
|
402
|
+
@IsNumber()
|
|
403
|
+
feeAmount;
|
|
404
|
+
}
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* See the License for the specific language governing permissions and
|
|
13
13
|
* limitations under the License.
|
|
14
14
|
*/
|
|
15
|
-
import { BatchDto, GalaChainResponse, UnauthorizedError } from "@gala-chain/api";
|
|
15
|
+
import { BatchDto, ChainCallDTO, GalaChainResponse, UnauthorizedError } from "@gala-chain/api";
|
|
16
16
|
import {
|
|
17
17
|
BatchWriteLimitExceededError,
|
|
18
18
|
EVALUATE,
|
|
@@ -41,9 +41,9 @@ import {
|
|
|
41
41
|
LaunchpadFinalizeFeeAllocation,
|
|
42
42
|
LaunchpadSale,
|
|
43
43
|
NativeTokenQuantityDto,
|
|
44
|
-
PreMintCalculationDto,
|
|
45
44
|
TradeCalculationResDto,
|
|
46
|
-
TradeResDto
|
|
45
|
+
TradeResDto,
|
|
46
|
+
TransactionFeeResDto
|
|
47
47
|
} from "../api/types";
|
|
48
48
|
import {
|
|
49
49
|
buyExactTokenFeeGate,
|
|
@@ -56,7 +56,6 @@ import {
|
|
|
56
56
|
authorizeLaunchpadBatchSubmitter,
|
|
57
57
|
buyExactToken,
|
|
58
58
|
buyWithNative,
|
|
59
|
-
calculatePreMintTokens,
|
|
60
59
|
callMemeTokenIn,
|
|
61
60
|
callMemeTokenOut,
|
|
62
61
|
callNativeTokenIn,
|
|
@@ -72,10 +71,13 @@ import {
|
|
|
72
71
|
sellExactToken,
|
|
73
72
|
sellWithNative
|
|
74
73
|
} from "./launchpad";
|
|
74
|
+
import { fetchLaunchpadFeeAmount } from "./launchpad/fetchLaunchpadFeeAmount";
|
|
75
75
|
|
|
76
76
|
export class LaunchpadContract extends GalaContract {
|
|
77
77
|
constructor() {
|
|
78
|
-
super("Launchpad", version
|
|
78
|
+
super("Launchpad", version, {
|
|
79
|
+
allowNonRegisteredUsers: true
|
|
80
|
+
});
|
|
79
81
|
}
|
|
80
82
|
|
|
81
83
|
@Submit({
|
|
@@ -204,21 +206,28 @@ export class LaunchpadContract extends GalaContract {
|
|
|
204
206
|
return callMemeTokenIn(ctx, dto);
|
|
205
207
|
}
|
|
206
208
|
|
|
207
|
-
@GalaTransaction({
|
|
208
|
-
type: EVALUATE,
|
|
209
|
-
in: PreMintCalculationDto,
|
|
210
|
-
out: String
|
|
211
|
-
})
|
|
212
|
-
public async CalculatePreMintTokens(dto: PreMintCalculationDto): Promise<string> {
|
|
213
|
-
return calculatePreMintTokens(dto);
|
|
214
|
-
}
|
|
215
|
-
|
|
216
209
|
@Evaluate({
|
|
210
|
+
in: ChainCallDTO,
|
|
217
211
|
out: LaunchpadFeeConfig,
|
|
218
212
|
allowedOrgs: ["CuratorOrg"]
|
|
219
213
|
})
|
|
220
|
-
public async FetchLaunchpadFeeConfig(
|
|
221
|
-
|
|
214
|
+
public async FetchLaunchpadFeeConfig(
|
|
215
|
+
ctx: GalaChainContext,
|
|
216
|
+
dto: ChainCallDTO
|
|
217
|
+
): Promise<LaunchpadFeeConfig> {
|
|
218
|
+
return fetchLaunchpadFeeConfig(ctx, dto);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
@GalaTransaction({
|
|
222
|
+
type: EVALUATE,
|
|
223
|
+
in: ChainCallDTO,
|
|
224
|
+
out: TransactionFeeResDto
|
|
225
|
+
})
|
|
226
|
+
public async FetchLaunchpadFeeAmount(
|
|
227
|
+
ctx: GalaChainContext,
|
|
228
|
+
dto: ChainCallDTO
|
|
229
|
+
): Promise<TransactionFeeResDto> {
|
|
230
|
+
return fetchLaunchpadFeeAmount(ctx, dto);
|
|
222
231
|
}
|
|
223
232
|
|
|
224
233
|
@GalaTransaction({
|
|
@@ -0,0 +1,222 @@
|
|
|
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
|
+
GalaChainResponse,
|
|
17
|
+
TokenBalance,
|
|
18
|
+
TokenClass,
|
|
19
|
+
TokenClassKey,
|
|
20
|
+
TokenInstance,
|
|
21
|
+
UserAlias,
|
|
22
|
+
ValidationFailedError,
|
|
23
|
+
asValidUserAlias,
|
|
24
|
+
randomUniqueKey
|
|
25
|
+
} from "@gala-chain/api";
|
|
26
|
+
import { currency, fixture, users } from "@gala-chain/test";
|
|
27
|
+
import BigNumber from "bignumber.js";
|
|
28
|
+
import { plainToInstance } from "class-transformer";
|
|
29
|
+
|
|
30
|
+
import {
|
|
31
|
+
ExactTokenQuantityDto,
|
|
32
|
+
LaunchpadFeeConfig,
|
|
33
|
+
LaunchpadSale,
|
|
34
|
+
NativeTokenQuantityDto
|
|
35
|
+
} from "../../api/types";
|
|
36
|
+
import { LaunchpadContract } from "../LaunchpadContract";
|
|
37
|
+
import launchpadgala from "../test/launchpadgala";
|
|
38
|
+
|
|
39
|
+
describe("buyWithNative", () => {
|
|
40
|
+
let currencyClass: TokenClass;
|
|
41
|
+
let currencyInstance: TokenInstance;
|
|
42
|
+
let launchpadGalaClass: TokenClass;
|
|
43
|
+
let launchpadGalaInstance: TokenInstance;
|
|
44
|
+
let launchpadGalaClassKey: TokenClassKey;
|
|
45
|
+
let vaultAddress: UserAlias;
|
|
46
|
+
let sale: LaunchpadSale;
|
|
47
|
+
let salelaunchpadGalaBalance: TokenBalance;
|
|
48
|
+
let saleCurrencyBalance: TokenBalance;
|
|
49
|
+
let userlaunchpadGalaBalance: TokenBalance;
|
|
50
|
+
let userCurrencyBalance: TokenBalance;
|
|
51
|
+
|
|
52
|
+
beforeEach(() => {
|
|
53
|
+
//Given
|
|
54
|
+
currencyClass = currency.tokenClass();
|
|
55
|
+
currencyInstance = currency.tokenInstance();
|
|
56
|
+
launchpadGalaClass = launchpadgala.tokenClass();
|
|
57
|
+
launchpadGalaInstance = launchpadgala.tokenInstance();
|
|
58
|
+
launchpadGalaClassKey = launchpadgala.tokenClassKey();
|
|
59
|
+
|
|
60
|
+
launchpadGalaClass = plainToInstance(TokenClass, {
|
|
61
|
+
...launchpadgala.tokenClassPlain(),
|
|
62
|
+
decimals: 18
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
vaultAddress = asValidUserAlias(`service|${launchpadGalaClassKey.toStringKey()}$launchpad`);
|
|
66
|
+
|
|
67
|
+
// Initialize sale with manual values
|
|
68
|
+
sale = new LaunchpadSale(
|
|
69
|
+
vaultAddress,
|
|
70
|
+
launchpadGalaInstance.instanceKeyObj(),
|
|
71
|
+
undefined,
|
|
72
|
+
users.testUser1.identityKey
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
// Create sale balances - sale needs tokens to pay out
|
|
76
|
+
salelaunchpadGalaBalance = plainToInstance(TokenBalance, {
|
|
77
|
+
...launchpadgala.tokenBalance(),
|
|
78
|
+
owner: vaultAddress,
|
|
79
|
+
quantity: new BigNumber("1e+7")
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
saleCurrencyBalance = plainToInstance(TokenBalance, {
|
|
83
|
+
...currency.tokenBalance(),
|
|
84
|
+
owner: vaultAddress,
|
|
85
|
+
quantity: new BigNumber("1e+7")
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// Create user balances - user needs tokens to swap
|
|
89
|
+
userlaunchpadGalaBalance = plainToInstance(TokenBalance, {
|
|
90
|
+
...launchpadgala.tokenBalance(),
|
|
91
|
+
owner: users.testUser1.identityKey,
|
|
92
|
+
quantity: new BigNumber("1000000") // User has 10k launchpadGala tokens
|
|
93
|
+
});
|
|
94
|
+
userCurrencyBalance = plainToInstance(TokenBalance, {
|
|
95
|
+
...currency.tokenBalance(),
|
|
96
|
+
owner: users.testUser1.identityKey
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
test("User should be able to buy exact tokens, without fee configured", async () => {
|
|
101
|
+
//Given
|
|
102
|
+
const { ctx, contract } = fixture(LaunchpadContract)
|
|
103
|
+
.registeredUsers(users.testUser1)
|
|
104
|
+
.savedState(
|
|
105
|
+
currencyClass,
|
|
106
|
+
currencyInstance,
|
|
107
|
+
launchpadGalaClass,
|
|
108
|
+
launchpadGalaInstance,
|
|
109
|
+
sale,
|
|
110
|
+
salelaunchpadGalaBalance,
|
|
111
|
+
saleCurrencyBalance,
|
|
112
|
+
userlaunchpadGalaBalance,
|
|
113
|
+
userCurrencyBalance
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
const dto = new ExactTokenQuantityDto(vaultAddress, new BigNumber("500"));
|
|
117
|
+
|
|
118
|
+
dto.uniqueKey = randomUniqueKey();
|
|
119
|
+
dto.sign(users.testUser1.privateKey);
|
|
120
|
+
|
|
121
|
+
//When
|
|
122
|
+
const buyTokenRes = await contract.BuyExactToken(ctx, dto);
|
|
123
|
+
|
|
124
|
+
//Then
|
|
125
|
+
expect(buyTokenRes.Data).toMatchObject({
|
|
126
|
+
inputQuantity: "0.00825575",
|
|
127
|
+
totalFees: "0.00000000",
|
|
128
|
+
outputQuantity: "500",
|
|
129
|
+
tokenName: "AUTOMATEDTESTCOIN",
|
|
130
|
+
tradeType: "Buy",
|
|
131
|
+
vaultAddress: "service|GALA$Unit$none$none$launchpad",
|
|
132
|
+
userAddress: "client|testUser1",
|
|
133
|
+
isFinalized: false,
|
|
134
|
+
functionName: "BuyExactToken"
|
|
135
|
+
});
|
|
136
|
+
expect(buyTokenRes.Data?.inputQuantity).toEqual("0.00825575");
|
|
137
|
+
expect(buyTokenRes.Data?.outputQuantity).toEqual("500");
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
test("User should be able to buy tokens , fee configured check", async () => {
|
|
141
|
+
//Given
|
|
142
|
+
const launchpadConfig = new LaunchpadFeeConfig(users.testUser2.identityKey, Number("0.32"), [
|
|
143
|
+
users.testUser2.identityKey
|
|
144
|
+
]);
|
|
145
|
+
|
|
146
|
+
const { ctx, contract } = fixture(LaunchpadContract)
|
|
147
|
+
.registeredUsers(users.testUser1)
|
|
148
|
+
.savedState(
|
|
149
|
+
currencyClass,
|
|
150
|
+
currencyInstance,
|
|
151
|
+
launchpadGalaClass,
|
|
152
|
+
launchpadGalaInstance,
|
|
153
|
+
sale,
|
|
154
|
+
salelaunchpadGalaBalance,
|
|
155
|
+
saleCurrencyBalance,
|
|
156
|
+
userlaunchpadGalaBalance,
|
|
157
|
+
userCurrencyBalance,
|
|
158
|
+
launchpadConfig
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
const dto = new ExactTokenQuantityDto(vaultAddress, new BigNumber("5430"));
|
|
162
|
+
|
|
163
|
+
dto.uniqueKey = randomUniqueKey();
|
|
164
|
+
dto.sign(users.testUser1.privateKey);
|
|
165
|
+
|
|
166
|
+
//When
|
|
167
|
+
const buyTokenRes = await contract.BuyExactToken(ctx, dto);
|
|
168
|
+
|
|
169
|
+
//Then
|
|
170
|
+
expect(buyTokenRes.Data).toMatchObject({
|
|
171
|
+
inputQuantity: "0.08991559",
|
|
172
|
+
totalFees: "0.02877299",
|
|
173
|
+
outputQuantity: "5430",
|
|
174
|
+
tokenName: "AUTOMATEDTESTCOIN",
|
|
175
|
+
tradeType: "Buy",
|
|
176
|
+
vaultAddress: "service|GALA$Unit$none$none$launchpad",
|
|
177
|
+
userAddress: "client|testUser1",
|
|
178
|
+
isFinalized: false,
|
|
179
|
+
functionName: "BuyExactToken"
|
|
180
|
+
});
|
|
181
|
+
expect(buyTokenRes.Data?.inputQuantity).toEqual("0.08991559");
|
|
182
|
+
expect(buyTokenRes.Data?.outputQuantity).toEqual("5430");
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
it("should throw error if user has insufficient funds incuding the transaction fees", async () => {
|
|
186
|
+
//Given
|
|
187
|
+
const launchpadConfig = new LaunchpadFeeConfig(users.testUser2.identityKey, Number("0.32"), [
|
|
188
|
+
users.testUser2.identityKey
|
|
189
|
+
]);
|
|
190
|
+
const { ctx, contract } = fixture(LaunchpadContract)
|
|
191
|
+
.registeredUsers(users.testUser1)
|
|
192
|
+
.savedState(
|
|
193
|
+
currencyClass,
|
|
194
|
+
currencyInstance,
|
|
195
|
+
launchpadGalaClass,
|
|
196
|
+
launchpadGalaInstance,
|
|
197
|
+
sale,
|
|
198
|
+
salelaunchpadGalaBalance,
|
|
199
|
+
saleCurrencyBalance,
|
|
200
|
+
userlaunchpadGalaBalance,
|
|
201
|
+
userCurrencyBalance,
|
|
202
|
+
launchpadConfig
|
|
203
|
+
);
|
|
204
|
+
|
|
205
|
+
const dto = new NativeTokenQuantityDto(vaultAddress, new BigNumber("10000000"));
|
|
206
|
+
|
|
207
|
+
dto.uniqueKey = randomUniqueKey();
|
|
208
|
+
dto.sign(users.testUser1.privateKey);
|
|
209
|
+
|
|
210
|
+
//When
|
|
211
|
+
const buyTokenRes = await contract.BuyWithNative(ctx, dto);
|
|
212
|
+
|
|
213
|
+
//Then
|
|
214
|
+
expect(buyTokenRes).toEqual(
|
|
215
|
+
GalaChainResponse.Error(
|
|
216
|
+
new ValidationFailedError(
|
|
217
|
+
"Insufficient balance: Total amount required including fee is 2166101.31430784"
|
|
218
|
+
)
|
|
219
|
+
)
|
|
220
|
+
);
|
|
221
|
+
});
|
|
222
|
+
});
|
|
@@ -12,7 +12,14 @@
|
|
|
12
12
|
* See the License for the specific language governing permissions and
|
|
13
13
|
* limitations under the License.
|
|
14
14
|
*/
|
|
15
|
-
import {
|
|
15
|
+
import { ValidationFailedError } from "@gala-chain/api";
|
|
16
|
+
import {
|
|
17
|
+
GalaChainContext,
|
|
18
|
+
fetchOrCreateBalance,
|
|
19
|
+
fetchTokenClass,
|
|
20
|
+
putChainObject,
|
|
21
|
+
transferToken
|
|
22
|
+
} from "@gala-chain/chaincode";
|
|
16
23
|
import BigNumber from "bignumber.js";
|
|
17
24
|
|
|
18
25
|
import { ExactTokenQuantityDto, LaunchpadSale, TradeResDto } from "../../api/types";
|
|
@@ -82,6 +89,14 @@ export async function buyExactToken(
|
|
|
82
89
|
// Transfer transaction fees
|
|
83
90
|
const launchpadFeeAddressConfiguration = await fetchLaunchpadFeeAddress(ctx);
|
|
84
91
|
if (launchpadFeeAddressConfiguration && transactionFees) {
|
|
92
|
+
const totalRequired = new BigNumber(buyTokenDTO.tokenQuantity).plus(transactionFees);
|
|
93
|
+
|
|
94
|
+
const buyerBalance = await fetchOrCreateBalance(ctx, ctx.callingUser, sale.nativeToken);
|
|
95
|
+
if (buyerBalance.getQuantityTotal().lt(totalRequired)) {
|
|
96
|
+
throw new ValidationFailedError(
|
|
97
|
+
`Insufficient balance: Total amount required including fee is ${totalRequired}`
|
|
98
|
+
);
|
|
99
|
+
}
|
|
85
100
|
await transferToken(ctx, {
|
|
86
101
|
from: ctx.callingUser,
|
|
87
102
|
to: launchpadFeeAddressConfiguration.feeAddress,
|
|
@@ -135,6 +150,7 @@ export async function buyExactToken(
|
|
|
135
150
|
vaultAddress: buyTokenDTO.vaultAddress,
|
|
136
151
|
userAddress: ctx.callingUser,
|
|
137
152
|
isFinalized: isSaleFinalized,
|
|
138
|
-
functionName: "BuyExactToken"
|
|
153
|
+
functionName: "BuyExactToken",
|
|
154
|
+
uniqueKey: buyTokenDTO.uniqueKey
|
|
139
155
|
};
|
|
140
156
|
}
|
|
@@ -0,0 +1,221 @@
|
|
|
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
|
+
GalaChainResponse,
|
|
17
|
+
TokenBalance,
|
|
18
|
+
TokenClass,
|
|
19
|
+
TokenClassKey,
|
|
20
|
+
TokenInstance,
|
|
21
|
+
UserAlias,
|
|
22
|
+
ValidationFailedError,
|
|
23
|
+
asValidUserAlias,
|
|
24
|
+
randomUniqueKey
|
|
25
|
+
} from "@gala-chain/api";
|
|
26
|
+
import { currency, fixture, users } from "@gala-chain/test";
|
|
27
|
+
import BigNumber from "bignumber.js";
|
|
28
|
+
import { plainToInstance } from "class-transformer";
|
|
29
|
+
|
|
30
|
+
import { LaunchpadFeeConfig, LaunchpadSale, NativeTokenQuantityDto } from "../../api/types";
|
|
31
|
+
import { LaunchpadContract } from "../LaunchpadContract";
|
|
32
|
+
import launchpadgala from "../test/launchpadgala";
|
|
33
|
+
|
|
34
|
+
describe("buyWithNative", () => {
|
|
35
|
+
let currencyClass: TokenClass;
|
|
36
|
+
let currencyInstance: TokenInstance;
|
|
37
|
+
let launchpadGalaClass: TokenClass;
|
|
38
|
+
let launchpadGalaInstance: TokenInstance;
|
|
39
|
+
let launchpadGalaClassKey: TokenClassKey;
|
|
40
|
+
let vaultAddress: UserAlias;
|
|
41
|
+
let sale: LaunchpadSale;
|
|
42
|
+
let salelaunchpadGalaBalance: TokenBalance;
|
|
43
|
+
let saleCurrencyBalance: TokenBalance;
|
|
44
|
+
let userlaunchpadGalaBalance: TokenBalance;
|
|
45
|
+
let userCurrencyBalance: TokenBalance;
|
|
46
|
+
|
|
47
|
+
beforeEach(() => {
|
|
48
|
+
//Given
|
|
49
|
+
currencyClass = currency.tokenClass();
|
|
50
|
+
currencyInstance = currency.tokenInstance();
|
|
51
|
+
launchpadGalaClass = launchpadgala.tokenClass();
|
|
52
|
+
|
|
53
|
+
launchpadGalaClass = plainToInstance(TokenClass, {
|
|
54
|
+
...launchpadgala.tokenClassPlain(),
|
|
55
|
+
decimals: 18
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
launchpadGalaInstance = launchpadgala.tokenInstance();
|
|
59
|
+
launchpadGalaClassKey = launchpadgala.tokenClassKey();
|
|
60
|
+
|
|
61
|
+
vaultAddress = asValidUserAlias(`service|${launchpadGalaClassKey.toStringKey()}$launchpad`);
|
|
62
|
+
|
|
63
|
+
// Initialize sale with manual values
|
|
64
|
+
sale = new LaunchpadSale(
|
|
65
|
+
vaultAddress,
|
|
66
|
+
launchpadGalaInstance.instanceKeyObj(),
|
|
67
|
+
undefined,
|
|
68
|
+
users.testUser1.identityKey
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
// Create sale balances - sale needs tokens to pay out
|
|
72
|
+
salelaunchpadGalaBalance = plainToInstance(TokenBalance, {
|
|
73
|
+
...launchpadgala.tokenBalance(),
|
|
74
|
+
owner: vaultAddress,
|
|
75
|
+
quantity: new BigNumber("1e+7")
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
saleCurrencyBalance = plainToInstance(TokenBalance, {
|
|
79
|
+
...currency.tokenBalance(),
|
|
80
|
+
owner: vaultAddress,
|
|
81
|
+
quantity: new BigNumber("1e+7")
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// Create user balances - user needs tokens to swap
|
|
85
|
+
userlaunchpadGalaBalance = plainToInstance(TokenBalance, {
|
|
86
|
+
...launchpadgala.tokenBalance(),
|
|
87
|
+
owner: users.testUser1.identityKey,
|
|
88
|
+
quantity: new BigNumber("1000000") // User has 10k launchpadGala tokens
|
|
89
|
+
});
|
|
90
|
+
userCurrencyBalance = plainToInstance(TokenBalance, {
|
|
91
|
+
...currency.tokenBalance(),
|
|
92
|
+
owner: users.testUser1.identityKey
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
test("User should be able to buy tokens with providing native gala , without fee configured", async () => {
|
|
97
|
+
//Given
|
|
98
|
+
const { ctx, contract } = fixture(LaunchpadContract)
|
|
99
|
+
.registeredUsers(users.testUser1)
|
|
100
|
+
.savedState(
|
|
101
|
+
currencyClass,
|
|
102
|
+
currencyInstance,
|
|
103
|
+
launchpadGalaClass,
|
|
104
|
+
launchpadGalaInstance,
|
|
105
|
+
sale,
|
|
106
|
+
salelaunchpadGalaBalance,
|
|
107
|
+
saleCurrencyBalance,
|
|
108
|
+
userlaunchpadGalaBalance,
|
|
109
|
+
userCurrencyBalance
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
const dto = new NativeTokenQuantityDto(vaultAddress, new BigNumber("150"));
|
|
113
|
+
|
|
114
|
+
dto.uniqueKey = randomUniqueKey();
|
|
115
|
+
dto.sign(users.testUser1.privateKey);
|
|
116
|
+
|
|
117
|
+
//When
|
|
118
|
+
const buyTokenRes = await contract.BuyWithNative(ctx, dto);
|
|
119
|
+
|
|
120
|
+
//Then
|
|
121
|
+
expect(buyTokenRes.Data).toMatchObject({
|
|
122
|
+
inputQuantity: "150",
|
|
123
|
+
totalFees: "0.00000000",
|
|
124
|
+
outputQuantity: "2101667.8890651635002",
|
|
125
|
+
tokenName: "AUTOMATEDTESTCOIN",
|
|
126
|
+
tradeType: "Buy",
|
|
127
|
+
vaultAddress: "service|GALA$Unit$none$none$launchpad",
|
|
128
|
+
userAddress: "client|testUser1",
|
|
129
|
+
isFinalized: false,
|
|
130
|
+
functionName: "BuyWithNative"
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
expect(buyTokenRes.Data?.inputQuantity).toEqual("150");
|
|
134
|
+
expect(buyTokenRes.Data?.outputQuantity).toEqual("2101667.8890651635002");
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
test("User should be able to buy tokens , fee configured check", async () => {
|
|
138
|
+
//Given
|
|
139
|
+
const launchpadConfig = new LaunchpadFeeConfig(users.testUser2.identityKey, Number("0.32"), [
|
|
140
|
+
users.testUser2.identityKey
|
|
141
|
+
]);
|
|
142
|
+
|
|
143
|
+
const { ctx, contract } = fixture(LaunchpadContract)
|
|
144
|
+
.registeredUsers(users.testUser1)
|
|
145
|
+
.savedState(
|
|
146
|
+
currencyClass,
|
|
147
|
+
currencyInstance,
|
|
148
|
+
launchpadGalaClass,
|
|
149
|
+
launchpadGalaInstance,
|
|
150
|
+
sale,
|
|
151
|
+
salelaunchpadGalaBalance,
|
|
152
|
+
saleCurrencyBalance,
|
|
153
|
+
userlaunchpadGalaBalance,
|
|
154
|
+
userCurrencyBalance,
|
|
155
|
+
launchpadConfig
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
const dto = new NativeTokenQuantityDto(vaultAddress, new BigNumber("1000"));
|
|
159
|
+
dto.uniqueKey = randomUniqueKey();
|
|
160
|
+
dto.sign(users.testUser1.privateKey);
|
|
161
|
+
|
|
162
|
+
//When
|
|
163
|
+
const buyTokenRes = await contract.BuyWithNative(ctx, dto);
|
|
164
|
+
|
|
165
|
+
//Then
|
|
166
|
+
expect(buyTokenRes.Data).toMatchObject({
|
|
167
|
+
inputQuantity: "1000",
|
|
168
|
+
totalFees: "320.00000000",
|
|
169
|
+
outputQuantity: "3663321.3628130557168",
|
|
170
|
+
tokenName: "AUTOMATEDTESTCOIN",
|
|
171
|
+
tradeType: "Buy",
|
|
172
|
+
vaultAddress: "service|GALA$Unit$none$none$launchpad",
|
|
173
|
+
userAddress: "client|testUser1",
|
|
174
|
+
isFinalized: false,
|
|
175
|
+
functionName: "BuyWithNative"
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
expect(buyTokenRes.Data?.totalFees).toEqual("320.00000000");
|
|
179
|
+
expect(buyTokenRes.Data?.inputQuantity).toEqual("1000");
|
|
180
|
+
expect(buyTokenRes.Data?.outputQuantity).toEqual("3663321.3628130557168");
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
it("should throw error if user has insufficient funds incuding the transaction fees", async () => {
|
|
184
|
+
//Given
|
|
185
|
+
const launchpadConfig = new LaunchpadFeeConfig(users.testUser2.identityKey, Number("0.32"), [
|
|
186
|
+
users.testUser2.identityKey
|
|
187
|
+
]);
|
|
188
|
+
|
|
189
|
+
const { ctx, contract } = fixture(LaunchpadContract)
|
|
190
|
+
.registeredUsers(users.testUser1)
|
|
191
|
+
.savedState(
|
|
192
|
+
currencyClass,
|
|
193
|
+
currencyInstance,
|
|
194
|
+
launchpadGalaClass,
|
|
195
|
+
launchpadGalaInstance,
|
|
196
|
+
sale,
|
|
197
|
+
salelaunchpadGalaBalance,
|
|
198
|
+
saleCurrencyBalance,
|
|
199
|
+
userlaunchpadGalaBalance,
|
|
200
|
+
userCurrencyBalance,
|
|
201
|
+
launchpadConfig
|
|
202
|
+
);
|
|
203
|
+
|
|
204
|
+
const dto = new NativeTokenQuantityDto(vaultAddress, new BigNumber("10000000"));
|
|
205
|
+
|
|
206
|
+
dto.uniqueKey = randomUniqueKey();
|
|
207
|
+
dto.sign(users.testUser1.privateKey);
|
|
208
|
+
|
|
209
|
+
//When
|
|
210
|
+
const buyTokenRes = await contract.BuyWithNative(ctx, dto);
|
|
211
|
+
|
|
212
|
+
//Then
|
|
213
|
+
expect(buyTokenRes).toEqual(
|
|
214
|
+
GalaChainResponse.Error(
|
|
215
|
+
new ValidationFailedError(
|
|
216
|
+
"Insufficient balance: Total amount required including fee is 2166101.31430784"
|
|
217
|
+
)
|
|
218
|
+
)
|
|
219
|
+
);
|
|
220
|
+
});
|
|
221
|
+
});
|
|
@@ -12,7 +12,14 @@
|
|
|
12
12
|
* See the License for the specific language governing permissions and
|
|
13
13
|
* limitations under the License.
|
|
14
14
|
*/
|
|
15
|
-
import {
|
|
15
|
+
import { ValidationFailedError } from "@gala-chain/api";
|
|
16
|
+
import {
|
|
17
|
+
GalaChainContext,
|
|
18
|
+
fetchOrCreateBalance,
|
|
19
|
+
fetchTokenClass,
|
|
20
|
+
putChainObject,
|
|
21
|
+
transferToken
|
|
22
|
+
} from "@gala-chain/chaincode";
|
|
16
23
|
import BigNumber from "bignumber.js";
|
|
17
24
|
|
|
18
25
|
import { ExactTokenQuantityDto, LaunchpadSale, NativeTokenQuantityDto, TradeResDto } from "../../api/types";
|
|
@@ -79,13 +86,22 @@ export async function buyWithNative(
|
|
|
79
86
|
// Check for slippage condition
|
|
80
87
|
if (buyTokenDTO.expectedToken && buyTokenDTO.expectedToken.comparedTo(tokensToBuy) > 0) {
|
|
81
88
|
throw new SlippageToleranceExceededError(
|
|
82
|
-
"Tokens expected from this operation are more than the
|
|
89
|
+
"Tokens expected from this operation are more than the actual amount that will be provided."
|
|
83
90
|
);
|
|
84
91
|
}
|
|
85
92
|
|
|
86
93
|
// Transfer transaction fees to launchpad fee address
|
|
87
94
|
const launchpadFeeAddressConfiguration = await fetchLaunchpadFeeAddress(ctx);
|
|
88
95
|
if (launchpadFeeAddressConfiguration && transactionFees) {
|
|
96
|
+
const totalRequired = new BigNumber(buyTokenDTO.nativeTokenQuantity).plus(transactionFees);
|
|
97
|
+
|
|
98
|
+
const buyerBalance = await fetchOrCreateBalance(ctx, ctx.callingUser, sale.nativeToken);
|
|
99
|
+
if (buyerBalance.getQuantityTotal().lt(totalRequired)) {
|
|
100
|
+
throw new ValidationFailedError(
|
|
101
|
+
`Insufficient balance: Total amount required including fee is ${totalRequired}`
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
89
105
|
await transferToken(ctx, {
|
|
90
106
|
from: ctx.callingUser,
|
|
91
107
|
to: launchpadFeeAddressConfiguration.feeAddress,
|
|
@@ -138,6 +154,7 @@ export async function buyWithNative(
|
|
|
138
154
|
vaultAddress: buyTokenDTO.vaultAddress,
|
|
139
155
|
userAddress: ctx.callingUser,
|
|
140
156
|
isFinalized: isSaleFinalized,
|
|
141
|
-
functionName: "BuyWithNative"
|
|
157
|
+
functionName: "BuyWithNative",
|
|
158
|
+
uniqueKey: buyTokenDTO.uniqueKey
|
|
142
159
|
};
|
|
143
160
|
}
|