diff --git a/.gitignore b/.gitignore index 9e1c819..868b8fa 100644 --- a/.gitignore +++ b/.gitignore @@ -3,5 +3,7 @@ # Dependency directory node_modules/ +locklift.config.js + # Byte-compiled / optimized / DLL files __pycache__/ \ No newline at end of file diff --git a/demo/BulkMint/locklift.config.js b/demo/BulkMint/locklift.config.template.js similarity index 100% rename from demo/BulkMint/locklift.config.js rename to demo/BulkMint/locklift.config.template.js diff --git a/demo/Farming/.gitignore b/demo/Farming/.gitignore new file mode 100644 index 0000000..3833ad9 --- /dev/null +++ b/demo/Farming/.gitignore @@ -0,0 +1,11 @@ +*.code + +# Dependency directory +node_modules/ + +locklift.config.ts + +# Byte-compiled / optimized / DLL files +__pycache__/ + +.prettierrc \ No newline at end of file diff --git a/demo/Farming/build/Collection.abi.json b/demo/Farming/build/Collection.abi.json new file mode 100644 index 0000000..d9c6097 --- /dev/null +++ b/demo/Farming/build/Collection.abi.json @@ -0,0 +1,141 @@ +{ + "ABI version": 2, + "version": "2.2", + "header": ["pubkey", "time", "expire"], + "functions": [ + { + "name": "constructor", + "inputs": [ + {"name":"codeNft","type":"cell"}, + {"name":"ownerPubkey","type":"uint256"} + ], + "outputs": [ + ] + }, + { + "name": "mintNft", + "inputs": [ + ], + "outputs": [ + ] + }, + { + "name": "setRemainOnNft", + "inputs": [ + {"name":"remainOnNft","type":"uint128"} + ], + "outputs": [ + ] + }, + { + "name": "owner", + "inputs": [ + {"name":"answerId","type":"uint32"} + ], + "outputs": [ + {"name":"pubkey","type":"uint256"} + ] + }, + { + "name": "transferOwnership", + "inputs": [ + {"name":"newOwner","type":"uint256"} + ], + "outputs": [ + ] + }, + { + "name": "totalSupply", + "inputs": [ + {"name":"answerId","type":"uint32"} + ], + "outputs": [ + {"name":"count","type":"uint128"} + ] + }, + { + "name": "nftCode", + "inputs": [ + {"name":"answerId","type":"uint32"} + ], + "outputs": [ + {"name":"code","type":"cell"} + ] + }, + { + "name": "nftCodeHash", + "inputs": [ + {"name":"answerId","type":"uint32"} + ], + "outputs": [ + {"name":"codeHash","type":"uint256"} + ] + }, + { + "name": "nftAddress", + "inputs": [ + {"name":"answerId","type":"uint32"}, + {"name":"id","type":"uint256"} + ], + "outputs": [ + {"name":"nft","type":"address"} + ] + }, + { + "name": "supportsInterface", + "inputs": [ + {"name":"answerId","type":"uint32"}, + {"name":"interfaceID","type":"uint32"} + ], + "outputs": [ + {"name":"value0","type":"bool"} + ] + } + ], + "data": [ + ], + "events": [ + { + "name": "OwnershipTransferred", + "inputs": [ + {"name":"oldOwner","type":"uint256"}, + {"name":"newOwner","type":"uint256"} + ], + "outputs": [ + ] + }, + { + "name": "NftCreated", + "inputs": [ + {"name":"id","type":"uint256"}, + {"name":"nft","type":"address"}, + {"name":"owner","type":"address"}, + {"name":"manager","type":"address"}, + {"name":"creator","type":"address"} + ], + "outputs": [ + ] + }, + { + "name": "NftBurned", + "inputs": [ + {"name":"id","type":"uint256"}, + {"name":"nft","type":"address"}, + {"name":"owner","type":"address"}, + {"name":"manager","type":"address"} + ], + "outputs": [ + ] + } + ], + "fields": [ + {"name":"_pubkey","type":"uint256"}, + {"name":"_timestamp","type":"uint64"}, + {"name":"_constructorFlag","type":"bool"}, + {"name":"_supportedInterfaces","type":"optional(cell)"}, + {"name":"_codeNft","type":"cell"}, + {"name":"_totalSupply","type":"uint128"}, + {"name":"_owner","type":"uint256"}, + {"name":"_remainOnNft","type":"uint128"} + ] +} diff --git a/demo/Farming/build/Collection.base64 b/demo/Farming/build/Collection.base64 new file mode 100644 index 0000000..0106554 --- /dev/null +++ b/demo/Farming/build/Collection.base64 @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/demo/Farming/build/Collection.tvc b/demo/Farming/build/Collection.tvc new file mode 100644 index 0000000..9378c26 Binary files /dev/null and b/demo/Farming/build/Collection.tvc differ diff --git a/demo/Farming/build/FarmingPool.abi.json b/demo/Farming/build/FarmingPool.abi.json new file mode 100644 index 0000000..7f26b19 --- /dev/null +++ b/demo/Farming/build/FarmingPool.abi.json @@ -0,0 +1,286 @@ +{ + "ABI version": 2, + "version": "2.2", + "header": ["pubkey", "time", "expire"], + "functions": [ + { + "name": "constructor", + "inputs": [ + {"name":"owner","type":"address"}, + {"name":"collection","type":"address"}, + {"name":"rewardTokenRoot","type":"address"}, + {"name":"codeNft","type":"cell"}, + {"name":"codeUserData","type":"cell"}, + {"name":"farmStartTime","type":"uint32"}, + {"name":"rewardPerSecond","type":"uint128"}, + {"name":"vestingPeriod","type":"uint32"}, + {"name":"vestingRatio","type":"uint32"} + ], + "outputs": [ + ] + }, + { + "name": "receiveTokenWalletAddress", + "inputs": [ + {"name":"wallet","type":"address"} + ], + "outputs": [ + ] + }, + { + "name": "onAcceptTokensTransfer", + "inputs": [ + {"name":"tokenRoot","type":"address"}, + {"name":"amount","type":"uint128"}, + {"name":"sender","type":"address"}, + {"name":"senderWallet","type":"address"}, + {"name":"remainingGasTo","type":"address"}, + {"name":"payload","type":"cell"} + ], + "outputs": [ + ] + }, + { + "name": "onNftChangeManager", + "inputs": [ + {"name":"id","type":"uint256"}, + {"name":"owner","type":"address"}, + {"name":"oldManager","type":"address"}, + {"name":"newManager","type":"address"}, + {"name":"collection","type":"address"}, + {"name":"sendGasTo","type":"address"}, + {"name":"payload","type":"cell"} + ], + "outputs": [ + ] + }, + { + "name": "finishDeposit", + "inputs": [ + {"name":"depositNonce","type":"uint64"}, + {"name":"vested","type":"uint128"} + ], + "outputs": [ + ] + }, + { + "name": "finishWithdraw", + "inputs": [ + {"name":"user","type":"address"}, + {"name":"vested","type":"uint128"}, + {"name":"sendGasTo","type":"address"}, + {"name":"nft","type":"address"} + ], + "outputs": [ + ] + }, + { + "name": "calculateRewardData", + "inputs": [ + ], + "outputs": [ + {"name":"lastRewardTime","type":"uint32"}, + {"name":"accRewardPerShare","type":"uint256"}, + {"name":"unclaimedReward","type":"uint128"} + ] + }, + { + "name": "setEndTime", + "inputs": [ + {"name":"farmEndTime","type":"uint32"}, + {"name":"sendGasTo","type":"address"} + ], + "outputs": [ + ] + }, + { + "name": "withdraw", + "inputs": [ + {"name":"nft","type":"address"}, + {"name":"sendGasTo","type":"address"} + ], + "outputs": [ + ] + }, + { + "name": "withdrawUnclaimed", + "inputs": [ + {"name":"to","type":"address"}, + {"name":"sendGasTo","type":"address"} + ], + "outputs": [ + ] + }, + { + "name": "claimRewardForUser", + "inputs": [ + {"name":"user","type":"address"}, + {"name":"sendGasTo","type":"address"} + ], + "outputs": [ + ] + }, + { + "name": "claimReward", + "inputs": [ + {"name":"sendGasTo","type":"address"} + ], + "outputs": [ + ] + }, + { + "name": "getUserDataAddress", + "inputs": [ + {"name":"answerId","type":"uint32"}, + {"name":"user","type":"address"} + ], + "outputs": [ + {"name":"value0","type":"address"} + ] + }, + { + "name": "getInfo", + "inputs": [ + {"name":"answerId","type":"uint32"} + ], + "outputs": [ + {"name":"active","type":"bool"}, + {"name":"totalDeposits","type":"uint128"}, + {"name":"farmStartTime","type":"uint32"}, + {"name":"farmEndTime","type":"uint32"}, + {"name":"rewardPerSecond","type":"uint128"}, + {"name":"lastRewardTime","type":"uint32"}, + {"name":"accRewardPerShare","type":"uint256"}, + {"name":"unclaimedReward","type":"uint128"}, + {"name":"vestingPeriod","type":"uint32"}, + {"name":"vestingRatio","type":"uint32"}, + {"name":"rewardTokenRoot","type":"address"}, + {"name":"rewardTokenWallet","type":"address"}, + {"name":"rewardTokenWalletBalance","type":"uint128"} + ] + }, + { + "name": "dummy", + "inputs": [ + {"name":"user_wallet","type":"address"} + ], + "outputs": [ + ] + }, + { + "name": "supportsInterface", + "inputs": [ + {"name":"answerId","type":"uint32"}, + {"name":"interfaceID","type":"uint32"} + ], + "outputs": [ + {"name":"value0","type":"bool"} + ] + }, + { + "name": "owner", + "inputs": [ + ], + "outputs": [ + {"name":"owner","type":"address"} + ] + }, + { + "name": "transferOwnership", + "inputs": [ + {"name":"newOwner","type":"address"} + ], + "outputs": [ + ] + } + ], + "data": [ + ], + "events": [ + { + "name": "RewardDeposit", + "inputs": [ + {"name":"tokenRoot","type":"address"}, + {"name":"amount","type":"uint128"} + ], + "outputs": [ + ] + }, + { + "name": "Deposit", + "inputs": [ + {"name":"depositNonce","type":"uint64"}, + {"name":"user","type":"address"}, + {"name":"nft","type":"address"}, + {"name":"reward","type":"uint128"}, + {"name":"rewardDebt","type":"uint128"} + ], + "outputs": [ + ] + }, + { + "name": "Withdraw", + "inputs": [ + {"name":"user","type":"address"}, + {"name":"nft","type":"address"}, + {"name":"reward","type":"uint128"}, + {"name":"reward_debt","type":"uint128"} + ], + "outputs": [ + ] + }, + { + "name": "Claim", + "inputs": [ + {"name":"user","type":"address"}, + {"name":"reward","type":"uint128"}, + {"name":"reward_debt","type":"uint128"} + ], + "outputs": [ + ] + }, + { + "name": "FarmEndTimeSet", + "inputs": [ + {"name":"time","type":"uint32"} + ], + "outputs": [ + ] + }, + { + "name": "OwnershipTransferred", + "inputs": [ + {"name":"oldOwner","type":"address"}, + {"name":"newOwner","type":"address"} + ], + "outputs": [ + ] + } + ], + "fields": [ + {"name":"_pubkey","type":"uint256"}, + {"name":"_timestamp","type":"uint64"}, + {"name":"_constructorFlag","type":"bool"}, + {"name":"_checkList","type":"uint8"}, + {"name":"_owner","type":"address"}, + {"name":"_supportedInterfaces","type":"optional(cell)"}, + {"name":"_rewardTokenRoot","type":"address"}, + {"name":"_rewardTokenWallet","type":"address"}, + {"name":"_rewardTokenWalletBalance","type":"uint128"}, + {"name":"_collection","type":"address"}, + {"name":"_codeNft","type":"cell"}, + {"name":"_codeUserData","type":"cell"}, + {"name":"_active","type":"bool"}, + {"name":"_totalDeposits","type":"uint128"}, + {"name":"_depositNonce","type":"uint64"}, + {"components":[{"name":"nft","type":"address"},{"name":"owner","type":"address"},{"name":"sendGasTo","type":"address"}],"name":"_deposits","type":"map(uint64,tuple)"}, + {"name":"_farmStartTime","type":"uint32"}, + {"name":"_farmEndTime","type":"uint32"}, + {"name":"_rewardPerSecond","type":"uint128"}, + {"name":"_lastRewardTime","type":"uint32"}, + {"name":"_accRewardPerShare","type":"uint256"}, + {"name":"_unclaimedReward","type":"uint128"}, + {"name":"_vestingPeriod","type":"uint32"}, + {"name":"_vestingRatio","type":"uint32"} + ] +} diff --git a/demo/Farming/build/FarmingPool.base64 b/demo/Farming/build/FarmingPool.base64 new file mode 100644 index 0000000..f034a29 --- /dev/null +++ b/demo/Farming/build/FarmingPool.base64 @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/demo/Farming/build/FarmingPool.tvc b/demo/Farming/build/FarmingPool.tvc new file mode 100644 index 0000000..cd1af29 Binary files /dev/null and b/demo/Farming/build/FarmingPool.tvc differ diff --git a/demo/Farming/build/NFTFarming.abi.json b/demo/Farming/build/NFTFarming.abi.json deleted file mode 100644 index 8ef3dd5..0000000 --- a/demo/Farming/build/NFTFarming.abi.json +++ /dev/null @@ -1,182 +0,0 @@ -{ - "ABI version": 2, - "version": "2.2", - "header": ["pubkey", "time", "expire"], - "functions": [ - { - "name": "constructor", - "inputs": [ - {"name":"owner","type":"address"}, - {"name":"collection","type":"address"}, - {"name":"rewardTokenRoot","type":"address"}, - {"name":"codeNft","type":"cell"}, - {"name":"lockPeriod","type":"uint128"}, - {"name":"farmStartTime","type":"uint128"}, - {"name":"rewardPerSecond","type":"uint128"} - ], - "outputs": [ - ] - }, - { - "name": "receiveTokenWalletAddress", - "inputs": [ - {"name":"wallet","type":"address"} - ], - "outputs": [ - ] - }, - { - "name": "onNftChangeManager", - "inputs": [ - {"name":"id","type":"uint256"}, - {"name":"owner","type":"address"}, - {"name":"oldManager","type":"address"}, - {"name":"newManager","type":"address"}, - {"name":"collection","type":"address"}, - {"name":"sendGasTo","type":"address"}, - {"name":"payload","type":"cell"} - ], - "outputs": [ - ] - }, - { - "name": "onAcceptTokensTransfer", - "inputs": [ - {"name":"tokenRoot","type":"address"}, - {"name":"amount","type":"uint128"}, - {"name":"sender","type":"address"}, - {"name":"senderWallet","type":"address"}, - {"name":"remainingGasTo","type":"address"}, - {"name":"payload","type":"cell"} - ], - "outputs": [ - ] - }, - { - "name": "finishDeposit", - "inputs": [ - {"name":"nft","type":"address"} - ], - "outputs": [ - ] - }, - { - "name": "claimReward", - "inputs": [ - {"name":"amount","type":"uint128"} - ], - "outputs": [ - ] - }, - { - "name": "calculateRewardData", - "inputs": [ - {"name":"answerId","type":"uint32"} - ], - "outputs": [ - {"name":"lastRewardTime","type":"uint128"}, - {"name":"accRewardPerShare","type":"uint128"} - ] - }, - { - "name": "setRewardPerSecond", - "inputs": [ - {"name":"rewardPerSecond","type":"uint128"} - ], - "outputs": [ - ] - }, - { - "name": "getDetails", - "inputs": [ - {"name":"answerId","type":"uint32"} - ], - "outputs": [ - {"name":"active","type":"bool"}, - {"name":"collection","type":"address"}, - {"name":"rewardTokenRoot","type":"address"}, - {"name":"rewardTokenWallet","type":"address"}, - {"name":"rewardTokenWalletBalance","type":"uint128"}, - {"name":"farmStartTime","type":"uint128"}, - {"name":"rewardPerSecond","type":"uint128"}, - {"name":"lockPeriod","type":"uint128"}, - {"name":"lastRewardTime","type":"uint128"}, - {"name":"accRewardPerShare","type":"uint128"} - ] - }, - { - "name": "owner", - "inputs": [ - ], - "outputs": [ - {"name":"owner","type":"address"} - ] - }, - { - "name": "transferOwnership", - "inputs": [ - {"name":"newOwner","type":"address"} - ], - "outputs": [ - ] - }, - { - "name": "_depositsNum", - "inputs": [ - ], - "outputs": [ - {"name":"_depositsNum","type":"uint128"} - ] - }, - { - "name": "_deposits", - "inputs": [ - ], - "outputs": [ - {"components":[{"name":"depositor","type":"address"},{"name":"sendGasTo","type":"address"},{"name":"startDepositTime","type":"uint256"}],"name":"_deposits","type":"map(address,tuple)"} - ] - }, - { - "name": "_balances", - "inputs": [ - ], - "outputs": [ - {"name":"_balances","type":"map(address,uint128)"} - ] - } - ], - "data": [ - ], - "events": [ - { - "name": "OwnershipTransferred", - "inputs": [ - {"name":"oldOwner","type":"address"}, - {"name":"newOwner","type":"address"} - ], - "outputs": [ - ] - } - ], - "fields": [ - {"name":"_pubkey","type":"uint256"}, - {"name":"_timestamp","type":"uint64"}, - {"name":"_constructorFlag","type":"bool"}, - {"name":"_checkList","type":"uint8"}, - {"name":"_owner","type":"address"}, - {"name":"_active","type":"bool"}, - {"name":"_collection","type":"address"}, - {"name":"_codeNft","type":"cell"}, - {"name":"_rewardTokenRoot","type":"address"}, - {"name":"_rewardTokenWallet","type":"address"}, - {"name":"_rewardTokenWalletBalance","type":"uint128"}, - {"name":"_farmStartTime","type":"uint128"}, - {"name":"_rewardPerSecond","type":"uint128"}, - {"name":"_lockPeriod","type":"uint128"}, - {"name":"_lastRewardTime","type":"uint128"}, - {"name":"_accRewardPerShare","type":"uint128"}, - {"name":"_depositsNum","type":"uint128"}, - {"components":[{"name":"depositor","type":"address"},{"name":"sendGasTo","type":"address"},{"name":"startDepositTime","type":"uint256"}],"name":"_deposits","type":"map(address,tuple)"}, - {"name":"_balances","type":"map(address,uint128)"} - ] -} diff --git a/demo/Farming/build/NFTFarming.base64 b/demo/Farming/build/NFTFarming.base64 deleted file mode 100644 index 08042fc..0000000 --- a/demo/Farming/build/NFTFarming.base64 +++ /dev/null @@ -1,55 +0,0 @@ -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 diff --git a/demo/Farming/build/NFTFarming.tvc b/demo/Farming/build/NFTFarming.tvc deleted file mode 100644 index 00bf9df..0000000 Binary files a/demo/Farming/build/NFTFarming.tvc and /dev/null differ diff --git a/demo/Farming/build/Nft.abi.json b/demo/Farming/build/Nft.abi.json index 5b5e473..fb2a2cd 100644 --- a/demo/Farming/build/Nft.abi.json +++ b/demo/Farming/build/Nft.abi.json @@ -8,61 +8,11 @@ "inputs": [ {"name":"owner","type":"address"}, {"name":"sendGasTo","type":"address"}, - {"name":"remainOnNft","type":"uint128"}, - {"name":"json","type":"string"}, - {"name":"indexDeployValue","type":"uint128"}, - {"name":"indexDestroyValue","type":"uint128"}, - {"name":"codeIndex","type":"cell"} + {"name":"remainOnNft","type":"uint128"} ], "outputs": [ ] }, - { - "name": "burn", - "inputs": [ - {"name":"dest","type":"address"} - ], - "outputs": [ - ] - }, - { - "name": "indexCode", - "inputs": [ - {"name":"answerId","type":"uint32"} - ], - "outputs": [ - {"name":"code","type":"cell"} - ] - }, - { - "name": "indexCodeHash", - "inputs": [ - {"name":"answerId","type":"uint32"} - ], - "outputs": [ - {"name":"hash","type":"uint256"} - ] - }, - { - "name": "resolveIndex", - "inputs": [ - {"name":"answerId","type":"uint32"}, - {"name":"collection","type":"address"}, - {"name":"owner","type":"address"} - ], - "outputs": [ - {"name":"index","type":"address"} - ] - }, - { - "name": "getJson", - "inputs": [ - {"name":"answerId","type":"uint32"} - ], - "outputs": [ - {"name":"json","type":"string"} - ] - }, { "name": "transfer", "inputs": [ @@ -169,10 +119,6 @@ {"name":"_id","type":"uint256"}, {"name":"_collection","type":"address"}, {"name":"_owner","type":"address"}, - {"name":"_manager","type":"address"}, - {"name":"_json","type":"string"}, - {"name":"_indexDeployValue","type":"uint128"}, - {"name":"_indexDestroyValue","type":"uint128"}, - {"name":"_codeIndex","type":"cell"} + {"name":"_manager","type":"address"} ] } diff --git a/demo/Farming/build/Nft.base64 b/demo/Farming/build/Nft.base64 index 660c3ec..7a0627a 100644 --- a/demo/Farming/build/Nft.base64 +++ b/demo/Farming/build/Nft.base64 @@ -1,59 +1 @@ -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 \ No newline at end of file diff --git a/demo/Farming/build/Nft.tvc b/demo/Farming/build/Nft.tvc index a03beab..e196874 100644 Binary files a/demo/Farming/build/Nft.tvc and b/demo/Farming/build/Nft.tvc differ diff --git a/demo/Farming/build/TokenRoot.abi.json b/demo/Farming/build/TokenRoot.abi.json new file mode 100644 index 0000000..6b185eb --- /dev/null +++ b/demo/Farming/build/TokenRoot.abi.json @@ -0,0 +1,244 @@ +{ + "ABI version": 2, + "version": "2.2", + "header": ["pubkey", "time", "expire"], + "functions": [ + { + "name": "constructor", + "inputs": [ + {"name":"initialSupplyTo","type":"address"}, + {"name":"initialSupply","type":"uint128"}, + {"name":"deployWalletValue","type":"uint128"}, + {"name":"mintDisabled","type":"bool"}, + {"name":"burnByRootDisabled","type":"bool"}, + {"name":"burnPaused","type":"bool"}, + {"name":"remainingGasTo","type":"address"} + ], + "outputs": [ + ] + }, + { + "name": "supportsInterface", + "inputs": [ + {"name":"answerId","type":"uint32"}, + {"name":"interfaceID","type":"uint32"} + ], + "outputs": [ + {"name":"value0","type":"bool"} + ] + }, + { + "name": "disableMint", + "inputs": [ + {"name":"answerId","type":"uint32"} + ], + "outputs": [ + {"name":"value0","type":"bool"} + ] + }, + { + "name": "mintDisabled", + "inputs": [ + {"name":"answerId","type":"uint32"} + ], + "outputs": [ + {"name":"value0","type":"bool"} + ] + }, + { + "name": "burnTokens", + "inputs": [ + {"name":"amount","type":"uint128"}, + {"name":"walletOwner","type":"address"}, + {"name":"remainingGasTo","type":"address"}, + {"name":"callbackTo","type":"address"}, + {"name":"payload","type":"cell"} + ], + "outputs": [ + ] + }, + { + "name": "disableBurnByRoot", + "inputs": [ + {"name":"answerId","type":"uint32"} + ], + "outputs": [ + {"name":"value0","type":"bool"} + ] + }, + { + "name": "burnByRootDisabled", + "inputs": [ + {"name":"answerId","type":"uint32"} + ], + "outputs": [ + {"name":"value0","type":"bool"} + ] + }, + { + "name": "burnPaused", + "inputs": [ + {"name":"answerId","type":"uint32"} + ], + "outputs": [ + {"name":"value0","type":"bool"} + ] + }, + { + "name": "setBurnPaused", + "inputs": [ + {"name":"answerId","type":"uint32"}, + {"name":"paused","type":"bool"} + ], + "outputs": [ + {"name":"value0","type":"bool"} + ] + }, + { + "name": "transferOwnership", + "inputs": [ + {"name":"newOwner","type":"address"}, + {"name":"remainingGasTo","type":"address"}, + {"components":[{"name":"value","type":"uint128"},{"name":"payload","type":"cell"}],"name":"callbacks","type":"map(address,tuple)"} + ], + "outputs": [ + ] + }, + { + "name": "name", + "inputs": [ + {"name":"answerId","type":"uint32"} + ], + "outputs": [ + {"name":"value0","type":"string"} + ] + }, + { + "name": "symbol", + "inputs": [ + {"name":"answerId","type":"uint32"} + ], + "outputs": [ + {"name":"value0","type":"string"} + ] + }, + { + "name": "decimals", + "inputs": [ + {"name":"answerId","type":"uint32"} + ], + "outputs": [ + {"name":"value0","type":"uint8"} + ] + }, + { + "name": "totalSupply", + "inputs": [ + {"name":"answerId","type":"uint32"} + ], + "outputs": [ + {"name":"value0","type":"uint128"} + ] + }, + { + "name": "walletCode", + "inputs": [ + {"name":"answerId","type":"uint32"} + ], + "outputs": [ + {"name":"value0","type":"cell"} + ] + }, + { + "name": "rootOwner", + "inputs": [ + {"name":"answerId","type":"uint32"} + ], + "outputs": [ + {"name":"value0","type":"address"} + ] + }, + { + "name": "walletOf", + "inputs": [ + {"name":"answerId","type":"uint32"}, + {"name":"walletOwner","type":"address"} + ], + "outputs": [ + {"name":"value0","type":"address"} + ] + }, + { + "name": "deployWallet", + "inputs": [ + {"name":"answerId","type":"uint32"}, + {"name":"walletOwner","type":"address"}, + {"name":"deployWalletValue","type":"uint128"} + ], + "outputs": [ + {"name":"tokenWallet","type":"address"} + ] + }, + { + "name": "mint", + "inputs": [ + {"name":"amount","type":"uint128"}, + {"name":"recipient","type":"address"}, + {"name":"deployWalletValue","type":"uint128"}, + {"name":"remainingGasTo","type":"address"}, + {"name":"notify","type":"bool"}, + {"name":"payload","type":"cell"} + ], + "outputs": [ + ] + }, + { + "name": "acceptBurn", + "id": "0x192B51B1", + "inputs": [ + {"name":"amount","type":"uint128"}, + {"name":"walletOwner","type":"address"}, + {"name":"remainingGasTo","type":"address"}, + {"name":"callbackTo","type":"address"}, + {"name":"payload","type":"cell"} + ], + "outputs": [ + ] + }, + { + "name": "sendSurplusGas", + "inputs": [ + {"name":"to","type":"address"} + ], + "outputs": [ + ] + } + ], + "data": [ + {"key":1,"name":"name_","type":"string"}, + {"key":2,"name":"symbol_","type":"string"}, + {"key":3,"name":"decimals_","type":"uint8"}, + {"key":4,"name":"rootOwner_","type":"address"}, + {"key":5,"name":"walletCode_","type":"cell"}, + {"key":6,"name":"randomNonce_","type":"uint256"}, + {"key":7,"name":"deployer_","type":"address"} + ], + "events": [ + ], + "fields": [ + {"name":"_pubkey","type":"uint256"}, + {"name":"_timestamp","type":"uint64"}, + {"name":"_constructorFlag","type":"bool"}, + {"name":"name_","type":"string"}, + {"name":"symbol_","type":"string"}, + {"name":"decimals_","type":"uint8"}, + {"name":"rootOwner_","type":"address"}, + {"name":"walletCode_","type":"cell"}, + {"name":"totalSupply_","type":"uint128"}, + {"name":"burnPaused_","type":"bool"}, + {"name":"burnByRootDisabled_","type":"bool"}, + {"name":"mintDisabled_","type":"bool"}, + {"name":"randomNonce_","type":"uint256"}, + {"name":"deployer_","type":"address"} + ] +} diff --git a/demo/Farming/build/TokenRoot.base64 b/demo/Farming/build/TokenRoot.base64 new file mode 100644 index 0000000..4bfd331 --- /dev/null +++ b/demo/Farming/build/TokenRoot.base64 @@ -0,0 +1,81 @@ +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 diff --git a/demo/Farming/build/TokenRoot.tvc b/demo/Farming/build/TokenRoot.tvc new file mode 100644 index 0000000..0a4c30f Binary files /dev/null and b/demo/Farming/build/TokenRoot.tvc differ diff --git a/demo/Farming/build/TokenWallet.abi.json b/demo/Farming/build/TokenWallet.abi.json new file mode 100644 index 0000000..24f6394 --- /dev/null +++ b/demo/Farming/build/TokenWallet.abi.json @@ -0,0 +1,162 @@ +{ + "ABI version": 2, + "version": "2.2", + "header": ["pubkey", "time", "expire"], + "functions": [ + { + "name": "constructor", + "inputs": [ + ], + "outputs": [ + ] + }, + { + "name": "supportsInterface", + "inputs": [ + {"name":"answerId","type":"uint32"}, + {"name":"interfaceID","type":"uint32"} + ], + "outputs": [ + {"name":"value0","type":"bool"} + ] + }, + { + "name": "destroy", + "inputs": [ + {"name":"remainingGasTo","type":"address"} + ], + "outputs": [ + ] + }, + { + "name": "burnByRoot", + "inputs": [ + {"name":"amount","type":"uint128"}, + {"name":"remainingGasTo","type":"address"}, + {"name":"callbackTo","type":"address"}, + {"name":"payload","type":"cell"} + ], + "outputs": [ + ] + }, + { + "name": "burn", + "inputs": [ + {"name":"amount","type":"uint128"}, + {"name":"remainingGasTo","type":"address"}, + {"name":"callbackTo","type":"address"}, + {"name":"payload","type":"cell"} + ], + "outputs": [ + ] + }, + { + "name": "balance", + "inputs": [ + {"name":"answerId","type":"uint32"} + ], + "outputs": [ + {"name":"value0","type":"uint128"} + ] + }, + { + "name": "owner", + "inputs": [ + {"name":"answerId","type":"uint32"} + ], + "outputs": [ + {"name":"value0","type":"address"} + ] + }, + { + "name": "root", + "inputs": [ + {"name":"answerId","type":"uint32"} + ], + "outputs": [ + {"name":"value0","type":"address"} + ] + }, + { + "name": "walletCode", + "inputs": [ + {"name":"answerId","type":"uint32"} + ], + "outputs": [ + {"name":"value0","type":"cell"} + ] + }, + { + "name": "transfer", + "inputs": [ + {"name":"amount","type":"uint128"}, + {"name":"recipient","type":"address"}, + {"name":"deployWalletValue","type":"uint128"}, + {"name":"remainingGasTo","type":"address"}, + {"name":"notify","type":"bool"}, + {"name":"payload","type":"cell"} + ], + "outputs": [ + ] + }, + { + "name": "transferToWallet", + "inputs": [ + {"name":"amount","type":"uint128"}, + {"name":"recipientTokenWallet","type":"address"}, + {"name":"remainingGasTo","type":"address"}, + {"name":"notify","type":"bool"}, + {"name":"payload","type":"cell"} + ], + "outputs": [ + ] + }, + { + "name": "acceptTransfer", + "id": "0x67A0B95F", + "inputs": [ + {"name":"amount","type":"uint128"}, + {"name":"sender","type":"address"}, + {"name":"remainingGasTo","type":"address"}, + {"name":"notify","type":"bool"}, + {"name":"payload","type":"cell"} + ], + "outputs": [ + ] + }, + { + "name": "acceptMint", + "id": "0x4384F298", + "inputs": [ + {"name":"amount","type":"uint128"}, + {"name":"remainingGasTo","type":"address"}, + {"name":"notify","type":"bool"}, + {"name":"payload","type":"cell"} + ], + "outputs": [ + ] + }, + { + "name": "sendSurplusGas", + "inputs": [ + {"name":"to","type":"address"} + ], + "outputs": [ + ] + } + ], + "data": [ + {"key":1,"name":"root_","type":"address"}, + {"key":2,"name":"owner_","type":"address"} + ], + "events": [ + ], + "fields": [ + {"name":"_pubkey","type":"uint256"}, + {"name":"_timestamp","type":"uint64"}, + {"name":"_constructorFlag","type":"bool"}, + {"name":"root_","type":"address"}, + {"name":"owner_","type":"address"}, + {"name":"balance_","type":"uint128"} + ] +} diff --git a/demo/Farming/build/TokenWallet.base64 b/demo/Farming/build/TokenWallet.base64 new file mode 100644 index 0000000..404c348 --- /dev/null +++ b/demo/Farming/build/TokenWallet.base64 @@ -0,0 +1,50 @@ +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 +OzoAFHNvbCAwLjU3LjEAAAAMIPhh7R7Z diff --git a/demo/Farming/build/TokenWallet.tvc b/demo/Farming/build/TokenWallet.tvc new file mode 100644 index 0000000..1eb487d Binary files /dev/null and b/demo/Farming/build/TokenWallet.tvc differ diff --git a/demo/Farming/build/UserData.abi.json b/demo/Farming/build/UserData.abi.json new file mode 100644 index 0000000..fe8976b --- /dev/null +++ b/demo/Farming/build/UserData.abi.json @@ -0,0 +1,119 @@ +{ + "ABI version": 2, + "version": "2.2", + "header": ["pubkey", "time", "expire"], + "functions": [ + { + "name": "constructor", + "inputs": [ + {"name":"vestingPeriod","type":"uint32"}, + {"name":"vestingRatio","type":"uint32"} + ], + "outputs": [ + ] + }, + { + "name": "pendingReward", + "inputs": [ + {"name":"accRewardPerShare","type":"uint256"}, + {"name":"poolLastRewardTime","type":"uint32"}, + {"name":"farmEndTime","type":"uint32"} + ], + "outputs": [ + {"name":"entitled","type":"uint128"}, + {"name":"vested","type":"uint128"}, + {"name":"poolDebt","type":"uint128"}, + {"name":"vestingTime","type":"uint32"} + ] + }, + { + "name": "increasePoolDebt", + "inputs": [ + {"name":"poolDebt","type":"uint128"}, + {"name":"sendGasTo","type":"address"} + ], + "outputs": [ + ] + }, + { + "name": "processDeposit", + "inputs": [ + {"name":"depositNonce","type":"uint64"}, + {"name":"nft","type":"address"}, + {"name":"accRewardPerShare","type":"uint256"}, + {"name":"poolLastRewardTime","type":"uint32"}, + {"name":"farmEndTime","type":"uint32"} + ], + "outputs": [ + ] + }, + { + "name": "processWithdraw", + "inputs": [ + {"name":"nft","type":"address"}, + {"name":"accRewardPerShare","type":"uint256"}, + {"name":"poolLastRewardTime","type":"uint32"}, + {"name":"farmEndTime","type":"uint32"}, + {"name":"sendGasTo","type":"address"} + ], + "outputs": [ + ] + }, + { + "name": "processClaimReward", + "inputs": [ + {"name":"accRewardPerShare","type":"uint256"}, + {"name":"poolLastRewardTime","type":"uint32"}, + {"name":"farmEndTime","type":"uint32"}, + {"name":"sendGasTo","type":"address"} + ], + "outputs": [ + ] + }, + { + "name": "getInfo", + "inputs": [ + {"name":"answerId","type":"uint32"} + ], + "outputs": [ + {"name":"lastRewardTime","type":"uint32"}, + {"name":"vestingPeriod","type":"uint32"}, + {"name":"vestingRatio","type":"uint32"}, + {"name":"amount","type":"uint128"}, + {"name":"vestingTime","type":"uint32"}, + {"name":"rewardDebt","type":"uint128"}, + {"name":"entitled","type":"uint128"}, + {"name":"poolDebt","type":"uint128"} + ] + }, + { + "name": "_deposits", + "inputs": [ + ], + "outputs": [ + {"name":"_deposits","type":"address[]"} + ] + } + ], + "data": [ + {"key":1,"name":"_farmPool","type":"address"}, + {"key":2,"name":"_user","type":"address"} + ], + "events": [ + ], + "fields": [ + {"name":"_pubkey","type":"uint256"}, + {"name":"_timestamp","type":"uint64"}, + {"name":"_constructorFlag","type":"bool"}, + {"name":"_farmPool","type":"address"}, + {"name":"_user","type":"address"}, + {"name":"_lastRewardTime","type":"uint32"}, + {"name":"_vestingPeriod","type":"uint32"}, + {"name":"_vestingRatio","type":"uint32"}, + {"name":"_vestingTime","type":"uint32"}, + {"name":"_rewardDebt","type":"uint128"}, + {"name":"_entitled","type":"uint128"}, + {"name":"_poolDebt","type":"uint128"}, + {"name":"_deposits","type":"address[]"} + ] +} diff --git a/demo/Farming/build/UserData.base64 b/demo/Farming/build/UserData.base64 new file mode 100644 index 0000000..ec86550 --- /dev/null +++ b/demo/Farming/build/UserData.base64 @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/demo/Farming/build/UserData.tvc b/demo/Farming/build/UserData.tvc new file mode 100644 index 0000000..81e3d68 Binary files /dev/null and b/demo/Farming/build/UserData.tvc differ diff --git a/demo/Farming/build/Wallet.abi.json b/demo/Farming/build/Wallet.abi.json new file mode 100644 index 0000000..76452e6 --- /dev/null +++ b/demo/Farming/build/Wallet.abi.json @@ -0,0 +1,54 @@ +{ + "ABI version": 2, + "version": "2.2", + "header": ["pubkey", "time", "expire"], + "functions": [ + { + "name": "constructor", + "inputs": [ + ], + "outputs": [ + ] + }, + { + "name": "sendTransaction", + "inputs": [ + {"name":"dest","type":"address"}, + {"name":"value","type":"uint128"}, + {"name":"bounce","type":"bool"}, + {"name":"flags","type":"uint8"}, + {"name":"payload","type":"cell"} + ], + "outputs": [ + ] + }, + { + "name": "owner", + "inputs": [ + ], + "outputs": [ + {"name":"owner","type":"uint256"} + ] + }, + { + "name": "_randomNonce", + "inputs": [ + ], + "outputs": [ + {"name":"_randomNonce","type":"uint256"} + ] + } + ], + "data": [ + {"key":1,"name":"_randomNonce","type":"uint256"} + ], + "events": [ + ], + "fields": [ + {"name":"_pubkey","type":"uint256"}, + {"name":"_timestamp","type":"uint64"}, + {"name":"_constructorFlag","type":"bool"}, + {"name":"owner","type":"uint256"}, + {"name":"_randomNonce","type":"uint256"} + ] +} diff --git a/demo/Farming/build/Wallet.base64 b/demo/Farming/build/Wallet.base64 new file mode 100644 index 0000000..409c702 --- /dev/null +++ b/demo/Farming/build/Wallet.base64 @@ -0,0 +1 @@ +te6ccgECFQEAAnIAAgE0AwEBAcACAEPQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgBCSK7VMg4wMgwP/jAiDA/uMC8gsSBQQUArztRNDXScMB+GYh2zzTAAGOHIMI1xgg+QEB0wABlNP/AwGTAvhC4iD4ZfkQ8qiV0wAB8nri0z8B+EMhufK0IPgjgQPoqIIIG3dAoLnytPhj0x8B+CO88rnTHwHbPPI8CgYDSu1E0NdJwwH4ZiLQ1wsDqTgA3CHHAOMCIdcNH/K8IeMDAds88jwREQYEUCCCEBF46b264wIgghA7UzMfuuMCIIIQTO5kbLrjAiCCEGi1Xz+64wIPDgsHA1Iw+EJu4wD4RvJz0fhFIG6SMHDe+EK68uH0+AD4RSBukjBw3ts82zzyAAoJCAAs+Ev4SvhD+ELIy//LP8+Dy//L/8ntVAAE+GoBYu1E0NdJwgGOJnDtRND0BXBxIoBA9A5vkZPXC//e+Gv4aoBA9A7yvdcL//hicPhj4w0QA0Iw+Eby4Ez4Qm7jACGT1NHQ3vpA03/SANMH1NHbPOMA8gAQDQwAKO1E0NP/0z8x+ENYyMv/yz/Oye1UAFT4RSBukjBw3vhKuvLh9fgAVQJVEsjPhYDKAM+EQM4B+gJxzwtqzMkB+wABUDDR2zz4SyGOHI0EcAAAAAAAAAAAAAAAAC7UzMfgyM7L/8lw+wDe8gAQAVAw0ds8+EohjhyNBHAAAAAAAAAAAAAAAAAkXjpvYMjOy//JcPsA3vIAEAAu7UTQ0//TP9MAMdP/0//R+Gv4avhj+GIACvhG8uBMAgr0pCD0oRQTABRzb2wgMC42MS4yAAA= \ No newline at end of file diff --git a/demo/Farming/build/Wallet.tvc b/demo/Farming/build/Wallet.tvc new file mode 100644 index 0000000..3f5dfee Binary files /dev/null and b/demo/Farming/build/Wallet.tvc differ diff --git a/demo/Farming/build/factorySource.ts b/demo/Farming/build/factorySource.ts new file mode 100644 index 0000000..aedce14 --- /dev/null +++ b/demo/Farming/build/factorySource.ts @@ -0,0 +1,26 @@ +const collectionAbi = {"ABIversion":2,"version":"2.2","header":["pubkey","time","expire"],"functions":[{"name":"constructor","inputs":[{"name":"codeNft","type":"cell"},{"name":"ownerPubkey","type":"uint256"}],"outputs":[]},{"name":"mintNft","inputs":[],"outputs":[]},{"name":"setRemainOnNft","inputs":[{"name":"remainOnNft","type":"uint128"}],"outputs":[]},{"name":"owner","inputs":[{"name":"answerId","type":"uint32"}],"outputs":[{"name":"pubkey","type":"uint256"}]},{"name":"transferOwnership","inputs":[{"name":"newOwner","type":"uint256"}],"outputs":[]},{"name":"totalSupply","inputs":[{"name":"answerId","type":"uint32"}],"outputs":[{"name":"count","type":"uint128"}]},{"name":"nftCode","inputs":[{"name":"answerId","type":"uint32"}],"outputs":[{"name":"code","type":"cell"}]},{"name":"nftCodeHash","inputs":[{"name":"answerId","type":"uint32"}],"outputs":[{"name":"codeHash","type":"uint256"}]},{"name":"nftAddress","inputs":[{"name":"answerId","type":"uint32"},{"name":"id","type":"uint256"}],"outputs":[{"name":"nft","type":"address"}]},{"name":"supportsInterface","inputs":[{"name":"answerId","type":"uint32"},{"name":"interfaceID","type":"uint32"}],"outputs":[{"name":"value0","type":"bool"}]}],"data":[],"events":[{"name":"OwnershipTransferred","inputs":[{"name":"oldOwner","type":"uint256"},{"name":"newOwner","type":"uint256"}],"outputs":[]},{"name":"NftCreated","inputs":[{"name":"id","type":"uint256"},{"name":"nft","type":"address"},{"name":"owner","type":"address"},{"name":"manager","type":"address"},{"name":"creator","type":"address"}],"outputs":[]},{"name":"NftBurned","inputs":[{"name":"id","type":"uint256"},{"name":"nft","type":"address"},{"name":"owner","type":"address"},{"name":"manager","type":"address"}],"outputs":[]}],"fields":[{"name":"_pubkey","type":"uint256"},{"name":"_timestamp","type":"uint64"},{"name":"_constructorFlag","type":"bool"},{"name":"_supportedInterfaces","type":"optional(cell)"},{"name":"_codeNft","type":"cell"},{"name":"_totalSupply","type":"uint128"},{"name":"_owner","type":"uint256"},{"name":"_remainOnNft","type":"uint128"}]} as const +const farmingPoolAbi = {"ABIversion":2,"version":"2.2","header":["pubkey","time","expire"],"functions":[{"name":"constructor","inputs":[{"name":"owner","type":"address"},{"name":"collection","type":"address"},{"name":"rewardTokenRoot","type":"address"},{"name":"codeNft","type":"cell"},{"name":"codeUserData","type":"cell"},{"name":"farmStartTime","type":"uint32"},{"name":"rewardPerSecond","type":"uint128"},{"name":"vestingPeriod","type":"uint32"},{"name":"vestingRatio","type":"uint32"}],"outputs":[]},{"name":"receiveTokenWalletAddress","inputs":[{"name":"wallet","type":"address"}],"outputs":[]},{"name":"onAcceptTokensTransfer","inputs":[{"name":"tokenRoot","type":"address"},{"name":"amount","type":"uint128"},{"name":"sender","type":"address"},{"name":"senderWallet","type":"address"},{"name":"remainingGasTo","type":"address"},{"name":"payload","type":"cell"}],"outputs":[]},{"name":"onNftChangeManager","inputs":[{"name":"id","type":"uint256"},{"name":"owner","type":"address"},{"name":"oldManager","type":"address"},{"name":"newManager","type":"address"},{"name":"collection","type":"address"},{"name":"sendGasTo","type":"address"},{"name":"payload","type":"cell"}],"outputs":[]},{"name":"finishDeposit","inputs":[{"name":"depositNonce","type":"uint64"},{"name":"vested","type":"uint128"}],"outputs":[]},{"name":"finishWithdraw","inputs":[{"name":"user","type":"address"},{"name":"vested","type":"uint128"},{"name":"sendGasTo","type":"address"},{"name":"nft","type":"address"}],"outputs":[]},{"name":"calculateRewardData","inputs":[],"outputs":[{"name":"lastRewardTime","type":"uint32"},{"name":"accRewardPerShare","type":"uint256"},{"name":"unclaimedReward","type":"uint128"}]},{"name":"setEndTime","inputs":[{"name":"farmEndTime","type":"uint32"},{"name":"sendGasTo","type":"address"}],"outputs":[]},{"name":"withdraw","inputs":[{"name":"nft","type":"address"},{"name":"sendGasTo","type":"address"}],"outputs":[]},{"name":"withdrawUnclaimed","inputs":[{"name":"to","type":"address"},{"name":"sendGasTo","type":"address"}],"outputs":[]},{"name":"claimRewardForUser","inputs":[{"name":"user","type":"address"},{"name":"sendGasTo","type":"address"}],"outputs":[]},{"name":"claimReward","inputs":[{"name":"sendGasTo","type":"address"}],"outputs":[]},{"name":"getUserDataAddress","inputs":[{"name":"answerId","type":"uint32"},{"name":"user","type":"address"}],"outputs":[{"name":"value0","type":"address"}]},{"name":"getInfo","inputs":[{"name":"answerId","type":"uint32"}],"outputs":[{"name":"active","type":"bool"},{"name":"totalDeposits","type":"uint128"},{"name":"farmStartTime","type":"uint32"},{"name":"farmEndTime","type":"uint32"},{"name":"rewardPerSecond","type":"uint128"},{"name":"lastRewardTime","type":"uint32"},{"name":"accRewardPerShare","type":"uint256"},{"name":"unclaimedReward","type":"uint128"},{"name":"vestingPeriod","type":"uint32"},{"name":"vestingRatio","type":"uint32"},{"name":"rewardTokenRoot","type":"address"},{"name":"rewardTokenWallet","type":"address"},{"name":"rewardTokenWalletBalance","type":"uint128"}]},{"name":"dummy","inputs":[{"name":"user_wallet","type":"address"}],"outputs":[]},{"name":"supportsInterface","inputs":[{"name":"answerId","type":"uint32"},{"name":"interfaceID","type":"uint32"}],"outputs":[{"name":"value0","type":"bool"}]},{"name":"owner","inputs":[],"outputs":[{"name":"owner","type":"address"}]},{"name":"transferOwnership","inputs":[{"name":"newOwner","type":"address"}],"outputs":[]}],"data":[],"events":[{"name":"RewardDeposit","inputs":[{"name":"tokenRoot","type":"address"},{"name":"amount","type":"uint128"}],"outputs":[]},{"name":"Deposit","inputs":[{"name":"depositNonce","type":"uint64"},{"name":"user","type":"address"},{"name":"nft","type":"address"},{"name":"reward","type":"uint128"},{"name":"rewardDebt","type":"uint128"}],"outputs":[]},{"name":"Withdraw","inputs":[{"name":"user","type":"address"},{"name":"nft","type":"address"},{"name":"reward","type":"uint128"},{"name":"reward_debt","type":"uint128"}],"outputs":[]},{"name":"Claim","inputs":[{"name":"user","type":"address"},{"name":"reward","type":"uint128"},{"name":"reward_debt","type":"uint128"}],"outputs":[]},{"name":"FarmEndTimeSet","inputs":[{"name":"time","type":"uint32"}],"outputs":[]},{"name":"OwnershipTransferred","inputs":[{"name":"oldOwner","type":"address"},{"name":"newOwner","type":"address"}],"outputs":[]}],"fields":[{"name":"_pubkey","type":"uint256"},{"name":"_timestamp","type":"uint64"},{"name":"_constructorFlag","type":"bool"},{"name":"_checkList","type":"uint8"},{"name":"_owner","type":"address"},{"name":"_supportedInterfaces","type":"optional(cell)"},{"name":"_rewardTokenRoot","type":"address"},{"name":"_rewardTokenWallet","type":"address"},{"name":"_rewardTokenWalletBalance","type":"uint128"},{"name":"_collection","type":"address"},{"name":"_codeNft","type":"cell"},{"name":"_codeUserData","type":"cell"},{"name":"_active","type":"bool"},{"name":"_totalDeposits","type":"uint128"},{"name":"_depositNonce","type":"uint64"},{"components":[{"name":"nft","type":"address"},{"name":"owner","type":"address"},{"name":"sendGasTo","type":"address"}],"name":"_deposits","type":"map(uint64,tuple)"},{"name":"_farmStartTime","type":"uint32"},{"name":"_farmEndTime","type":"uint32"},{"name":"_rewardPerSecond","type":"uint128"},{"name":"_lastRewardTime","type":"uint32"},{"name":"_accRewardPerShare","type":"uint256"},{"name":"_unclaimedReward","type":"uint128"},{"name":"_vestingPeriod","type":"uint32"},{"name":"_vestingRatio","type":"uint32"}]} as const +const nftAbi = {"ABIversion":2,"version":"2.2","header":["pubkey","time","expire"],"functions":[{"name":"constructor","inputs":[{"name":"owner","type":"address"},{"name":"sendGasTo","type":"address"},{"name":"remainOnNft","type":"uint128"}],"outputs":[]},{"name":"transfer","inputs":[{"name":"to","type":"address"},{"name":"sendGasTo","type":"address"},{"components":[{"name":"value","type":"uint128"},{"name":"payload","type":"cell"}],"name":"callbacks","type":"map(address,tuple)"}],"outputs":[]},{"name":"changeOwner","inputs":[{"name":"newOwner","type":"address"},{"name":"sendGasTo","type":"address"},{"components":[{"name":"value","type":"uint128"},{"name":"payload","type":"cell"}],"name":"callbacks","type":"map(address,tuple)"}],"outputs":[]},{"name":"changeManager","inputs":[{"name":"newManager","type":"address"},{"name":"sendGasTo","type":"address"},{"components":[{"name":"value","type":"uint128"},{"name":"payload","type":"cell"}],"name":"callbacks","type":"map(address,tuple)"}],"outputs":[]},{"name":"getInfo","inputs":[{"name":"answerId","type":"uint32"}],"outputs":[{"name":"id","type":"uint256"},{"name":"owner","type":"address"},{"name":"manager","type":"address"},{"name":"collection","type":"address"}]},{"name":"supportsInterface","inputs":[{"name":"answerId","type":"uint32"},{"name":"interfaceID","type":"uint32"}],"outputs":[{"name":"value0","type":"bool"}]}],"data":[{"key":1,"name":"_id","type":"uint256"}],"events":[{"name":"NftCreated","inputs":[{"name":"id","type":"uint256"},{"name":"owner","type":"address"},{"name":"manager","type":"address"},{"name":"collection","type":"address"}],"outputs":[]},{"name":"OwnerChanged","inputs":[{"name":"oldOwner","type":"address"},{"name":"newOwner","type":"address"}],"outputs":[]},{"name":"ManagerChanged","inputs":[{"name":"oldManager","type":"address"},{"name":"newManager","type":"address"}],"outputs":[]},{"name":"NftBurned","inputs":[{"name":"id","type":"uint256"},{"name":"owner","type":"address"},{"name":"manager","type":"address"},{"name":"collection","type":"address"}],"outputs":[]}],"fields":[{"name":"_pubkey","type":"uint256"},{"name":"_timestamp","type":"uint64"},{"name":"_constructorFlag","type":"bool"},{"name":"_supportedInterfaces","type":"optional(cell)"},{"name":"_id","type":"uint256"},{"name":"_collection","type":"address"},{"name":"_owner","type":"address"},{"name":"_manager","type":"address"}]} as const +const tokenRootAbi = {"ABIversion":2,"version":"2.2","header":["pubkey","time","expire"],"functions":[{"name":"constructor","inputs":[{"name":"initialSupplyTo","type":"address"},{"name":"initialSupply","type":"uint128"},{"name":"deployWalletValue","type":"uint128"},{"name":"mintDisabled","type":"bool"},{"name":"burnByRootDisabled","type":"bool"},{"name":"burnPaused","type":"bool"},{"name":"remainingGasTo","type":"address"}],"outputs":[]},{"name":"supportsInterface","inputs":[{"name":"answerId","type":"uint32"},{"name":"interfaceID","type":"uint32"}],"outputs":[{"name":"value0","type":"bool"}]},{"name":"disableMint","inputs":[{"name":"answerId","type":"uint32"}],"outputs":[{"name":"value0","type":"bool"}]},{"name":"mintDisabled","inputs":[{"name":"answerId","type":"uint32"}],"outputs":[{"name":"value0","type":"bool"}]},{"name":"burnTokens","inputs":[{"name":"amount","type":"uint128"},{"name":"walletOwner","type":"address"},{"name":"remainingGasTo","type":"address"},{"name":"callbackTo","type":"address"},{"name":"payload","type":"cell"}],"outputs":[]},{"name":"disableBurnByRoot","inputs":[{"name":"answerId","type":"uint32"}],"outputs":[{"name":"value0","type":"bool"}]},{"name":"burnByRootDisabled","inputs":[{"name":"answerId","type":"uint32"}],"outputs":[{"name":"value0","type":"bool"}]},{"name":"burnPaused","inputs":[{"name":"answerId","type":"uint32"}],"outputs":[{"name":"value0","type":"bool"}]},{"name":"setBurnPaused","inputs":[{"name":"answerId","type":"uint32"},{"name":"paused","type":"bool"}],"outputs":[{"name":"value0","type":"bool"}]},{"name":"transferOwnership","inputs":[{"name":"newOwner","type":"address"},{"name":"remainingGasTo","type":"address"},{"components":[{"name":"value","type":"uint128"},{"name":"payload","type":"cell"}],"name":"callbacks","type":"map(address,tuple)"}],"outputs":[]},{"name":"name","inputs":[{"name":"answerId","type":"uint32"}],"outputs":[{"name":"value0","type":"string"}]},{"name":"symbol","inputs":[{"name":"answerId","type":"uint32"}],"outputs":[{"name":"value0","type":"string"}]},{"name":"decimals","inputs":[{"name":"answerId","type":"uint32"}],"outputs":[{"name":"value0","type":"uint8"}]},{"name":"totalSupply","inputs":[{"name":"answerId","type":"uint32"}],"outputs":[{"name":"value0","type":"uint128"}]},{"name":"walletCode","inputs":[{"name":"answerId","type":"uint32"}],"outputs":[{"name":"value0","type":"cell"}]},{"name":"rootOwner","inputs":[{"name":"answerId","type":"uint32"}],"outputs":[{"name":"value0","type":"address"}]},{"name":"walletOf","inputs":[{"name":"answerId","type":"uint32"},{"name":"walletOwner","type":"address"}],"outputs":[{"name":"value0","type":"address"}]},{"name":"deployWallet","inputs":[{"name":"answerId","type":"uint32"},{"name":"walletOwner","type":"address"},{"name":"deployWalletValue","type":"uint128"}],"outputs":[{"name":"tokenWallet","type":"address"}]},{"name":"mint","inputs":[{"name":"amount","type":"uint128"},{"name":"recipient","type":"address"},{"name":"deployWalletValue","type":"uint128"},{"name":"remainingGasTo","type":"address"},{"name":"notify","type":"bool"},{"name":"payload","type":"cell"}],"outputs":[]},{"name":"acceptBurn","id":"0x192B51B1","inputs":[{"name":"amount","type":"uint128"},{"name":"walletOwner","type":"address"},{"name":"remainingGasTo","type":"address"},{"name":"callbackTo","type":"address"},{"name":"payload","type":"cell"}],"outputs":[]},{"name":"sendSurplusGas","inputs":[{"name":"to","type":"address"}],"outputs":[]}],"data":[{"key":1,"name":"name_","type":"string"},{"key":2,"name":"symbol_","type":"string"},{"key":3,"name":"decimals_","type":"uint8"},{"key":4,"name":"rootOwner_","type":"address"},{"key":5,"name":"walletCode_","type":"cell"},{"key":6,"name":"randomNonce_","type":"uint256"},{"key":7,"name":"deployer_","type":"address"}],"events":[],"fields":[{"name":"_pubkey","type":"uint256"},{"name":"_timestamp","type":"uint64"},{"name":"_constructorFlag","type":"bool"},{"name":"name_","type":"string"},{"name":"symbol_","type":"string"},{"name":"decimals_","type":"uint8"},{"name":"rootOwner_","type":"address"},{"name":"walletCode_","type":"cell"},{"name":"totalSupply_","type":"uint128"},{"name":"burnPaused_","type":"bool"},{"name":"burnByRootDisabled_","type":"bool"},{"name":"mintDisabled_","type":"bool"},{"name":"randomNonce_","type":"uint256"},{"name":"deployer_","type":"address"}]} as const +const tokenWalletAbi = {"ABIversion":2,"version":"2.2","header":["pubkey","time","expire"],"functions":[{"name":"constructor","inputs":[],"outputs":[]},{"name":"supportsInterface","inputs":[{"name":"answerId","type":"uint32"},{"name":"interfaceID","type":"uint32"}],"outputs":[{"name":"value0","type":"bool"}]},{"name":"destroy","inputs":[{"name":"remainingGasTo","type":"address"}],"outputs":[]},{"name":"burnByRoot","inputs":[{"name":"amount","type":"uint128"},{"name":"remainingGasTo","type":"address"},{"name":"callbackTo","type":"address"},{"name":"payload","type":"cell"}],"outputs":[]},{"name":"burn","inputs":[{"name":"amount","type":"uint128"},{"name":"remainingGasTo","type":"address"},{"name":"callbackTo","type":"address"},{"name":"payload","type":"cell"}],"outputs":[]},{"name":"balance","inputs":[{"name":"answerId","type":"uint32"}],"outputs":[{"name":"value0","type":"uint128"}]},{"name":"owner","inputs":[{"name":"answerId","type":"uint32"}],"outputs":[{"name":"value0","type":"address"}]},{"name":"root","inputs":[{"name":"answerId","type":"uint32"}],"outputs":[{"name":"value0","type":"address"}]},{"name":"walletCode","inputs":[{"name":"answerId","type":"uint32"}],"outputs":[{"name":"value0","type":"cell"}]},{"name":"transfer","inputs":[{"name":"amount","type":"uint128"},{"name":"recipient","type":"address"},{"name":"deployWalletValue","type":"uint128"},{"name":"remainingGasTo","type":"address"},{"name":"notify","type":"bool"},{"name":"payload","type":"cell"}],"outputs":[]},{"name":"transferToWallet","inputs":[{"name":"amount","type":"uint128"},{"name":"recipientTokenWallet","type":"address"},{"name":"remainingGasTo","type":"address"},{"name":"notify","type":"bool"},{"name":"payload","type":"cell"}],"outputs":[]},{"name":"acceptTransfer","id":"0x67A0B95F","inputs":[{"name":"amount","type":"uint128"},{"name":"sender","type":"address"},{"name":"remainingGasTo","type":"address"},{"name":"notify","type":"bool"},{"name":"payload","type":"cell"}],"outputs":[]},{"name":"acceptMint","id":"0x4384F298","inputs":[{"name":"amount","type":"uint128"},{"name":"remainingGasTo","type":"address"},{"name":"notify","type":"bool"},{"name":"payload","type":"cell"}],"outputs":[]},{"name":"sendSurplusGas","inputs":[{"name":"to","type":"address"}],"outputs":[]}],"data":[{"key":1,"name":"root_","type":"address"},{"key":2,"name":"owner_","type":"address"}],"events":[],"fields":[{"name":"_pubkey","type":"uint256"},{"name":"_timestamp","type":"uint64"},{"name":"_constructorFlag","type":"bool"},{"name":"root_","type":"address"},{"name":"owner_","type":"address"},{"name":"balance_","type":"uint128"}]} as const +const userDataAbi = {"ABIversion":2,"version":"2.2","header":["pubkey","time","expire"],"functions":[{"name":"constructor","inputs":[{"name":"vestingPeriod","type":"uint32"},{"name":"vestingRatio","type":"uint32"}],"outputs":[]},{"name":"pendingReward","inputs":[{"name":"accRewardPerShare","type":"uint256"},{"name":"poolLastRewardTime","type":"uint32"},{"name":"farmEndTime","type":"uint32"}],"outputs":[{"name":"entitled","type":"uint128"},{"name":"vested","type":"uint128"},{"name":"poolDebt","type":"uint128"},{"name":"vestingTime","type":"uint32"}]},{"name":"increasePoolDebt","inputs":[{"name":"poolDebt","type":"uint128"},{"name":"sendGasTo","type":"address"}],"outputs":[]},{"name":"processDeposit","inputs":[{"name":"depositNonce","type":"uint64"},{"name":"nft","type":"address"},{"name":"accRewardPerShare","type":"uint256"},{"name":"poolLastRewardTime","type":"uint32"},{"name":"farmEndTime","type":"uint32"}],"outputs":[]},{"name":"processWithdraw","inputs":[{"name":"nft","type":"address"},{"name":"accRewardPerShare","type":"uint256"},{"name":"poolLastRewardTime","type":"uint32"},{"name":"farmEndTime","type":"uint32"},{"name":"sendGasTo","type":"address"}],"outputs":[]},{"name":"processClaimReward","inputs":[{"name":"accRewardPerShare","type":"uint256"},{"name":"poolLastRewardTime","type":"uint32"},{"name":"farmEndTime","type":"uint32"},{"name":"sendGasTo","type":"address"}],"outputs":[]},{"name":"getInfo","inputs":[{"name":"answerId","type":"uint32"}],"outputs":[{"name":"lastRewardTime","type":"uint32"},{"name":"vestingPeriod","type":"uint32"},{"name":"vestingRatio","type":"uint32"},{"name":"amount","type":"uint128"},{"name":"vestingTime","type":"uint32"},{"name":"rewardDebt","type":"uint128"},{"name":"entitled","type":"uint128"},{"name":"poolDebt","type":"uint128"}]},{"name":"_deposits","inputs":[],"outputs":[{"name":"_deposits","type":"address[]"}]}],"data":[{"key":1,"name":"_farmPool","type":"address"},{"key":2,"name":"_user","type":"address"}],"events":[],"fields":[{"name":"_pubkey","type":"uint256"},{"name":"_timestamp","type":"uint64"},{"name":"_constructorFlag","type":"bool"},{"name":"_farmPool","type":"address"},{"name":"_user","type":"address"},{"name":"_lastRewardTime","type":"uint32"},{"name":"_vestingPeriod","type":"uint32"},{"name":"_vestingRatio","type":"uint32"},{"name":"_vestingTime","type":"uint32"},{"name":"_rewardDebt","type":"uint128"},{"name":"_entitled","type":"uint128"},{"name":"_poolDebt","type":"uint128"},{"name":"_deposits","type":"address[]"}]} as const +const walletAbi = {"ABIversion":2,"version":"2.2","header":["pubkey","time","expire"],"functions":[{"name":"constructor","inputs":[],"outputs":[]},{"name":"sendTransaction","inputs":[{"name":"dest","type":"address"},{"name":"value","type":"uint128"},{"name":"bounce","type":"bool"},{"name":"flags","type":"uint8"},{"name":"payload","type":"cell"}],"outputs":[]},{"name":"owner","inputs":[],"outputs":[{"name":"owner","type":"uint256"}]},{"name":"_randomNonce","inputs":[],"outputs":[{"name":"_randomNonce","type":"uint256"}]}],"data":[{"key":1,"name":"_randomNonce","type":"uint256"}],"events":[],"fields":[{"name":"_pubkey","type":"uint256"},{"name":"_timestamp","type":"uint64"},{"name":"_constructorFlag","type":"bool"},{"name":"owner","type":"uint256"},{"name":"_randomNonce","type":"uint256"}]} as const + +export const factorySource = { + Collection: collectionAbi, + FarmingPool: farmingPoolAbi, + Nft: nftAbi, + TokenRoot: tokenRootAbi, + TokenWallet: tokenWalletAbi, + UserData: userDataAbi, + Wallet: walletAbi +} as const + +export type FactorySource = typeof factorySource +export type CollectionAbi = typeof collectionAbi +export type FarmingPoolAbi = typeof farmingPoolAbi +export type NftAbi = typeof nftAbi +export type TokenRootAbi = typeof tokenRootAbi +export type TokenWalletAbi = typeof tokenWalletAbi +export type UserDataAbi = typeof userDataAbi +export type WalletAbi = typeof walletAbi diff --git a/demo/Farming/contracts/Collection.sol b/demo/Farming/contracts/Collection.sol new file mode 100644 index 0000000..f56b0b8 --- /dev/null +++ b/demo/Farming/contracts/Collection.sol @@ -0,0 +1,85 @@ +pragma ever-solidity >= 0.58.1; + +pragma AbiHeader expire; +pragma AbiHeader time; +pragma AbiHeader pubkey; + + +import '@itgold/everscale-tip/contracts/TIP4_1/TIP4_1Collection.sol'; +import '@itgold/everscale-tip/contracts/access/OwnableExternal.sol'; +import './Nft.sol'; + + +contract Collection is TIP4_1Collection, OwnableExternal { + + /** + * Errors + **/ + uint8 constant sender_is_not_owner = 101; + uint8 constant value_is_less_than_required = 102; + + /// _remainOnNft - the number of crystals that will remain after the entire mint + /// process is completed on the Nft contract + uint128 _remainOnNft = 0.3 ton; + + constructor( + TvmCell codeNft, + uint256 ownerPubkey + ) OwnableExternal( + ownerPubkey + ) TIP4_1Collection ( + codeNft + ) public { + tvm.accept(); + } + + function mintNft() external virtual { + require(msg.value > _remainOnNft + 0.1 ton, value_is_less_than_required); + tvm.rawReserve(0, 4); + + uint256 id = uint256(_totalSupply); + _totalSupply++; + + TvmCell codeNft = _buildNftCode(address(this)); + TvmCell stateNft = _buildNftState(codeNft, id); + address nftAddr = new Nft{ + stateInit: stateNft, + value: 0, + flag: 128 + }( + msg.sender, + msg.sender, + _remainOnNft + ); + + emit NftCreated( + id, + nftAddr, + msg.sender, + msg.sender, + msg.sender + ); + + } + + function setRemainOnNft(uint128 remainOnNft) external virtual { + require(TIP4_1Collection._isOwner(), sender_is_not_owner); + _remainOnNft = remainOnNft; + } + + function _isOwner() internal override onlyOwner returns(bool){ + return true; + } + + function _buildNftState( + TvmCell code, + uint256 id + ) internal virtual override pure returns (TvmCell) { + return tvm.buildStateInit({ + contr: Nft, + varInit: {_id: id}, + code: code + }); + } + +} \ No newline at end of file diff --git a/demo/Farming/contracts/FarmingPool.sol b/demo/Farming/contracts/FarmingPool.sol new file mode 100644 index 0000000..57a5e99 --- /dev/null +++ b/demo/Farming/contracts/FarmingPool.sol @@ -0,0 +1,538 @@ +pragma ever-solidity >= 0.58.1; + +pragma AbiHeader expire; +pragma AbiHeader time; +pragma AbiHeader pubkey; + +import 'broxus-ton-tokens-contracts/contracts/interfaces/ITokenRoot.sol'; +import 'broxus-ton-tokens-contracts/contracts/interfaces/ITokenWallet.sol'; +import 'broxus-ton-tokens-contracts/contracts/interfaces/IAcceptTokensTransferCallback.sol'; +import '@itgold/everscale-tip/contracts/TIP4_1/interfaces/INftChangeManager.sol'; +import '@itgold/everscale-tip/contracts/TIP4_1/interfaces/ITIP4_1NFT.sol'; +import '@itgold/everscale-tip/contracts/TIP4_1/TIP4_1Nft.sol'; +import '@itgold/everscale-tip/contracts/access/OwnableInternal.sol'; +import '@itgold/everscale-tip/contracts/TIP6/TIP6.sol'; +import 'abstract/Checks.sol'; +import 'UserData.sol'; + +import 'interfaces/IUserData.sol'; +import 'interfaces/IFarmingPool.sol'; + +contract FarmingPool is IFarmingPool, INftChangeManager, IAcceptTokensTransferCallback, Checks, OwnableInternal, TIP6 { + + struct PendingDeposit { + address nft; + address owner; + address sendGasTo; + } + + // constants + uint128 constant TOKEN_WALLET_DEPLOY_VALUE = 0.5 ever; + uint128 constant TOKEN_WALLET_DEPLOY_GRAMS_VALUE = 0.1 ever; + uint128 constant TOKEN_TRANSFER_VALUE = 0.5 ever; + uint128 constant CALLBACK_VALUE = 0.1 ever; + uint128 constant SET_END_TIME_VALUE = 0.5 ever; + uint128 constant MIN_CALL_MSG_VALUE = 0.5 ever; + uint128 constant INCREASE_DEBT_VALUE = 0.3 ever; + uint128 constant USER_DATA_DEPLOY_VALUE = 0.5 ever; + + uint32 constant MAX_UINT32 = 0xFFFFFFFF; + uint128 constant SCALING_FACTOR = 1e18; + + /// errors + uint8 constant NOT_USER_DATA = 105; + uint8 constant ZERO_AMOUNT_INPUT = 107; + uint8 constant LOW_WITHDRAW_MSG_VALUE = 108; + uint8 constant BAD_FARM_END_TIME = 115; + uint8 constant WRONG_INTERVAL = 110; + + // checks + uint8 constant CHECK_WALLET_ADDR = 1; + + address _rewardTokenRoot; + address _rewardTokenWallet; + uint128 _rewardTokenWalletBalance; + + address _collection; + TvmCell _codeNft; + TvmCell _codeUserData; + + bool _active = false; + + uint128 _totalDeposits = 0; + uint64 _depositNonce = 0; + /// depositNonce (key) => depositor + mapping (uint64 => PendingDeposit) _deposits; + + uint32 _farmStartTime; + uint32 _farmEndTime; + uint128 _rewardPerSecond; + + uint32 _lastRewardTime; + uint256 _accRewardPerShare; + uint128 _unclaimedReward; + + /// in sec + uint32 _vestingPeriod; + /// 1000 = 100%, 100 = 10% + uint32 _vestingRatio; + + event RewardDeposit(address tokenRoot, uint128 amount); + event Deposit(uint64 depositNonce, address user, address nft, uint128 reward, uint128 rewardDebt); + event Withdraw(address user, address nft, uint128 reward, uint128 reward_debt); + event Claim(address user, uint128 reward, uint128 reward_debt); + event FarmEndTimeSet(uint32 time); + + constructor( + address owner, + address collection, + address rewardTokenRoot, + TvmCell codeNft, + TvmCell codeUserData, + uint32 farmStartTime, + uint128 rewardPerSecond, + uint32 vestingPeriod, + uint32 vestingRatio + ) OwnableInternal ( + owner + ) Checks( + CHECK_WALLET_ADDR + ) public { + require(address(this).balance > TOKEN_WALLET_DEPLOY_VALUE); + + tvm.accept(); + _collection = collection; + _rewardTokenRoot = rewardTokenRoot; + _codeNft = codeNft; + _farmStartTime = farmStartTime; + _rewardPerSecond = rewardPerSecond; + _vestingPeriod = vestingPeriod; + _vestingRatio = vestingRatio; + _codeUserData = codeUserData; + + _supportedInterfaces[ + bytes4(tvm.functionId(INftChangeManager.onNftChangeManager)) + ] = true; + + _supportedInterfaces[ + bytes4(tvm.functionId(IAcceptTokensTransferCallback.onAcceptTokensTransfer)) + ] = true; + + _supportedInterfaces[ + bytes4(tvm.functionId(IFarmingPool.finishDeposit)) ^ + bytes4(tvm.functionId(IFarmingPool.finishWithdraw)) ^ + bytes4(tvm.functionId(IFarmingPool.receiveTokenWalletAddress)) ^ + bytes4(tvm.functionId(IFarmingPool.setEndTime)) ^ + bytes4(tvm.functionId(IFarmingPool.withdraw)) ^ + bytes4(tvm.functionId(IFarmingPool.withdrawUnclaimed)) ^ + bytes4(tvm.functionId(IFarmingPool.claimRewardForUser)) ^ + bytes4(tvm.functionId(IFarmingPool.claimReward)) ^ + bytes4(tvm.functionId(IFarmingPool.getUserDataAddress)) ^ + bytes4(tvm.functionId(IFarmingPool.getInfo)) + ] = true; + + _setUp(); + } + + function _setUp() internal view virtual { + // Deploy reward token wallet + ITokenRoot(_rewardTokenRoot).deployWallet{value: TOKEN_WALLET_DEPLOY_VALUE, callback: FarmingPool.receiveTokenWalletAddress}( + address(this), // owner + TOKEN_WALLET_DEPLOY_GRAMS_VALUE + ); + } + + function _passCheck(uint8 check) internal virtual override { + _checkList &= ~check; + if (_isCheckListEmpty()) { + _active = true; + } + } + + function receiveTokenWalletAddress( + address wallet + ) external override virtual { + require(msg.sender == _rewardTokenRoot); + + _rewardTokenWallet = wallet; + _passCheck(CHECK_WALLET_ADDR); + } + + function _transferReward( + address userDataAddr, + address receiverAddr, + uint128 amount, + address sendGasTo, + address nft, + bool deploy + ) internal virtual returns (uint128 reward, uint128 rewardDebt){ + reward = amount; + rewardDebt = 0; + + if (_rewardTokenWalletBalance < amount) { + rewardDebt = amount - _rewardTokenWalletBalance; + reward -= rewardDebt; + } + + if (userDataAddr != address.makeAddrNone()) { + if (rewardDebt > 0) { + IUserData(userDataAddr).increasePoolDebt{value: INCREASE_DEBT_VALUE, flag: 0}(rewardDebt, sendGasTo); + } + } + + uint128 deployValue = 0; + TvmBuilder builder; + builder.store(nft); + if (reward > 0) { + if (deploy) { + deployValue = TOKEN_WALLET_DEPLOY_GRAMS_VALUE; + } + + ITokenWallet(_rewardTokenWallet).transfer{value: TOKEN_TRANSFER_VALUE, flag: 0}( + reward, + receiverAddr, + deployValue, + sendGasTo, + true, + builder.toCell() + ); + _rewardTokenWalletBalance -= reward; + } + + return (reward, rewardDebt); + } + + function onAcceptTokensTransfer( + address tokenRoot, + uint128 amount, + address sender, + address senderWallet, + address remainingGasTo, + TvmCell payload + ) external override virtual { + tvm.rawReserve(0, 4); + tokenRoot; + + if (msg.sender == _rewardTokenWallet) { + _rewardTokenWalletBalance += amount; + + emit RewardDeposit(_rewardTokenRoot, amount); + } else { + ITokenWallet(senderWallet).transfer{value: 0, flag: 128}( + amount, + sender, + 0, + remainingGasTo, + true, + payload + ); + return; + } + + remainingGasTo.transfer(0, false, 128); + } + + function onNftChangeManager( + uint256 id, + address owner, + address oldManager, + address newManager, + address collection, + address sendGasTo, + TvmCell payload + ) external override { + tvm.rawReserve(0, 4); + payload; // disable warning + + if ( + !_active || + _collection != collection || + _resolveNft(id, collection) != msg.sender || + newManager != address(this) || + msg.value < (MIN_CALL_MSG_VALUE + TOKEN_WALLET_DEPLOY_VALUE) + ) { + mapping(address => ITIP4_1NFT.CallbackParams) callbacks; + ITIP4_1NFT(msg.sender).changeManager{value: 0, flag: 128, bounce: false}( + oldManager, + sendGasTo, + callbacks + ); + return; + } + + _updatePoolInfo(); + + _totalDeposits++; + PendingDeposit deposit = PendingDeposit(msg.sender, owner, sendGasTo); + _deposits[_depositNonce] = deposit; + + address userDataAddr = getUserDataAddress(owner); + IUserData(userDataAddr).processDeposit{value: 0, flag: 128}(_depositNonce, msg.sender, _accRewardPerShare, _lastRewardTime, _farmEndTime); + _depositNonce++; + } + + function _resolveNft( + uint256 id, + address collection + ) internal virtual view returns(address nft) { + TvmBuilder salt; + salt.store(collection); + TvmCell code = tvm.setCodeSalt(_codeNft, salt.toCell()); + TvmCell state = tvm.buildStateInit({ + contr: TIP4_1Nft, + varInit: {_id: id}, + code: code + }); + nft = address.makeAddrStd(collection.wid, tvm.hash(state)); + } + + function finishDeposit(uint64 depositNonce, uint128 vested) external virtual override { + PendingDeposit deposit = _deposits[depositNonce]; + address expectedAddr = getUserDataAddress(deposit.owner); + require (expectedAddr == msg.sender, NOT_USER_DATA); + tvm.rawReserve(0, 4); + + ( + uint128 reward, + uint128 rewardDebt + ) = _transferReward(expectedAddr, deposit.owner, vested, deposit.sendGasTo, deposit.nft, false); + + emit Deposit(depositNonce, deposit.owner, deposit.nft, reward, rewardDebt); + delete _deposits[depositNonce]; + + deposit.sendGasTo.transfer(0, false, 128); + } + + function finishWithdraw( + address user, + uint128 vested, + address sendGasTo, + address nft + ) external virtual override { + address expectedAddr = getUserDataAddress(user); + require (expectedAddr == msg.sender, NOT_USER_DATA); + tvm.rawReserve(0, 4); + + ( + uint128 reward, + uint128 rewardDebt + ) = _transferReward(expectedAddr, user, vested, sendGasTo, nft, false); + + // withdraw is called + if (nft.value != 0) { + _totalDeposits -= 1; + + emit Withdraw(user, nft, reward, rewardDebt); + mapping(address => ITIP4_1NFT.CallbackParams) callbacks; + ITIP4_1NFT(nft).changeManager{value: 0, flag: 128, bounce: false}( + user, + sendGasTo, + callbacks + ); + // claim is called + } else { + emit Claim(user, reward, rewardDebt); + sendGasTo.transfer(0, false, 128); + } + } + + function _updatePoolInfo() internal virtual { + (uint32 lastRewardTime, uint256 accRewardPerShare, uint128 unclaimedReward) = calculateRewardData(); + _lastRewardTime = lastRewardTime; + _accRewardPerShare = accRewardPerShare; + _unclaimedReward = unclaimedReward; + } + + function _getMultiplier(uint32 from, uint32 to) private view returns(uint32) { + require (from <= to, WRONG_INTERVAL); + + if ((from > _farmEndTime && _farmEndTime != 0) || (to < _farmStartTime)) { + return 0; + } + + if (to > _farmEndTime && _farmEndTime != 0) { + to = _farmEndTime; + } + + if (from < _farmStartTime) { + from = _farmStartTime; + } + + return to - from; + } + + function calculateRewardData() public virtual view returns (uint32 lastRewardTime, uint256 accRewardPerShare, uint128 unclaimedReward) { + lastRewardTime = _lastRewardTime; + accRewardPerShare = _accRewardPerShare; + unclaimedReward = _unclaimedReward; + + if (now < _farmStartTime) { + lastRewardTime = now; + return (lastRewardTime, accRewardPerShare, unclaimedReward); + } + + if (now > lastRewardTime) { + if (lastRewardTime < _farmStartTime) { + lastRewardTime = math.min(_farmStartTime, now); + } + + if (lastRewardTime >= _farmStartTime) { + uint32 multiplier = _getMultiplier(lastRewardTime, now); + uint128 newReward = _rewardPerSecond * multiplier; + uint32 newRewardTime; + if (_farmEndTime > 0) { + newRewardTime = math.min(now, _farmEndTime); + } else { + newRewardTime = now; + } + + if (_totalDeposits == 0) { + unclaimedReward += newReward; + } else { + uint256 scaledReward = uint256(newReward) * SCALING_FACTOR; + accRewardPerShare += scaledReward / _totalDeposits; + + } + + lastRewardTime = newRewardTime; + } + } + return (lastRewardTime, accRewardPerShare, unclaimedReward); + } + + function setEndTime(uint32 farmEndTime, address sendGasTo) external override virtual onlyOwner { + require (msg.value >= SET_END_TIME_VALUE); + require (farmEndTime >= now, BAD_FARM_END_TIME); + require (_farmEndTime == 0, BAD_FARM_END_TIME); + + tvm.rawReserve(0, 4); + + _farmEndTime = farmEndTime; + emit FarmEndTimeSet(_farmEndTime); + sendGasTo.transfer(0, false, 128); + } + + function withdraw(address nft, address sendGasTo) external override virtual { + require (nft.value != 0, ZERO_AMOUNT_INPUT); + require (msg.value >= MIN_CALL_MSG_VALUE + TOKEN_TRANSFER_VALUE, LOW_WITHDRAW_MSG_VALUE); + tvm.rawReserve(0, 4); + + _updatePoolInfo(); + + address userDataAddr = getUserDataAddress(msg.sender); + IUserData(userDataAddr).processWithdraw{value: 0, flag: 128}(nft, _accRewardPerShare, _lastRewardTime, _farmEndTime, sendGasTo); + } + + function withdrawUnclaimed(address to, address sendGasTo) external override virtual onlyOwner { + require (msg.value >= MIN_CALL_MSG_VALUE + TOKEN_TRANSFER_VALUE + TOKEN_WALLET_DEPLOY_GRAMS_VALUE, LOW_WITHDRAW_MSG_VALUE); + tvm.rawReserve(0, 4); + + _transferReward(address.makeAddrNone(), to, _unclaimedReward, sendGasTo, address.makeAddrNone(), true); + _unclaimedReward = 0; + + sendGasTo.transfer(0, false, 128); + } + + function claimRewardForUser(address user, address sendGasTo) external override { + require (msg.value >= MIN_CALL_MSG_VALUE + TOKEN_TRANSFER_VALUE, LOW_WITHDRAW_MSG_VALUE); + tvm.rawReserve(0, 4); + + _updatePoolInfo(); + + address userDataAddr = getUserDataAddress(user); + IUserData(userDataAddr).processClaimReward{value: 0, flag: 128}(_accRewardPerShare, _lastRewardTime, _farmEndTime, sendGasTo); + } + + function claimReward(address sendGasTo) external override virtual { + require (msg.value >= MIN_CALL_MSG_VALUE + TOKEN_TRANSFER_VALUE, LOW_WITHDRAW_MSG_VALUE); + tvm.rawReserve(0, 4); + + _updatePoolInfo(); + + address userDataAddr = getUserDataAddress(msg.sender); + IUserData(userDataAddr).processClaimReward{value: 0, flag: 128}(_accRewardPerShare, _lastRewardTime, _farmEndTime, sendGasTo); + } + + function _buildUserInitData(address user) internal virtual view returns (TvmCell) { + return tvm.buildStateInit({ + contr: UserData, + varInit: { + _farmPool: address(this), + _user: user + }, + code: _codeUserData + }); + } + + function getUserDataAddress(address user) public view virtual override responsible returns (address) { + return { value: 0, flag: 64, bounce: false } address(tvm.hash(_buildUserInitData(user))); + } + + function deployUserData(address userDataOwner) internal view virtual returns (address) { + return new UserData{ + stateInit: _buildUserInitData(userDataOwner), + value: USER_DATA_DEPLOY_VALUE + }( + _vestingPeriod, + _vestingRatio + ); + } + + function getInfo() public view override responsible returns( + bool active, + uint128 totalDeposits, + uint32 farmStartTime, + uint32 farmEndTime, + uint128 rewardPerSecond, + uint32 lastRewardTime, + uint256 accRewardPerShare, + uint128 unclaimedReward, + uint32 vestingPeriod, + uint32 vestingRatio, + address rewardTokenRoot, + address rewardTokenWallet, + uint128 rewardTokenWalletBalance + ) { + return{ + value: 0, + flag: 64, + bounce: false + }( + _active, + _totalDeposits, + _farmStartTime, + _farmEndTime, + _rewardPerSecond, + _lastRewardTime, + _accRewardPerShare, + _unclaimedReward, + _vestingPeriod, + _vestingRatio, + _rewardTokenRoot, + _rewardTokenWallet, + _rewardTokenWalletBalance + ); + } + + onBounce(TvmSlice slice) external virtual { + tvm.accept(); + + uint32 functionId = slice.decode(uint32); + // if processing failed - contract was not deployed. Deploy and try again + if (functionId == tvm.functionId(UserData.processDeposit)) { + tvm.rawReserve(0, 4); + + uint64 nonce = slice.decode(uint64); + PendingDeposit deposit = _deposits[nonce]; + address userDataAddr = deployUserData(deposit.owner); + ITokenRoot(_rewardTokenRoot).deployWallet{value: TOKEN_WALLET_DEPLOY_VALUE, callback: FarmingPool.dummy}( + deposit.owner, + TOKEN_WALLET_DEPLOY_GRAMS_VALUE // deploy grams + ); + + IUserData(userDataAddr).processDeposit{value: 0, flag: 128}(nonce, deposit.nft, _accRewardPerShare, _lastRewardTime, _farmEndTime); + } + } + + function dummy(address user_wallet) external pure virtual { tvm.rawReserve(0, 4); } +} diff --git a/demo/Farming/contracts/NFTFarming.sol b/demo/Farming/contracts/NFTFarming.sol deleted file mode 100644 index de656d2..0000000 --- a/demo/Farming/contracts/NFTFarming.sol +++ /dev/null @@ -1,333 +0,0 @@ -pragma ton-solidity >= 0.58.1; - -pragma AbiHeader expire; -pragma AbiHeader time; -pragma AbiHeader pubkey; - -import 'broxus-ton-tokens-contracts/contracts/interfaces/ITokenRoot.sol'; -import 'broxus-ton-tokens-contracts/contracts/interfaces/ITokenWallet.sol'; -import 'broxus-ton-tokens-contracts/contracts/interfaces/IAcceptTokensTransferCallback.sol'; -import '@itgold/everscale-tip/contracts/TIP4_1/interfaces/INftChangeManager.sol'; -import '@itgold/everscale-tip/contracts/TIP4_1/interfaces/ITIP4_1NFT.sol'; -import '@itgold/everscale-tip/contracts/TIP4_1/TIP4_1Nft.sol'; -import '@itgold/everscale-tip/contracts/access/OwnableInternal.sol'; -import 'abstract/Checks.sol'; - - -contract NFTFarming is INftChangeManager, IAcceptTokensTransferCallback, Checks, OwnableInternal { - - struct Deposit { - address depositor; - address sendGasTo; - uint startDepositTime; - } - - // constants - uint128 constant TOKEN_WALLET_DEPLOY_VALUE = 0.5 ever; - uint128 constant TOKEN_WALLET_DEPLOY_GRAMS_VALUE = 0.1 ever; - uint128 constant TOKEN_TRANSFER_VALUE = 1 ever; - uint128 constant CALLBACK_VALUE = 0.1 ever; - - // checks - uint8 constant CHECK_WALLET_ADDR = 1; - - bool _active = false; - - address _collection; - TvmCell _codeNft; - - address _rewardTokenRoot; - address _rewardTokenWallet; - uint128 _rewardTokenWalletBalance; - - uint128 _farmStartTime; - uint128 _rewardPerSecond; - uint128 _lockPeriod; - - uint128 _lastRewardTime; - uint128 _accRewardPerShare; - - uint128 public _depositsNum; - mapping(address => Deposit) public _deposits; - mapping(address => uint128) public _balances; - - constructor( - address owner, - address collection, - address rewardTokenRoot, - TvmCell codeNft, - uint128 lockPeriod, - uint128 farmStartTime, - uint128 rewardPerSecond - ) OwnableInternal ( - owner - ) Checks( - CHECK_WALLET_ADDR - ) public { - require(address(this).balance > TOKEN_WALLET_DEPLOY_VALUE); - tvm.accept(); - - _depositsNum = 0; - _collection = collection; - _rewardTokenRoot = rewardTokenRoot; - _codeNft = codeNft; - _lockPeriod = lockPeriod; - _farmStartTime = farmStartTime; - _rewardPerSecond = rewardPerSecond; - - _setUp(); - } - - function _setUp() internal virtual { - ITokenRoot(_rewardTokenRoot).deployWallet{value: TOKEN_WALLET_DEPLOY_VALUE, callback: NFTFarming.receiveTokenWalletAddress}( - address(this), - TOKEN_WALLET_DEPLOY_GRAMS_VALUE - ); - } - - function _passCheck(uint8 check) internal virtual override { - _checkList &= ~check; - if (_isCheckListEmpty()) { - _active = true; - } - } - - function receiveTokenWalletAddress( - address wallet - ) external virtual { - require(msg.sender == _rewardTokenRoot); - - _rewardTokenWallet = wallet; - _passCheck(CHECK_WALLET_ADDR); - } - - function onNftChangeManager( - uint256 id, - address owner, - address oldManager, - address newManager, - address collection, - address sendGasTo, - TvmCell payload - ) external override { - tvm.rawReserve(0, 4); - - if ( - !_active || - _collection != collection || - _resolveNft(id, collection) != msg.sender || - (oldManager != address(this) && newManager != address(this)) - ) { - mapping(address => ITIP4_1NFT.CallbackParams) callbacks; - ITIP4_1NFT(msg.sender).changeManager{value: 0, flag: 128, bounce: false}( - oldManager, - sendGasTo, - callbacks - ); - return; - } - - _updatePoolInfo(); - if (_deposits.exists(msg.sender) && oldManager == address(this)) { - _depositsNum--; - delete _deposits[msg.sender]; - } else { - _depositsNum++; - _deposits[msg.sender] = Deposit(owner, sendGasTo, now); - if (!_balances.exists(owner)) { - _balances[owner] = 0; - } - } - - sendGasTo.transfer({value: 0, flag: 128 + 2, bounce: false}); - } - - function _resolveNft( - uint256 id, - address collection - ) internal virtual view returns(address nft) { - TvmBuilder salt; - salt.store(collection); - TvmCell code = tvm.setCodeSalt(_codeNft, salt.toCell()); - TvmCell state = tvm.buildStateInit({ - contr: TIP4_1Nft, - varInit: {_id: id}, - code: code - }); - nft = address.makeAddrStd(collection.wid, tvm.hash(state)); - } - - function onAcceptTokensTransfer( - address tokenRoot, - uint128 amount, - address sender, - address senderWallet, - address remainingGasTo, - TvmCell payload - ) external override { - require(_rewardTokenWallet == msg.sender); - tvm.rawReserve(0, 4); - - _rewardTokenWalletBalance += amount; - - remainingGasTo.transfer({value: 0, flag: 128 + 2}); - } - - function _transferReward( - address depositor, - uint128 amount, - address sendGasTo - ) internal virtual returns (uint128 reward){ - TvmCell empty; - ITokenWallet(_rewardTokenWallet).transfer{value: TOKEN_TRANSFER_VALUE, flag: 0}( - amount, - depositor, - TOKEN_WALLET_DEPLOY_VALUE, - sendGasTo, - true, - empty - ); - - _balances[depositor] -= amount; - _rewardTokenWalletBalance -= amount; - - if (_balances[depositor] == 0) { - delete _balances[depositor]; - } - } - - function finishDeposit( - address nft - ) external virtual { - require (_deposits.exists(nft)); - require (_deposits[nft].startDepositTime + _lockPeriod < now); - require (_deposits[nft].depositor == msg.sender); - require (msg.value >= TOKEN_TRANSFER_VALUE + CALLBACK_VALUE); - tvm.rawReserve(0, 4); - - _updatePoolInfo(); - - Deposit deposit = _deposits[nft]; - - mapping(address => ITIP4_1NFT.CallbackParams) callbacks; - TvmCell emptyCell; - callbacks[address(this)] = ITIP4_1NFT.CallbackParams(CALLBACK_VALUE, emptyCell); - ITIP4_1NFT(nft).changeManager{value: 0, flag: 128}( - deposit.depositor, - deposit.sendGasTo, - callbacks - ); - } - - function claimReward( - uint128 amount - ) external virtual { - require (_balances.exists(msg.sender)); - require (msg.value > TOKEN_TRANSFER_VALUE); - tvm.rawReserve(0, 4); - - _updatePoolInfo(); - require (_balances[msg.sender] >= amount && _rewardTokenWalletBalance >= amount); - - _transferReward( - msg.sender, - amount, - msg.sender - ); - - msg.sender.transfer({value: 0, flag: 128 + 2}); - } - - function _updatePoolInfo() internal virtual { - (uint128 lastRewardTime, uint128 accRewardPerShare) = calculateRewardData(); - - _lastRewardTime = lastRewardTime; - _accRewardPerShare = accRewardPerShare; - - if (_accRewardPerShare != 0) { - _payReward(); - } - } - - function _payReward() internal virtual { - for ((address nft, Deposit deposit) : _deposits) { - if (!_balances.exists(deposit.depositor)) { - _balances[deposit.depositor] = 0; - } - _balances[deposit.depositor] += _accRewardPerShare; - } - _accRewardPerShare = 0; - } - - function calculateRewardData() public virtual view responsible returns(uint128 lastRewardTime, uint128 accRewardPerShare) { - lastRewardTime = _lastRewardTime; - accRewardPerShare = _accRewardPerShare; - - // reward rounds still not started, nothing to calculate - if (now < _farmStartTime) { - lastRewardTime = now; - return (lastRewardTime, accRewardPerShare); - } - - if (now > _farmStartTime) { - if (lastRewardTime < _farmStartTime) { - lastRewardTime = _farmStartTime; - } - - if (_depositsNum > 0) { - uint128 reward = _rewardPerSecond * (now - lastRewardTime); - accRewardPerShare = reward / _depositsNum; - } - lastRewardTime = now; - } - - return {value: 0, flag: 64, bounce: false} (lastRewardTime, accRewardPerShare); - } - - function setRewardPerSecond(uint128 rewardPerSecond) external onlyOwner { - _updatePoolInfo(); - - _rewardPerSecond = rewardPerSecond; - } - - onBounce(TvmSlice slice) external virtual { - require(msg.sender == _rewardTokenRoot); - tvm.accept(); - - uint32 functionId = slice.decode(uint32); - if (functionId == tvm.functionId(ITokenRoot.deployWallet)) { - ITokenRoot(_rewardTokenRoot).deployWallet{value: TOKEN_WALLET_DEPLOY_VALUE, callback: NFTFarming.receiveTokenWalletAddress}( - address(this), - TOKEN_WALLET_DEPLOY_GRAMS_VALUE - ); - } - - } - - function getDetails() public view responsible returns( - bool active, - address collection, - address rewardTokenRoot, - address rewardTokenWallet, - uint128 rewardTokenWalletBalance, - uint128 farmStartTime, - uint128 rewardPerSecond, - uint128 lockPeriod, - uint128 lastRewardTime, - uint128 accRewardPerShare - ) { - return {value: 0, flag: 64, bounce: false} ( - _active, - _collection, - _rewardTokenRoot, - _rewardTokenWallet, - _rewardTokenWalletBalance, - _farmStartTime, - _rewardPerSecond, - _lockPeriod, - _lastRewardTime, - _accRewardPerShare - ); - } - -} diff --git a/demo/Farming/contracts/Nft.sol b/demo/Farming/contracts/Nft.sol new file mode 100644 index 0000000..0ab8300 --- /dev/null +++ b/demo/Farming/contracts/Nft.sol @@ -0,0 +1,22 @@ +pragma ever-solidity >= 0.58.1; + +pragma AbiHeader expire; +pragma AbiHeader time; +pragma AbiHeader pubkey; + + +import '@itgold/everscale-tip/contracts/TIP4_1/TIP4_1Nft.sol'; + +contract Nft is TIP4_1Nft { + + constructor( + address owner, + address sendGasTo, + uint128 remainOnNft + ) TIP4_1Nft( + owner, + sendGasTo, + remainOnNft + ) public {} + +} \ No newline at end of file diff --git a/demo/Farming/contracts/UserData.sol b/demo/Farming/contracts/UserData.sol new file mode 100644 index 0000000..81d7ca0 --- /dev/null +++ b/demo/Farming/contracts/UserData.sol @@ -0,0 +1,309 @@ +pragma ton-solidity >= 0.58.1; + +pragma AbiHeader expire; +pragma AbiHeader time; +pragma AbiHeader pubkey; + +import 'interfaces/IUserData.sol'; +import 'interfaces/IFarmingPool.sol'; + +contract UserData is IUserData { + + uint8 constant NOT_FARM_POOL = 101; + + uint128 constant SCALING_FACTOR = 1e18; + uint32 constant MAX_VESTING_RATIO = 1000; + + address static _farmPool; + address static _user; + + uint32 _lastRewardTime; + uint32 _vestingPeriod; + // number from 0 to 1000 (0% to 100%). 0 means vesting is disabled + uint32 _vestingRatio; + + uint32 _vestingTime; + uint128 _rewardDebt; + uint128 _entitled; + uint128 _poolDebt; + + /// nft addresses + address[] public _deposits; + + constructor( + uint32 vestingPeriod, + uint32 vestingRatio + ) public { + require(msg.sender == _farmPool); + + _vestingPeriod = vestingPeriod; + _vestingRatio = vestingRatio; + } + + function pendingReward( + uint256 accRewardPerShare, + uint32 poolLastRewardTime, + uint32 farmEndTime + ) external view override returns (uint128 entitled, uint128 vested, uint128 poolDebt, uint32 vestingTime) { + ( + entitled, + vested, + vestingTime + ) = _computeVesting(uint128(_deposits.length), _rewardDebt, accRewardPerShare, poolLastRewardTime, farmEndTime); + + return (entitled, vested, poolDebt, vestingTime); + } + + function _isEven(uint64 num) internal pure returns (bool) { + return (num / 2) == 0 ? true : false; + } + + function _rangeSum(uint64 range) internal pure returns (uint64) { + if (_isEven(range)) { + return (range / 2) * range + (range / 2); + } + return ((range / 2) + 1) * range; + } + + // interval should be less than max + function _rangeIntervalAverage(uint32 interval, uint32 max) internal pure returns (uint256) { + return (_rangeSum(uint64(interval)) * SCALING_FACTOR) / max; + } + + // only applied if _interval is bigger than vestingPeriod, will throw integer overflow otherwise + function _computeVestedForInterval(uint128 entitled, uint32 interval) internal view returns (uint128, uint128) { + uint32 periodsPassed = ((interval / _vestingPeriod) - 1); + uint32 fullVestedPart = periodsPassed * _vestingPeriod + interval % _vestingPeriod; + uint32 partlyVestedPart = interval - fullVestedPart; + + // get part of entitled reward that already vested, because their vesting period is passed + uint128 clearPart1 = uint128((((fullVestedPart * SCALING_FACTOR) / interval) * entitled) / SCALING_FACTOR); + uint128 vestedPart = entitled - clearPart1; + + // now calculate vested share of remaining part + uint256 clearPart2Share = _rangeIntervalAverage(partlyVestedPart, _vestingPeriod) / partlyVestedPart; + uint128 clearPart2 = uint128(vestedPart * clearPart2Share / SCALING_FACTOR); + uint128 remainingEntitled = vestedPart - clearPart2; + + return (clearPart1 + clearPart2, remainingEntitled); + } + + function _computeVestedForNewlyEntitled( + uint128 entitled, + uint32 poolLastRewardTime, + uint32 farmEndTime + ) internal view returns (uint128 vested) { + if (entitled == 0) { + return 0; + } + if (farmEndTime == 0 || poolLastRewardTime < farmEndTime) { + uint32 age = poolLastRewardTime - _lastRewardTime; + + if (age > _vestingPeriod) { + (uint128 vestedPart, uint128 _) = _computeVestedForInterval(entitled, age); + return vestedPart; + } else { + uint256 clearPartShare = _rangeIntervalAverage(age, _vestingPeriod) / age; + return uint128(entitled * clearPartShare / SCALING_FACTOR); + } + } else { + uint32 ageBefore = farmEndTime - _lastRewardTime; + uint32 ageAfter = math.min(poolLastRewardTime - farmEndTime, _vestingPeriod); + + uint128 vestedBefore; + uint128 entitledBefore; + if (ageBefore > _vestingPeriod) { + (vestedBefore, entitledBefore) = _computeVestedForInterval(entitled, ageBefore); + } else { + uint256 clearPartShare = _rangeIntervalAverage(ageBefore, _vestingPeriod) / ageBefore; + vestedBefore = uint128(entitled * clearPartShare / SCALING_FACTOR); + entitledBefore = entitled - vestedBefore; + } + + uint128 vestedAfter = entitledBefore * ageAfter / _vestingPeriod; + return (vestedBefore + vestedAfter); + } + } + + function _computeVesting( + uint128 amount, + uint128 rewardDebt, + uint256 accRewardPerShare, + uint32 poolLastRewardTime, + uint32 farmEndTime + ) internal view returns (uint128, uint128, uint32) { + uint32 newVestingTime; + uint128 newlyVested; + uint128 updatedEntitled; + uint128 newEntitled; + + uint256 reward = uint256(amount) * accRewardPerShare; + newEntitled = uint128(reward / SCALING_FACTOR) - rewardDebt; + if (_vestingRatio > 0) { + uint128 vestingPart = (newEntitled * _vestingRatio) / MAX_VESTING_RATIO; + uint128 clearPart = newEntitled - vestingPart; + + if (_lastRewardTime < farmEndTime || farmEndTime == 0) { + newlyVested = _computeVestedForNewlyEntitled(vestingPart, poolLastRewardTime, farmEndTime); + } else { + // no new entitled rewards after farm end, nothing to compute + newlyVested = 0; + } + + uint32 age2 = poolLastRewardTime >= _vestingTime ? _vestingPeriod : poolLastRewardTime - _lastRewardTime; + uint256 vested = uint256(_entitled) * age2; + uint128 toVest = age2 >= _vestingPeriod + ? _entitled + : uint128(vested / (_vestingTime - _lastRewardTime)); + + uint128 remainingEntitled = _entitled == 0 ? 0 : _entitled - toVest; + uint128 unreleasedNewly = vestingPart - newlyVested; + uint128 pending = remainingEntitled + unreleasedNewly; + + if (pending == 0) { + newVestingTime = poolLastRewardTime; + } else if (remainingEntitled == 0) { + newVestingTime = poolLastRewardTime + _vestingPeriod; + } else if (unreleasedNewly == 0) { + newVestingTime = _vestingTime; + } else { + uint32 age3 = _vestingTime - poolLastRewardTime; + uint32 period = uint32(((remainingEntitled * age3) + (unreleasedNewly * _vestingPeriod)) / pending); + newVestingTime = poolLastRewardTime + math.min(period, _vestingPeriod); + } + + newVestingTime = farmEndTime > 0 ? math.min(farmEndTime + _vestingPeriod, newVestingTime) : newVestingTime; + updatedEntitled = _entitled + vestingPart - toVest - newlyVested; + newlyVested += toVest + clearPart; + } else { + newlyVested = newEntitled; + } + + return (updatedEntitled, newlyVested, newVestingTime); + } + + function increasePoolDebt(uint128 poolDebt, address sendGasTo) external override { + require(msg.sender == _farmPool, NOT_FARM_POOL); + tvm.rawReserve(0, 4); + + _poolDebt += poolDebt; + + sendGasTo.transfer(0, false, 128); + } + + function processDeposit( + uint64 depositNonce, + address nft, + uint256 accRewardPerShare, + uint32 poolLastRewardTime, + uint32 farmEndTime + ) external override { + require(msg.sender == _farmPool, NOT_FARM_POOL); + tvm.rawReserve(0, 4); + + uint128 prevAmount = uint128(_deposits.length); + uint128 prevRewardDebt = _rewardDebt; + + _deposits.push(nft); + uint256 reward = _deposits.length * accRewardPerShare; + _rewardDebt = uint128(reward / SCALING_FACTOR); + + ( + uint128 entitled, + uint128 vested, + uint32 vestingTime + ) = _computeVesting(prevAmount, prevRewardDebt, accRewardPerShare, poolLastRewardTime, farmEndTime); + _entitled = entitled; + _vestingTime = vestingTime; + _lastRewardTime = poolLastRewardTime; + + vested += _poolDebt; + _poolDebt = 0; + + IFarmingPool(msg.sender).finishDeposit{value: 0, flag: 128}(depositNonce, vested); + } + + function _withdraw( + address nft, + uint256 accRewardPerShare, + uint32 poolLastRewardTime, + uint32 farmEndTime, + address sendGasTo + ) internal { + uint128 prevAmount = uint128(_deposits.length); + uint128 prevRewardDebt = _rewardDebt; + + for (uint i = 0; i < _deposits.length; i++) { + if (nft == _deposits[i]) { + delete _deposits[i]; + _deposits[i] = _deposits[_deposits.length - 1]; + _deposits.pop(); + } + } + + uint256 reward = uint128(_deposits.length) * accRewardPerShare; + _rewardDebt = uint128(reward / SCALING_FACTOR); + + ( + uint128 entitled, + uint128 vested, + uint32 vestingTime + ) = _computeVesting(prevAmount, prevRewardDebt, accRewardPerShare, poolLastRewardTime, farmEndTime); + _entitled = entitled; + _vestingTime = vestingTime; + _lastRewardTime = poolLastRewardTime; + + vested += _poolDebt; + _poolDebt = 0; + + IFarmingPool(msg.sender).finishWithdraw{value: 0, flag: 128}(_user, vested, sendGasTo, nft); + } + + function processWithdraw( + address nft, + uint256 accRewardPerShare, + uint32 poolLastRewardTime, + uint32 farmEndTime, + address sendGasTo + ) external override { + require (msg.sender == _farmPool, NOT_FARM_POOL); + tvm.rawReserve(0, 4); + + _withdraw(nft, accRewardPerShare, poolLastRewardTime, farmEndTime, sendGasTo); + } + + function processClaimReward( + uint256 accRewardPerShare, + uint32 poolLastRewardTime, + uint32 farmEndTime, + address sendGasTo + ) external override { + require (msg.sender == _farmPool, NOT_FARM_POOL); + tvm.rawReserve(0, 4); + + _withdraw(address(0), accRewardPerShare, poolLastRewardTime, farmEndTime, sendGasTo); + } + + function getInfo() public view override responsible returns( + uint32 lastRewardTime, + uint32 vestingPeriod, + uint32 vestingRatio, + uint128 amount, + uint32 vestingTime, + uint128 rewardDebt, + uint128 entitled, + uint128 poolDebt + ) { + return {value: 0, flag: 64, bounce: false} ( + _lastRewardTime, + _vestingPeriod, + _vestingRatio, + uint128(_deposits.length), + _vestingTime, + _rewardDebt, + _entitled, + _poolDebt + ); + } + +} diff --git a/demo/Farming/contracts/Wallet.sol b/demo/Farming/contracts/Wallet.sol new file mode 100644 index 0000000..033e241 --- /dev/null +++ b/demo/Farming/contracts/Wallet.sol @@ -0,0 +1,43 @@ +pragma ton-solidity >= 0.39.0; +pragma AbiHeader expire; +pragma AbiHeader pubkey; + +contract Account { + uint public owner; + uint public static _randomNonce; + + modifier onlyOwner() { + require(msg.pubkey() == owner, 501); + _; + } + + modifier checkPubKey() { + require(msg.pubkey() == tvm.pubkey(), 500); + _; + } + + constructor() public checkPubKey { + tvm.accept(); + setOwnership(msg.pubkey()); + } + + function setOwnership(uint newOwner) internal { + owner = newOwner; + } + + function sendTransaction( + address dest, + uint128 value, + bool bounce, + uint8 flags, + TvmCell payload + ) + public + view + onlyOwner + { + tvm.accept(); + + dest.transfer(value, bounce, flags, payload); + } +} \ No newline at end of file diff --git a/demo/Farming/contracts/abstract/Checks.sol b/demo/Farming/contracts/abstract/Checks.sol index 1739c6a..51da25a 100644 --- a/demo/Farming/contracts/abstract/Checks.sol +++ b/demo/Farming/contracts/abstract/Checks.sol @@ -1,6 +1,6 @@ /// We recommend using the compiler version 0.58.1. /// You can use other versions, but we do not guarantee compatibility of the compiler version. -pragma ton-solidity = 0.58.1; +pragma ton-solidity >= 0.58.1; pragma AbiHeader expire; pragma AbiHeader time; diff --git a/demo/Farming/contracts/interfaces/IFarmingPool.sol b/demo/Farming/contracts/interfaces/IFarmingPool.sol new file mode 100644 index 0000000..cbf3ede --- /dev/null +++ b/demo/Farming/contracts/interfaces/IFarmingPool.sol @@ -0,0 +1,33 @@ +pragma ton-solidity > 0.58.1; + +interface IFarmingPool { + function finishDeposit(uint64 depositNonce, uint128 vested) external; + function finishWithdraw( + address user, + uint128 vested, + address sendGasTo, + address nft + ) external; + function receiveTokenWalletAddress(address wallet) external; + function setEndTime(uint32 farmEndTime, address sendGasTo) external; + function withdraw(address nft, address sendGasTo) external; + function withdrawUnclaimed(address to, address sendGasTo) external; + function claimRewardForUser(address user, address sendGasTo) external; + function claimReward(address sendGasTo) external; + function getUserDataAddress(address user) external view responsible returns(address); + function getInfo() external view responsible returns( + bool active, + uint128 totalDeposits, + uint32 farmStartTime, + uint32 farmEndTime, + uint128 rewardPerSecond, + uint32 lastRewardTime, + uint256 accRewardPerShare, + uint128 unclaimedReward, + uint32 vestingPeriod, + uint32 vestingRatio, + address rewardTokenRoot, + address rewardTokenWallet, + uint128 rewardTokenWalletBalance + ); +} \ No newline at end of file diff --git a/demo/Farming/contracts/interfaces/IUserData.sol b/demo/Farming/contracts/interfaces/IUserData.sol new file mode 100644 index 0000000..1cdee90 --- /dev/null +++ b/demo/Farming/contracts/interfaces/IUserData.sol @@ -0,0 +1,47 @@ +pragma ton-solidity > 0.58.1; + +interface IUserData { + + function increasePoolDebt(uint128 poolDebt, address sendGasTo) external; + function processDeposit( + uint64 depositNonce, + address nft, + uint256 accRewardPerShare, + uint32 poolLastRewardTime, + uint32 farmEndTime + ) external; + function processWithdraw( + address nft, + uint256 accRewardPerShare, + uint32 poolLastRewardTime, + uint32 farmEndTime, + address sendGasTo + ) external; + function processClaimReward( + uint256 accRewardPerShare, + uint32 poolLastRewardTime, + uint32 farmEndTime, + address sendGasTo + ) external; + function pendingReward( + uint256 accRewardPerShare, + uint32 poolLastRewardTime, + uint32 farmEndTime + ) external view returns ( + uint128 entitled, + uint128 vested, + uint128 poolDebt, + uint32 vestingTime + ); + function getInfo() external view responsible returns( + uint32 lastRewardTime, + uint32 vestingPeriod, + uint32 vestingRatio, + uint128 amount, + uint32 vestingTime, + uint128 rewardDebt, + uint128 entitled, + uint128 poolDebt + ); + +} \ No newline at end of file diff --git a/demo/Farming/giverSettings/index.ts b/demo/Farming/giverSettings/index.ts new file mode 100644 index 0000000..312baa0 --- /dev/null +++ b/demo/Farming/giverSettings/index.ts @@ -0,0 +1,145 @@ +import { Address, Contract, Giver, ProviderRpcClient, Transaction } from "locklift"; +import { Ed25519KeyPair } from "everscale-standalone-client"; + +export class SimpleGiver implements Giver { + public giverContract: Contract; + + constructor(ever: ProviderRpcClient, readonly keyPair: Ed25519KeyPair, address: string) { + const giverAddr = new Address(address); + this.giverContract = new ever.Contract(simpleGiverAbi, giverAddr); + } + + public async sendTo(sendTo: Address, value: string): Promise<{ transaction: Transaction; output?: {} }> { + return this.giverContract.methods + .sendTransaction({ + value: value, + dest: sendTo, + bounce: false, + }) + .sendExternal({ publicKey: this.keyPair.publicKey }); + } + } + + +export class GiverWallet implements Giver { + public giverContract: Contract; + + constructor(ever: ProviderRpcClient, readonly keyPair: Ed25519KeyPair, address: string) { + const giverAddr = new Address(address); + this.giverContract = new ever.Contract(giverWalletAbi, giverAddr); + } + + public async sendTo(sendTo: Address, value: string): Promise<{ transaction: Transaction; output?: {} }> { + return this.giverContract.methods + .sendGrams({ + dest: sendTo, + amount: value, + }) + .sendExternal({ publicKey: this.keyPair.publicKey }); + } +} + +const simpleGiverAbi = { + "ABI version": 2, + header: ["time", "expire"], + functions: [ + { + name: "upgrade", + inputs: [{ name: "newcode", type: "cell" }], + outputs: [], + }, + { + name: "sendTransaction", + inputs: [ + { name: "dest", type: "address" }, + { name: "value", type: "uint128" }, + { name: "bounce", type: "bool" }, + ], + outputs: [], + }, + { + name: "getMessages", + inputs: [], + outputs: [ + { + components: [ + { name: "hash", type: "uint256" }, + { name: "expireAt", type: "uint64" }, + ], + name: "messages", + type: "tuple[]", + }, + ], + }, + { + name: "constructor", + inputs: [], + outputs: [], + }, + ], + events: [], +} as const; + +const giverWalletAbi = { + "ABI version":2, + "version":"2.2", + "header":["pubkey","time","expire"], + "functions": [ + { + "name":"constructor", + "inputs": [ + { "name":"_owner","type":"uint256"} + ], + "outputs":[] + }, + { + "name":"sendGrams", + "inputs": [ + { "name":"dest","type":"address"}, + { "name":"amount","type":"uint64"} + ], + "outputs":[] + }, + { + "name":"transferOwnership", + "inputs": [ + { "name":"newOwner","type":"uint256"} + ], + "outputs":[] + }, + { + "name":"owner", + "inputs":[], + "outputs": [ + {"name":"owner","type":"uint256"} + ] + }, + { + "name":"_randomNonce", + "inputs":[], + "outputs": [ + { "name":"_randomNonce","type":"uint256"} + ] + } + ], + "data": [ + {"key":1,"name":"_randomNonce","type":"uint256"} + ], + "events": [ + { + "name":"OwnershipTransferred", + "inputs": [ + {"name":"previousOwner","type":"uint256"}, + {"name":"newOwner","type":"uint256"} + ], + "outputs":[] + } + ], + "fields": [ + {"name":"_pubkey","type":"uint256"}, + {"name":"_timestamp","type":"uint64"}, + {"name":"_constructorFlag","type":"bool"}, + {"name":"owner","type":"uint256"}, + {"name":"_randomNonce","type":"uint256"} + ], +} as const; diff --git a/demo/Farming/locklift.config.template.ts b/demo/Farming/locklift.config.template.ts new file mode 100644 index 0000000..ac1dc3b --- /dev/null +++ b/demo/Farming/locklift.config.template.ts @@ -0,0 +1,71 @@ +import { LockliftConfig } from "locklift"; +import { FactorySource } from "./build/factorySource"; +import { SimpleGiver, GiverWallet } from "./giverSettings"; + +declare global { + const locklift: import("locklift").Locklift; +} + +const LOCAL_NETWORK_ENDPOINT = "http://188.227.35.77/"; +const RFLD_ENDPOINT = "https://rfld-dapp.itgold.io/graphql"; + +const config: LockliftConfig = { + compiler: { + version: "0.61.2", + externalContracts: { + "node_modules/broxus-ton-tokens-contracts/build": ['TokenRoot', 'TokenWallet'] + } + }, + linker: { + version: "0.15.48", + }, + networks: { + local: { + connection: { + group: "localnet", + type: "graphql", + data: { + endpoints: [LOCAL_NETWORK_ENDPOINT], + latencyDetectionInterval: 1000, + local: true, + }, + }, + giver: { + giverFactory: (ever, keyPair, address) => new SimpleGiver(ever, keyPair, address), + address: "0:ece57bcc6c530283becbbd8a3b24d3c5987cdddc3c8b7b33be6e4a6312490415", + key: "172af540e43a524763dd53b26a066d472a97c4de37d5498170564510608250c3", + }, + tracing: { + endpoint: LOCAL_NETWORK_ENDPOINT, + }, + keys: { + amount: 20, + }, + }, + rfld: { + connection: { + group: "rfld", + type: "graphql", + data: { + endpoints: [RFLD_ENDPOINT], + latencyDetectionInterval: 1000, + local: false, + }, + }, + giver: { + giverFactory: (ever, keyPair, address) => new GiverWallet(ever, keyPair, address), + address: "0:3e0dffb41dd61c048cb322cfd43c21d9fc93b7596259d43cc3ac122539cbf4eb", + key: "e237e6aff07ee21b7023f715b2c130d988631577454ec06908a2e5b78aad4d86", + }, + keys: { + phrase: "load ring repeat glass evidence awake fame try extend catch trigger rookie", + amount: 20, + }, + } + }, + mocha: { + timeout: 2000000, + }, +}; + +export default config; diff --git a/demo/Farming/package-lock.json b/demo/Farming/package-lock.json index 70bb2db..70e28bb 100644 --- a/demo/Farming/package-lock.json +++ b/demo/Farming/package-lock.json @@ -1,28 +1,28 @@ { - "name": "farming", + "name": "locklift-project", "version": "1.0.0", "lockfileVersion": 1, "requires": true, "dependencies": { "@babel/code-frame": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", - "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", "requires": { - "@babel/highlight": "^7.16.7" + "@babel/highlight": "^7.18.6" } }, "@babel/helper-validator-identifier": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", - "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==" + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", + "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==" }, "@babel/highlight": { - "version": "7.17.9", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.17.9.tgz", - "integrity": "sha512-J9PfEKCbFIv2X5bjTMiZu6Vf341N05QIY+d6FvVKynkG1S7G0j3I0QoRtWIrXhZ+/Nlb5Q0MzqL7TokEJ5BNHg==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", "requires": { - "@babel/helper-validator-identifier": "^7.16.7", + "@babel/helper-validator-identifier": "^7.18.6", "chalk": "^2.0.0", "js-tokens": "^4.0.0" }, @@ -56,17 +56,12 @@ "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" }, "supports-color": { "version": "5.5.0", @@ -79,46 +74,18 @@ } }, "@babel/runtime": { - "version": "7.17.9", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.9.tgz", - "integrity": "sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.9.tgz", + "integrity": "sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==", "requires": { "regenerator-runtime": "^0.13.4" } }, - "@broxus/contracts": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@broxus/contracts/-/contracts-1.0.4.tgz", - "integrity": "sha512-N6KRLeUdNlHPqDJUMiOrtsxx6xTiWc/2v+SrqXP4P5pDYiz5urFtNKapDH4CMFft9L4w2GEsGDszRq+x25i+/Q==", - "requires": { - "chai": "^4.3.4", - "chai-as-promised": "^7.1.1", - "locklift": "^1.4.5", - "mocha-logger": "^1.0.7" - }, - "dependencies": { - "locklift": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/locklift/-/locklift-1.5.3.tgz", - "integrity": "sha512-HX1WnLxuDVXpbGcPkfvDlBRq5M5c+Iw2B0KYEhkaX1AvWO2fo1sd4ILOeKq5ApLgpA7n5gZIXIX/E7G9H1KekQ==", - "requires": { - "@broxus/contracts": "^1.0.3", - "@tonclient/core": "^1.28.0", - "@tonclient/lib-node": "^1.28.0", - "bignumber.js": "^9.0.1", - "commander": "^7.2.0", - "directory-tree": "^2.2.7", - "ejs": "^3.1.6", - "execa": "^5.0.0", - "fs-extra": "^9.1.0", - "mocha": "^8.3.2", - "superstruct": "^0.14.2", - "tablemark": "^2.0.0", - "ton-client-js": "^0.28.1", - "underscore": "^1.13.1" - } - } - } + "@broxus/await-semaphore": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@broxus/await-semaphore/-/await-semaphore-0.1.5.tgz", + "integrity": "sha512-g464HtHHKxk6r6bkZc+lET1PuSgcFxlLHVb7EAqfxTlx6DRcYkjPRIQQhRHB3BQ6zRpfMrYkppL0tBtRED+HNA==", + "dev": true }, "@itgold/everscale-tip": { "version": "1.1.3", @@ -168,16 +135,16 @@ } }, "@octokit/openapi-types": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-11.2.0.tgz", - "integrity": "sha512-PBsVO+15KSlGmiI8QAzaqvsNlZlrDlyAJYcrXBCvVUxCp7VnXjkwPoFHgjEJXx3WF9BAwkA6nfCUA7i9sODzKA==" + "version": "12.11.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-12.11.0.tgz", + "integrity": "sha512-VsXyi8peyRq9PqIz/tpqiL2w3w80OgVMwBHltTml3LmVvXiphgeqmY9mvBw9Wu7e0QWk/fqD37ux8yP5uVekyQ==" }, "@octokit/plugin-paginate-rest": { - "version": "2.17.0", - "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.17.0.tgz", - "integrity": "sha512-tzMbrbnam2Mt4AhuyCHvpRkS0oZ5MvwwcQPYGtMv4tUa5kkzG58SVB0fcsLulOZQeRnOgdkZWkRUiyBlh0Bkyw==", + "version": "2.21.3", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.21.3.tgz", + "integrity": "sha512-aCZTEf0y2h3OLbrgKkrfFdjRL6eSOo8komneVQJnYecAxIej7Bafor2xhuDJOIFau4pk0i/P28/XgtbyPF0ZHw==", "requires": { - "@octokit/types": "^6.34.0" + "@octokit/types": "^6.40.0" } }, "@octokit/plugin-request-log": { @@ -186,11 +153,11 @@ "integrity": "sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA==" }, "@octokit/plugin-rest-endpoint-methods": { - "version": "5.13.0", - "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.13.0.tgz", - "integrity": "sha512-uJjMTkN1KaOIgNtUPMtIXDOjx6dGYysdIFhgA52x4xSadQCz3b/zJexvITDVpANnfKPW/+E0xkOvLntqMYpviA==", + "version": "5.16.2", + "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.16.2.tgz", + "integrity": "sha512-8QFz29Fg5jDuTPXVtey05BLm7OB+M8fnvE64RNegzX7U+5NUXcOcnpTIK0YfSHBg8gYd0oxIq3IZTe9SfPZiRw==", "requires": { - "@octokit/types": "^6.34.0", + "@octokit/types": "^6.39.0", "deprecation": "^2.3.1" } }, @@ -229,17 +196,17 @@ } }, "@octokit/types": { - "version": "6.34.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.34.0.tgz", - "integrity": "sha512-s1zLBjWhdEI2zwaoSgyOFoKSl109CUcVBCc7biPJ3aAf6LGLU6szDvi31JPU7bxfla2lqfhjbbg/5DdFNxOwHw==", + "version": "6.41.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.41.0.tgz", + "integrity": "sha512-eJ2jbzjdijiL3B4PrSQaSjuF2sPEQPVCPzBvTHJD9Nz+9dw2SGH4K4xeQJ77YfTq5bRQ+bD8wT11JbeDPmxmGg==", "requires": { - "@octokit/openapi-types": "^11.2.0" + "@octokit/openapi-types": "^12.11.0" } }, "@sindresorhus/is": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-2.1.1.tgz", - "integrity": "sha512-/aPsuoj/1Dw/kzhkgz+ES6TxG0zfTMGLwuK2ZG00k/iJzYHTLCE8mVU8EPqEOp/lmxPoq1C1C9RYToRKb2KEfg==" + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==" }, "@szmarczak/http-timer": { "version": "4.0.6", @@ -249,16 +216,6 @@ "defer-to-connect": "^2.0.0" } }, - "@tonclient/core": { - "version": "1.30.0", - "resolved": "https://registry.npmjs.org/@tonclient/core/-/core-1.30.0.tgz", - "integrity": "sha512-/3ECtGoyOs22U3QjD0stxxPOS39tumFvkx2xly3QJmIUhZccoFMwgWzah8QelLz4+nzzaDJxGeVgiknfgsGSZg==" - }, - "@tonclient/lib-node": { - "version": "1.30.0", - "resolved": "https://registry.npmjs.org/@tonclient/lib-node/-/lib-node-1.30.0.tgz", - "integrity": "sha512-gp2l5E0rDOJOYA3J9U0RxDu/kkUVkvGrQfOieyc6qd1EcwS+Zuac4KJvmrpxITkUBNDCJd2dhLeXoyOIjdQe/g==" - }, "@types/cacheable-request": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.2.tgz", @@ -270,6 +227,12 @@ "@types/responselike": "*" } }, + "@types/chai": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.3.tgz", + "integrity": "sha512-hC7OMnszpxhZPduX+m+nrx+uFoLkWOMiR4oa/AZF3MuSETYTZmFfJAHqZEM8MVlvfG7BEUcgvtwoCTxBp6hm3g==", + "dev": true + }, "@types/http-cache-semantics": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz", @@ -280,6 +243,13 @@ "resolved": "https://registry.npmjs.org/@types/json-buffer/-/json-buffer-3.0.0.tgz", "integrity": "sha512-3YP80IxxFJB4b5tYC2SUPwkg0XQLiu0nWvhRgEatgjf+29IcWO9X1k8xRv5DGssJ/lCrjYTjQPcobJr2yWIVuQ==" }, + "@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true, + "optional": true + }, "@types/keyv": { "version": "3.1.4", "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", @@ -288,10 +258,16 @@ "@types/node": "*" } }, + "@types/mocha": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.1.1.tgz", + "integrity": "sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw==", + "dev": true + }, "@types/node": { - "version": "17.0.27", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.27.tgz", - "integrity": "sha512-4/Ke7bbWOasuT3kceBZFGakP1dYN2XFd8v2l9bqF2LNWrmeU07JLpp56aEeG6+Q3olqO5TvXpW0yaiYnZJ5CXg==" + "version": "18.7.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.6.tgz", + "integrity": "sha512-EdxgKRXgYsNITy5mjjXjVE/CS8YENSdhiagGrLqjG0pvA2owgJ6i4l7wy/PFZGC0B1/H20lWKN7ONVDNYDZm7A==" }, "@types/responselike": { "version": "1.0.0", @@ -318,6 +294,13 @@ "requires": { "@types/node": ">=6", "tslib": "^1.9.3" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + } } }, "@wry/equality": { @@ -326,6 +309,13 @@ "integrity": "sha512-mwEVBDUVODlsQQ5dfuLUS5/Tf7jqUKyhKYHmVi4fPB6bDMOfWvUPJmKgS1Z7Za/sOI3vzWt4+O7yCiL/70MogA==", "requires": { "tslib": "^1.9.3" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + } } }, "ajv": { @@ -373,6 +363,13 @@ "requires": { "apollo-utilities": "^1.3.4", "tslib": "^1.10.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + } } }, "apollo-cache-inmemory": { @@ -385,6 +382,13 @@ "optimism": "^0.10.0", "ts-invariant": "^0.4.0", "tslib": "^1.10.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + } } }, "apollo-client": { @@ -400,6 +404,13 @@ "ts-invariant": "^0.4.0", "tslib": "^1.10.0", "zen-observable": "^0.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + } } }, "apollo-link": { @@ -411,6 +422,13 @@ "ts-invariant": "^0.4.0", "tslib": "^1.9.3", "zen-observable-ts": "^0.8.21" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + } } }, "apollo-link-context": { @@ -420,6 +438,13 @@ "requires": { "apollo-link": "^1.2.14", "tslib": "^1.9.3" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + } } }, "apollo-link-http": { @@ -430,6 +455,13 @@ "apollo-link": "^1.2.14", "apollo-link-http-common": "^0.2.16", "tslib": "^1.9.3" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + } } }, "apollo-link-http-common": { @@ -440,6 +472,13 @@ "apollo-link": "^1.2.14", "ts-invariant": "^0.4.0", "tslib": "^1.9.3" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + } } }, "apollo-link-ws": { @@ -449,6 +488,13 @@ "requires": { "apollo-link": "^1.2.14", "tslib": "^1.9.3" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + } } }, "apollo-utilities": { @@ -460,6 +506,13 @@ "fast-json-stable-stringify": "^2.0.0", "ts-invariant": "^0.4.0", "tslib": "^1.10.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + } } }, "argparse": { @@ -467,10 +520,23 @@ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, + "array-back": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", + "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==", + "dev": true + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", + "dev": true + }, "assertion-error": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==" + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true }, "astral-regex": { "version": "2.0.0", @@ -478,24 +544,36 @@ "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==" }, "async": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", - "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==" + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", + "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==", + "dev": true }, "async-limiter": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" }, - "at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==" + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true + }, + "axios": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz", + "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==", + "dev": true, + "requires": { + "follow-redirects": "^1.14.9", + "form-data": "^4.0.0" + } }, "backo2": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", - "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=" + "integrity": "sha512-zj6Z6M7Eq+PBZ7PQxl5NT665MvJdAkzp0f60nAJ+sLaSCBPMwVak5ZegFbgVCzFcCJTKFoMizvM5Ld7+JrRJHA==" }, "balanced-match": { "version": "1.0.2", @@ -508,9 +586,9 @@ "integrity": "sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ==" }, "bignumber.js": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.2.tgz", - "integrity": "sha512-GAcQvbpsM0pUb0zw1EI0KhQEZ+lRwR5fYaAp3vPOYuP7aDvGy6cVN6XHLauvF8SOga2y0dcLcjt3iQDTSEliyw==" + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.0.tgz", + "integrity": "sha512-4LwHK4nfDOraBCtst+wOWIHbu1vhvAPJK8g8nROd4iuc3PSEjWif/qwbkh8jwCJz6yDBvtU4KPynETgrfh7y3A==" }, "binary-extensions": { "version": "2.2.0", @@ -518,12 +596,11 @@ "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==" }, "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "balanced-match": "^1.0.0" } }, "braces": { @@ -540,8 +617,8 @@ "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==" }, "broxus-ton-tokens-contracts": { - "version": "git+https://github.com/broxus/ton-eth-bridge-token-contracts.git#6503e61880c03fb45741c177c25f4955dca5f0df", - "from": "git+https://github.com/broxus/ton-eth-bridge-token-contracts.git", + "version": "git+https://github.com/broxus/tip3.git#6503e61880c03fb45741c177c25f4955dca5f0df", + "from": "git+https://github.com/broxus/tip3.git", "requires": { "bignumber.js": "^9.0.1", "chai-as-promised": "^7.1.1", @@ -554,21 +631,170 @@ "ton-client-js": "^0.28.1" }, "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "chokidar": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz", + "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==", + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.3.1", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.5.0" + } + }, "commander": { "version": "8.3.0", "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==" + }, + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "requires": { + "ms": "2.1.2" + }, + "dependencies": { + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "js-yaml": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz", + "integrity": "sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==", + "requires": { + "argparse": "^2.0.1" + } + }, + "log-symbols": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz", + "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==", + "requires": { + "chalk": "^4.0.0" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "mocha": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.4.0.tgz", + "integrity": "sha512-hJaO0mwDXmZS4ghXsvPVriOhsxQ7ofcpQdm8dE+jISUOKopitvnXFQmpRR7jd2K6VBG6E26gU3IAbXXGIbu4sQ==", + "requires": { + "@ungap/promise-all-settled": "1.1.2", + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.1", + "debug": "4.3.1", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.1.6", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "4.0.0", + "log-symbols": "4.0.0", + "minimatch": "3.0.4", + "ms": "2.1.3", + "nanoid": "3.1.20", + "serialize-javascript": "5.0.1", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "which": "2.0.2", + "wide-align": "1.1.3", + "workerpool": "6.1.0", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + } + }, + "nanoid": { + "version": "3.1.20", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.20.tgz", + "integrity": "sha512-a1cQNyczgKbLX9jwbS/+d7W8fX/RfgYR7lVWwWOGIPNgK2m0MWvrGF6/m4kk6U3QcFMnZf3RIhL0v2Jgh/0Uxw==" + }, + "readdirp": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", + "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", + "requires": { + "picomatch": "^2.2.1" + } + }, + "serialize-javascript": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz", + "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==", + "requires": { + "randombytes": "^2.1.0" + } + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "requires": { + "has-flag": "^4.0.0" + } + }, + "workerpool": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.1.0.tgz", + "integrity": "sha512-toV7q9rWNYha963Pl/qyeZ6wG+3nnsyvolaNUS8+R5Wtw6qJPTxIlOP1ZSvcGhEJw+l3HMMmtiNo9Gl61G4GVg==" } } }, + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, "cacheable-lookup": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-2.0.1.tgz", - "integrity": "sha512-EMMbsiOTcdngM/K6gV/OxF2x0t07+vMOWxZNSCRQMjO2MY2nhZQ6OYhOOpyQrbhqsgtvKGI7hcq6xjnA92USjg==", - "requires": { - "@types/keyv": "^3.1.1", - "keyv": "^4.0.0" - } + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", + "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==" }, "cacheable-request": { "version": "7.0.2", @@ -582,16 +808,6 @@ "lowercase-keys": "^2.0.0", "normalize-url": "^6.0.1", "responselike": "^2.0.0" - }, - "dependencies": { - "get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "requires": { - "pump": "^3.0.0" - } - } } }, "camelcase": { @@ -603,6 +819,7 @@ "version": "4.3.6", "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.6.tgz", "integrity": "sha512-bbcp3YfHCUzMOvKqsztczerVgBKSsEijCySNlHHbX3VG1nskvqjz5Rfso1gGwD6w6oOV3eI60pKuMOV5MV7p3Q==", + "dev": true, "requires": { "assertion-error": "^1.1.0", "check-error": "^1.0.2", @@ -628,27 +845,17 @@ "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" - }, - "dependencies": { - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "requires": { - "has-flag": "^4.0.0" - } - } } }, "charenc": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", - "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=" + "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==" }, "check-error": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", - "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=" + "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==" }, "chokidar": { "version": "3.5.3", @@ -668,15 +875,15 @@ "cli-cursor": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "integrity": "sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw==", "requires": { "restore-cursor": "^2.0.0" } }, "cli-spinners": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.1.tgz", - "integrity": "sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==" + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.7.0.tgz", + "integrity": "sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==" }, "cliui": { "version": "7.0.4", @@ -691,21 +898,14 @@ "clone": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=" + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==" }, "clone-response": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", - "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", + "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", "requires": { "mimic-response": "^1.0.0" - }, - "dependencies": { - "mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==" - } } }, "color-convert": { @@ -726,15 +926,113 @@ "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==" }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "command-line-args": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.2.1.tgz", + "integrity": "sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg==", + "dev": true, + "requires": { + "array-back": "^3.1.0", + "find-replace": "^3.0.0", + "lodash.camelcase": "^4.3.0", + "typical": "^4.0.0" + } + }, + "command-line-usage": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-6.1.3.tgz", + "integrity": "sha512-sH5ZSPr+7UStsloltmDh7Ce5fb8XPlHyoPzTpyyMuYCtervL65+ubVZ6Q61cFtFl62UyJlc8/JwERRbAFPUqgw==", + "dev": true, + "requires": { + "array-back": "^4.0.2", + "chalk": "^2.4.2", + "table-layout": "^1.0.2", + "typical": "^5.2.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "array-back": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", + "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", + "dev": true + } + } + }, "commander": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==" + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true }, "compress-brotli": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/compress-brotli/-/compress-brotli-1.3.6.tgz", - "integrity": "sha512-au99/GqZtUtiCBliqLFbWlhnCxn+XSYjwZ77q6mKN4La4qOXDoLVPZ50iXr0WmAyMxl8yqoq3Yq4OeQNPPkyeQ==", + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/compress-brotli/-/compress-brotli-1.3.8.tgz", + "integrity": "sha512-lVcQsjhxhIXsuupfy9fmZUFtAIdBmXA7EGY6GBdgZ++qkM9zG4YFT8iU7FoBxzryNDMOpD1HIFHUSX4D87oqhQ==", "requires": { "@types/json-buffer": "~3.0.0", "json-buffer": "~3.0.1" @@ -743,27 +1041,17 @@ "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" - }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, "crypt": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", - "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=" + "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==" }, "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "requires": { "ms": "2.1.2" }, @@ -781,25 +1069,39 @@ "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==" }, "decompress-response": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-5.0.0.tgz", - "integrity": "sha512-TLZWWybuxWgoW7Lykv+gq9xvzOsUjQ9tF09Tj6NSTYGMTCHNXzrPnD6Hi+TgZq19PyTAGH4Ll/NIM/eTGglnMw==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", "requires": { - "mimic-response": "^2.0.0" + "mimic-response": "^3.1.0" + }, + "dependencies": { + "mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==" + } } }, "deep-eql": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "dev": true, "requires": { "type-detect": "^4.0.0" } }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true + }, "defaults": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", - "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", + "integrity": "sha512-s82itHOnYrN0Ib8r+z7laQz3sdE+4FP3d9Q7VLO7U+KRT+CR0GsWuyHxzdAY82I7cXv0G/twrqomTJLOssO5HA==", "requires": { "clone": "^1.0.2" } @@ -809,6 +1111,12 @@ "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==" }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true + }, "deprecation": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", @@ -820,24 +1128,25 @@ "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==" }, "directory-tree": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/directory-tree/-/directory-tree-2.3.1.tgz", - "integrity": "sha512-hxolIHCtQ/a56CUywaLzGD/V78zPwFihI+UK/4ZjOp7GoV4Mptmtv95yavOn/RlnTi7cCMjszvfcNrwCoWLH+Q==" + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/directory-tree/-/directory-tree-3.3.0.tgz", + "integrity": "sha512-7NT+6BjkwRKvVP5dCkYhO/pRHQJ5Jw8ww1detHLiD9/IPdTzFz6Lz9aCm0zRgp2zfECXPxBoNdzR3VTEhljeHg==", + "dev": true, + "requires": { + "command-line-args": "^5.2.0", + "command-line-usage": "^6.1.1" + } }, "dotenv": { "version": "8.2.0", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==" }, - "duplexer3": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", - "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=" - }, "ejs": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.7.tgz", - "integrity": "sha512-BIar7R6abbUxDA3bfXrO4DSgwo8I+fB5/1zgujl3HLLjwd6+9iOnrT+t3grn2qbk9vOgBubXOFwX2m9axoFaGw==", + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.8.tgz", + "integrity": "sha512-/sXZeMlhS0ArkfX2Aw780gJzXSMPnKjtspYZv+f3NiKLlubezAHDU5+9xz6gd3/NhG3txQCo6xlglmTS+oTGEQ==", + "dev": true, "requires": { "jake": "^10.8.5" } @@ -855,35 +1164,57 @@ "once": "^1.4.0" } }, + "env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true + }, "escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" }, "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" }, "eventemitter3": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz", "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==" }, - "execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "requires": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" + "events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true + }, + "everscale-crypto": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/everscale-crypto/-/everscale-crypto-0.1.1.tgz", + "integrity": "sha512-DoocTqkz1cayTu4UDdP7dUEcDMfCqchNNKhIgsXQAqhlwRExsNQ1Omo2C/JiuQ3rMzr3XxvqrCwLeLTiOrbXYQ==", + "dev": true + }, + "everscale-inpage-provider": { + "version": "0.3.34", + "resolved": "https://registry.npmjs.org/everscale-inpage-provider/-/everscale-inpage-provider-0.3.34.tgz", + "integrity": "sha512-0tcwcHY43TXY4eqjOJAinVm4LGO5yVq0z/ONVwcPBSfwaIa+yYYvZE3dbIBNlfJyOVfpMnVR3SAyQFSKrVlcWg==", + "dev": true + }, + "everscale-standalone-client": { + "version": "2.0.27", + "resolved": "https://registry.npmjs.org/everscale-standalone-client/-/everscale-standalone-client-2.0.27.tgz", + "integrity": "sha512-25Uig2DQLGFfIOXYidKG6fWAE0Bee7k4Y79G3rC9dBFiySsHk/fdMoetwmSZlYsxfenqWlG92s1bFpDRK8WC5A==", + "dev": true, + "requires": { + "@broxus/await-semaphore": "^0.1.5", + "events": "^3.3.0", + "everscale-inpage-provider": "^0.3.33", + "fast-safe-stringify": "^2.1.1", + "nekoton-wasm": "^0.5.12", + "node-fetch": "^2.6.7" } }, "fast-deep-equal": { @@ -896,26 +1227,26 @@ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" }, + "fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "dev": true + }, "filelist": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.3.tgz", - "integrity": "sha512-LwjCsruLWQULGYKy7TX0OPtrL9kLpojOFKc5VCTxdFTV7w5zbsgqVKfnkKG7Qgjtq50gKfO56hJv88OfcGb70Q==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", + "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", + "dev": true, "requires": { "minimatch": "^5.0.1" }, "dependencies": { - "brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "requires": { - "balanced-match": "^1.0.0" - } - }, "minimatch": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", - "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", + "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "dev": true, "requires": { "brace-expansion": "^2.0.1" } @@ -930,6 +1261,15 @@ "to-regex-range": "^5.0.1" } }, + "find-replace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-3.0.0.tgz", + "integrity": "sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==", + "dev": true, + "requires": { + "array-back": "^3.0.1" + } + }, "find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -945,16 +1285,16 @@ "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==" }, "flow-typed": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/flow-typed/-/flow-typed-3.7.0.tgz", - "integrity": "sha512-Mxl4c445SbvX1IBJQ+WRcPsRp3LxRMorHH57db4tBuuzNKg/Qpeo9CwdBQbFr39Xz1lxlOTPOP2ZNFLnCzb0fA==", + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/flow-typed/-/flow-typed-3.8.0.tgz", + "integrity": "sha512-Lgmj8K69kbTz7UjKjiuaG/UNaZpyoyCGKU9wL9wrcqw0a9GNvuRe7llueHSJThKyuOsymEmZf3TOpMUD2Fw1HQ==", "requires": { "@octokit/rest": "^18.12.0", "colors": "1.4.0", "flowgen": "^1.10.0", "fs-extra": "^8.1.0", "glob": "^7.1.6", - "got": "^10.5.7", + "got": "^11.8.5", "md5": "^2.2.1", "mkdirp": "^1.0.3", "node-stream-zip": "^1.15.0", @@ -984,7 +1324,7 @@ "decamelize": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==" }, "find-up": { "version": "4.1.0", @@ -1008,7 +1348,7 @@ "jsonfile": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", "requires": { "graceful-fs": "^4.1.6" } @@ -1021,6 +1361,11 @@ "p-locate": "^4.1.0" } }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" + }, "p-limit": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", @@ -1037,6 +1382,11 @@ "p-limit": "^2.2.0" } }, + "prettier": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", + "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==" + }, "universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", @@ -1087,9 +1437,9 @@ } }, "flowgen": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/flowgen/-/flowgen-1.19.0.tgz", - "integrity": "sha512-fP78dAGRuxpx9NLc+aIMkdW9ScjzHNA5wm+LLI4uFmAFo9T0xzEU6XgTXFbGBgSVwIL467D+fg39x73CR8012A==", + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/flowgen/-/flowgen-1.20.1.tgz", + "integrity": "sha512-Wus3KAhsOF7CiZGkBKZawf0AJXe06Wot6UGQt7h9QS6MBtBkFgG30wTAgpy1byA3FKYb059vO341XtN8LUhenQ==", "requires": { "@babel/code-frame": "^7.16.7", "@babel/highlight": "^7.16.7", @@ -1106,10 +1456,10 @@ "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==" }, - "prettier": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.6.2.tgz", - "integrity": "sha512-PkUpF+qoXTqhOeWL9fu7As8LXsIUZ1WYaJiY/a7McAQzxjk82OF0tibkFXVCDImZtWxbvojFjerkiLb0/q8mew==" + "typescript": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz", + "integrity": "sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA==" } } }, @@ -1123,14 +1473,6 @@ "minimatch": "~5.0.0" }, "dependencies": { - "brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "requires": { - "balanced-match": "^1.0.0" - } - }, "minimatch": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", @@ -1141,12 +1483,29 @@ } } }, + "follow-redirects": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz", + "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==", + "dev": true + }, + "form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, "fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, "requires": { - "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" @@ -1155,7 +1514,7 @@ "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, "fsevents": { "version": "2.3.2", @@ -1176,17 +1535,22 @@ "get-func-name": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", - "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=" + "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==", + "dev": true }, "get-stdin": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-5.0.1.tgz", - "integrity": "sha1-Ei4WFZHiH/TFJTAwVpPyDmOTo5g=" + "integrity": "sha512-jZV7n6jGE3Gt7fgSTJoz91Ak5MuTLwMwkoYdjxuJ/AmjIsE1UC03y/IWkZCQGEvVNS9qoRNwy5BCqxImv0FVeA==", + "dev": true }, "get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==" + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "requires": { + "pump": "^3.0.0" + } }, "glob": { "version": "7.2.0", @@ -1199,16 +1563,6 @@ "minimatch": "^3.0.4", "once": "^1.3.0", "path-is-absolute": "^1.0.0" - }, - "dependencies": { - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "requires": { - "brace-expansion": "^1.1.7" - } - } } }, "glob-parent": { @@ -1220,35 +1574,21 @@ } }, "got": { - "version": "10.7.0", - "resolved": "https://registry.npmjs.org/got/-/got-10.7.0.tgz", - "integrity": "sha512-aWTDeNw9g+XqEZNcTjMMZSy7B7yE9toWOFYip7ofFTLleJhvZwUxxTxkTpKvF+p1SAA4VHmuEy7PiHTHyq8tJg==", + "version": "11.8.5", + "resolved": "https://registry.npmjs.org/got/-/got-11.8.5.tgz", + "integrity": "sha512-o0Je4NvQObAuZPHLFoRSkdG2lTgtcynqymzg2Vupdx6PorhaT5MCbIyXG6d4D94kk8ZG57QeosgdiqfJWhEhlQ==", "requires": { - "@sindresorhus/is": "^2.0.0", - "@szmarczak/http-timer": "^4.0.0", + "@sindresorhus/is": "^4.0.0", + "@szmarczak/http-timer": "^4.0.5", "@types/cacheable-request": "^6.0.1", - "cacheable-lookup": "^2.0.0", - "cacheable-request": "^7.0.1", - "decompress-response": "^5.0.0", - "duplexer3": "^0.1.4", - "get-stream": "^5.0.0", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^5.0.3", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "http2-wrapper": "^1.0.0-beta.5.2", "lowercase-keys": "^2.0.0", - "mimic-response": "^2.1.0", "p-cancelable": "^2.0.0", - "p-event": "^4.0.0", - "responselike": "^2.0.0", - "to-readable-stream": "^2.0.0", - "type-fest": "^0.10.0" - }, - "dependencies": { - "get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "requires": { - "pump": "^3.0.0" - } - } + "responselike": "^2.0.0" } }, "graceful-fs": { @@ -1294,15 +1634,19 @@ "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==" }, - "human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==" + "http2-wrapper": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", + "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", + "requires": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.0.0" + } }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "requires": { "once": "^1.3.0", "wrappy": "1" @@ -1332,9 +1676,9 @@ "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" }, "is-core-module": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", - "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", + "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", "requires": { "has": "^1.0.3" } @@ -1342,7 +1686,7 @@ "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==" }, "is-fullwidth-code-point": { "version": "3.0.0", @@ -1372,11 +1716,6 @@ "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==" }, - "is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" - }, "is-unicode-supported": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", @@ -1385,7 +1724,7 @@ "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, "iterall": { "version": "1.3.0", @@ -1396,21 +1735,12 @@ "version": "10.8.5", "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.5.tgz", "integrity": "sha512-sVpxYeuAhWt0OTWITwT98oyV0GsXyMlXCF+3L1SuafBVUIr/uILGRB+NqwkzhgXKvoJpDIpQvqkUALgdmQsQxw==", + "dev": true, "requires": { "async": "^3.2.3", "chalk": "^4.0.2", "filelist": "^1.0.1", "minimatch": "^3.0.4" - }, - "dependencies": { - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "requires": { - "brace-expansion": "^1.1.7" - } - } } }, "js-tokens": { @@ -1436,21 +1766,32 @@ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" }, + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "optional": true, + "requires": { + "minimist": "^1.2.0" + } + }, "jsonfile": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, "requires": { "graceful-fs": "^4.1.6", "universalify": "^2.0.0" } }, "keyv": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.2.2.tgz", - "integrity": "sha512-uYS0vKTlBIjNCAUqrjlxmruxOEiZxZIHXyp32sdcGmP+ukFrmWUnE//RcPXJH3Vxrni1H2gsQbjHE0bH7MtMQQ==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.3.3.tgz", + "integrity": "sha512-AcysI17RvakTh8ir03+a3zJr5r0ovnAH/XTXei/4HIv3bL2K/jzvgivLK9UuI/JbU1aJjM3NSAnVvVVd3n+4DQ==", "requires": { - "compress-brotli": "^1.3.6", + "compress-brotli": "^1.3.8", "json-buffer": "3.0.1" } }, @@ -1468,22 +1809,31 @@ } }, "locklift": { - "version": "git+https://github.com/broxus/ton-locklift.git#028ed8b5f19a571b0e9dc3f703f3e3067ba74f43", - "from": "git+https://github.com/broxus/ton-locklift.git", + "version": "2.1.10", + "resolved": "https://registry.npmjs.org/locklift/-/locklift-2.1.10.tgz", + "integrity": "sha512-0Hqrhv5MBDZJtRHJD7bF8lgnsBQkAWrVeAxQ9o9pLTZ4eUCAGOCvOqY93dT67pHGUe/08vkVeWv32G7BBj44zQ==", + "dev": true, "requires": { - "@broxus/contracts": "^1.0.3", - "@tonclient/core": "^1.28.0", - "@tonclient/lib-node": "^1.28.0", + "axios": "^0.27.2", "bignumber.js": "^9.0.1", + "chalk": "^4.1.2", "commander": "^7.2.0", - "directory-tree": "^2.2.7", + "directory-tree": "^3.2.2", "ejs": "^3.1.6", - "execa": "^5.0.0", - "fs-extra": "^9.1.0", - "mocha": "^8.3.2", - "superstruct": "^0.14.2", + "env-paths": "^2.2.1", + "everscale-crypto": "^0.1.1", + "everscale-inpage-provider": "^0.3.34", + "everscale-standalone-client": "^2.0.27", + "fs-extra": "^10.1.0", + "lodash": "^4.17.21", + "mocha": "^10.0.0", + "node-gzip": "^1.1.2", + "rxjs": "^7.5.6", + "superstruct": "^0.16.0", "tablemark": "^2.0.0", - "ton-client-js": "^0.28.1", + "ts-mocha": "^10.0.0", + "tsconfig-paths": "^4.0.0", + "typescript": "^4.7.4", "underscore": "^1.13.1" } }, @@ -1492,10 +1842,16 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, + "lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "dev": true + }, "lodash.truncate": { "version": "4.4.2", "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=" + "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==" }, "log-symbols": { "version": "4.1.0", @@ -1510,6 +1866,7 @@ "version": "2.3.4", "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.4.tgz", "integrity": "sha512-OvKfgCC2Ndby6aSTREl5aCCPTNIzlDfQZvZxNUrBrihDhL3xcrYegTblhmEiCrg2kKQz4XsFIaemE5BF4ybSaQ==", + "dev": true, "requires": { "get-func-name": "^2.0.0" } @@ -1517,13 +1874,20 @@ "lower-case": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", - "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw=" + "integrity": "sha512-2Fgx1Ycm599x+WGpIYwJOvsjmXFzTSc34IwDWALRA/8AopUKAVPwfJ+h5+f85BCp0PWmmJcWzEpxOpoXycMpdA==", + "dev": true }, "lowercase-keys": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==" }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, "md5": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", @@ -1534,90 +1898,142 @@ "is-buffer": "~1.1.6" } }, - "merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "requires": { + "mime-db": "1.52.0" + } }, "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==" }, "mimic-response": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", - "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==" }, "minimatch": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz", - "integrity": "sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "requires": { "brace-expansion": "^1.1.7" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + } } }, "minimist": { "version": "1.2.6", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", + "dev": true }, "mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "requires": { + "minimist": "^1.2.6" + } }, "mocha": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.4.0.tgz", - "integrity": "sha512-hJaO0mwDXmZS4ghXsvPVriOhsxQ7ofcpQdm8dE+jISUOKopitvnXFQmpRR7jd2K6VBG6E26gU3IAbXXGIbu4sQ==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.0.0.tgz", + "integrity": "sha512-0Wl+elVUD43Y0BqPZBzZt8Tnkw9CMUdNYnUsTfOM1vuhJVZL+kiesFYsqwBkEEuEixaiPe5ZQdqDgX2jddhmoA==", + "dev": true, "requires": { "@ungap/promise-all-settled": "1.1.2", "ansi-colors": "4.1.1", "browser-stdout": "1.3.1", - "chokidar": "3.5.1", - "debug": "4.3.1", + "chokidar": "3.5.3", + "debug": "4.3.4", "diff": "5.0.0", "escape-string-regexp": "4.0.0", "find-up": "5.0.0", - "glob": "7.1.6", - "growl": "1.10.5", + "glob": "7.2.0", "he": "1.2.0", - "js-yaml": "4.0.0", - "log-symbols": "4.0.0", - "minimatch": "3.0.4", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "5.0.1", "ms": "2.1.3", - "nanoid": "3.1.20", - "serialize-javascript": "5.0.1", + "nanoid": "3.3.3", + "serialize-javascript": "6.0.0", "strip-json-comments": "3.1.1", "supports-color": "8.1.1", - "which": "2.0.2", - "wide-align": "1.1.3", - "workerpool": "6.1.0", + "workerpool": "6.2.1", "yargs": "16.2.0", "yargs-parser": "20.2.4", "yargs-unparser": "2.0.0" }, "dependencies": { - "chokidar": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz", - "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==", + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "minimatch": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "dev": true, "requires": { - "anymatch": "~3.1.1", - "braces": "~3.0.2", - "fsevents": "~2.3.1", - "glob-parent": "~5.1.0", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.5.0" + "brace-expansion": "^2.0.1" + } + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "mocha-logger": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/mocha-logger/-/mocha-logger-1.0.8.tgz", + "integrity": "sha512-TrdbQqsWUO9TtyRpL2wInVVcp00BSWQazweWIgq5uGYTpHrQZrMjtihystmP6Vk+HuGRHdvNq7lRM/LQNULSog==", + "requires": { + "mocha": "^9.2.2" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", "requires": { "ms": "2.1.2" }, @@ -1629,79 +2045,19 @@ } } }, - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "js-yaml": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz", - "integrity": "sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==", - "requires": { - "argparse": "^2.0.1" - } - }, - "log-symbols": { + "escape-string-regexp": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz", - "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==", - "requires": { - "chalk": "^4.0.0" - } + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" }, "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz", + "integrity": "sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g==", "requires": { "brace-expansion": "^1.1.7" } }, - "nanoid": { - "version": "3.1.20", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.20.tgz", - "integrity": "sha512-a1cQNyczgKbLX9jwbS/+d7W8fX/RfgYR7lVWwWOGIPNgK2m0MWvrGF6/m4kk6U3QcFMnZf3RIhL0v2Jgh/0Uxw==" - }, - "readdirp": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", - "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", - "requires": { - "picomatch": "^2.2.1" - } - }, - "serialize-javascript": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz", - "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==", - "requires": { - "randombytes": "^2.1.0" - } - }, - "workerpool": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.1.0.tgz", - "integrity": "sha512-toV7q9rWNYha963Pl/qyeZ6wG+3nnsyvolaNUS8+R5Wtw6qJPTxIlOP1ZSvcGhEJw+l3HMMmtiNo9Gl61G4GVg==" - } - } - }, - "mocha-logger": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/mocha-logger/-/mocha-logger-1.0.8.tgz", - "integrity": "sha512-TrdbQqsWUO9TtyRpL2wInVVcp00BSWQazweWIgq5uGYTpHrQZrMjtihystmP6Vk+HuGRHdvNq7lRM/LQNULSog==", - "requires": { - "mocha": "^9.2.2" - }, - "dependencies": { "mocha": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.2.tgz", @@ -1732,6 +2088,24 @@ "yargs-parser": "20.2.4", "yargs-unparser": "2.0.0" } + }, + "nanoid": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", + "integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==" + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "requires": { + "has-flag": "^4.0.0" + } + }, + "workerpool": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz", + "integrity": "sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==" } } }, @@ -1741,14 +2115,22 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "nanoid": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", - "integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==" + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", + "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", + "dev": true + }, + "nekoton-wasm": { + "version": "0.5.12", + "resolved": "https://registry.npmjs.org/nekoton-wasm/-/nekoton-wasm-0.5.12.tgz", + "integrity": "sha512-9nrmf0NmqQLVqkeEP6hut3tCfPpYeTjSKRDSF/P1AC/I7wHqGDmdIL4XPCzxMDKES8LXDdg1KcQdfegyoKnTdQ==", + "dev": true }, "no-case": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", + "dev": true, "requires": { "lower-case": "^1.1.1" } @@ -1761,6 +2143,12 @@ "whatwg-url": "^5.0.0" } }, + "node-gzip": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/node-gzip/-/node-gzip-1.1.2.tgz", + "integrity": "sha512-ZB6zWpfZHGtxZnPMrJSKHVPrRjURoUzaDbLFj3VO70mpLTW5np96vXyHwft4Id0o+PYIzgDkBUjIzaNHhQ8srw==", + "dev": true + }, "node-stream-zip": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/node-stream-zip/-/node-stream-zip-1.15.0.tgz", @@ -1776,28 +2164,20 @@ "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==" }, - "npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "requires": { - "path-key": "^3.0.0" - } - }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "requires": { "wrappy": "1" } }, "onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ==", "requires": { - "mimic-fn": "^2.1.0" + "mimic-fn": "^1.0.0" } }, "opentracing": { @@ -1860,17 +2240,12 @@ "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" }, "log-symbols": { "version": "2.2.0", @@ -1903,19 +2278,6 @@ "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==" }, - "p-event": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/p-event/-/p-event-4.2.0.tgz", - "integrity": "sha512-KXatOjCRXXkSePPb1Nbi0p0m+gQAwdlbhi4wQKJPI1HsMQS9g+Sqp2o+QHziPr7eYJyOZet836KoHEVM1mwOrQ==", - "requires": { - "p-timeout": "^3.1.0" - } - }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" - }, "p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -1932,14 +2294,6 @@ "p-limit": "^3.0.2" } }, - "p-timeout": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", - "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", - "requires": { - "p-finally": "^1.0.0" - } - }, "p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", @@ -1953,12 +2307,7 @@ "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" }, "path-parse": { "version": "1.0.7", @@ -1968,7 +2317,8 @@ "pathval": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", - "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==" + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true }, "picomatch": { "version": "2.3.1", @@ -1976,9 +2326,9 @@ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" }, "prettier": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", - "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==" + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", + "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==" }, "prompts": { "version": "2.4.2", @@ -2003,6 +2353,11 @@ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" }, + "quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==" + }, "randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -2022,11 +2377,17 @@ "rechoir": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", "requires": { "resolve": "^1.1.6" } }, + "reduce-flatten": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-2.0.0.tgz", + "integrity": "sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==", + "dev": true + }, "regenerator-runtime": { "version": "0.13.9", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", @@ -2035,7 +2396,7 @@ "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==" }, "require-from-string": { "version": "2.0.2", @@ -2048,19 +2409,24 @@ "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" }, "resolve": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", - "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", "requires": { - "is-core-module": "^2.8.1", + "is-core-module": "^2.9.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" } }, + "resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==" + }, "responselike": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.0.tgz", - "integrity": "sha512-xH48u3FTB9VsZw7R+vvgaKeLKzT6jOogbQhEe/jewwnZgzPcnyWui2Av6JpoYZF/91uueC+lqhWqeURw5/qhCw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", + "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", "requires": { "lowercase-keys": "^2.0.0" } @@ -2068,25 +2434,10 @@ "restore-cursor": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "integrity": "sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q==", "requires": { "onetime": "^2.0.0", "signal-exit": "^3.0.2" - }, - "dependencies": { - "mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==" - }, - "onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", - "requires": { - "mimic-fn": "^1.0.0" - } - } } }, "rimraf": { @@ -2097,6 +2448,15 @@ "glob": "^7.1.3" } }, + "rxjs": { + "version": "7.5.6", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.6.tgz", + "integrity": "sha512-dnyv2/YsXhnm461G+R/Pe5bWP41Nm6LBXEYWI6eiFP4fiwx6WRI/CD0zbdVAudd9xwLEF2IDcKXLHit0FYjUzw==", + "dev": true, + "requires": { + "tslib": "^2.1.0" + } + }, "safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -2110,7 +2470,8 @@ "sentence-case": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/sentence-case/-/sentence-case-2.1.1.tgz", - "integrity": "sha1-H24t2jnBaL+S0T+G1KkYkz9mftQ=", + "integrity": "sha512-ENl7cYHaK/Ktwk5OTD+aDbQ3uC8IByu/6Bkg+HDv8Mm+XnBnppVNalcfJTNsp1ibstKh030/JKQQWglDvtKwEQ==", + "dev": true, "requires": { "no-case": "^2.2.0", "upper-case-first": "^1.1.2" @@ -2127,20 +2488,7 @@ "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" }, "shelljs": { "version": "0.8.5", @@ -2172,10 +2520,27 @@ "is-fullwidth-code-point": "^3.0.0" } }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, "split-text-to-chunks": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/split-text-to-chunks/-/split-text-to-chunks-1.0.0.tgz", "integrity": "sha512-HLtEwXK/T4l7QZSJ/kOSsZC0o5e2Xg3GzKKFxm0ZexJXw0Bo4CaEl39l7MCSRHk9EOOL5jT8JIDjmhTtcoe6lQ==", + "dev": true, "requires": { "get-stdin": "^5.0.1", "minimist": "^1.2.0" @@ -2199,10 +2564,11 @@ "ansi-regex": "^5.0.1" } }, - "strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==" + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true }, "strip-json-comments": { "version": "3.1.1", @@ -2222,14 +2588,15 @@ } }, "superstruct": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-0.14.2.tgz", - "integrity": "sha512-nPewA6m9mR3d6k7WkZ8N8zpTWfenFH3q9pA2PkuiZxINr9DKB2+40wEQf0ixn8VaGuJ78AB6iWOtStI+/4FKZQ==" + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-0.16.0.tgz", + "integrity": "sha512-IDQtwnnlaan1NhuHqyD/U11lROYvCQ79JyfwlFU9xEVHzqV/Ys/RrwmHPCG0CVH/1g0BuodEjH1msxK2UHxehA==", + "dev": true }, "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "requires": { "has-flag": "^4.0.0" } @@ -2256,20 +2623,42 @@ "strip-ansi": "^6.0.1" } }, + "table-layout": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-1.0.2.tgz", + "integrity": "sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A==", + "dev": true, + "requires": { + "array-back": "^4.0.1", + "deep-extend": "~0.6.0", + "typical": "^5.2.0", + "wordwrapjs": "^4.0.0" + }, + "dependencies": { + "array-back": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", + "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==", + "dev": true + }, + "typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", + "dev": true + } + } + }, "tablemark": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/tablemark/-/tablemark-2.0.0.tgz", "integrity": "sha512-bgvShWeSUIWO4j6NH7wGrn1xUQMJ/LRZFIRWE6ka5CFNfQ5qOP9FB4amKCurUUr7C0K4AJGHYDLkaf8A6t5Aww==", + "dev": true, "requires": { "sentence-case": "^2.1.1", "split-text-to-chunks": "^1.0.0" } }, - "to-readable-stream": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-2.1.0.tgz", - "integrity": "sha512-o3Qa6DGg1CEXshSdvWNX2sN4QHqg03SPq7U6jPXRahlQdl5dK8oXjkU/2/sGrnOZKeGV1zLSO8qPwyKklPPE7w==" - }, "to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -2302,7 +2691,7 @@ "tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, "ts-invariant": { "version": "0.4.4", @@ -2310,37 +2699,117 @@ "integrity": "sha512-uEtWkFM/sdZvRNNDL3Ehu4WVpwaulhwQszV8mrtcdeE8nN00BV9mAmQ88RkrBhFgl9gMgvjJLAQcZbnPXI9mlA==", "requires": { "tslib": "^1.9.3" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + } + } + }, + "ts-mocha": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/ts-mocha/-/ts-mocha-10.0.0.tgz", + "integrity": "sha512-VRfgDO+iiuJFlNB18tzOfypJ21xn2xbuZyDvJvqpTbWgkAgD17ONGr8t+Tl8rcBtOBdjXp5e/Rk+d39f7XBHRw==", + "dev": true, + "requires": { + "ts-node": "7.0.1", + "tsconfig-paths": "^3.5.0" + }, + "dependencies": { + "tsconfig-paths": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", + "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==", + "dev": true, + "optional": true, + "requires": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + } + } + }, + "ts-node": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-7.0.1.tgz", + "integrity": "sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw==", + "dev": true, + "requires": { + "arrify": "^1.0.0", + "buffer-from": "^1.1.0", + "diff": "^3.1.0", + "make-error": "^1.1.1", + "minimist": "^1.2.0", + "mkdirp": "^0.5.1", + "source-map-support": "^0.5.6", + "yn": "^2.0.0" + }, + "dependencies": { + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true + } + } + }, + "tsconfig-paths": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.1.0.tgz", + "integrity": "sha512-AHx4Euop/dXFC+Vx589alFba8QItjF+8hf8LtmuiCwHyI4rHXQtOOENaM8kvYf5fR0dRChy3wzWIZ9WbB7FWow==", + "dev": true, + "requires": { + "json5": "^2.2.1", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + }, + "dependencies": { + "json5": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", + "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "dev": true + } } }, "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", + "dev": true }, "type-detect": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==" - }, - "type-fest": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.10.0.tgz", - "integrity": "sha512-EUV9jo4sffrwlg8s0zDhP0T2WD3pru5Xi0+HTE3zTUmBaZNhfkite9PdSJwdXLwPVW0jnAHT56pZHIOYckPEiw==" + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true }, "typescript": { - "version": "4.4.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz", - "integrity": "sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA==" + "version": "4.7.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", + "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", + "dev": true }, "typescript-compiler": { "version": "1.4.1-2", "resolved": "https://registry.npmjs.org/typescript-compiler/-/typescript-compiler-1.4.1-2.tgz", - "integrity": "sha1-uk99si2RU0oZKdkACdzhYety/T8=" + "integrity": "sha512-EMopKmoAEJqA4XXRFGOb7eSBhmQMbBahW6P1Koayeatp0b4AW2q/bBqYWkpG7QVQc9HGQUiS4trx2ZHcnAaZUg==" + }, + "typical": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz", + "integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==", + "dev": true }, "underscore": { - "version": "1.13.3", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.3.tgz", - "integrity": "sha512-QvjkYpiD+dJJraRA8+dGAU4i7aBbb2s0S3jA45TFOvg2VgqvdCDd/3N6CqA8gluk1W91GLoXg5enMUx560QzuA==" + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.4.tgz", + "integrity": "sha512-BQFnUDuAQ4Yf/cYY5LNrK9NCJFKriaRbD9uR1fTeXnBeoa97W0i41qkZfGO9pSo8I5KzjAcSY2XYtdf0oKd7KQ==", + "dev": true }, "universal-user-agent": { "version": "6.0.0", @@ -2350,17 +2819,20 @@ "universalify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==" + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true }, "upper-case": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", - "integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=" + "integrity": "sha512-WRbjgmYzgXkCV7zNVpy5YgrHgbBv126rMALQQMrmzOVC4GM2waQ9x7xtm8VU+1yF2kWyPzI9zbZ48n4vSxwfSA==", + "dev": true }, "upper-case-first": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/upper-case-first/-/upper-case-first-1.1.2.tgz", - "integrity": "sha1-XXm+3P8UQZUY/S7bCgUHybaFkRU=", + "integrity": "sha512-wINKYvI3Db8dtjikdAqoBbZoP6Q+PZUyfMR7pmwHzjC2quzSkUq5DmPrTtPEqHaz8AGtmsB4TqwapMTM1QAQOQ==", + "dev": true, "requires": { "upper-case": "^1.1.1" } @@ -2376,7 +2848,7 @@ "wcwidth": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", - "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", "requires": { "defaults": "^1.0.3" } @@ -2384,12 +2856,12 @@ "webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" }, "whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", "requires": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" @@ -2406,7 +2878,7 @@ "which-module": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" + "integrity": "sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==" }, "wide-align": { "version": "1.1.3", @@ -2424,7 +2896,7 @@ "is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==" }, "string-width": { "version": "2.1.1", @@ -2438,17 +2910,36 @@ "strip-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", "requires": { "ansi-regex": "^3.0.0" } } } }, + "wordwrapjs": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-4.0.1.tgz", + "integrity": "sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA==", + "dev": true, + "requires": { + "reduce-flatten": "^2.0.0", + "typical": "^5.2.0" + }, + "dependencies": { + "typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", + "dev": true + } + } + }, "workerpool": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz", - "integrity": "sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==" + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", + "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", + "dev": true }, "wrap-ansi": { "version": "7.0.0", @@ -2463,7 +2954,7 @@ "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, "ws": { "version": "5.2.3", @@ -2508,6 +2999,12 @@ "is-plain-obj": "^2.1.0" } }, + "yn": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz", + "integrity": "sha512-uTv8J/wiWTgUTg+9vLTi//leUl5vDQS6uii/emeTb2ssY7vl6QWf2fFbIIGjnhjvbdKlU0ed7QPgY1htTC86jQ==", + "dev": true + }, "yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", @@ -2525,6 +3022,13 @@ "requires": { "tslib": "^1.9.3", "zen-observable": "^0.8.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + } } } } diff --git a/demo/Farming/package.json b/demo/Farming/package.json index 1d63322..cfd6589 100644 --- a/demo/Farming/package.json +++ b/demo/Farming/package.json @@ -1,18 +1,28 @@ { - "name": "farming", - "version": "1.0.1", + "name": "nft-farming", + "version": "2.0.0", "description": "", - "main": "index.js", "scripts": { - "deploy": "locklift run --config locklift.config.js --network local --script scripts/1-deploy-farming.js" + "deploy-collection": "npx locklift run --network rfld --script scripts/3-deploy-collection.ts --disable-build", + "deploy-root": "npx locklift run --network rfld --script scripts/2-deploy-token-root.ts --disable-build", + "mint-nft": "npx locklift run --network rfld --script scripts/4-mint-nft.ts --disable-build" }, - "keywords": [], "author": "", "license": "ISC", + "devDependencies": { + "@types/chai": "^4.3.3", + "@types/mocha": "^9.1.1", + "@types/node": "^18.7.6", + "chai": "^4.3.6", + "everscale-standalone-client": "^2.0.27", + "locklift": "^2.1.10", + "prettier": "^2.7.1", + "ts-mocha": "^10.0.0", + "typescript": "^4.7.4" + }, "dependencies": { "@itgold/everscale-tip": "^1.1.3", - "broxus-ton-tokens-contracts": "git+https://github.com/broxus/ton-eth-bridge-token-contracts.git", - "locklift": "git+https://github.com/broxus/ton-locklift.git", - "prompts": "^2.4.2" + "bignumber.js": "^9.1.0", + "broxus-ton-tokens-contracts": "git+https://github.com/broxus/tip3.git" } } diff --git a/demo/Farming/scripts/1-deploy-farming.js b/demo/Farming/scripts/1-deploy-farming.js deleted file mode 100644 index bebbb42..0000000 --- a/demo/Farming/scripts/1-deploy-farming.js +++ /dev/null @@ -1,90 +0,0 @@ -const { - isValidTonAddress -} = require('./utils'); -const prompts = require('prompts'); - -async function main() { - - const promptsData = []; - - promptsData.push({ - type: 'text', - name: 'collection', - message: 'Collection address', - validate: value => isValidTonAddress(value) ? true : 'Invalid TON address' - }); - - promptsData.push({ - type: 'text', - name: 'rewardTokenRoot', - message: 'RewardTokenRoot (TIP3 Root) address', - validate: value => isValidTonAddress(value) ? true : 'Invalid TON address' - }); - - promptsData.push({ - type: 'text', - name: 'lockPeriod', - message: 'Lock period', - validate: value => !!value - }); - - promptsData.push({ - type: 'text', - name: 'farmStartTime', - message: 'Farm start time', - validate: value => !!value - }); - - promptsData.push({ - type: 'text', - name: 'rewardPerSecond', - message: 'Reward per second', - validate: value => !!value - }); - - promptsData.push({ - type: 'text', - name: 'owner', - message: 'Owner address', - validate: value => isValidTonAddress(value) ? true : 'Invalid TON address' - }); - - const Farming = await locklift.factory.getContract('NFTFarming'); - const Nft = await locklift.factory.getContract('Nft'); - const [keyPair] = await locklift.keys.getKeyPairs(); - - const response = await prompts(promptsData); - - const collection = response.collection; - const rewardTokenRoot = response.rewardTokenRoot; - const lockPeriod = response.lockPeriod; - const farmStartTime = response.farmStartTime; - const rewardPerSecond = response.rewardPerSecond; - const owner = response.owner; - - const farming = await locklift.giver.deployContract({ - contract: Farming, - constructorParams: { - owner: owner, - collection: collection, - rewardTokenRoot: rewardTokenRoot, - codeNft: Nft.code, - lockPeriod: lockPeriod, - farmStartTime: farmStartTime, - rewardPerSecond: rewardPerSecond - }, - initParams: { - }, - keyPair, - }); - - console.log(`Farming deployed at: ${farming.address}`); -} - - -main() - .then(() => process.exit(0)) - .catch(e => { - console.log(e); - process.exit(1); - }); diff --git a/demo/Farming/scripts/1-deploy-pool.ts b/demo/Farming/scripts/1-deploy-pool.ts new file mode 100644 index 0000000..bf9dd33 --- /dev/null +++ b/demo/Farming/scripts/1-deploy-pool.ts @@ -0,0 +1,98 @@ +import prompts from 'prompts'; +import { Address } from "everscale-inpage-provider"; +import { + isValidEverAddress, +} from './utils'; + +async function main() { + const promptsData = []; + + promptsData.push({ + type: 'text', + name: 'owner', + message: 'Owner address', + validate: value => isValidEverAddress(value) ? true : 'Invalid Ever address' + }); + + promptsData.push({ + type: 'text', + name: 'collection', + message: 'Collection address', + validate: value => isValidEverAddress(value) ? true : 'Invalid Ever address' + }); + + promptsData.push({ + type: 'text', + name: 'rewardTokenRoot', + message: 'Reward token root address', + validate: value => isValidEverAddress(value) ? true : 'Invalid Ever address' + }); + + promptsData.push({ + type: 'text', + name: 'farmStartTime', + message: 'Farm start time (default: now + 100sec)', + validate: value => value === '' || !!value + }); + + promptsData.push({ + type: 'text', + name: 'rewardPerSecond', + message: 'Reward per second', + validate: value => !!value + }); + + promptsData.push({ + type: 'text', + name: 'vestingPeriod', + message: 'Vesting period (in sec)', + validate: value => !!value + }); + + promptsData.push({ + type: 'text', + name: 'vestingRatio', + message: 'Vesting ratio (1 = 0.1% 1000 = 100%)', + validate: value => !!value + }); + + const response = await prompts(promptsData); + + let owner = response.owner; + let collection = response.collection; + let rewardTokenRoot = response.rewardTokenRoot; + let farmStartTime = response.farmStartTime; + let rewardPerSecond = response.rewardPerSecond; + let vestingPeriod = response.vestingPeriod; + let vestingRatio = response.vestingRatio; + + let keyPair = (await locklift.keystore.getSigner("0"))!; + let UserData = await locklift.factory.getContractArtifacts('UserData'); + let Nft = await locklift.factory.getContractArtifacts('Nft'); + const { contract: farmingPool, tx } = await locklift.factory.deployContract({ + contract: "FarmingPool", + publicKey: keyPair.publicKey, + constructorParams: { + owner: owner, + collection: collection, + rewardTokenRoot: rewardTokenRoot, + codeNft: Nft.code, + codeUserData: UserData.code, + farmStartTime: farmStartTime, + rewardPerSecond: rewardPerSecond, + vestingPeriod: vestingPeriod, + vestingRatio: vestingRatio, + }, + initParams: {}, + value: locklift.utils.toNano(10) + }); + + console.log(`FarmingPool deployed at: ${farmingPool.address.toString()}`); +} + +main() +.then(() => process.exit(0)) +.catch(e => { + console.log(e); + process.exit(1); +}); diff --git a/demo/Farming/scripts/2-deploy-token-root.ts b/demo/Farming/scripts/2-deploy-token-root.ts new file mode 100644 index 0000000..1e96630 --- /dev/null +++ b/demo/Farming/scripts/2-deploy-token-root.ts @@ -0,0 +1,142 @@ +import prompts from 'prompts'; +import { Address } from "everscale-inpage-provider"; + +import { + isValidEverAddress, + isNumeric +} from './utils'; +// import { zeroAddress } from 'constants'; +import BigNumber from 'bignumber.js'; +BigNumber.config({EXPONENTIAL_AT: 257}); + +const zeroAddress = "0:0000000000000000000000000000000000000000000000000000000000000000"; + +async function main() { + const promptsData = []; + + promptsData.push({ + type: 'text', + name: 'rootOwner', + message: 'Root owner', + validate: value => isValidEverAddress(value) ? true : 'Invalid Ever address' + }); + + promptsData.push({ + type: 'text', + name: 'name', + message: 'Name', + validate: value => !!value + }); + + promptsData.push({ + type: 'text', + name: 'symbol', + message: 'Symbol', + validate: value => !!value + }); + + promptsData.push({ + type: 'text', + name: 'decimals', + message: 'Decimals', + validate: value => isNumeric(value) && (+value) <= 18 ? true : 'Invalid number' + }); + + let disableMint; + promptsData.push({ + type: 'select', + name: 'disableMint', + message: 'Disable mint (fixed supply)', + choices: [ + { title: 'No', value: 'false' }, + { title: 'Yes', value: 'true' } + ], + }); + + let disableBurnByRoot; + promptsData.push({ + type: 'select', + name: 'disableBurnByRoot', + message: 'Disable burn by root owner', + choices: [ + { title: 'Yes', value: 'true' }, + { title: 'No', value: 'false' } + ], + }); + + let pauseBurn; + promptsData.push({ + type: 'select', + name: 'pauseBurn', + message: 'Pause burn', + choices: [ + { title: 'No', value: 'false' }, + { title: 'Yes', value: 'true' } + ], + }); + + promptsData.push({ + type: 'text', + name: 'initialSupplyTo', + message: 'Initial supply to address (default: NO INITIAL SUPPLY)', + validate: value => value === '' || isValidEverAddress(value) ? true : 'Invalid Ever address' + }); + + const response = await prompts(promptsData); + + const initialSupplyTo = response.initialSupplyTo || zeroAddress; + const rootOwner = new Address(response.rootOwner); + const name = response.name; + const symbol = response.symbol; + const decimals = +response.decimals; + disableMint = typeof(disableMint) === 'boolean' ? disableMint : response.disableMint === 'true'; + disableBurnByRoot = typeof(disableBurnByRoot) === 'boolean' ? disableBurnByRoot : response.disableBurnByRoot === 'true'; + pauseBurn = typeof(pauseBurn) === 'boolean' ? pauseBurn : response.pauseBurn === 'true'; + + let initialSupply; + if (initialSupplyTo !== zeroAddress) { + initialSupply = (await prompts({ + type: 'text', + name: 'initialSupply', + message: 'Initial supply (amount)', + validate: value => isNumeric(value) ? true : 'Invalid number' + })).initialSupply || '0'; + } else { + initialSupply = '0'; + } + + let keyPair = (await locklift.keystore.getSigner("0"))!; + let TokenWallet = await locklift.factory.getContractArtifacts('TokenWallet'); + const { contract: tokenRoot, tx } = await locklift.factory.deployContract({ + contract: "TokenRoot", + publicKey: keyPair.publicKey, + constructorParams: { + initialSupplyTo: new Address(initialSupplyTo), + initialSupply: new BigNumber(initialSupply).shiftedBy(decimals).toFixed(), + deployWalletValue: locklift.utils.toNano(0.1), + mintDisabled: disableMint, + burnByRootDisabled: disableBurnByRoot, + burnPaused: pauseBurn, + remainingGasTo: new Address(zeroAddress) + }, + initParams: { + deployer_: new Address(zeroAddress), + randomNonce_: locklift.utils.getRandomNonce(), + rootOwner_: rootOwner, + name_: name, + symbol_: symbol, + decimals_: decimals, + walletCode_: TokenWallet.code, + }, + value: locklift.utils.toNano(10), + }); + + console.log(`TokenRoot deployed at: ${tokenRoot.address.toString()}`); +} + +main() +.then(() => process.exit(0)) +.catch(e => { + console.log(e); + process.exit(1); +}); diff --git a/demo/Farming/scripts/3-deploy-collection.ts b/demo/Farming/scripts/3-deploy-collection.ts new file mode 100644 index 0000000..1a8a4b1 --- /dev/null +++ b/demo/Farming/scripts/3-deploy-collection.ts @@ -0,0 +1,32 @@ +import { generateBip39Phrase, deriveBip39Phrase, makeBip39Path } from "everscale-crypto"; + +async function main() { + let keyPair = (await locklift.keystore.getSigner("0"))!; + let Nft = await locklift.factory.getContractArtifacts('Nft'); + // const randKeypair = await locklift.ton.client.crypto.generate_random_sign_keys(); + let phrase = generateBip39Phrase(12); + phrase = "hero cave pencil nasty dolphin jewel try ridge valid away sell awesome"; + // console.log(phrase); + let path = makeBip39Path(0x1); + let randKeypair = deriveBip39Phrase(phrase, path); + console.log(randKeypair); + const { contract: collection, tx } = await locklift.factory.deployContract({ + contract: "Collection", + publicKey: randKeypair.publicKey, + constructorParams: { + codeNft: Nft.code, + ownerPubkey: "0x" + keyPair.publicKey + }, + initParams: {}, + value: locklift.utils.toNano(5), + }); + + console.log(`Collection deployed at: ${collection.address.toString()}`); +} + +main() +.then(() => process.exit(0)) +.catch(e => { + console.log(e); + process.exit(1); +}); diff --git a/demo/Farming/scripts/4-mint-nft.ts b/demo/Farming/scripts/4-mint-nft.ts new file mode 100644 index 0000000..6cfeade --- /dev/null +++ b/demo/Farming/scripts/4-mint-nft.ts @@ -0,0 +1,67 @@ +import { + isValidEverAddress, +} from './utils'; +import prompts from 'prompts'; +import { Address } from "everscale-inpage-provider"; + +async function main() { + + const keyPair = (await locklift.keystore.getSigner("0"))!; + + const promptsData = []; + + promptsData.push({ + type: 'text', + name: 'collection', + message: 'Collection address', + validate: value => isValidEverAddress(value) ? true : 'Invalid Ever address' + }); + + promptsData.push({ + type: 'text', + name: 'owner', + message: 'Owner address', + validate: value => isValidEverAddress(value) ? true : 'Invalid Ever address' + }); + + const response = await prompts(promptsData); + + let accountsFactory = locklift.factory.getAccountsFactory( + "Wallet", + ); + let collectionOwner = await accountsFactory.getAccount(new Address(response.owner), keyPair.publicKey); + + let collection = await locklift.factory.getDeployedContract( + "Collection", + new Address(response.collection), + ); + + await collectionOwner.runTarget( + { + contract: collection, + value: locklift.utils.toNano(3), + }, + collection => + collection.methods.mintNft({}), + ); + + const totalSupply = await collection.methods.totalSupply({ + answerId: 0 + }).call(); + + let id = totalSupply['count'] - 1; + const nftAddr = await collection.methods.nftAddress({ + id: id, + answerId: 0, + }).call(); + + console.log("Nft was successfully minted!"); + console.log("Address: " + nftAddr['nft']['_address']); +} + +main() + .then(() => process.exit(0)) + .catch(e => { + console.log(e); + process.exit(1); +}); \ No newline at end of file diff --git a/demo/Farming/scripts/5-deploy-owner.ts b/demo/Farming/scripts/5-deploy-owner.ts new file mode 100644 index 0000000..9544229 --- /dev/null +++ b/demo/Farming/scripts/5-deploy-owner.ts @@ -0,0 +1,23 @@ +async function main() { + let keyPair = (await locklift.keystore.getSigner("0"))!; + let accountsFactory = locklift.factory.getAccountsFactory( + "Wallet", + ); + const {account: owner, tx} = await accountsFactory.deployNewAccount({ + publicKey: keyPair.publicKey, + initParams: { + _randomNonce: locklift.utils.getRandomNonce(), + }, + constructorParams: {}, + value: locklift.utils.toNano(5) + }); + + console.log(`Owner wallet deployed at: ${owner.address.toString()}`); +} + +main() +.then(() => process.exit(0)) +.catch(e => { + console.log(e); + process.exit(1); +}); diff --git a/demo/Farming/scripts/utils.ts b/demo/Farming/scripts/utils.ts new file mode 100644 index 0000000..b9ce9da --- /dev/null +++ b/demo/Farming/scripts/utils.ts @@ -0,0 +1,8 @@ +const isValidEverAddress = (address) => /^(?:-1|0):[0-9a-fA-F]{64}$/.test(address); + +const isNumeric = (value) => /^-?\d+$/.test(value); + +module.exports = { + isValidEverAddress, + isNumeric +} \ No newline at end of file diff --git a/demo/Farming/test/1-main.ts b/demo/Farming/test/1-main.ts new file mode 100644 index 0000000..708054d --- /dev/null +++ b/demo/Farming/test/1-main.ts @@ -0,0 +1,355 @@ +import { expect } from "chai"; +import { Contract, Signer } from "locklift"; +import { FactorySource } from "../build/factorySource"; +import { SimpleKeystore } from "everscale-standalone-client/nodejs"; +import { Address } from "everscale-inpage-provider"; +import { Account } from "locklift/factory"; +import { + setupTokenRoot, + setupCollection, + setupPool, + deployAccount, + TokenRoot, + Collection, + NFT, + FarmingPool, + TokenWallet, + sleep, + checkReward +} from "./utils"; + +let signer: Signer; +let adminAccount: Account; +let rewardTokenRoot: TokenRoot; +let collection: Collection; +let user1: Account; +let user2: Account; +let userNft1_1: NFT; +let userNft1_2: NFT; +let userNft2: NFT; +let farmPool: FarmingPool; +let farmPoolWallet: string; +let farmStart: number; +let farmEnd: number; +let rewardPerSec: number; +let adminRewardWallet: TokenWallet; +let event1; + +describe("Setup test", async function () { + before(async () => { + let randKeypair = SimpleKeystore.generateKeyPair(); + await locklift.keystore.addKeyPair("random", randKeypair); + signer = (await locklift.keystore.getSigner("random"))!; + }); + + describe("Setup contracts", async function () { + describe("TIP3 tokens", async function () { + it('Deploy admin', async function() { + adminAccount = await deployAccount(); + }); + + it('Deploy roots', async function() { + rewardTokenRoot = await setupTokenRoot(signer, "Reward token", "RT", adminAccount); + collection = await setupCollection(signer); + }); + + it('Mint tokens', async function() { + adminRewardWallet = await rewardTokenRoot.mint(1e18, adminAccount); + }); + }); + + describe("Users", async function () { + it('Deploy users accounts', async function() { + let users = []; + for(let i of [1, 2]){ + const user = await deployAccount(); + users.push(user); + } + [user1, user2] = users; + }); + + it('Mint tip4 tokens(nft\'s)', async function() { + userNft1_1 = await collection.mintNft(user1); + userNft1_2 = await collection.mintNft(user1); + userNft2 = await collection.mintNft(user2); + + expect(await locklift.provider.getBalance(userNft1_1.nft.address).then(balance => Number(balance))).to.be.above(0); + expect(await locklift.provider.getBalance(userNft1_2.nft.address).then(balance => Number(balance))).to.be.above(0); + expect(await locklift.provider.getBalance(userNft2.nft.address).then(balance => Number(balance))).to.be.above(0); + }); + }); + }); + + describe("Base staking pipeline testing", async function () { + describe("Farm pool", async function () { + it('Deploy farm pool', async function() { + farmStart = Math.floor(Date.now() / 1000); + farmEnd = Math.floor(Date.now() / 1000) + 10000; + rewardPerSec = 1; + + farmPool = await setupPool( + adminAccount, + collection.collection, + rewardTokenRoot.tokenRoot, + farmStart, + rewardPerSec, + 0, + 0 + ); + + farmPoolWallet = await farmPool.wallet(); + }); + + it('Sending reward tokens to pool', async function() { + const amount = (farmEnd - farmStart) * rewardPerSec; + + await farmPool.deposit(adminRewardWallet, amount); + const pastEvents = await farmPool.farmPool.getPastEvents({ filter: event => event.event === "RewardDeposit" }); + [event1] = pastEvents.events; + + expect(Number(event1.data.amount)).to.be.equal(amount); + expect(event1.data.tokenRoot.toString()).to.be.equal(rewardTokenRoot.tokenRoot.address.toString()); + + const info = await farmPool.info(); + const rewardBalance = info.rewardTokenWalletBalance; + + expect(Number(rewardBalance)).to.be.equal(amount); + }); + + it('User1 deposit 1st token', async function() { + await userNft1_1.changeManager(farmPool.farmPool, user1); + + const pastEvents = await farmPool.farmPool.getPastEvents({ filter: event => event.event === "Deposit" }); + let depositEvent = pastEvents.events[0]; + + expect(depositEvent.data.user.toString()).to.be.equal(user1.address.toString()); + expect(depositEvent.data.nft.toString()).to.be.equal(userNft1_1.nft.address.toString()); + + let expUserDataAddr = await farmPool.userDataAddress(user1.address.toString()); + expect(await locklift.provider.getBalance(expUserDataAddr).then(balance => Number(balance))).to.be.above(0); + + let expWalletAddr = await rewardTokenRoot.walletAddr(user1); + expect(await locklift.provider.getBalance(expWalletAddr).then(balance => Number(balance))).to.be.above(0); + }); + + it('User1 deposit 2nd token', async function() { + let preInfo = await farmPool.info(); + let user1Wallet = await rewardTokenRoot.wallet(user1); + let userOldWalletBalance = await user1Wallet.balance(); + + let user1Data = await farmPool.userData(user1); + let prevRewardDebt = await user1Data.rewardDebt(); + let prevNumOfDeposits = await user1Data.numOfDeposits(); + + await userNft1_2.changeManager(farmPool.farmPool, user1); + let newInfo = await farmPool.info(); + expect(Number(newInfo.lastRewardTime)).to.be.above(Number(preInfo.lastRewardTime)); + + await checkReward( + user1Wallet, + Number(userOldWalletBalance), + prevRewardDebt, + Number(newInfo.accRewardPerShare), + prevNumOfDeposits + ); + }); + + it('User1 claim half of staked amount', async function() { + let preInfo = await farmPool.info(); + let user1Wallet = await rewardTokenRoot.wallet(user1); + let userOldWalletBalance = await user1Wallet.balance(); + + await sleep(2000); + + let user1Data = await farmPool.userData(user1); + let prevRewardDebt = await user1Data.rewardDebt(); + let prevNumOfDeposits = await user1Data.numOfDeposits(); + + await farmPool.claimReward(user1); + + let newInfo = await farmPool.info(); + expect(Number(newInfo.lastRewardTime)).to.be.above(Number(preInfo.lastRewardTime)); + + await checkReward( + user1Wallet, + Number(userOldWalletBalance), + prevRewardDebt, + Number(newInfo.accRewardPerShare), + prevNumOfDeposits + ); + }); + + it('Withdraw tokens', async function() { + let preInfo = await farmPool.info(); + let user1Wallet = await rewardTokenRoot.wallet(user1); + let userOldWalletBalance = await user1Wallet.balance(); + + let user1Data = await farmPool.userData(user1); + let prevRewardDebt = await user1Data.rewardDebt(); + let prevNumOfDeposits = await user1Data.numOfDeposits(); + + await farmPool.withdraw(user1, userNft1_1.nft.address); + await userNft1_1.updateManager(user1); + + let newInfo = await farmPool.info(); + expect(Number(newInfo.lastRewardTime)).to.be.above(Number(preInfo.lastRewardTime)); + + let reward = await checkReward( + user1Wallet, + Number(userOldWalletBalance), + prevRewardDebt, + Number(newInfo.accRewardPerShare), + prevNumOfDeposits + ); + + let pastEvents = await farmPool.farmPool.getPastEvents({ filter: event => event.event === "Withdraw" }); + let withdrawEvent = pastEvents.events[0]; + + expect(Number(newInfo.totalDeposits)).to.be.equal(Number(preInfo.totalDeposits) - 1); + + expect(withdrawEvent.data.user.toString()).to.be.equal(user1.address.toString()); + expect(withdrawEvent.data.nft.toString()).to.be.equal(userNft1_1.nft.address.toString()); + expect(Number(withdrawEvent.data.reward)).to.be.equal(reward); + expect(Number(withdrawEvent.data.reward_debt)).to.be.equal(0); + + preInfo = await farmPool.info(); + user1Wallet = await rewardTokenRoot.wallet(user1); + userOldWalletBalance = await user1Wallet.balance(); + user1Data = await farmPool.userData(user1); + prevRewardDebt = await user1Data.rewardDebt(); + prevNumOfDeposits = await user1Data.numOfDeposits(); + + await farmPool.withdraw(user1, userNft1_2.nft.address); + await userNft1_2.updateManager(user1); + + newInfo = await farmPool.info(); + + reward = await checkReward( + user1Wallet, + Number(userOldWalletBalance), + prevRewardDebt, + Number(newInfo.accRewardPerShare), + prevNumOfDeposits + ); + + pastEvents = await farmPool.farmPool.getPastEvents({ filter: event => event.event === "Withdraw" }); + withdrawEvent = pastEvents.events[0]; + + expect(withdrawEvent.data.user.toString()).to.be.equal(user1.address.toString()); + expect(withdrawEvent.data.nft.toString()).to.be.equal(userNft1_2.nft.address.toString()); + expect(Number(withdrawEvent.data.reward)).to.be.equal(reward); + expect(Number(withdrawEvent.data.reward_debt)).to.be.equal(0); + }); + + it('Multiple users farming', async function() { + await userNft1_1.changeManager(farmPool.farmPool, user1); + + let pastEvents = await farmPool.farmPool.getPastEvents({ filter: event => event.event === "Deposit" }); + let depositEvent = pastEvents.events[0]; + + expect(depositEvent.data.user.toString()).to.be.equal(user1.address.toString()); + expect(depositEvent.data.nft.toString()).to.be.equal(userNft1_1.nft.address.toString()); + + let expUserDataAddr = await farmPool.userDataAddress(user1.address.toString()); + expect(await locklift.provider.getBalance(expUserDataAddr).then(balance => Number(balance))).to.be.above(0); + let expWalletAddr = await rewardTokenRoot.walletAddr(user1); + expect(await locklift.provider.getBalance(expWalletAddr).then(balance => Number(balance))).to.be.above(0); + + await userNft2.changeManager(farmPool.farmPool, user2); + + pastEvents = await farmPool.farmPool.getPastEvents({ filter: event => event.event === "Deposit" }); + depositEvent = pastEvents.events[0]; + + expect(depositEvent.data.user.toString()).to.be.equal(user2.address.toString()); + expect(depositEvent.data.nft.toString()).to.be.equal(userNft2.nft.address.toString()); + + expUserDataAddr = await farmPool.userDataAddress(user2.address.toString()); + expect(await locklift.provider.getBalance(expUserDataAddr).then(balance => Number(balance))).to.be.above(0); + + expWalletAddr = await rewardTokenRoot.walletAddr(user2); + expect(await locklift.provider.getBalance(expWalletAddr).then(balance => Number(balance))).to.be.above(0); + + let preInfo = await farmPool.info(); + let user1Wallet = await rewardTokenRoot.wallet(user1); + let userOldWalletBalance = await user1Wallet.balance(); + + let user1Data = await farmPool.userData(user1); + let prevRewardDebt = await user1Data.rewardDebt(); + let prevNumOfDeposits = await user1Data.numOfDeposits(); + + await farmPool.withdraw(user1, userNft1_1.nft.address); + await userNft1_1.updateManager(user1); + + let newInfo = await farmPool.info(); + expect(Number(newInfo.lastRewardTime)).to.be.above(Number(preInfo.lastRewardTime)); + + let reward = await checkReward( + user1Wallet, + Number(userOldWalletBalance), + prevRewardDebt, + Number(newInfo.accRewardPerShare), + prevNumOfDeposits + ); + + let withdrawEvents = await farmPool.farmPool.getPastEvents({ filter: event => event.event === "Withdraw" }); + let withdrawEvent = withdrawEvents.events[0]; + + expect(Number(newInfo.totalDeposits)).to.be.equal(Number(preInfo.totalDeposits) - 1); + + expect(withdrawEvent.data.user.toString()).to.be.equal(user1.address.toString()); + expect(withdrawEvent.data.nft.toString()).to.be.equal(userNft1_1.nft.address.toString()); + expect(Number(withdrawEvent.data.reward)).to.be.equal(reward); + expect(Number(withdrawEvent.data.reward_debt)).to.be.equal(0); + + preInfo = await farmPool.info(); + let user2Wallet = await rewardTokenRoot.wallet(user2); + userOldWalletBalance = await user2Wallet.balance(); + let user2Data = await farmPool.userData(user2); + prevRewardDebt = await user2Data.rewardDebt(); + prevNumOfDeposits = await user2Data.numOfDeposits(); + + await farmPool.withdraw(user2, userNft2.nft.address); + await userNft2.updateManager(user2); + + newInfo = await farmPool.info(); + expect(Number(newInfo.lastRewardTime)).to.be.above(Number(preInfo.lastRewardTime)); + + reward = await checkReward( + user2Wallet, + Number(userOldWalletBalance), + prevRewardDebt, + Number(newInfo.accRewardPerShare), + prevNumOfDeposits + ); + + withdrawEvents = await farmPool.farmPool.getPastEvents({ filter: event => event.event === "Withdraw" }); + withdrawEvent = withdrawEvents.events[0]; + + expect(Number(newInfo.totalDeposits)).to.be.equal(Number(preInfo.totalDeposits) - 1); + + expect(withdrawEvent.data.user.toString()).to.be.equal(user2.address.toString()); + expect(withdrawEvent.data.nft.toString()).to.be.equal(userNft2.nft.address.toString()); + expect(Number(withdrawEvent.data.reward)).to.be.equal(reward); + expect(Number(withdrawEvent.data.reward_debt)).to.be.equal(0); + }); + + it('Withdraw unclaimed tokens', async function() { + await userNft1_1.changeManager(farmPool.farmPool, user1); + + let info = await farmPool.info(); + let withdrawWallet = await rewardTokenRoot.wallet(adminAccount); + let withdrawWalletBalance = await withdrawWallet.balance(); + let unclaimedReward = Number(info.unclaimedReward); + + if (Number(unclaimedReward) > 0) { + await farmPool.withdrawUnclaimed(adminAccount.address); + + let newWithdrawWalletBalance = await withdrawWallet.balance(); + let expectedBalance = Number(withdrawWalletBalance) + Number(unclaimedReward); + + expect(Number(newWithdrawWalletBalance)).to.be.equal(expectedBalance); + } + }); + }); + }); +}); \ No newline at end of file diff --git a/demo/Farming/test/2-vesting.ts b/demo/Farming/test/2-vesting.ts new file mode 100644 index 0000000..d25ca37 --- /dev/null +++ b/demo/Farming/test/2-vesting.ts @@ -0,0 +1,298 @@ +import { expect } from "chai"; +import { Contract, Signer } from "locklift"; +import { FactorySource } from "../build/factorySource"; +import { SimpleKeystore } from "everscale-standalone-client/nodejs"; +import { Address } from "everscale-inpage-provider"; +import { Account } from "locklift/factory"; +import { + setupTokenRoot, + setupCollection, + setupPool, + deployAccount, + TokenRoot, + Collection, + NFT, + FarmingPool, + TokenWallet, + sleep, + checkReward, + checkRewardVesting, + computeVesting +} from "./utils"; + +let signer: Signer; +let adminAccount: Account; +let rewardTokenRoot: TokenRoot; +let collection: Collection; +let user1: Account; +let user2: Account; +let userNft1_1: NFT; +let userNft1_2: NFT; +let userNft2: NFT; +let farmPool: FarmingPool; +let farmPoolWallet: string; +let farmStart: number; +let farmEnd: number; +let rewardPerSec: number; +let adminRewardWallet: TokenWallet; +let event1; +let vestingPeriod: number; +let vestingRatio: number; + +describe("Vesting test", async function () { + before(async () => { + let randKeypair = SimpleKeystore.generateKeyPair(); + await locklift.keystore.addKeyPair("random", randKeypair); + signer = (await locklift.keystore.getSigner("random"))!; + }); + + describe("Setup contracts", async function () { + describe("TIP3 tokens", async function () { + it('Deploy admin', async function() { + adminAccount = await deployAccount(); + }); + + it('Deploy roots', async function() { + rewardTokenRoot = await setupTokenRoot(signer, "Reward token", "RT", adminAccount); + collection = await setupCollection(signer); + }); + + it('Mint tokens', async function() { + adminRewardWallet = await rewardTokenRoot.mint(1e18, adminAccount); + }); + }); + + describe("Users", async function () { + it('Deploy users accounts', async function() { + let users = []; + for(let i of [1, 2]){ + const user = await deployAccount(); + users.push(user); + } + [user1, user2] = users; + }); + + it('Mint tip4 tokens(nft\'s)', async function() { + userNft1_1 = await collection.mintNft(user1); + userNft1_2 = await collection.mintNft(user1); + userNft2 = await collection.mintNft(user2); + + expect(await locklift.provider.getBalance(userNft1_1.nft.address).then(balance => Number(balance))).to.be.above(0); + expect(await locklift.provider.getBalance(userNft1_2.nft.address).then(balance => Number(balance))).to.be.above(0); + expect(await locklift.provider.getBalance(userNft2.nft.address).then(balance => Number(balance))).to.be.above(0); + }); + }); + }); + + describe("Base staking pipeline testing", async function () { + describe("Farm pool", async function () { + it('Deploy farm pool', async function() { + farmStart = Math.floor(Date.now() / 1000); + farmEnd = Math.floor(Date.now() / 1000) + 10000; + rewardPerSec = 1000; + vestingPeriod = 3600; // = 1h + vestingRatio = 500; // = 50% + + farmPool = await setupPool( + adminAccount, + collection.collection, + rewardTokenRoot.tokenRoot, + farmStart, + rewardPerSec, + vestingPeriod, + vestingRatio + ); + + farmPoolWallet = await farmPool.wallet(); + }); + + it('Sending reward tokens to pool', async function() { + const amount = (farmEnd - farmStart) * rewardPerSec; + + await farmPool.deposit(adminRewardWallet, amount); + const pastEvents = await farmPool.farmPool.getPastEvents({ filter: event => event.event === "RewardDeposit" }); + [event1] = pastEvents.events; + + expect(Number(event1.data.amount)).to.be.equal(amount); + expect(event1.data.tokenRoot.toString()).to.be.equal(rewardTokenRoot.tokenRoot.address.toString()); + + const info = await farmPool.info(); + const rewardBalance = info.rewardTokenWalletBalance; + + expect(Number(rewardBalance)).to.be.equal(amount); + }); + + it('User1 deposit 1st token', async function() { + await userNft1_1.changeManager(farmPool.farmPool, user1); + + const pastEvents = await farmPool.farmPool.getPastEvents({ filter: event => event.event === "Deposit" }); + let depositEvent = pastEvents.events[0]; + + expect(depositEvent.data.user.toString()).to.be.equal(user1.address.toString()); + expect(depositEvent.data.nft.toString()).to.be.equal(userNft1_1.nft.address.toString()); + + let expUserDataAddr = await farmPool.userDataAddress(user1.address.toString()); + expect(await locklift.provider.getBalance(expUserDataAddr).then(balance => Number(balance))).to.be.above(0); + + let expWalletAddr = await rewardTokenRoot.walletAddr(user1); + expect(await locklift.provider.getBalance(expWalletAddr).then(balance => Number(balance))).to.be.above(0); + }); + + it('User1 deposit 2nd token', async function() { + let preInfo = await farmPool.info(); + let user1Wallet = await rewardTokenRoot.wallet(user1); + + let user1Data = await farmPool.userData(user1); + let oldInfo = await user1Data.info(); + let amount = Number(oldInfo.amount); + let rewardDebt = Number(oldInfo.rewardDebt); + let vestingTime = Number(oldInfo.vestingTime); + let entitled = Number(oldInfo.entitled); + let lastRewardTime = Number(oldInfo.lastRewardTime); + + await userNft1_2.changeManager(farmPool.farmPool, user1); + let newInfo = await farmPool.info(); + expect(Number(newInfo.lastRewardTime)).to.be.above(Number(preInfo.lastRewardTime)); + + let newUserDataInfo = await user1Data.info(); + let accRewardPerShare = Number(newInfo.accRewardPerShare); + let poolLastRewardTime = Number(newUserDataInfo.lastRewardTime); + + await computeVesting( + amount, + rewardDebt, + accRewardPerShare, + poolLastRewardTime, + lastRewardTime, + 0, + vestingRatio, + vestingPeriod, + vestingTime, + entitled + ); + }); + + it('User1 claim half of staked amount', async function() { + let preInfo = await farmPool.info(); + let user1Wallet = await rewardTokenRoot.wallet(user1); + let userOldWalletBalance = await user1Wallet.balance(); + + await sleep(2000); + + let user1Data = await farmPool.userData(user1); + let oldInfo = await user1Data.info(); + let amount = Number(oldInfo.amount); + let rewardDebt = Number(oldInfo.rewardDebt); + let vestingTime = Number(oldInfo.vestingTime); + let entitled = Number(oldInfo.entitled); + let lastRewardTime = Number(oldInfo.lastRewardTime); + + await farmPool.claimReward(user1); + + let newInfo = await farmPool.info(); + expect(Number(newInfo.lastRewardTime)).to.be.above(Number(preInfo.lastRewardTime)); + + let newUserDataInfo = await user1Data.info(); + let accRewardPerShare = Number(newInfo.accRewardPerShare); + let poolLastRewardTime = Number(newUserDataInfo.lastRewardTime); + + await computeVesting( + amount, + rewardDebt, + accRewardPerShare, + poolLastRewardTime, + lastRewardTime, + 0, + vestingRatio, + vestingPeriod, + vestingTime, + entitled + ); + }); + + it('Withdraw tokens', async function() { + let preInfo = await farmPool.info(); + let user1Wallet = await rewardTokenRoot.wallet(user1); + let userOldWalletBalance = await user1Wallet.balance(); + + let user1Data = await farmPool.userData(user1); + let oldInfo = await user1Data.info(); + let amount = Number(oldInfo.amount); + let rewardDebt = Number(oldInfo.rewardDebt); + let vestingTime = Number(oldInfo.vestingTime); + let entitled = Number(oldInfo.entitled); + let lastRewardTime = Number(oldInfo.lastRewardTime); + + await farmPool.withdraw(user1, userNft1_1.nft.address); + await userNft1_1.updateManager(user1); + + let newInfo = await farmPool.info(); + expect(Number(newInfo.lastRewardTime)).to.be.above(Number(preInfo.lastRewardTime)); + + let newUserDataInfo = await user1Data.info(); + let accRewardPerShare = Number(newInfo.accRewardPerShare); + let poolLastRewardTime = Number(newUserDataInfo.lastRewardTime); + + await computeVesting( + amount, + rewardDebt, + accRewardPerShare, + poolLastRewardTime, + lastRewardTime, + 0, + vestingRatio, + vestingPeriod, + vestingTime, + entitled + ); + + let pastEvents = await farmPool.farmPool.getPastEvents({ filter: event => event.event === "Withdraw" }); + let withdrawEvent = pastEvents.events[0]; + + expect(Number(newInfo.totalDeposits)).to.be.equal(Number(preInfo.totalDeposits) - 1); + + expect(withdrawEvent.data.user.toString()).to.be.equal(user1.address.toString()); + expect(withdrawEvent.data.nft.toString()).to.be.equal(userNft1_1.nft.address.toString()); + expect(Number(withdrawEvent.data.reward_debt)).to.be.equal(0); + + oldInfo = await user1Data.info(); + amount = Number(oldInfo.amount); + rewardDebt = Number(oldInfo.rewardDebt); + vestingTime = Number(oldInfo.vestingTime); + entitled = Number(oldInfo.entitled); + lastRewardTime = Number(oldInfo.lastRewardTime); + + await farmPool.withdraw(user1, userNft1_2.nft.address); + await userNft1_2.updateManager(user1); + + newInfo = await farmPool.info(); + expect(Number(newInfo.lastRewardTime)).to.be.above(Number(preInfo.lastRewardTime)); + + newUserDataInfo = await user1Data.info(); + accRewardPerShare = Number(newInfo.accRewardPerShare); + poolLastRewardTime = Number(newUserDataInfo.lastRewardTime); + + await computeVesting( + amount, + rewardDebt, + accRewardPerShare, + poolLastRewardTime, + lastRewardTime, + 0, + vestingRatio, + vestingPeriod, + vestingTime, + entitled + ); + + pastEvents = await farmPool.farmPool.getPastEvents({ filter: event => event.event === "Withdraw" }); + withdrawEvent = pastEvents.events[0]; + + expect(withdrawEvent.data.user.toString()).to.be.equal(user1.address.toString()); + expect(withdrawEvent.data.nft.toString()).to.be.equal(userNft1_2.nft.address.toString()); + expect(Number(withdrawEvent.data.reward_debt)).to.be.equal(0); + }); + + }); + }); +}); \ No newline at end of file diff --git a/demo/Farming/test/utils.ts b/demo/Farming/test/utils.ts new file mode 100644 index 0000000..981a6d7 --- /dev/null +++ b/demo/Farming/test/utils.ts @@ -0,0 +1,933 @@ +const logger = require("mocha-logger"); +import { Address } from "everscale-inpage-provider"; +import { Contract, Signer } from "locklift"; +import { FactorySource } from "../build/factorySource"; +import { expect } from "chai"; +import { Account } from "locklift/factory"; +import { SimpleKeystore } from "everscale-standalone-client/nodejs"; +import { LargeNumberLike } from "crypto"; +const BigNumber = require("bignumber.js"); + + +export const zeroAddress = new Address("0:0000000000000000000000000000000000000000000000000000000000000000"); + + +// -------------------------- ENTITIES ---------------------------- +export class TokenWallet { + wallet: Contract; + _owner: Account; + + constructor(walletContract: Contract, walletOwner: Account) { + this.wallet = walletContract; + this._owner = walletOwner; + } + + static async from_addr(addr: string, owner: Account) { + let userTokenWallet = await locklift.factory.getDeployedContract( + 'TokenWallet', + new Address(addr), + ); + + return new TokenWallet(userTokenWallet, owner); + } + + async owner() { + const response = await this.wallet.methods.owner({answerId: 0}).call(); + return response.value0; + } + + async root() { + const response = await this.wallet.methods.root({answerId: 0}).call(); + return response.value0; + } + + async balance() { + const response = await this.wallet.methods.balance({answerId: 0}).call(); + return response.value0; + } + + async transfer(amount: number, receiver_or_addr: any, notify: Boolean = false, payload='', tracing=null, allowed_codes={compute: []}) { + let addr = receiver_or_addr.address; + if (addr === undefined) { + addr = receiver_or_addr; + } + + if (tracing) { + return await locklift.tracing.trace( + this._owner.runTarget( + { + contract: this.wallet, + value: locklift.utils.toNano(5), + }, + wallet => + wallet.methods.transfer({ + amount: amount, + recipient: addr, + deployWalletValue: 0, + remainingGasTo: this._owner.address, + notify: notify, + payload: payload + }), + ), + { + allowedCodes: allowed_codes, + }, + ); + } else { + return await this._owner.runTarget( + { + contract: this.wallet, + value: locklift.utils.toNano(5), + }, + wallet => + wallet.methods.transfer({ + amount: amount, + recipient: addr, + deployWalletValue: 0, + remainingGasTo: this._owner.address, + notify: notify, + payload: payload + }), + ); + } + + } +} + +export class TokenRoot { + tokenRoot: Contract; + owner: Account; + + constructor(token_contract: Contract, token_owner: Account) { + this.tokenRoot = token_contract; + this.owner = token_owner; + } + + static async from_addr(addr: string, owner: Account) { + let rootToken = await locklift.factory.getDeployedContract( + 'TokenRoot', + new Address(addr), + ); + return new TokenRoot(rootToken, owner); + } + + async walletAddr(user_or_addr: any) { + let addr = user_or_addr.address; + if (addr === undefined) { + addr = user_or_addr; + } + + const walletOf = await this.tokenRoot.methods.walletOf({ + answerId: 0, + walletOwner: addr + }).call(); + + return walletOf.value0; + } + + async wallet(user: Account) { + const wallet_addr = await this.walletAddr(user); + return TokenWallet.from_addr(wallet_addr.toString(), user); + } + + async deployWallet(account: Account) { + + await account.runTarget( + { + contract: this.tokenRoot, + value: locklift.utils.toNano(2), + }, + tokenRoot => + tokenRoot.methods.deployWallet({ + answerId: 0, + walletOwner: account.address, + deployWalletValue: locklift.utils.toNano(1), + }), + ); + + const addr = await this.walletAddr(account); + + logger.log(`User token wallet: ${addr}`); + return TokenWallet.from_addr(addr.toString(), account); + } + + async mint(mint_amount: number, user: Account) { + await this.owner.runTarget( + { + contract: this.tokenRoot, + value: locklift.utils.toNano(3), + }, + tokenRoot => + tokenRoot.methods.mint({ + amount: mint_amount, + recipient: user.address, + deployWalletValue: locklift.utils.toNano(1), + remainingGasTo: this.owner.address, + notify: false, + payload: '' + }), + ); + + const walletAddr = await this.walletAddr(user); + + logger.log(`User token wallet: ${walletAddr}`); + return TokenWallet.from_addr(walletAddr.toString(), user); + } +} + +export class NFT { + nft: Contract; + _owner: Account; + _manager: Account; + + constructor(nft_contract: Contract, owner: Account) { + this.nft = nft_contract; + this._owner = owner; + this._manager = owner; + } + + static async from_addr(addr: string, owner: Account) { + let userNft = await locklift.factory.getDeployedContract( + 'Nft', + new Address(addr), + ); + + return new NFT(userNft, owner); + } + + async owner() { + const response = await this.nft.methods.getInfo({answerId: 0}).call(); + return response.owner; + } + + async collection() { + const response = await this.nft.methods.getInfo({answerId: 0}).call(); + return response.collection; + } + + async manager() { + const response = await this.nft.methods.getInfo({answerId: 0}).call(); + return response.manager; + } + + async transfer(to, sendGasTo, tracing=null, allowed_codes={compute: []}) { + let sendGas = sendGasTo.address; + if (sendGas === undefined) { + sendGas = sendGasTo; + } + + if (tracing) { + const res = await locklift.tracing.trace( + this._manager.runTarget( + { + contract: this.nft, + value: locklift.utils.toNano(1), + }, + nft => + nft.methods.transfer({ + to: to.address, + sendGasTo: sendGas, + callbacks: [] + }), + ), + { + allowedCodes: allowed_codes, + }, + ); + + this._manager = to; + this._owner = to; + return res; + } else { + const res = await this._manager.runTarget( + { + contract: this.nft, + value: locklift.utils.toNano(1), + }, + nft => + nft.methods.transfer({ + to: to.address, + sendGasTo: sendGas, + callbacks: [] + }), + ); + + this._manager = to; + this._owner = to; + return res; + } + } + + async changeOwner(newOwner: Account, sendGasTo: any, tracing=null, allowed_codes={compute: []}, callbacks = []) { + let sendGas = sendGasTo.address; + if (sendGas === undefined) { + sendGas = sendGasTo; + } + + if (tracing) { + const res = await locklift.tracing.trace( + this._manager.runTarget( + { + contract: this.nft, + value: locklift.utils.toNano(2), + }, + nft => + nft.methods.changeOwner({ + newOwner: newOwner.address, + sendGasTo: sendGas, + callbacks: [[newOwner.address, {value: locklift.utils.toNano(1.2), payload: ''}]] + }), + ), + { + allowedCodes: allowed_codes, + }, + ); + + this._owner = newOwner; + return res; + } else { + const res = await this._manager.runTarget( + { + contract: this.nft, + value: locklift.utils.toNano(2), + }, + nft => + nft.methods.changeOwner({ + newOwner: newOwner.address, + sendGasTo: sendGas, + callbacks: [[newOwner.address, {value: locklift.utils.toNano(1.2), payload: ''}]] + }), + ); + + this._owner = newOwner; + return res; + } + + } + + async updateManager(manager) { + this._manager = manager; + } + + async changeManager(newManager: any, sendGasTo: any, tracing=null, allowed_codes={compute: []}) { + let sendGas = sendGasTo.address; + if (sendGas === undefined) { + sendGas = sendGasTo; + } + + if (tracing) { + const res = await locklift.tracing.trace( + this._manager.runTarget( + { + contract: this.nft, + value: locklift.utils.toNano(2), + }, + nft => + nft.methods.changeManager({ + newManager: newManager.address, + sendGasTo: sendGas, + callbacks: [[newManager.address, {value: locklift.utils.toNano(1.2), payload: ''}]] + }), + ), + { + allowedCodes: allowed_codes, + }, + ); + + this._manager = newManager; + return res; + } else { + const res = await this._manager.runTarget( + { + contract: this.nft, + value: locklift.utils.toNano(2), + }, + nft => + nft.methods.changeManager({ + newManager: newManager.address, + sendGasTo: sendGas, + callbacks: [[newManager.address, {value: locklift.utils.toNano(1.2), payload: ''}]] + }), + ); + + this._manager = newManager; + return res; + } + + } +} + +export class Collection { + collection: Contract; + ownerSigner: Signer; + + constructor(collection_contract: Contract, ownerSigner: Signer) { + this.collection = collection_contract; + this.ownerSigner = ownerSigner; + } + + static async from_addr (addr: string, owner) { + let collectionContract = await locklift.factory.getDeployedContract( + 'Collection', + new Address(addr), + ); + return new Collection(collectionContract, owner); + } + + async nftAddress(id: number) { + const nftAddr = await this.collection.methods.nftAddress({ + answerId: 0, + id: id + }).call(); + + return nftAddr.nft; + } + + async totalSupply() { + const totalSupply = await this.collection.methods.totalSupply({ + answerId: 0 + }).call(); + + return totalSupply.count; + } + + async mintNft(ownerAccount, tracing=null, allowed_codes={compute: []}) { + + const totalSupplyRes = await this.collection.methods.totalSupply({answerId: 0}).call(); + const id = totalSupplyRes.count; + if (tracing) { + await locklift.tracing.trace( + await ownerAccount.runTarget( + { + contract: this.collection, + value: locklift.utils.toNano(1), + }, + collection => + collection.methods.mintNft({}), + ), + { + allowedCodes: allowed_codes, + }, + ); + } else { + await ownerAccount.runTarget( + { + contract: this.collection, + value: locklift.utils.toNano(1), + }, + collection => + collection.methods.mintNft({}), + ); + } + + const response = await this.collection.methods.nftAddress({answerId: 0, id: id}).call(); + const nft = await locklift.factory.getDeployedContract( + "Nft", + new Address(response.nft.toString()), + ); + + return new NFT(nft, ownerAccount); + } +} + +export class FarmingPool { + farmPool: Contract; + _owner; + _wallet: string; + + constructor(farm_pool_contract: Contract, owner) { + this.farmPool = farm_pool_contract; + this._owner = owner; + } + + async info() { + return await this.farmPool.methods.getInfo({answerId: 0}).call(); + } + + async wallet() { + if (this._wallet !== undefined) { + return this._wallet; + } + const details = await this.info(); + this._wallet = details.rewardTokenWallet.toString(); + return this._wallet; + } + + static async from_addr(addr: string, owner) { + let farmPoolContract = await locklift.factory.getDeployedContract( + 'FarmingPool', + new Address(addr), + ); + return new FarmingPool(farmPoolContract, owner); + } + + async userDataAddress(user) { + const userData = await this.farmPool.methods.getUserDataAddress({ + answerId: 0, + user: user + }).call(); + + return userData.value0; + } + + async deposit(fromWallet: TokenWallet, amount: number, allowed_codes={compute: []}){ + return await fromWallet.transfer(amount, this.farmPool, true, "", null, allowed_codes); + } + + async calculateRewardData() { + return await this.farmPool.methods.calculateRewardData({}).call(); + } + + async claimReward(user: Account, tracing=null, allowed_codes={compute: []}){ + if (tracing) { + return await locklift.tracing.trace( + user.runTarget( + { + contract: this.farmPool, + value: locklift.utils.toNano(5), + }, + farmPool => + farmPool.methods.claimReward({ + sendGasTo: user.address + }), + ), + { + allowedCodes: allowed_codes, + }, + ); + } else { + return await user.runTarget( + { + contract: this.farmPool, + value: locklift.utils.toNano(5), + }, + farmPool => + farmPool.methods.claimReward({ + sendGasTo: user.address + }), + ); + } + } + + async withdraw(user: Account, nftAddress: Address, tracing=null, allowed_codes={compute: []}){ + if (tracing) { + return await locklift.tracing.trace( + user.runTarget( + { + contract: this.farmPool, + value: locklift.utils.toNano(5), + }, + farmPool => + farmPool.methods.withdraw({ + nft: nftAddress, + sendGasTo: user.address + }), + ), + { + allowedCodes: allowed_codes, + }, + ); + } else { + return await user.runTarget( + { + contract: this.farmPool, + value: locklift.utils.toNano(5), + }, + farmPool => + farmPool.methods.withdraw({ + nft: nftAddress, + sendGasTo: user.address + }), + ); + } + } + + async withdrawUnclaimed(receiver: Address){ + return await this._owner.runTarget( + { + contract: this.farmPool, + value: locklift.utils.toNano(5), + }, + farmPool => + farmPool.methods.withdrawUnclaimed({ + to: receiver, + sendGasTo: this._owner.address + }), + ); + } + + async userData(user: Account) { + const userDataAddr = await this.userDataAddress(user.address); + return UserData.from_addr(userDataAddr.toString(), user); + } +} + +export class UserData { + userData: Contract; + _owner: Account; + + constructor(userData: Contract, owner: Account) { + this.userData = userData; + this._owner = owner; + } + + static async from_addr(addr: string, owner: Account) { + let userData = await locklift.factory.getDeployedContract( + 'UserData', + new Address(addr), + ); + + return new UserData(userData, owner); + } + + async pendingReward(accRewardPerShare: number, poolLastRewardTime: number, farmEndTime: number) { + return await this.userData.methods.pendingReward({accRewardPerShare: accRewardPerShare, poolLastRewardTime: poolLastRewardTime, farmEndTime: farmEndTime}).call(); + } + + async info() { + return await this.userData.methods.getInfo({answerId: 0}).call(); + } + + async rewardDebt() { + let info = await this.info(); + return Number(info.rewardDebt); + } + + async lastRewardTime() { + let info = await this.info(); + return Number(info.lastRewardTime); + } + + async numOfDeposits() { + let _deposits = await this.userData.methods._deposits({}).call(); + let deposits = _deposits._deposits; + return deposits.length; + } + +} + +// -------------------------- SETUP METHODS -------------------------- + +export const setupTokenRoot = async function(signer: Signer, token_name: string, token_symbol: string, owner) { + + const TokenWallet = await locklift.factory.getContractArtifacts('TokenWallet'); + const { contract: tokenRoot, tx } = await locklift.factory.deployContract({ + contract: "TokenRoot", + publicKey: signer.publicKey, + constructorParams: { + initialSupplyTo: zeroAddress, + initialSupply: 0, + deployWalletValue: 0, + mintDisabled: false, + burnByRootDisabled: false, + burnPaused: false, + remainingGasTo: owner.address + }, + initParams: { + name_: token_name, + symbol_: token_symbol, + decimals_: 9, + rootOwner_: owner.address, + walletCode_: TokenWallet.code, + randomNonce_: locklift.utils.getRandomNonce(), + deployer_: zeroAddress + }, + value: locklift.utils.toNano(5) + }); + + logger.log(`Token root address: ${tokenRoot.address}`); + + const name = await tokenRoot.methods.name({answerId: 0}).call(); + + expect(name.value0).to.be.equal(token_name, 'Wrong root name'); + expect(await locklift.provider.getBalance(tokenRoot.address).then(balance => Number(balance))).to.be.above(0, 'Root balance empty'); + return new TokenRoot(tokenRoot, owner); +} + +export const setupCollection = async function(signer: Signer) { + + const Nft = await locklift.factory.getContractArtifacts('Nft'); + const { contract: collection, tx } = await locklift.factory.deployContract({ + contract: "Collection", + publicKey: signer.publicKey, + constructorParams: { + codeNft: Nft.code, + ownerPubkey: "0x" + signer.publicKey + }, + initParams: {}, + value: locklift.utils.toNano(5) + }); + + logger.log(`Collection address: ${collection.address}`); + + expect(await locklift.provider.getBalance(collection.address).then(balance => Number(balance))).to.be.above(0, 'Collection balance empty'); + return new Collection(collection, signer); +} + +export const setupPool = async function(owner, collection, rewardTokenRoot, farmStartTime, rewardPerSecond, vestingPeriod, vestingRatio) { + + let randKeypair = SimpleKeystore.generateKeyPair(); + await locklift.keystore.addKeyPair("random", randKeypair); + let signer = (await locklift.keystore.getSigner("random"))!; + + let UserData = await locklift.factory.getContractArtifacts('UserData'); + let Nft = await locklift.factory.getContractArtifacts('Nft'); + const { contract: farmingPool, tx } = await locklift.factory.deployContract({ + contract: "FarmingPool", + publicKey: signer.publicKey, + constructorParams: { + owner: owner.address, + collection: collection.address, + rewardTokenRoot: rewardTokenRoot.address, + codeNft: Nft.code, + codeUserData: UserData.code, + farmStartTime: farmStartTime, + rewardPerSecond: rewardPerSecond, + vestingPeriod: vestingPeriod, + vestingRatio: vestingRatio, + }, + initParams: {}, + value: locklift.utils.toNano(5) + }); + + logger.log(`Farming pool address: ${farmingPool.address}`); + + return new FarmingPool(farmingPool, owner); +} + +export const deployAccount = async function() { + let signer = (await locklift.keystore.getSigner("0"))!; + let accountsFactory = await locklift.factory.getAccountsFactory( + "Wallet", + ); + + const {account: account, tx} = await accountsFactory.deployNewAccount({ + publicKey: signer.publicKey, + initParams: { + _randomNonce: locklift.utils.getRandomNonce(), + }, + constructorParams: {}, + value: locklift.utils.toNano(15) + }); + + expect(await locklift.provider.getBalance(account.address).then(balance => Number(balance))).to.be.above(0, 'Bad account balance'); + + logger.log(`Account address: ${account.address}`); + + return account; +} + +export async function sleep(ms) { + return; +} + +export const checkReward = async function( + userWallet: TokenWallet, + prevBalance: number, + prevRewardDebt: number, + accRewardPerShare: number, + depositsNum: number +) { + const expectedReward = Math.floor((accRewardPerShare * depositsNum) / 1e18) - (prevRewardDebt); + const userNewWalletBalance = await userWallet.balance(); + const reward = Number(userNewWalletBalance) - prevBalance; + + expect(reward).to.be.equal(expectedReward, 'Bad reward'); + return expectedReward; +} + +export const checkRewardVesting = async function( + userWallet: TokenWallet, + userData: UserData, + _entitled: number, + _vestingTime: number, + prevBalance: number, + prevRewardTime: number, + newRewardTime: number, + _rewardPerSec: number, + vestingRatio: number, + vestingPeriod: number +) { + const user_bal_after = Number(await userWallet.balance()); + const entitled = _entitled; + const vestingTime = _vestingTime; + const real_reward = user_bal_after - prevBalance; + + const time_passed = newRewardTime - prevRewardTime; + const expected_reward = _rewardPerSec * time_passed; + + const vesting_part = expected_reward * vestingRatio / 1000; + const clear_part = expected_reward - vesting_part; + + // TODO: up to new math + const newly_vested = Math.floor((vesting_part * time_passed) / (time_passed + vestingPeriod)); + + const age = newRewardTime >= vestingTime ? vestingPeriod : (newRewardTime - prevRewardTime); + let to_vest = age >= vestingPeriod ? entitled : Math.floor((entitled * age) / (vestingTime - prevRewardTime)); + + const remaining_entitled = entitled === 0 ? 0 : entitled - to_vest; + const unreleased_newly = vesting_part - newly_vested; + const pending = remaining_entitled + unreleased_newly; + + + let new_vesting_time; + // Compute the vesting time (i.e. when the entitled reward to be all vested) + if (pending === 0) { + new_vesting_time = newRewardTime; + } else if (remaining_entitled === 0) { + // only new reward, set vesting time to vesting period + new_vesting_time = newRewardTime + vestingPeriod; + } else if (unreleased_newly === 0) { + // only unlocking old reward, dont change vesting time + new_vesting_time = vestingTime; + } else { + // "old" reward and, perhaps, "new" reward are pending - the weighted average applied + const age3 = vestingTime - newRewardTime; + const period = Math.floor(((remaining_entitled * age3) + (unreleased_newly * vestingPeriod)) / pending); + new_vesting_time = newRewardTime + Math.min(period, vestingPeriod); + } + + const final_entitled = entitled + vesting_part - to_vest - newly_vested; + + const newly_vested_ = new BigNumber(newly_vested); + console.log("final_entitled" + final_entitled); + const final_vested = newly_vested_ + to_vest + clear_part; + console.log("final_vested" + final_vested) + + // console.log( + // entitled + // vesting_part.toFixed(), + // to_vest.toFixed(), + // newly_vested.toFixed(), + // final_entitled.toFixed() + // ); + + // console.log(final_vested.toFixed(0), newly_vested_ + to_vest + clear_part); + // console.log(prevRewardTime.toFixed(0), newRewardTime.toFixed(0)); + + // expect(real_reward.toFixed(0)).to.be.equal(final_vested.toFixed(0), 'Bad vested reward'); + // // console.log(entitled.toFixed(0), final_entitled.toFixed(0)); + // expect(final_entitled.toFixed(0)).to.be.equal(details.entitled[token_idx].toFixed(0), 'Bad entitled reward'); + // expect(new_vesting_time.toFixed(0)).to.be.equal(details.vestingTime.toFixed(0), 'Bad vesting time'); + return real_reward; +} + + +// export const computeVestedForInterval = async function( +// entitled: number, +// interval: number, +// vestingPeriod: number +// ) { +// let periodsPassed = +// } + +export const isEven = async function ( + num: number +) { + return num % 2 == 0; +} + +export const rangeSum = async function (range: number) { + if (await isEven(range)) { + return Math.floor(range / 2) * range + Math.floor(range / 2); + } + return (Math.floor(range / 2) + 1) * range; +} + +export const rangeIntervalAverage = async function ( + interval: number, + max: number +) { + return Math.floor((await rangeSum(interval) * 1e18) / max); +} + +export const computeVestedForNewlyEntitled = async function( + entitled: number, + oldLastRewardTime: number, + farmEndTime: number, + poolLastRewardTime: number, + vestingPeriod: number +) { + if (entitled == 0) { + return 0; + } + + if (farmEndTime == 0 || oldLastRewardTime < farmEndTime) { + let age = oldLastRewardTime - poolLastRewardTime; + + if (age > vestingPeriod) { + + } else { + let clearPartShare = Math.floor(await rangeIntervalAverage(age, vestingPeriod) / age); + return Math.floor((entitled * clearPartShare) / 1e18); + } + } else { + let ageBefore = farmEndTime - oldLastRewardTime; + let ageAfter = Math.min(poolLastRewardTime - farmEndTime, vestingPeriod); + + let vestedBefore = 0; + let entitledBefore = 0; + if (ageBefore > vestingPeriod) { + + } else { + let clearPartShare = Math.floor(await rangeIntervalAverage(ageBefore, vestingPeriod) / ageBefore); + vestedBefore = Math.floor((entitled * clearPartShare) / 1e18); + entitledBefore = entitled - vestedBefore; + } + + let vestedAfter = Math.floor(entitledBefore * ageAfter / vestingPeriod); + return (vestedBefore + vestedAfter); + } +} + +export const computeVesting = async function( + amount: number, + rewardDebt: number, + accRewardPerShare: number, + poolLastRewardTime: number, + oldLastRewardTime: number, + farmEndTime: number, + vestingRatio: number, + vestingPeriod: number, + vestingTime: number, + entitled: number +) { + let updatedEntitled; + let newlyVested: any = 0; + + let reward = amount * accRewardPerShare; + let newEntitled = Math.floor(reward / 1e18) - rewardDebt; + + if (vestingRatio > 0) { + let vestingPart = Math.floor((newEntitled * vestingRatio) / 1000); + let clearPart = newEntitled - vestingPart; + + if (oldLastRewardTime < farmEndTime || farmEndTime == 0) { + newlyVested = await computeVestedForNewlyEntitled(vestingPart, oldLastRewardTime, farmEndTime, poolLastRewardTime, vestingPeriod); + } else { + newlyVested = 0; + } + + let age2 = poolLastRewardTime >= vestingTime ? vestingPeriod : poolLastRewardTime; + let vested = entitled * age2; + let toVest = age2 >= vestingPeriod ? entitled : Math.floor(vested / (vestingTime - oldLastRewardTime)); + + let remainingEntitled = entitled == 0 ? 0 : entitled - toVest; + let unreleasedNewly = vestingPart - newlyVested; + + updatedEntitled = entitled + vestingPart - toVest - newlyVested; + let test = newlyVested + toVest + clearPart; + // newlyVested = newlyVested + toVest + clearPart; + // console.log("vestingPart " + vestingPart); + // console.log("clearPart" + clearPart); + // console.log("toVest " + toVest); + // console.log("test " + test); + } else { + newlyVested = newEntitled; + } + + // console.log("updatedEntitled " + updatedEntitled); + // console.log("newly_ested" + newlyVested); + + return newlyVested; +} diff --git a/demo/Farming/tsconfig.json b/demo/Farming/tsconfig.json new file mode 100644 index 0000000..3593b6a --- /dev/null +++ b/demo/Farming/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "target": "es5" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */, + "module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */, + + "strict": true /* Enable all strict type-checking options. */, + "types": ["node", "mocha"] /* Type declaration files to be included in compilation. */, + "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */, + + "skipLibCheck": true /* Skip type checking of declaration files. */, + "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ + } +} diff --git a/demo/Farming/locklift.config.js b/demo/Lottery/locklift.config.template.js similarity index 100% rename from demo/Farming/locklift.config.js rename to demo/Lottery/locklift.config.template.js diff --git a/demo/Lottery/package-lock.json b/demo/Lottery/package-lock.json index 8f5156d..b4460d7 100644 --- a/demo/Lottery/package-lock.json +++ b/demo/Lottery/package-lock.json @@ -1393,6 +1393,11 @@ "json-buffer": "3.0.1" } }, + "kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==" + }, "locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -1700,6 +1705,15 @@ "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==" }, + "prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "requires": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + } + }, "pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", @@ -1844,6 +1858,11 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, + "sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" + }, "slice-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", diff --git a/demo/Lottery/package.json b/demo/Lottery/package.json index 4e6d5ae..a4f3ccf 100644 --- a/demo/Lottery/package.json +++ b/demo/Lottery/package.json @@ -4,12 +4,15 @@ "description": "Lottery demo", "scripts": { "build": "locklift build --config locklift.config.js", - "deploy": "locklift run --config locklift.config.js --network devnet --script scripts/1-deploy-collection.js" + "deploy": "locklift run --config locklift.config.js --network local --script scripts/1-deploy-collection.js", + "mint": "locklift run --config locklift.config.js --network local --script scripts/2-mint-nft.js", + "get-prize": "locklift run --config locklift.config.js --network local --script scripts/3-get-prize.js" }, "author": "itgold.io", "license": "MIT", "dependencies": { "@itgold/everscale-tip": "^1.1.3", - "locklift": "git+https://github.com/broxus/ton-locklift.git" + "locklift": "git+https://github.com/broxus/ton-locklift.git", + "prompts": "^2.4.2" } } diff --git a/demo/Lottery/safemultisig/SafeMultisigWallet.abi.json b/demo/Lottery/safemultisig/SafeMultisigWallet.abi.json new file mode 100644 index 0000000..bd0d131 --- /dev/null +++ b/demo/Lottery/safemultisig/SafeMultisigWallet.abi.json @@ -0,0 +1,123 @@ +{ + "ABI version": 2, + "header": ["pubkey", "time", "expire"], + "functions": [ + { + "name": "constructor", + "inputs": [ + {"name":"owners","type":"uint256[]"}, + {"name":"reqConfirms","type":"uint8"} + ], + "outputs": [ + ] + }, + { + "name": "acceptTransfer", + "inputs": [ + {"name":"payload","type":"bytes"} + ], + "outputs": [ + ] + }, + { + "name": "sendTransaction", + "inputs": [ + {"name":"dest","type":"address"}, + {"name":"value","type":"uint128"}, + {"name":"bounce","type":"bool"}, + {"name":"flags","type":"uint8"}, + {"name":"payload","type":"cell"} + ], + "outputs": [ + ] + }, + { + "name": "submitTransaction", + "inputs": [ + {"name":"dest","type":"address"}, + {"name":"value","type":"uint128"}, + {"name":"bounce","type":"bool"}, + {"name":"allBalance","type":"bool"}, + {"name":"payload","type":"cell"} + ], + "outputs": [ + {"name":"transId","type":"uint64"} + ] + }, + { + "name": "confirmTransaction", + "inputs": [ + {"name":"transactionId","type":"uint64"} + ], + "outputs": [ + ] + }, + { + "name": "isConfirmed", + "inputs": [ + {"name":"mask","type":"uint32"}, + {"name":"index","type":"uint8"} + ], + "outputs": [ + {"name":"confirmed","type":"bool"} + ] + }, + { + "name": "getParameters", + "inputs": [ + ], + "outputs": [ + {"name":"maxQueuedTransactions","type":"uint8"}, + {"name":"maxCustodianCount","type":"uint8"}, + {"name":"expirationTime","type":"uint64"}, + {"name":"minValue","type":"uint128"}, + {"name":"requiredTxnConfirms","type":"uint8"} + ] + }, + { + "name": "getTransaction", + "inputs": [ + {"name":"transactionId","type":"uint64"} + ], + "outputs": [ + {"components":[{"name":"id","type":"uint64"},{"name":"confirmationsMask","type":"uint32"},{"name":"signsRequired","type":"uint8"},{"name":"signsReceived","type":"uint8"},{"name":"creator","type":"uint256"},{"name":"index","type":"uint8"},{"name":"dest","type":"address"},{"name":"value","type":"uint128"},{"name":"sendFlags","type":"uint16"},{"name":"payload","type":"cell"},{"name":"bounce","type":"bool"}],"name":"trans","type":"tuple"} + ] + }, + { + "name": "getTransactions", + "inputs": [ + ], + "outputs": [ + {"components":[{"name":"id","type":"uint64"},{"name":"confirmationsMask","type":"uint32"},{"name":"signsRequired","type":"uint8"},{"name":"signsReceived","type":"uint8"},{"name":"creator","type":"uint256"},{"name":"index","type":"uint8"},{"name":"dest","type":"address"},{"name":"value","type":"uint128"},{"name":"sendFlags","type":"uint16"},{"name":"payload","type":"cell"},{"name":"bounce","type":"bool"}],"name":"transactions","type":"tuple[]"} + ] + }, + { + "name": "getTransactionIds", + "inputs": [ + ], + "outputs": [ + {"name":"ids","type":"uint64[]"} + ] + }, + { + "name": "getCustodians", + "inputs": [ + ], + "outputs": [ + {"components":[{"name":"index","type":"uint8"},{"name":"pubkey","type":"uint256"}],"name":"custodians","type":"tuple[]"} + ] + } + ], + "data": [ + ], + "events": [ + { + "name": "TransferAccepted", + "inputs": [ + {"name":"payload","type":"bytes"} + ], + "outputs": [ + ] + } + ] +} diff --git a/demo/Lottery/safemultisig/SafeMultisigWallet.base64 b/demo/Lottery/safemultisig/SafeMultisigWallet.base64 new file mode 100644 index 0000000..f4e9ac0 --- /dev/null +++ b/demo/Lottery/safemultisig/SafeMultisigWallet.base64 @@ -0,0 +1 @@ +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 diff --git a/demo/Lottery/safemultisig/SafeMultisigWallet.sol b/demo/Lottery/safemultisig/SafeMultisigWallet.sol new file mode 100644 index 0000000..dd5871a --- /dev/null +++ b/demo/Lottery/safemultisig/SafeMultisigWallet.sol @@ -0,0 +1,412 @@ +pragma solidity >=0.6.0; +pragma experimental ABIEncoderV2; +pragma ignoreIntOverflow; +pragma AbiHeader expire; +pragma AbiHeader pubkey; +pragma AbiHeader time; + +interface IAccept { + function acceptTransfer(bytes payload) external payable; +} + +/// @title Multisignature wallet +/// @author Tonlabs (https://tonlabs.io) +contract MultisigWallet is IAccept { + + /* + * Storage + */ + + struct Transaction { + // Transaction Id. + uint64 id; + // Transaction confirmations from custodians. + uint32 confirmationsMask; + // Number of required confirmations. + uint8 signsRequired; + // Number of confirmations already received. + uint8 signsReceived; + // Public key of custodian queued transaction. + uint256 creator; + // Index of custodian. + uint8 index; + // Destination address of gram transfer. + address payable dest; + // Amount of nanograms to transfer. + uint128 value; + // Flags for sending internal message (see SENDRAWMSG in TVM spec). + uint16 sendFlags; + // Payload used as body of outbound internal message. + TvmCell payload; + // Bounce flag for header of outbound internal message. + bool bounce; + } + + /* + * Constants + */ + uint8 constant MAX_QUEUED_REQUESTS = 5; + uint64 constant EXPIRATION_TIME = 3600; // lifetime is 1 hour + uint8 constant MAX_CUSTODIAN_COUNT = 32; + uint128 constant MIN_VALUE = 1e6; + uint constant MAX_CLEANUP_TXNS = 40; + + // Send flags. + // Forward fees for message will be paid from contract balance. + uint8 constant FLAG_PAY_FWD_FEE_FROM_BALANCE = 1; + // Tells node to ignore errors in action phase while outbound messages are sent. + uint8 constant FLAG_IGNORE_ERRORS = 2; + // Tells node to send all remaining balance. + uint8 constant FLAG_SEND_ALL_REMAINING = 128; + + /* + * Variables + */ + + // Public key of custodian who deployed a contract. + uint256 m_ownerKey; + // Binary mask with custodian requests (max 32 custodians). + uint256 m_requestsMask; + // Dictionary of queued transactions waiting confirmations. + mapping(uint64 => Transaction) m_transactions; + // Set of custodians, initiated in constructor, but values can be changed later in code. + mapping(uint256 => uint8) m_custodians; // pub_key -> custodian_index + // Read-only custodian count, initiated in constructor. + uint8 m_custodianCount; + // Default number of confirmations needed to execute transaction. + uint8 m_defaultRequiredConfirmations; + + /* + Exception codes: + 100 - message sender is not a custodian; + 102 - transaction does not exist; + 103 - operation is already confirmed by this custodian; + 107 - input value is too low; + 108 - wallet should have only one custodian; + 113 - Too many requests for one custodian; + 117 - invalid number of custodians; + 121 - payload size is too big; + */ + + /* + * Events + */ + event TransferAccepted(bytes payload); + + /* + * Runtime functions + */ + function tvm_ctos(TvmCell cell) private pure returns (uint /* slice */) {} + function tvm_tree_cell_size(uint slice) private pure returns (uint, uint) {} + + /* + * Constructor + */ + + /// @dev Internal function called from constructor to initialize custodians. + function _initialize(uint256[] owners, uint8 reqConfirms) inline private { + uint8 ownerCount = 0; + m_ownerKey = owners[0]; + + uint256 len = owners.length; + for (uint256 i = 0; (i < len && ownerCount < MAX_CUSTODIAN_COUNT); i++) { + uint256 key = owners[i]; + if (!m_custodians.exists(key)) { + m_custodians[key] = ownerCount++; + } + } + m_defaultRequiredConfirmations = ownerCount <= reqConfirms ? ownerCount : reqConfirms; + m_custodianCount = ownerCount; + } + + /// @dev Contract constructor. + /// @param owners Array of custodian keys. + /// @param reqConfirms Default number of confirmations required for executing transaction. + constructor(uint256[] owners, uint8 reqConfirms) public { + require(msg.pubkey() == tvm.pubkey(), 100); + require(owners.length > 0 && owners.length <= MAX_CUSTODIAN_COUNT, 117); + tvm.accept(); + _initialize(owners, reqConfirms); + } + + /* + * Inline helper macros + */ + + /// @dev Returns queued transaction count by custodian with defined index. + function _getMaskValue(uint256 mask, uint8 index) inline private pure returns (uint8) { + return uint8((mask >> (8 * uint256(index))) & 0xFF); + } + + /// @dev Increment queued transaction count by custodian with defined index. + function _incMaskValue(uint256 mask, uint8 index) inline private pure returns (uint256) { + return mask + (1 << (8 * uint256(index))); + } + + /// @dev Decrement queued transaction count by custodian with defined index. + function _decMaskValue(uint256 mask, uint8 index) inline private pure returns (uint256) { + return mask - (1 << (8 * uint256(index))); + } + + /// @dev Checks bit with defined index in the mask. + function _checkBit(uint32 mask, uint8 index) inline private pure returns (bool) { + return (mask & (uint32(1) << index)) != 0; + } + + /// @dev Checks if object is confirmed by custodian. + function _isConfirmed(uint32 mask, uint8 custodianIndex) inline private pure returns (bool) { + return _checkBit(mask, custodianIndex); + } + + /// @dev Sets custodian confirmation bit in the mask. + function _setConfirmed(uint32 mask, uint8 custodianIndex) inline private pure returns (uint32) { + mask |= (uint32(1) << custodianIndex); + return mask; + } + + /// @dev Checks that custodian with supplied public key exists in custodian set. + function _findCustodian(uint256 senderKey) inline private view returns (uint8) { + (bool exists, uint8 index) = m_custodians.fetch(senderKey); + require(exists, 100); + return index; + } + + /// @dev Generates new id for object. + function _generateId() inline private view returns (uint64) { + return (uint64(now) << 32) | (tvm.transLT() & 0xFFFFFFFF); + } + + /// @dev Returns timestamp after which transactions are treated as expired. + function _getExpirationBound() inline private view returns (uint64) { + return (uint64(now) - EXPIRATION_TIME) << 32; + } + + /// @dev Returns transfer flags according to input value and `allBalance` flag. + function _getSendFlags(uint128 value, bool allBalance) inline private pure returns (uint8, uint128) { + uint8 flags = FLAG_IGNORE_ERRORS | FLAG_PAY_FWD_FEE_FROM_BALANCE; + if (allBalance) { + flags = FLAG_IGNORE_ERRORS | FLAG_SEND_ALL_REMAINING; + value = uint128(address(this).balance); + } + return (flags, value); + } + + /* + * Public functions + */ + + /// @dev A payable method for accepting incoming funds. Generates + /// an event with incoming payload. + /// @param payload Payload from message body. + function acceptTransfer(bytes payload) external override payable { + emit TransferAccepted(payload); + } + + /// @dev Allows custodian if she is the only owner of multisig to transfer funds with minimal fees. + /// @param dest Transfer target address. + /// @param value Amount of funds to transfer. + /// @param bounce Bounce flag. Set true if need to transfer funds to existing account; + /// set false to create new account. + /// @param flags `sendmsg` flags. + /// @param payload Tree of cells used as body of outbound internal message. + function sendTransaction( + address payable dest, + uint128 value, + bool bounce, + uint8 flags, + TvmCell payload) public view + { + require(m_custodianCount == 1, 108); + require(msg.pubkey() == m_ownerKey, 100); + tvm.accept(); + dest.transfer(value, bounce, flags, payload); + } + + /// @dev Allows custodian to submit and confirm new transaction. + /// @param dest Transfer target address. + /// @param value Nanograms value to transfer. + /// @param bounce Bounce flag. Set true if need to transfer grams to existing account; set false to create new account. + /// @param allBalance Set true if need to transfer all remaining balance. + /// @param payload Tree of cells used as body of outbound internal message. + /// @return transId Transaction ID. + function submitTransaction( + address payable dest, + uint128 value, + bool bounce, + bool allBalance, + TvmCell payload) + public returns (uint64 transId) + { + uint256 senderKey = msg.pubkey(); + uint8 index = _findCustodian(senderKey); + require(value >= MIN_VALUE, 107); + (uint bits, uint cells) = tvm_tree_cell_size(tvm_ctos(payload)); + require(bits < 8192 && cells < 8, 121); + _removeExpiredTransactions(); + require(_getMaskValue(m_requestsMask, index) < MAX_QUEUED_REQUESTS, 113); + tvm.accept(); + + (uint8 flags, uint128 realValue) = _getSendFlags(value, allBalance); + uint8 requiredSigns = m_defaultRequiredConfirmations; + + if (requiredSigns == 1) { + dest.transfer(realValue, bounce, flags, payload); + return 0; + } else { + m_requestsMask = _incMaskValue(m_requestsMask, index); + uint64 trId = _generateId(); + Transaction txn = Transaction(trId, 0/*mask*/, requiredSigns, 0/*signsReceived*/, + senderKey, index, dest, realValue, flags, payload, bounce); + + _confirmTransaction(trId, txn, index); + return trId; + } + } + + /// @dev Allows custodian to confirm a transaction. + /// @param transactionId Transaction ID. + function confirmTransaction(uint64 transactionId) public { + uint8 index = _findCustodian(msg.pubkey()); + _removeExpiredTransactions(); + (bool trexists, Transaction txn) = m_transactions.fetch(transactionId); + require(trexists, 102); + require(!_isConfirmed(txn.confirmationsMask, index), 103); + tvm.accept(); + + _confirmTransaction(transactionId, txn, index); + } + + /* + * Internal functions + */ + + /// @dev Confirms transaction by custodian with defined index. + /// @param transactionId Transaction id to confirm. + /// @param txn Transaction object to confirm. + /// @param custodianIndex Index of custodian. + function _confirmTransaction(uint64 transactionId, Transaction txn, uint8 custodianIndex) inline private { + if ((txn.signsReceived + 1) >= txn.signsRequired) { + txn.dest.transfer(txn.value, txn.bounce, txn.sendFlags, txn.payload); + m_requestsMask = _decMaskValue(m_requestsMask, txn.index); + delete m_transactions[transactionId]; + } else { + txn.confirmationsMask = _setConfirmed(txn.confirmationsMask, custodianIndex); + txn.signsReceived++; + m_transactions[transactionId] = txn; + } + } + + /// @dev Removes expired transactions from storage. + function _removeExpiredTransactions() inline private { + uint64 marker = _getExpirationBound(); + (uint64 trId, Transaction txn, bool success) = m_transactions.min(); + + bool needCleanup = success && (trId <= marker); + if (!needCleanup) { return; } + + tvm.accept(); + uint i = 0; + while (needCleanup && i < MAX_CLEANUP_TXNS) { + // transaction is expired, remove it + i++; + m_requestsMask = _decMaskValue(m_requestsMask, txn.index); + delete m_transactions[trId]; + + (trId, txn, success) = m_transactions.next(trId); + needCleanup = success && (trId <= marker); + } + tvm.commit(); + } + + /* + * Get methods + */ + + /// @dev Helper get-method for checking if custodian confirmation bit is set. + /// @return confirmed True if confirmation bit is set. + function isConfirmed(uint32 mask, uint8 index) public pure returns (bool confirmed) { + confirmed = _isConfirmed(mask, index); + } + + /// @dev Get-method that returns wallet configuration parameters. + /// @return maxQueuedTransactions The maximum number of unconfirmed transactions that a custodian can submit. + /// @return maxCustodianCount The maximum allowed number of wallet custodians. + /// @return expirationTime Transaction lifetime in seconds. + /// @return minValue The minimum value allowed to transfer in one transaction. + /// @return requiredTxnConfirms The minimum number of confirmations required to execute transaction. + function getParameters() public view + returns (uint8 maxQueuedTransactions, + uint8 maxCustodianCount, + uint64 expirationTime, + uint128 minValue, + uint8 requiredTxnConfirms) { + + maxQueuedTransactions = MAX_QUEUED_REQUESTS; + maxCustodianCount = MAX_CUSTODIAN_COUNT; + expirationTime = EXPIRATION_TIME; + minValue = MIN_VALUE; + requiredTxnConfirms = m_defaultRequiredConfirmations; + } + + /// @dev Get-method that returns transaction info by id. + /// @return trans Transaction structure. + /// Throws exception if transaction does not exist. + function getTransaction(uint64 transactionId) public view + returns (Transaction trans) { + (bool exists, Transaction txn) = m_transactions.fetch(transactionId); + require(exists, 102); + trans = txn; + } + + /// @dev Get-method that returns array of pending transactions. + /// Returns not expired transactions only. + /// @return transactions Array of queued transactions. + function getTransactions() public view returns (Transaction[] transactions) { + uint64 bound = _getExpirationBound(); + (uint64 id, Transaction txn, bool success) = m_transactions.min(); + while (success) { + // returns only not expired transactions + if (id > bound) { + transactions.push(txn); + } + (id, txn, success) = m_transactions.next(id); + } + } + + /// @dev Get-method that returns submitted transaction ids. + /// @return ids Array of transaction ids. + function getTransactionIds() public view returns (uint64[] ids) { + uint64 trId = 0; + bool success = false; + (trId, , success) = m_transactions.min(); + while (success) { + ids.push(trId); + (trId, , success) = m_transactions.next(trId); + } + } + + /// @dev Helper structure to return information about custodian. + /// Used in getCustodians(). + struct CustodianInfo { + uint8 index; + uint256 pubkey; + } + + /// @dev Get-method that returns info about wallet custodians. + /// @return custodians Array of custodians. + function getCustodians() public view returns (CustodianInfo[] custodians) { + (uint256 key, uint8 index, bool success) = m_custodians.min(); + while (success) { + custodians.push(CustodianInfo(index, key)); + (key, index, success) = m_custodians.next(key); + } + } + + /* + * Fallback and receive functions to receive simple transfers. + */ + + fallback () external payable {} + + receive () external payable {} +} \ No newline at end of file diff --git a/demo/Lottery/safemultisig/SafeMultisigWallet.tvc b/demo/Lottery/safemultisig/SafeMultisigWallet.tvc new file mode 100644 index 0000000..7584907 Binary files /dev/null and b/demo/Lottery/safemultisig/SafeMultisigWallet.tvc differ diff --git a/demo/Lottery/scripts/2-mint-nft.js b/demo/Lottery/scripts/2-mint-nft.js new file mode 100644 index 0000000..148c05d --- /dev/null +++ b/demo/Lottery/scripts/2-mint-nft.js @@ -0,0 +1,74 @@ +const { + isValidTonAddress +} = require('./utils'); +const prompts = require('prompts'); + +async function main() { + + const Collection = await locklift.factory.getContract('Collection'); + const [keyPair] = await locklift.keys.getKeyPairs(); + + const promptsData = []; + + promptsData.push({ + type: 'text', + name: 'collection', + message: 'Collection address', + validate: value => isValidTonAddress(value) ? true : 'Invalid TON address' + }); + + promptsData.push({ + type: 'text', + name: 'owner', + message: 'Owner address', + validate: value => isValidTonAddress(value) ? true : 'Invalid TON address' + }); + + promptsData.push({ + type: 'text', + name: 'json', + message: 'JSON', + validate: value => !!value + }) + + const response = await prompts(promptsData); + + const collectionOwner = await locklift.factory.getAccount('SafeMultisigWallet', 'safemultisig'); + collectionOwner.setAddress(response.owner); + + const collection = Collection; + collection.setAddress(response.collection); + + await collectionOwner.runTarget({ + contract: collection, + method: 'mintNft', + params: { + json: response.json, + delegatedPlayerAddress: collectionOwner.address + }, + value: locklift.utils.convertCrystal(3, 'nano'), + keyPair + }); + + const totalSupply = await collection.call({ + method: 'totalSupply', + params: {}, + }); + + const nftAddr = await collection.call({ + method: 'nftAddress', + params: { + id: totalSupply - 1 + }, + }); + + console.log("Nft was successfully minted!"); + console.log("Address: " + nftAddr); +} + +main() + .then(() => process.exit(0)) + .catch(e => { + console.log(e); + process.exit(1); + }); diff --git a/demo/Lottery/scripts/3-get-prize.js b/demo/Lottery/scripts/3-get-prize.js new file mode 100644 index 0000000..c501a7a --- /dev/null +++ b/demo/Lottery/scripts/3-get-prize.js @@ -0,0 +1,60 @@ +const { + isValidTonAddress +} = require('./utils'); +const prompts = require('prompts'); + +async function main() { + + const NFT = await locklift.factory.getContract('Nft'); + const [keyPair] = await locklift.keys.getKeyPairs(); + + const promptsData = []; + + promptsData.push({ + type: 'text', + name: 'nft', + message: 'NFT address', + validate: value => isValidTonAddress(value) ? true : 'Invalid TON address' + }); + + promptsData.push({ + type: 'text', + name: 'owner', + message: 'Owner address', + validate: value => isValidTonAddress(value) ? true : 'Invalid TON address' + }); + + const response = await prompts(promptsData); + + const nftOwner = await locklift.factory.getAccount('SafeMultisigWallet', 'safemultisig'); + nftOwner.setAddress(response.owner); + + const nft = NFT; + nft.setAddress(response.nft); + + await nftOwner.runTarget({ + contract: nft, + method: 'getPrize', + params: {}, + value: locklift.utils.convertCrystal(1, 'nano'), + keyPair + }); + + const winEvent = await nft.getEvents("TicketWon"); + const lostEvent = await nft.getEvents("TicketLost"); + + if (winEvent.length > 0) { + console.log("Your ticket won! ;) Winning amount: " + locklift.utils.convertCrystal(winEvent[0].value.winningAmount, 'ton') + " ever."); + } else if (lostEvent.length > 0) { + console.log("Your ticket lost! :("); + } else { + console.log("An error has occurred, please try again"); + } +} + +main() + .then(() => process.exit(0)) + .catch(e => { + console.log(e); + process.exit(1); + }); diff --git a/demo/Farming/scripts/utils.js b/demo/Lottery/scripts/utils.js similarity index 100% rename from demo/Farming/scripts/utils.js rename to demo/Lottery/scripts/utils.js diff --git a/demo/Lottery/locklift.config.js b/demo/StandardWebToken/locklift.config.template.js similarity index 100% rename from demo/Lottery/locklift.config.js rename to demo/StandardWebToken/locklift.config.template.js diff --git a/demo/StandardWebToken/package-lock.json b/demo/StandardWebToken/package-lock.json index 4e179f2..743fa02 100644 --- a/demo/StandardWebToken/package-lock.json +++ b/demo/StandardWebToken/package-lock.json @@ -1393,6 +1393,11 @@ "json-buffer": "3.0.1" } }, + "kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==" + }, "locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -1700,6 +1705,15 @@ "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==" }, + "prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "requires": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + } + }, "pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", @@ -1844,6 +1858,11 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, + "sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" + }, "slice-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", diff --git a/demo/StandardWebToken/package.json b/demo/StandardWebToken/package.json index 6d0877d..43c533b 100644 --- a/demo/StandardWebToken/package.json +++ b/demo/StandardWebToken/package.json @@ -4,12 +4,14 @@ "description": "Standard web token demo", "scripts": { "build": "locklift build --config locklift.config.js", - "deploy": "locklift run --config locklift.config.js --network devnet --script scripts/1-deploy-collection.js" + "deploy": "locklift run --config locklift.config.js --network local --script scripts/1-deploy-collection.js", + "mint": "locklift run --config locklift.config.js --network local --script scripts/2-mint-nft.js" }, "author": "itgold.io", "license": "MIT", "dependencies": { "@itgold/everscale-tip": "^1.1.3", - "locklift": "git+https://github.com/broxus/ton-locklift.git" + "locklift": "git+https://github.com/broxus/ton-locklift.git", + "prompts": "^2.4.2" } } diff --git a/demo/StandardWebToken/safemultisig/SafeMultisigWallet.abi.json b/demo/StandardWebToken/safemultisig/SafeMultisigWallet.abi.json new file mode 100644 index 0000000..bd0d131 --- /dev/null +++ b/demo/StandardWebToken/safemultisig/SafeMultisigWallet.abi.json @@ -0,0 +1,123 @@ +{ + "ABI version": 2, + "header": ["pubkey", "time", "expire"], + "functions": [ + { + "name": "constructor", + "inputs": [ + {"name":"owners","type":"uint256[]"}, + {"name":"reqConfirms","type":"uint8"} + ], + "outputs": [ + ] + }, + { + "name": "acceptTransfer", + "inputs": [ + {"name":"payload","type":"bytes"} + ], + "outputs": [ + ] + }, + { + "name": "sendTransaction", + "inputs": [ + {"name":"dest","type":"address"}, + {"name":"value","type":"uint128"}, + {"name":"bounce","type":"bool"}, + {"name":"flags","type":"uint8"}, + {"name":"payload","type":"cell"} + ], + "outputs": [ + ] + }, + { + "name": "submitTransaction", + "inputs": [ + {"name":"dest","type":"address"}, + {"name":"value","type":"uint128"}, + {"name":"bounce","type":"bool"}, + {"name":"allBalance","type":"bool"}, + {"name":"payload","type":"cell"} + ], + "outputs": [ + {"name":"transId","type":"uint64"} + ] + }, + { + "name": "confirmTransaction", + "inputs": [ + {"name":"transactionId","type":"uint64"} + ], + "outputs": [ + ] + }, + { + "name": "isConfirmed", + "inputs": [ + {"name":"mask","type":"uint32"}, + {"name":"index","type":"uint8"} + ], + "outputs": [ + {"name":"confirmed","type":"bool"} + ] + }, + { + "name": "getParameters", + "inputs": [ + ], + "outputs": [ + {"name":"maxQueuedTransactions","type":"uint8"}, + {"name":"maxCustodianCount","type":"uint8"}, + {"name":"expirationTime","type":"uint64"}, + {"name":"minValue","type":"uint128"}, + {"name":"requiredTxnConfirms","type":"uint8"} + ] + }, + { + "name": "getTransaction", + "inputs": [ + {"name":"transactionId","type":"uint64"} + ], + "outputs": [ + {"components":[{"name":"id","type":"uint64"},{"name":"confirmationsMask","type":"uint32"},{"name":"signsRequired","type":"uint8"},{"name":"signsReceived","type":"uint8"},{"name":"creator","type":"uint256"},{"name":"index","type":"uint8"},{"name":"dest","type":"address"},{"name":"value","type":"uint128"},{"name":"sendFlags","type":"uint16"},{"name":"payload","type":"cell"},{"name":"bounce","type":"bool"}],"name":"trans","type":"tuple"} + ] + }, + { + "name": "getTransactions", + "inputs": [ + ], + "outputs": [ + {"components":[{"name":"id","type":"uint64"},{"name":"confirmationsMask","type":"uint32"},{"name":"signsRequired","type":"uint8"},{"name":"signsReceived","type":"uint8"},{"name":"creator","type":"uint256"},{"name":"index","type":"uint8"},{"name":"dest","type":"address"},{"name":"value","type":"uint128"},{"name":"sendFlags","type":"uint16"},{"name":"payload","type":"cell"},{"name":"bounce","type":"bool"}],"name":"transactions","type":"tuple[]"} + ] + }, + { + "name": "getTransactionIds", + "inputs": [ + ], + "outputs": [ + {"name":"ids","type":"uint64[]"} + ] + }, + { + "name": "getCustodians", + "inputs": [ + ], + "outputs": [ + {"components":[{"name":"index","type":"uint8"},{"name":"pubkey","type":"uint256"}],"name":"custodians","type":"tuple[]"} + ] + } + ], + "data": [ + ], + "events": [ + { + "name": "TransferAccepted", + "inputs": [ + {"name":"payload","type":"bytes"} + ], + "outputs": [ + ] + } + ] +} diff --git a/demo/StandardWebToken/safemultisig/SafeMultisigWallet.base64 b/demo/StandardWebToken/safemultisig/SafeMultisigWallet.base64 new file mode 100644 index 0000000..f4e9ac0 --- /dev/null +++ b/demo/StandardWebToken/safemultisig/SafeMultisigWallet.base64 @@ -0,0 +1 @@ +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 diff --git a/demo/StandardWebToken/safemultisig/SafeMultisigWallet.sol b/demo/StandardWebToken/safemultisig/SafeMultisigWallet.sol new file mode 100644 index 0000000..dd5871a --- /dev/null +++ b/demo/StandardWebToken/safemultisig/SafeMultisigWallet.sol @@ -0,0 +1,412 @@ +pragma solidity >=0.6.0; +pragma experimental ABIEncoderV2; +pragma ignoreIntOverflow; +pragma AbiHeader expire; +pragma AbiHeader pubkey; +pragma AbiHeader time; + +interface IAccept { + function acceptTransfer(bytes payload) external payable; +} + +/// @title Multisignature wallet +/// @author Tonlabs (https://tonlabs.io) +contract MultisigWallet is IAccept { + + /* + * Storage + */ + + struct Transaction { + // Transaction Id. + uint64 id; + // Transaction confirmations from custodians. + uint32 confirmationsMask; + // Number of required confirmations. + uint8 signsRequired; + // Number of confirmations already received. + uint8 signsReceived; + // Public key of custodian queued transaction. + uint256 creator; + // Index of custodian. + uint8 index; + // Destination address of gram transfer. + address payable dest; + // Amount of nanograms to transfer. + uint128 value; + // Flags for sending internal message (see SENDRAWMSG in TVM spec). + uint16 sendFlags; + // Payload used as body of outbound internal message. + TvmCell payload; + // Bounce flag for header of outbound internal message. + bool bounce; + } + + /* + * Constants + */ + uint8 constant MAX_QUEUED_REQUESTS = 5; + uint64 constant EXPIRATION_TIME = 3600; // lifetime is 1 hour + uint8 constant MAX_CUSTODIAN_COUNT = 32; + uint128 constant MIN_VALUE = 1e6; + uint constant MAX_CLEANUP_TXNS = 40; + + // Send flags. + // Forward fees for message will be paid from contract balance. + uint8 constant FLAG_PAY_FWD_FEE_FROM_BALANCE = 1; + // Tells node to ignore errors in action phase while outbound messages are sent. + uint8 constant FLAG_IGNORE_ERRORS = 2; + // Tells node to send all remaining balance. + uint8 constant FLAG_SEND_ALL_REMAINING = 128; + + /* + * Variables + */ + + // Public key of custodian who deployed a contract. + uint256 m_ownerKey; + // Binary mask with custodian requests (max 32 custodians). + uint256 m_requestsMask; + // Dictionary of queued transactions waiting confirmations. + mapping(uint64 => Transaction) m_transactions; + // Set of custodians, initiated in constructor, but values can be changed later in code. + mapping(uint256 => uint8) m_custodians; // pub_key -> custodian_index + // Read-only custodian count, initiated in constructor. + uint8 m_custodianCount; + // Default number of confirmations needed to execute transaction. + uint8 m_defaultRequiredConfirmations; + + /* + Exception codes: + 100 - message sender is not a custodian; + 102 - transaction does not exist; + 103 - operation is already confirmed by this custodian; + 107 - input value is too low; + 108 - wallet should have only one custodian; + 113 - Too many requests for one custodian; + 117 - invalid number of custodians; + 121 - payload size is too big; + */ + + /* + * Events + */ + event TransferAccepted(bytes payload); + + /* + * Runtime functions + */ + function tvm_ctos(TvmCell cell) private pure returns (uint /* slice */) {} + function tvm_tree_cell_size(uint slice) private pure returns (uint, uint) {} + + /* + * Constructor + */ + + /// @dev Internal function called from constructor to initialize custodians. + function _initialize(uint256[] owners, uint8 reqConfirms) inline private { + uint8 ownerCount = 0; + m_ownerKey = owners[0]; + + uint256 len = owners.length; + for (uint256 i = 0; (i < len && ownerCount < MAX_CUSTODIAN_COUNT); i++) { + uint256 key = owners[i]; + if (!m_custodians.exists(key)) { + m_custodians[key] = ownerCount++; + } + } + m_defaultRequiredConfirmations = ownerCount <= reqConfirms ? ownerCount : reqConfirms; + m_custodianCount = ownerCount; + } + + /// @dev Contract constructor. + /// @param owners Array of custodian keys. + /// @param reqConfirms Default number of confirmations required for executing transaction. + constructor(uint256[] owners, uint8 reqConfirms) public { + require(msg.pubkey() == tvm.pubkey(), 100); + require(owners.length > 0 && owners.length <= MAX_CUSTODIAN_COUNT, 117); + tvm.accept(); + _initialize(owners, reqConfirms); + } + + /* + * Inline helper macros + */ + + /// @dev Returns queued transaction count by custodian with defined index. + function _getMaskValue(uint256 mask, uint8 index) inline private pure returns (uint8) { + return uint8((mask >> (8 * uint256(index))) & 0xFF); + } + + /// @dev Increment queued transaction count by custodian with defined index. + function _incMaskValue(uint256 mask, uint8 index) inline private pure returns (uint256) { + return mask + (1 << (8 * uint256(index))); + } + + /// @dev Decrement queued transaction count by custodian with defined index. + function _decMaskValue(uint256 mask, uint8 index) inline private pure returns (uint256) { + return mask - (1 << (8 * uint256(index))); + } + + /// @dev Checks bit with defined index in the mask. + function _checkBit(uint32 mask, uint8 index) inline private pure returns (bool) { + return (mask & (uint32(1) << index)) != 0; + } + + /// @dev Checks if object is confirmed by custodian. + function _isConfirmed(uint32 mask, uint8 custodianIndex) inline private pure returns (bool) { + return _checkBit(mask, custodianIndex); + } + + /// @dev Sets custodian confirmation bit in the mask. + function _setConfirmed(uint32 mask, uint8 custodianIndex) inline private pure returns (uint32) { + mask |= (uint32(1) << custodianIndex); + return mask; + } + + /// @dev Checks that custodian with supplied public key exists in custodian set. + function _findCustodian(uint256 senderKey) inline private view returns (uint8) { + (bool exists, uint8 index) = m_custodians.fetch(senderKey); + require(exists, 100); + return index; + } + + /// @dev Generates new id for object. + function _generateId() inline private view returns (uint64) { + return (uint64(now) << 32) | (tvm.transLT() & 0xFFFFFFFF); + } + + /// @dev Returns timestamp after which transactions are treated as expired. + function _getExpirationBound() inline private view returns (uint64) { + return (uint64(now) - EXPIRATION_TIME) << 32; + } + + /// @dev Returns transfer flags according to input value and `allBalance` flag. + function _getSendFlags(uint128 value, bool allBalance) inline private pure returns (uint8, uint128) { + uint8 flags = FLAG_IGNORE_ERRORS | FLAG_PAY_FWD_FEE_FROM_BALANCE; + if (allBalance) { + flags = FLAG_IGNORE_ERRORS | FLAG_SEND_ALL_REMAINING; + value = uint128(address(this).balance); + } + return (flags, value); + } + + /* + * Public functions + */ + + /// @dev A payable method for accepting incoming funds. Generates + /// an event with incoming payload. + /// @param payload Payload from message body. + function acceptTransfer(bytes payload) external override payable { + emit TransferAccepted(payload); + } + + /// @dev Allows custodian if she is the only owner of multisig to transfer funds with minimal fees. + /// @param dest Transfer target address. + /// @param value Amount of funds to transfer. + /// @param bounce Bounce flag. Set true if need to transfer funds to existing account; + /// set false to create new account. + /// @param flags `sendmsg` flags. + /// @param payload Tree of cells used as body of outbound internal message. + function sendTransaction( + address payable dest, + uint128 value, + bool bounce, + uint8 flags, + TvmCell payload) public view + { + require(m_custodianCount == 1, 108); + require(msg.pubkey() == m_ownerKey, 100); + tvm.accept(); + dest.transfer(value, bounce, flags, payload); + } + + /// @dev Allows custodian to submit and confirm new transaction. + /// @param dest Transfer target address. + /// @param value Nanograms value to transfer. + /// @param bounce Bounce flag. Set true if need to transfer grams to existing account; set false to create new account. + /// @param allBalance Set true if need to transfer all remaining balance. + /// @param payload Tree of cells used as body of outbound internal message. + /// @return transId Transaction ID. + function submitTransaction( + address payable dest, + uint128 value, + bool bounce, + bool allBalance, + TvmCell payload) + public returns (uint64 transId) + { + uint256 senderKey = msg.pubkey(); + uint8 index = _findCustodian(senderKey); + require(value >= MIN_VALUE, 107); + (uint bits, uint cells) = tvm_tree_cell_size(tvm_ctos(payload)); + require(bits < 8192 && cells < 8, 121); + _removeExpiredTransactions(); + require(_getMaskValue(m_requestsMask, index) < MAX_QUEUED_REQUESTS, 113); + tvm.accept(); + + (uint8 flags, uint128 realValue) = _getSendFlags(value, allBalance); + uint8 requiredSigns = m_defaultRequiredConfirmations; + + if (requiredSigns == 1) { + dest.transfer(realValue, bounce, flags, payload); + return 0; + } else { + m_requestsMask = _incMaskValue(m_requestsMask, index); + uint64 trId = _generateId(); + Transaction txn = Transaction(trId, 0/*mask*/, requiredSigns, 0/*signsReceived*/, + senderKey, index, dest, realValue, flags, payload, bounce); + + _confirmTransaction(trId, txn, index); + return trId; + } + } + + /// @dev Allows custodian to confirm a transaction. + /// @param transactionId Transaction ID. + function confirmTransaction(uint64 transactionId) public { + uint8 index = _findCustodian(msg.pubkey()); + _removeExpiredTransactions(); + (bool trexists, Transaction txn) = m_transactions.fetch(transactionId); + require(trexists, 102); + require(!_isConfirmed(txn.confirmationsMask, index), 103); + tvm.accept(); + + _confirmTransaction(transactionId, txn, index); + } + + /* + * Internal functions + */ + + /// @dev Confirms transaction by custodian with defined index. + /// @param transactionId Transaction id to confirm. + /// @param txn Transaction object to confirm. + /// @param custodianIndex Index of custodian. + function _confirmTransaction(uint64 transactionId, Transaction txn, uint8 custodianIndex) inline private { + if ((txn.signsReceived + 1) >= txn.signsRequired) { + txn.dest.transfer(txn.value, txn.bounce, txn.sendFlags, txn.payload); + m_requestsMask = _decMaskValue(m_requestsMask, txn.index); + delete m_transactions[transactionId]; + } else { + txn.confirmationsMask = _setConfirmed(txn.confirmationsMask, custodianIndex); + txn.signsReceived++; + m_transactions[transactionId] = txn; + } + } + + /// @dev Removes expired transactions from storage. + function _removeExpiredTransactions() inline private { + uint64 marker = _getExpirationBound(); + (uint64 trId, Transaction txn, bool success) = m_transactions.min(); + + bool needCleanup = success && (trId <= marker); + if (!needCleanup) { return; } + + tvm.accept(); + uint i = 0; + while (needCleanup && i < MAX_CLEANUP_TXNS) { + // transaction is expired, remove it + i++; + m_requestsMask = _decMaskValue(m_requestsMask, txn.index); + delete m_transactions[trId]; + + (trId, txn, success) = m_transactions.next(trId); + needCleanup = success && (trId <= marker); + } + tvm.commit(); + } + + /* + * Get methods + */ + + /// @dev Helper get-method for checking if custodian confirmation bit is set. + /// @return confirmed True if confirmation bit is set. + function isConfirmed(uint32 mask, uint8 index) public pure returns (bool confirmed) { + confirmed = _isConfirmed(mask, index); + } + + /// @dev Get-method that returns wallet configuration parameters. + /// @return maxQueuedTransactions The maximum number of unconfirmed transactions that a custodian can submit. + /// @return maxCustodianCount The maximum allowed number of wallet custodians. + /// @return expirationTime Transaction lifetime in seconds. + /// @return minValue The minimum value allowed to transfer in one transaction. + /// @return requiredTxnConfirms The minimum number of confirmations required to execute transaction. + function getParameters() public view + returns (uint8 maxQueuedTransactions, + uint8 maxCustodianCount, + uint64 expirationTime, + uint128 minValue, + uint8 requiredTxnConfirms) { + + maxQueuedTransactions = MAX_QUEUED_REQUESTS; + maxCustodianCount = MAX_CUSTODIAN_COUNT; + expirationTime = EXPIRATION_TIME; + minValue = MIN_VALUE; + requiredTxnConfirms = m_defaultRequiredConfirmations; + } + + /// @dev Get-method that returns transaction info by id. + /// @return trans Transaction structure. + /// Throws exception if transaction does not exist. + function getTransaction(uint64 transactionId) public view + returns (Transaction trans) { + (bool exists, Transaction txn) = m_transactions.fetch(transactionId); + require(exists, 102); + trans = txn; + } + + /// @dev Get-method that returns array of pending transactions. + /// Returns not expired transactions only. + /// @return transactions Array of queued transactions. + function getTransactions() public view returns (Transaction[] transactions) { + uint64 bound = _getExpirationBound(); + (uint64 id, Transaction txn, bool success) = m_transactions.min(); + while (success) { + // returns only not expired transactions + if (id > bound) { + transactions.push(txn); + } + (id, txn, success) = m_transactions.next(id); + } + } + + /// @dev Get-method that returns submitted transaction ids. + /// @return ids Array of transaction ids. + function getTransactionIds() public view returns (uint64[] ids) { + uint64 trId = 0; + bool success = false; + (trId, , success) = m_transactions.min(); + while (success) { + ids.push(trId); + (trId, , success) = m_transactions.next(trId); + } + } + + /// @dev Helper structure to return information about custodian. + /// Used in getCustodians(). + struct CustodianInfo { + uint8 index; + uint256 pubkey; + } + + /// @dev Get-method that returns info about wallet custodians. + /// @return custodians Array of custodians. + function getCustodians() public view returns (CustodianInfo[] custodians) { + (uint256 key, uint8 index, bool success) = m_custodians.min(); + while (success) { + custodians.push(CustodianInfo(index, key)); + (key, index, success) = m_custodians.next(key); + } + } + + /* + * Fallback and receive functions to receive simple transfers. + */ + + fallback () external payable {} + + receive () external payable {} +} \ No newline at end of file diff --git a/demo/StandardWebToken/safemultisig/SafeMultisigWallet.tvc b/demo/StandardWebToken/safemultisig/SafeMultisigWallet.tvc new file mode 100644 index 0000000..7584907 Binary files /dev/null and b/demo/StandardWebToken/safemultisig/SafeMultisigWallet.tvc differ diff --git a/demo/StandardWebToken/scripts/1-deploy-collection.js b/demo/StandardWebToken/scripts/1-deploy-collection.js index 207e9ae..f6a923c 100644 --- a/demo/StandardWebToken/scripts/1-deploy-collection.js +++ b/demo/StandardWebToken/scripts/1-deploy-collection.js @@ -1,12 +1,39 @@ +const { + isNumeric +} = require('./utils'); +const prompts = require('prompts'); + async function main() { + + const promptsData = []; + + promptsData.push({ + type: 'text', + name: 'json', + message: 'JSON', + validate: value => !!value + }) + + promptsData.push({ + type: 'text', + name: 'mintingFee', + message: 'Minting Fee', + validate: value => isNumeric(value) ? true : 'Invalid number' + }) + const Collection = await locklift.factory.getContract('Collection'); const Index = await locklift.factory.getContract('Index'); const IndexBasis = await locklift.factory.getContract('IndexBasis'); const Nft = await locklift.factory.getContract('Nft'); const [keyPair] = await locklift.keys.getKeyPairs(); + + const response = await prompts(promptsData); + const ownerPubkey = "0x440d2f6fe861c43007fe4e16e1531291200d3245a6bc6dfb931edd97a68a2e63"; - const json = "{}"; - const mintingFee = 500000000; + const json = response.json; + const mintingFee = response.mintingFee; + + console.log("Deploying..."); const collection = await locklift.giver.deployContract({ contract: Collection, diff --git a/demo/StandardWebToken/scripts/2-mint-nft.js b/demo/StandardWebToken/scripts/2-mint-nft.js new file mode 100644 index 0000000..f61098e --- /dev/null +++ b/demo/StandardWebToken/scripts/2-mint-nft.js @@ -0,0 +1,73 @@ +const { + isValidTonAddress +} = require('./utils'); +const prompts = require('prompts'); + +async function main() { + + const Collection = await locklift.factory.getContract('Collection'); + const [keyPair] = await locklift.keys.getKeyPairs(); + + const promptsData = []; + + promptsData.push({ + type: 'text', + name: 'collection', + message: 'Collection address', + validate: value => isValidTonAddress(value) ? true : 'Invalid TON address' + }); + + promptsData.push({ + type: 'text', + name: 'owner', + message: 'Owner address', + validate: value => isValidTonAddress(value) ? true : 'Invalid TON address' + }); + + promptsData.push({ + type: 'text', + name: 'json', + message: 'JSON', + validate: value => !!value + }) + + const response = await prompts(promptsData); + + const collectionOwner = await locklift.factory.getAccount('SafeMultisigWallet', 'safemultisig'); + collectionOwner.setAddress(response.owner); + + const collection = Collection; + collection.setAddress(response.collection); + + await collectionOwner.runTarget({ + contract: collection, + method: 'mintNft', + params: { + json: response.json, + }, + value: locklift.utils.convertCrystal(3, 'nano'), + keyPair + }); + + const totalSupply = await collection.call({ + method: 'totalSupply', + params: {}, + }); + + const nftAddr = await collection.call({ + method: 'nftAddress', + params: { + id: totalSupply - 1 + }, + }); + + console.log("Nft was successfully minted!"); + console.log("Address: " + nftAddr); +} + +main() + .then(() => process.exit(0)) + .catch(e => { + console.log(e); + process.exit(1); + }); diff --git a/demo/StandardWebToken/scripts/utils.js b/demo/StandardWebToken/scripts/utils.js new file mode 100644 index 0000000..d0e9922 --- /dev/null +++ b/demo/StandardWebToken/scripts/utils.js @@ -0,0 +1,8 @@ +const isValidTonAddress = (address) => /^(?:-1|0):[0-9a-fA-F]{64}$/.test(address); + +const isNumeric = (value) => /^-?\d+$/.test(value); + +module.exports = { + isValidTonAddress, + isNumeric +} \ No newline at end of file diff --git a/demo/StandardWebToken/locklift.config.js b/demo/TIP4_1/locklift.config.template.js similarity index 100% rename from demo/StandardWebToken/locklift.config.js rename to demo/TIP4_1/locklift.config.template.js diff --git a/demo/TIP4_1/package-lock.json b/demo/TIP4_1/package-lock.json index 8fb6147..900652f 100644 --- a/demo/TIP4_1/package-lock.json +++ b/demo/TIP4_1/package-lock.json @@ -1,6 +1,6 @@ { "name": "tip4_1", - "version": "1.0.0", + "version": "1.1.3", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -1393,6 +1393,11 @@ "json-buffer": "3.0.1" } }, + "kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==" + }, "locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -1700,6 +1705,15 @@ "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==" }, + "prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "requires": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + } + }, "pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", @@ -1844,6 +1858,11 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, + "sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" + }, "slice-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", diff --git a/demo/TIP4_1/package.json b/demo/TIP4_1/package.json index 6f9576c..45a6de8 100644 --- a/demo/TIP4_1/package.json +++ b/demo/TIP4_1/package.json @@ -4,12 +4,14 @@ "description": "TIP4_1 demo", "scripts": { "build": "locklift build --config locklift.config.js", - "deploy": "locklift run --config locklift.config.js --network devnet --script scripts/1-deploy-collection.js" + "deploy": "locklift run --config locklift.config.js --network devnet --script scripts/1-deploy-collection.js", + "mint": "locklift run --config locklift.config.js --network devnet --script scripts/2-mint-nft.js" }, "author": "itgold.io", "license": "MIT", "dependencies": { "@itgold/everscale-tip": "^1.1.3", - "locklift": "git+https://github.com/broxus/ton-locklift.git" + "locklift": "git+https://github.com/broxus/ton-locklift.git", + "prompts": "^2.4.2" } } diff --git a/demo/TIP4_1/safemultisig/SafeMultisigWallet.abi.json b/demo/TIP4_1/safemultisig/SafeMultisigWallet.abi.json new file mode 100644 index 0000000..bd0d131 --- /dev/null +++ b/demo/TIP4_1/safemultisig/SafeMultisigWallet.abi.json @@ -0,0 +1,123 @@ +{ + "ABI version": 2, + "header": ["pubkey", "time", "expire"], + "functions": [ + { + "name": "constructor", + "inputs": [ + {"name":"owners","type":"uint256[]"}, + {"name":"reqConfirms","type":"uint8"} + ], + "outputs": [ + ] + }, + { + "name": "acceptTransfer", + "inputs": [ + {"name":"payload","type":"bytes"} + ], + "outputs": [ + ] + }, + { + "name": "sendTransaction", + "inputs": [ + {"name":"dest","type":"address"}, + {"name":"value","type":"uint128"}, + {"name":"bounce","type":"bool"}, + {"name":"flags","type":"uint8"}, + {"name":"payload","type":"cell"} + ], + "outputs": [ + ] + }, + { + "name": "submitTransaction", + "inputs": [ + {"name":"dest","type":"address"}, + {"name":"value","type":"uint128"}, + {"name":"bounce","type":"bool"}, + {"name":"allBalance","type":"bool"}, + {"name":"payload","type":"cell"} + ], + "outputs": [ + {"name":"transId","type":"uint64"} + ] + }, + { + "name": "confirmTransaction", + "inputs": [ + {"name":"transactionId","type":"uint64"} + ], + "outputs": [ + ] + }, + { + "name": "isConfirmed", + "inputs": [ + {"name":"mask","type":"uint32"}, + {"name":"index","type":"uint8"} + ], + "outputs": [ + {"name":"confirmed","type":"bool"} + ] + }, + { + "name": "getParameters", + "inputs": [ + ], + "outputs": [ + {"name":"maxQueuedTransactions","type":"uint8"}, + {"name":"maxCustodianCount","type":"uint8"}, + {"name":"expirationTime","type":"uint64"}, + {"name":"minValue","type":"uint128"}, + {"name":"requiredTxnConfirms","type":"uint8"} + ] + }, + { + "name": "getTransaction", + "inputs": [ + {"name":"transactionId","type":"uint64"} + ], + "outputs": [ + {"components":[{"name":"id","type":"uint64"},{"name":"confirmationsMask","type":"uint32"},{"name":"signsRequired","type":"uint8"},{"name":"signsReceived","type":"uint8"},{"name":"creator","type":"uint256"},{"name":"index","type":"uint8"},{"name":"dest","type":"address"},{"name":"value","type":"uint128"},{"name":"sendFlags","type":"uint16"},{"name":"payload","type":"cell"},{"name":"bounce","type":"bool"}],"name":"trans","type":"tuple"} + ] + }, + { + "name": "getTransactions", + "inputs": [ + ], + "outputs": [ + {"components":[{"name":"id","type":"uint64"},{"name":"confirmationsMask","type":"uint32"},{"name":"signsRequired","type":"uint8"},{"name":"signsReceived","type":"uint8"},{"name":"creator","type":"uint256"},{"name":"index","type":"uint8"},{"name":"dest","type":"address"},{"name":"value","type":"uint128"},{"name":"sendFlags","type":"uint16"},{"name":"payload","type":"cell"},{"name":"bounce","type":"bool"}],"name":"transactions","type":"tuple[]"} + ] + }, + { + "name": "getTransactionIds", + "inputs": [ + ], + "outputs": [ + {"name":"ids","type":"uint64[]"} + ] + }, + { + "name": "getCustodians", + "inputs": [ + ], + "outputs": [ + {"components":[{"name":"index","type":"uint8"},{"name":"pubkey","type":"uint256"}],"name":"custodians","type":"tuple[]"} + ] + } + ], + "data": [ + ], + "events": [ + { + "name": "TransferAccepted", + "inputs": [ + {"name":"payload","type":"bytes"} + ], + "outputs": [ + ] + } + ] +} diff --git a/demo/TIP4_1/safemultisig/SafeMultisigWallet.base64 b/demo/TIP4_1/safemultisig/SafeMultisigWallet.base64 new file mode 100644 index 0000000..f4e9ac0 --- /dev/null +++ b/demo/TIP4_1/safemultisig/SafeMultisigWallet.base64 @@ -0,0 +1 @@ +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 diff --git a/demo/TIP4_1/safemultisig/SafeMultisigWallet.sol b/demo/TIP4_1/safemultisig/SafeMultisigWallet.sol new file mode 100644 index 0000000..dd5871a --- /dev/null +++ b/demo/TIP4_1/safemultisig/SafeMultisigWallet.sol @@ -0,0 +1,412 @@ +pragma solidity >=0.6.0; +pragma experimental ABIEncoderV2; +pragma ignoreIntOverflow; +pragma AbiHeader expire; +pragma AbiHeader pubkey; +pragma AbiHeader time; + +interface IAccept { + function acceptTransfer(bytes payload) external payable; +} + +/// @title Multisignature wallet +/// @author Tonlabs (https://tonlabs.io) +contract MultisigWallet is IAccept { + + /* + * Storage + */ + + struct Transaction { + // Transaction Id. + uint64 id; + // Transaction confirmations from custodians. + uint32 confirmationsMask; + // Number of required confirmations. + uint8 signsRequired; + // Number of confirmations already received. + uint8 signsReceived; + // Public key of custodian queued transaction. + uint256 creator; + // Index of custodian. + uint8 index; + // Destination address of gram transfer. + address payable dest; + // Amount of nanograms to transfer. + uint128 value; + // Flags for sending internal message (see SENDRAWMSG in TVM spec). + uint16 sendFlags; + // Payload used as body of outbound internal message. + TvmCell payload; + // Bounce flag for header of outbound internal message. + bool bounce; + } + + /* + * Constants + */ + uint8 constant MAX_QUEUED_REQUESTS = 5; + uint64 constant EXPIRATION_TIME = 3600; // lifetime is 1 hour + uint8 constant MAX_CUSTODIAN_COUNT = 32; + uint128 constant MIN_VALUE = 1e6; + uint constant MAX_CLEANUP_TXNS = 40; + + // Send flags. + // Forward fees for message will be paid from contract balance. + uint8 constant FLAG_PAY_FWD_FEE_FROM_BALANCE = 1; + // Tells node to ignore errors in action phase while outbound messages are sent. + uint8 constant FLAG_IGNORE_ERRORS = 2; + // Tells node to send all remaining balance. + uint8 constant FLAG_SEND_ALL_REMAINING = 128; + + /* + * Variables + */ + + // Public key of custodian who deployed a contract. + uint256 m_ownerKey; + // Binary mask with custodian requests (max 32 custodians). + uint256 m_requestsMask; + // Dictionary of queued transactions waiting confirmations. + mapping(uint64 => Transaction) m_transactions; + // Set of custodians, initiated in constructor, but values can be changed later in code. + mapping(uint256 => uint8) m_custodians; // pub_key -> custodian_index + // Read-only custodian count, initiated in constructor. + uint8 m_custodianCount; + // Default number of confirmations needed to execute transaction. + uint8 m_defaultRequiredConfirmations; + + /* + Exception codes: + 100 - message sender is not a custodian; + 102 - transaction does not exist; + 103 - operation is already confirmed by this custodian; + 107 - input value is too low; + 108 - wallet should have only one custodian; + 113 - Too many requests for one custodian; + 117 - invalid number of custodians; + 121 - payload size is too big; + */ + + /* + * Events + */ + event TransferAccepted(bytes payload); + + /* + * Runtime functions + */ + function tvm_ctos(TvmCell cell) private pure returns (uint /* slice */) {} + function tvm_tree_cell_size(uint slice) private pure returns (uint, uint) {} + + /* + * Constructor + */ + + /// @dev Internal function called from constructor to initialize custodians. + function _initialize(uint256[] owners, uint8 reqConfirms) inline private { + uint8 ownerCount = 0; + m_ownerKey = owners[0]; + + uint256 len = owners.length; + for (uint256 i = 0; (i < len && ownerCount < MAX_CUSTODIAN_COUNT); i++) { + uint256 key = owners[i]; + if (!m_custodians.exists(key)) { + m_custodians[key] = ownerCount++; + } + } + m_defaultRequiredConfirmations = ownerCount <= reqConfirms ? ownerCount : reqConfirms; + m_custodianCount = ownerCount; + } + + /// @dev Contract constructor. + /// @param owners Array of custodian keys. + /// @param reqConfirms Default number of confirmations required for executing transaction. + constructor(uint256[] owners, uint8 reqConfirms) public { + require(msg.pubkey() == tvm.pubkey(), 100); + require(owners.length > 0 && owners.length <= MAX_CUSTODIAN_COUNT, 117); + tvm.accept(); + _initialize(owners, reqConfirms); + } + + /* + * Inline helper macros + */ + + /// @dev Returns queued transaction count by custodian with defined index. + function _getMaskValue(uint256 mask, uint8 index) inline private pure returns (uint8) { + return uint8((mask >> (8 * uint256(index))) & 0xFF); + } + + /// @dev Increment queued transaction count by custodian with defined index. + function _incMaskValue(uint256 mask, uint8 index) inline private pure returns (uint256) { + return mask + (1 << (8 * uint256(index))); + } + + /// @dev Decrement queued transaction count by custodian with defined index. + function _decMaskValue(uint256 mask, uint8 index) inline private pure returns (uint256) { + return mask - (1 << (8 * uint256(index))); + } + + /// @dev Checks bit with defined index in the mask. + function _checkBit(uint32 mask, uint8 index) inline private pure returns (bool) { + return (mask & (uint32(1) << index)) != 0; + } + + /// @dev Checks if object is confirmed by custodian. + function _isConfirmed(uint32 mask, uint8 custodianIndex) inline private pure returns (bool) { + return _checkBit(mask, custodianIndex); + } + + /// @dev Sets custodian confirmation bit in the mask. + function _setConfirmed(uint32 mask, uint8 custodianIndex) inline private pure returns (uint32) { + mask |= (uint32(1) << custodianIndex); + return mask; + } + + /// @dev Checks that custodian with supplied public key exists in custodian set. + function _findCustodian(uint256 senderKey) inline private view returns (uint8) { + (bool exists, uint8 index) = m_custodians.fetch(senderKey); + require(exists, 100); + return index; + } + + /// @dev Generates new id for object. + function _generateId() inline private view returns (uint64) { + return (uint64(now) << 32) | (tvm.transLT() & 0xFFFFFFFF); + } + + /// @dev Returns timestamp after which transactions are treated as expired. + function _getExpirationBound() inline private view returns (uint64) { + return (uint64(now) - EXPIRATION_TIME) << 32; + } + + /// @dev Returns transfer flags according to input value and `allBalance` flag. + function _getSendFlags(uint128 value, bool allBalance) inline private pure returns (uint8, uint128) { + uint8 flags = FLAG_IGNORE_ERRORS | FLAG_PAY_FWD_FEE_FROM_BALANCE; + if (allBalance) { + flags = FLAG_IGNORE_ERRORS | FLAG_SEND_ALL_REMAINING; + value = uint128(address(this).balance); + } + return (flags, value); + } + + /* + * Public functions + */ + + /// @dev A payable method for accepting incoming funds. Generates + /// an event with incoming payload. + /// @param payload Payload from message body. + function acceptTransfer(bytes payload) external override payable { + emit TransferAccepted(payload); + } + + /// @dev Allows custodian if she is the only owner of multisig to transfer funds with minimal fees. + /// @param dest Transfer target address. + /// @param value Amount of funds to transfer. + /// @param bounce Bounce flag. Set true if need to transfer funds to existing account; + /// set false to create new account. + /// @param flags `sendmsg` flags. + /// @param payload Tree of cells used as body of outbound internal message. + function sendTransaction( + address payable dest, + uint128 value, + bool bounce, + uint8 flags, + TvmCell payload) public view + { + require(m_custodianCount == 1, 108); + require(msg.pubkey() == m_ownerKey, 100); + tvm.accept(); + dest.transfer(value, bounce, flags, payload); + } + + /// @dev Allows custodian to submit and confirm new transaction. + /// @param dest Transfer target address. + /// @param value Nanograms value to transfer. + /// @param bounce Bounce flag. Set true if need to transfer grams to existing account; set false to create new account. + /// @param allBalance Set true if need to transfer all remaining balance. + /// @param payload Tree of cells used as body of outbound internal message. + /// @return transId Transaction ID. + function submitTransaction( + address payable dest, + uint128 value, + bool bounce, + bool allBalance, + TvmCell payload) + public returns (uint64 transId) + { + uint256 senderKey = msg.pubkey(); + uint8 index = _findCustodian(senderKey); + require(value >= MIN_VALUE, 107); + (uint bits, uint cells) = tvm_tree_cell_size(tvm_ctos(payload)); + require(bits < 8192 && cells < 8, 121); + _removeExpiredTransactions(); + require(_getMaskValue(m_requestsMask, index) < MAX_QUEUED_REQUESTS, 113); + tvm.accept(); + + (uint8 flags, uint128 realValue) = _getSendFlags(value, allBalance); + uint8 requiredSigns = m_defaultRequiredConfirmations; + + if (requiredSigns == 1) { + dest.transfer(realValue, bounce, flags, payload); + return 0; + } else { + m_requestsMask = _incMaskValue(m_requestsMask, index); + uint64 trId = _generateId(); + Transaction txn = Transaction(trId, 0/*mask*/, requiredSigns, 0/*signsReceived*/, + senderKey, index, dest, realValue, flags, payload, bounce); + + _confirmTransaction(trId, txn, index); + return trId; + } + } + + /// @dev Allows custodian to confirm a transaction. + /// @param transactionId Transaction ID. + function confirmTransaction(uint64 transactionId) public { + uint8 index = _findCustodian(msg.pubkey()); + _removeExpiredTransactions(); + (bool trexists, Transaction txn) = m_transactions.fetch(transactionId); + require(trexists, 102); + require(!_isConfirmed(txn.confirmationsMask, index), 103); + tvm.accept(); + + _confirmTransaction(transactionId, txn, index); + } + + /* + * Internal functions + */ + + /// @dev Confirms transaction by custodian with defined index. + /// @param transactionId Transaction id to confirm. + /// @param txn Transaction object to confirm. + /// @param custodianIndex Index of custodian. + function _confirmTransaction(uint64 transactionId, Transaction txn, uint8 custodianIndex) inline private { + if ((txn.signsReceived + 1) >= txn.signsRequired) { + txn.dest.transfer(txn.value, txn.bounce, txn.sendFlags, txn.payload); + m_requestsMask = _decMaskValue(m_requestsMask, txn.index); + delete m_transactions[transactionId]; + } else { + txn.confirmationsMask = _setConfirmed(txn.confirmationsMask, custodianIndex); + txn.signsReceived++; + m_transactions[transactionId] = txn; + } + } + + /// @dev Removes expired transactions from storage. + function _removeExpiredTransactions() inline private { + uint64 marker = _getExpirationBound(); + (uint64 trId, Transaction txn, bool success) = m_transactions.min(); + + bool needCleanup = success && (trId <= marker); + if (!needCleanup) { return; } + + tvm.accept(); + uint i = 0; + while (needCleanup && i < MAX_CLEANUP_TXNS) { + // transaction is expired, remove it + i++; + m_requestsMask = _decMaskValue(m_requestsMask, txn.index); + delete m_transactions[trId]; + + (trId, txn, success) = m_transactions.next(trId); + needCleanup = success && (trId <= marker); + } + tvm.commit(); + } + + /* + * Get methods + */ + + /// @dev Helper get-method for checking if custodian confirmation bit is set. + /// @return confirmed True if confirmation bit is set. + function isConfirmed(uint32 mask, uint8 index) public pure returns (bool confirmed) { + confirmed = _isConfirmed(mask, index); + } + + /// @dev Get-method that returns wallet configuration parameters. + /// @return maxQueuedTransactions The maximum number of unconfirmed transactions that a custodian can submit. + /// @return maxCustodianCount The maximum allowed number of wallet custodians. + /// @return expirationTime Transaction lifetime in seconds. + /// @return minValue The minimum value allowed to transfer in one transaction. + /// @return requiredTxnConfirms The minimum number of confirmations required to execute transaction. + function getParameters() public view + returns (uint8 maxQueuedTransactions, + uint8 maxCustodianCount, + uint64 expirationTime, + uint128 minValue, + uint8 requiredTxnConfirms) { + + maxQueuedTransactions = MAX_QUEUED_REQUESTS; + maxCustodianCount = MAX_CUSTODIAN_COUNT; + expirationTime = EXPIRATION_TIME; + minValue = MIN_VALUE; + requiredTxnConfirms = m_defaultRequiredConfirmations; + } + + /// @dev Get-method that returns transaction info by id. + /// @return trans Transaction structure. + /// Throws exception if transaction does not exist. + function getTransaction(uint64 transactionId) public view + returns (Transaction trans) { + (bool exists, Transaction txn) = m_transactions.fetch(transactionId); + require(exists, 102); + trans = txn; + } + + /// @dev Get-method that returns array of pending transactions. + /// Returns not expired transactions only. + /// @return transactions Array of queued transactions. + function getTransactions() public view returns (Transaction[] transactions) { + uint64 bound = _getExpirationBound(); + (uint64 id, Transaction txn, bool success) = m_transactions.min(); + while (success) { + // returns only not expired transactions + if (id > bound) { + transactions.push(txn); + } + (id, txn, success) = m_transactions.next(id); + } + } + + /// @dev Get-method that returns submitted transaction ids. + /// @return ids Array of transaction ids. + function getTransactionIds() public view returns (uint64[] ids) { + uint64 trId = 0; + bool success = false; + (trId, , success) = m_transactions.min(); + while (success) { + ids.push(trId); + (trId, , success) = m_transactions.next(trId); + } + } + + /// @dev Helper structure to return information about custodian. + /// Used in getCustodians(). + struct CustodianInfo { + uint8 index; + uint256 pubkey; + } + + /// @dev Get-method that returns info about wallet custodians. + /// @return custodians Array of custodians. + function getCustodians() public view returns (CustodianInfo[] custodians) { + (uint256 key, uint8 index, bool success) = m_custodians.min(); + while (success) { + custodians.push(CustodianInfo(index, key)); + (key, index, success) = m_custodians.next(key); + } + } + + /* + * Fallback and receive functions to receive simple transfers. + */ + + fallback () external payable {} + + receive () external payable {} +} \ No newline at end of file diff --git a/demo/TIP4_1/safemultisig/SafeMultisigWallet.tvc b/demo/TIP4_1/safemultisig/SafeMultisigWallet.tvc new file mode 100644 index 0000000..7584907 Binary files /dev/null and b/demo/TIP4_1/safemultisig/SafeMultisigWallet.tvc differ diff --git a/demo/TIP4_1/scripts/2-mint-nft.js b/demo/TIP4_1/scripts/2-mint-nft.js new file mode 100644 index 0000000..de41014 --- /dev/null +++ b/demo/TIP4_1/scripts/2-mint-nft.js @@ -0,0 +1,64 @@ +const { + isValidTonAddress +} = require('./utils'); +const prompts = require('prompts'); + +async function main() { + + const Collection = await locklift.factory.getContract('Collection'); + const [keyPair] = await locklift.keys.getKeyPairs(); + + const promptsData = []; + + promptsData.push({ + type: 'text', + name: 'collection', + message: 'Collection address', + validate: value => isValidTonAddress(value) ? true : 'Invalid TON address' + }); + + promptsData.push({ + type: 'text', + name: 'owner', + message: 'Owner address', + validate: value => isValidTonAddress(value) ? true : 'Invalid TON address' + }); + + const response = await prompts(promptsData); + + const collectionOwner = await locklift.factory.getAccount('SafeMultisigWallet', 'safemultisig'); + collectionOwner.setAddress(response.owner); + + const collection = Collection; + collection.setAddress(response.collection); + + await collectionOwner.runTarget({ + contract: collection, + method: 'mintNft', + params: {}, + value: locklift.utils.convertCrystal(3, 'nano'), + keyPair + }); + + const totalSupply = await collection.call({ + method: 'totalSupply', + params: {}, + }); + + const nftAddr = await collection.call({ + method: 'nftAddress', + params: { + id: totalSupply - 1 + }, + }); + + console.log("Nft was successfully minted!"); + console.log("Address: " + nftAddr); +} + +main() + .then(() => process.exit(0)) + .catch(e => { + console.log(e); + process.exit(1); + }); diff --git a/demo/TIP4_1/scripts/utils.js b/demo/TIP4_1/scripts/utils.js new file mode 100644 index 0000000..d0e9922 --- /dev/null +++ b/demo/TIP4_1/scripts/utils.js @@ -0,0 +1,8 @@ +const isValidTonAddress = (address) => /^(?:-1|0):[0-9a-fA-F]{64}$/.test(address); + +const isNumeric = (value) => /^-?\d+$/.test(value); + +module.exports = { + isValidTonAddress, + isNumeric +} \ No newline at end of file diff --git a/demo/TIP4_1/locklift.config.js b/demo/TIP4_2/locklift.config.template.js similarity index 100% rename from demo/TIP4_1/locklift.config.js rename to demo/TIP4_2/locklift.config.template.js diff --git a/demo/TIP4_2/package-lock.json b/demo/TIP4_2/package-lock.json index ff5bdc6..7fa6066 100644 --- a/demo/TIP4_2/package-lock.json +++ b/demo/TIP4_2/package-lock.json @@ -1,6 +1,6 @@ { "name": "tip4_2", - "version": "1.0.0", + "version": "1.1.3", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -1393,6 +1393,11 @@ "json-buffer": "3.0.1" } }, + "kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==" + }, "locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -1700,6 +1705,15 @@ "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==" }, + "prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "requires": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + } + }, "pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", @@ -1844,6 +1858,11 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, + "sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" + }, "slice-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", diff --git a/demo/TIP4_2/package.json b/demo/TIP4_2/package.json index b7c258f..594eaf5 100644 --- a/demo/TIP4_2/package.json +++ b/demo/TIP4_2/package.json @@ -4,12 +4,14 @@ "description": "TIP4_2 demo", "scripts": { "build": "locklift build --config locklift.config.js", - "deploy": "locklift run --config locklift.config.js --network devnet --script scripts/1-deploy-collection.js" + "deploy": "locklift run --config locklift.config.js --network devnet --script scripts/1-deploy-collection.js", + "mint": "locklift run --config locklift.config.js --network devnet --script scripts/2-mint-nft.js" }, "author": "itgold.io", "license": "MIT", "dependencies": { "@itgold/everscale-tip": "^1.1.3", - "locklift": "git+https://github.com/broxus/ton-locklift.git" + "locklift": "git+https://github.com/broxus/ton-locklift.git", + "prompts": "^2.4.2" } -} \ No newline at end of file +} diff --git a/demo/TIP4_2/safemultisig/SafeMultisigWallet.abi.json b/demo/TIP4_2/safemultisig/SafeMultisigWallet.abi.json new file mode 100644 index 0000000..bd0d131 --- /dev/null +++ b/demo/TIP4_2/safemultisig/SafeMultisigWallet.abi.json @@ -0,0 +1,123 @@ +{ + "ABI version": 2, + "header": ["pubkey", "time", "expire"], + "functions": [ + { + "name": "constructor", + "inputs": [ + {"name":"owners","type":"uint256[]"}, + {"name":"reqConfirms","type":"uint8"} + ], + "outputs": [ + ] + }, + { + "name": "acceptTransfer", + "inputs": [ + {"name":"payload","type":"bytes"} + ], + "outputs": [ + ] + }, + { + "name": "sendTransaction", + "inputs": [ + {"name":"dest","type":"address"}, + {"name":"value","type":"uint128"}, + {"name":"bounce","type":"bool"}, + {"name":"flags","type":"uint8"}, + {"name":"payload","type":"cell"} + ], + "outputs": [ + ] + }, + { + "name": "submitTransaction", + "inputs": [ + {"name":"dest","type":"address"}, + {"name":"value","type":"uint128"}, + {"name":"bounce","type":"bool"}, + {"name":"allBalance","type":"bool"}, + {"name":"payload","type":"cell"} + ], + "outputs": [ + {"name":"transId","type":"uint64"} + ] + }, + { + "name": "confirmTransaction", + "inputs": [ + {"name":"transactionId","type":"uint64"} + ], + "outputs": [ + ] + }, + { + "name": "isConfirmed", + "inputs": [ + {"name":"mask","type":"uint32"}, + {"name":"index","type":"uint8"} + ], + "outputs": [ + {"name":"confirmed","type":"bool"} + ] + }, + { + "name": "getParameters", + "inputs": [ + ], + "outputs": [ + {"name":"maxQueuedTransactions","type":"uint8"}, + {"name":"maxCustodianCount","type":"uint8"}, + {"name":"expirationTime","type":"uint64"}, + {"name":"minValue","type":"uint128"}, + {"name":"requiredTxnConfirms","type":"uint8"} + ] + }, + { + "name": "getTransaction", + "inputs": [ + {"name":"transactionId","type":"uint64"} + ], + "outputs": [ + {"components":[{"name":"id","type":"uint64"},{"name":"confirmationsMask","type":"uint32"},{"name":"signsRequired","type":"uint8"},{"name":"signsReceived","type":"uint8"},{"name":"creator","type":"uint256"},{"name":"index","type":"uint8"},{"name":"dest","type":"address"},{"name":"value","type":"uint128"},{"name":"sendFlags","type":"uint16"},{"name":"payload","type":"cell"},{"name":"bounce","type":"bool"}],"name":"trans","type":"tuple"} + ] + }, + { + "name": "getTransactions", + "inputs": [ + ], + "outputs": [ + {"components":[{"name":"id","type":"uint64"},{"name":"confirmationsMask","type":"uint32"},{"name":"signsRequired","type":"uint8"},{"name":"signsReceived","type":"uint8"},{"name":"creator","type":"uint256"},{"name":"index","type":"uint8"},{"name":"dest","type":"address"},{"name":"value","type":"uint128"},{"name":"sendFlags","type":"uint16"},{"name":"payload","type":"cell"},{"name":"bounce","type":"bool"}],"name":"transactions","type":"tuple[]"} + ] + }, + { + "name": "getTransactionIds", + "inputs": [ + ], + "outputs": [ + {"name":"ids","type":"uint64[]"} + ] + }, + { + "name": "getCustodians", + "inputs": [ + ], + "outputs": [ + {"components":[{"name":"index","type":"uint8"},{"name":"pubkey","type":"uint256"}],"name":"custodians","type":"tuple[]"} + ] + } + ], + "data": [ + ], + "events": [ + { + "name": "TransferAccepted", + "inputs": [ + {"name":"payload","type":"bytes"} + ], + "outputs": [ + ] + } + ] +} diff --git a/demo/TIP4_2/safemultisig/SafeMultisigWallet.base64 b/demo/TIP4_2/safemultisig/SafeMultisigWallet.base64 new file mode 100644 index 0000000..f4e9ac0 --- /dev/null +++ b/demo/TIP4_2/safemultisig/SafeMultisigWallet.base64 @@ -0,0 +1 @@ +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 diff --git a/demo/TIP4_2/safemultisig/SafeMultisigWallet.sol b/demo/TIP4_2/safemultisig/SafeMultisigWallet.sol new file mode 100644 index 0000000..dd5871a --- /dev/null +++ b/demo/TIP4_2/safemultisig/SafeMultisigWallet.sol @@ -0,0 +1,412 @@ +pragma solidity >=0.6.0; +pragma experimental ABIEncoderV2; +pragma ignoreIntOverflow; +pragma AbiHeader expire; +pragma AbiHeader pubkey; +pragma AbiHeader time; + +interface IAccept { + function acceptTransfer(bytes payload) external payable; +} + +/// @title Multisignature wallet +/// @author Tonlabs (https://tonlabs.io) +contract MultisigWallet is IAccept { + + /* + * Storage + */ + + struct Transaction { + // Transaction Id. + uint64 id; + // Transaction confirmations from custodians. + uint32 confirmationsMask; + // Number of required confirmations. + uint8 signsRequired; + // Number of confirmations already received. + uint8 signsReceived; + // Public key of custodian queued transaction. + uint256 creator; + // Index of custodian. + uint8 index; + // Destination address of gram transfer. + address payable dest; + // Amount of nanograms to transfer. + uint128 value; + // Flags for sending internal message (see SENDRAWMSG in TVM spec). + uint16 sendFlags; + // Payload used as body of outbound internal message. + TvmCell payload; + // Bounce flag for header of outbound internal message. + bool bounce; + } + + /* + * Constants + */ + uint8 constant MAX_QUEUED_REQUESTS = 5; + uint64 constant EXPIRATION_TIME = 3600; // lifetime is 1 hour + uint8 constant MAX_CUSTODIAN_COUNT = 32; + uint128 constant MIN_VALUE = 1e6; + uint constant MAX_CLEANUP_TXNS = 40; + + // Send flags. + // Forward fees for message will be paid from contract balance. + uint8 constant FLAG_PAY_FWD_FEE_FROM_BALANCE = 1; + // Tells node to ignore errors in action phase while outbound messages are sent. + uint8 constant FLAG_IGNORE_ERRORS = 2; + // Tells node to send all remaining balance. + uint8 constant FLAG_SEND_ALL_REMAINING = 128; + + /* + * Variables + */ + + // Public key of custodian who deployed a contract. + uint256 m_ownerKey; + // Binary mask with custodian requests (max 32 custodians). + uint256 m_requestsMask; + // Dictionary of queued transactions waiting confirmations. + mapping(uint64 => Transaction) m_transactions; + // Set of custodians, initiated in constructor, but values can be changed later in code. + mapping(uint256 => uint8) m_custodians; // pub_key -> custodian_index + // Read-only custodian count, initiated in constructor. + uint8 m_custodianCount; + // Default number of confirmations needed to execute transaction. + uint8 m_defaultRequiredConfirmations; + + /* + Exception codes: + 100 - message sender is not a custodian; + 102 - transaction does not exist; + 103 - operation is already confirmed by this custodian; + 107 - input value is too low; + 108 - wallet should have only one custodian; + 113 - Too many requests for one custodian; + 117 - invalid number of custodians; + 121 - payload size is too big; + */ + + /* + * Events + */ + event TransferAccepted(bytes payload); + + /* + * Runtime functions + */ + function tvm_ctos(TvmCell cell) private pure returns (uint /* slice */) {} + function tvm_tree_cell_size(uint slice) private pure returns (uint, uint) {} + + /* + * Constructor + */ + + /// @dev Internal function called from constructor to initialize custodians. + function _initialize(uint256[] owners, uint8 reqConfirms) inline private { + uint8 ownerCount = 0; + m_ownerKey = owners[0]; + + uint256 len = owners.length; + for (uint256 i = 0; (i < len && ownerCount < MAX_CUSTODIAN_COUNT); i++) { + uint256 key = owners[i]; + if (!m_custodians.exists(key)) { + m_custodians[key] = ownerCount++; + } + } + m_defaultRequiredConfirmations = ownerCount <= reqConfirms ? ownerCount : reqConfirms; + m_custodianCount = ownerCount; + } + + /// @dev Contract constructor. + /// @param owners Array of custodian keys. + /// @param reqConfirms Default number of confirmations required for executing transaction. + constructor(uint256[] owners, uint8 reqConfirms) public { + require(msg.pubkey() == tvm.pubkey(), 100); + require(owners.length > 0 && owners.length <= MAX_CUSTODIAN_COUNT, 117); + tvm.accept(); + _initialize(owners, reqConfirms); + } + + /* + * Inline helper macros + */ + + /// @dev Returns queued transaction count by custodian with defined index. + function _getMaskValue(uint256 mask, uint8 index) inline private pure returns (uint8) { + return uint8((mask >> (8 * uint256(index))) & 0xFF); + } + + /// @dev Increment queued transaction count by custodian with defined index. + function _incMaskValue(uint256 mask, uint8 index) inline private pure returns (uint256) { + return mask + (1 << (8 * uint256(index))); + } + + /// @dev Decrement queued transaction count by custodian with defined index. + function _decMaskValue(uint256 mask, uint8 index) inline private pure returns (uint256) { + return mask - (1 << (8 * uint256(index))); + } + + /// @dev Checks bit with defined index in the mask. + function _checkBit(uint32 mask, uint8 index) inline private pure returns (bool) { + return (mask & (uint32(1) << index)) != 0; + } + + /// @dev Checks if object is confirmed by custodian. + function _isConfirmed(uint32 mask, uint8 custodianIndex) inline private pure returns (bool) { + return _checkBit(mask, custodianIndex); + } + + /// @dev Sets custodian confirmation bit in the mask. + function _setConfirmed(uint32 mask, uint8 custodianIndex) inline private pure returns (uint32) { + mask |= (uint32(1) << custodianIndex); + return mask; + } + + /// @dev Checks that custodian with supplied public key exists in custodian set. + function _findCustodian(uint256 senderKey) inline private view returns (uint8) { + (bool exists, uint8 index) = m_custodians.fetch(senderKey); + require(exists, 100); + return index; + } + + /// @dev Generates new id for object. + function _generateId() inline private view returns (uint64) { + return (uint64(now) << 32) | (tvm.transLT() & 0xFFFFFFFF); + } + + /// @dev Returns timestamp after which transactions are treated as expired. + function _getExpirationBound() inline private view returns (uint64) { + return (uint64(now) - EXPIRATION_TIME) << 32; + } + + /// @dev Returns transfer flags according to input value and `allBalance` flag. + function _getSendFlags(uint128 value, bool allBalance) inline private pure returns (uint8, uint128) { + uint8 flags = FLAG_IGNORE_ERRORS | FLAG_PAY_FWD_FEE_FROM_BALANCE; + if (allBalance) { + flags = FLAG_IGNORE_ERRORS | FLAG_SEND_ALL_REMAINING; + value = uint128(address(this).balance); + } + return (flags, value); + } + + /* + * Public functions + */ + + /// @dev A payable method for accepting incoming funds. Generates + /// an event with incoming payload. + /// @param payload Payload from message body. + function acceptTransfer(bytes payload) external override payable { + emit TransferAccepted(payload); + } + + /// @dev Allows custodian if she is the only owner of multisig to transfer funds with minimal fees. + /// @param dest Transfer target address. + /// @param value Amount of funds to transfer. + /// @param bounce Bounce flag. Set true if need to transfer funds to existing account; + /// set false to create new account. + /// @param flags `sendmsg` flags. + /// @param payload Tree of cells used as body of outbound internal message. + function sendTransaction( + address payable dest, + uint128 value, + bool bounce, + uint8 flags, + TvmCell payload) public view + { + require(m_custodianCount == 1, 108); + require(msg.pubkey() == m_ownerKey, 100); + tvm.accept(); + dest.transfer(value, bounce, flags, payload); + } + + /// @dev Allows custodian to submit and confirm new transaction. + /// @param dest Transfer target address. + /// @param value Nanograms value to transfer. + /// @param bounce Bounce flag. Set true if need to transfer grams to existing account; set false to create new account. + /// @param allBalance Set true if need to transfer all remaining balance. + /// @param payload Tree of cells used as body of outbound internal message. + /// @return transId Transaction ID. + function submitTransaction( + address payable dest, + uint128 value, + bool bounce, + bool allBalance, + TvmCell payload) + public returns (uint64 transId) + { + uint256 senderKey = msg.pubkey(); + uint8 index = _findCustodian(senderKey); + require(value >= MIN_VALUE, 107); + (uint bits, uint cells) = tvm_tree_cell_size(tvm_ctos(payload)); + require(bits < 8192 && cells < 8, 121); + _removeExpiredTransactions(); + require(_getMaskValue(m_requestsMask, index) < MAX_QUEUED_REQUESTS, 113); + tvm.accept(); + + (uint8 flags, uint128 realValue) = _getSendFlags(value, allBalance); + uint8 requiredSigns = m_defaultRequiredConfirmations; + + if (requiredSigns == 1) { + dest.transfer(realValue, bounce, flags, payload); + return 0; + } else { + m_requestsMask = _incMaskValue(m_requestsMask, index); + uint64 trId = _generateId(); + Transaction txn = Transaction(trId, 0/*mask*/, requiredSigns, 0/*signsReceived*/, + senderKey, index, dest, realValue, flags, payload, bounce); + + _confirmTransaction(trId, txn, index); + return trId; + } + } + + /// @dev Allows custodian to confirm a transaction. + /// @param transactionId Transaction ID. + function confirmTransaction(uint64 transactionId) public { + uint8 index = _findCustodian(msg.pubkey()); + _removeExpiredTransactions(); + (bool trexists, Transaction txn) = m_transactions.fetch(transactionId); + require(trexists, 102); + require(!_isConfirmed(txn.confirmationsMask, index), 103); + tvm.accept(); + + _confirmTransaction(transactionId, txn, index); + } + + /* + * Internal functions + */ + + /// @dev Confirms transaction by custodian with defined index. + /// @param transactionId Transaction id to confirm. + /// @param txn Transaction object to confirm. + /// @param custodianIndex Index of custodian. + function _confirmTransaction(uint64 transactionId, Transaction txn, uint8 custodianIndex) inline private { + if ((txn.signsReceived + 1) >= txn.signsRequired) { + txn.dest.transfer(txn.value, txn.bounce, txn.sendFlags, txn.payload); + m_requestsMask = _decMaskValue(m_requestsMask, txn.index); + delete m_transactions[transactionId]; + } else { + txn.confirmationsMask = _setConfirmed(txn.confirmationsMask, custodianIndex); + txn.signsReceived++; + m_transactions[transactionId] = txn; + } + } + + /// @dev Removes expired transactions from storage. + function _removeExpiredTransactions() inline private { + uint64 marker = _getExpirationBound(); + (uint64 trId, Transaction txn, bool success) = m_transactions.min(); + + bool needCleanup = success && (trId <= marker); + if (!needCleanup) { return; } + + tvm.accept(); + uint i = 0; + while (needCleanup && i < MAX_CLEANUP_TXNS) { + // transaction is expired, remove it + i++; + m_requestsMask = _decMaskValue(m_requestsMask, txn.index); + delete m_transactions[trId]; + + (trId, txn, success) = m_transactions.next(trId); + needCleanup = success && (trId <= marker); + } + tvm.commit(); + } + + /* + * Get methods + */ + + /// @dev Helper get-method for checking if custodian confirmation bit is set. + /// @return confirmed True if confirmation bit is set. + function isConfirmed(uint32 mask, uint8 index) public pure returns (bool confirmed) { + confirmed = _isConfirmed(mask, index); + } + + /// @dev Get-method that returns wallet configuration parameters. + /// @return maxQueuedTransactions The maximum number of unconfirmed transactions that a custodian can submit. + /// @return maxCustodianCount The maximum allowed number of wallet custodians. + /// @return expirationTime Transaction lifetime in seconds. + /// @return minValue The minimum value allowed to transfer in one transaction. + /// @return requiredTxnConfirms The minimum number of confirmations required to execute transaction. + function getParameters() public view + returns (uint8 maxQueuedTransactions, + uint8 maxCustodianCount, + uint64 expirationTime, + uint128 minValue, + uint8 requiredTxnConfirms) { + + maxQueuedTransactions = MAX_QUEUED_REQUESTS; + maxCustodianCount = MAX_CUSTODIAN_COUNT; + expirationTime = EXPIRATION_TIME; + minValue = MIN_VALUE; + requiredTxnConfirms = m_defaultRequiredConfirmations; + } + + /// @dev Get-method that returns transaction info by id. + /// @return trans Transaction structure. + /// Throws exception if transaction does not exist. + function getTransaction(uint64 transactionId) public view + returns (Transaction trans) { + (bool exists, Transaction txn) = m_transactions.fetch(transactionId); + require(exists, 102); + trans = txn; + } + + /// @dev Get-method that returns array of pending transactions. + /// Returns not expired transactions only. + /// @return transactions Array of queued transactions. + function getTransactions() public view returns (Transaction[] transactions) { + uint64 bound = _getExpirationBound(); + (uint64 id, Transaction txn, bool success) = m_transactions.min(); + while (success) { + // returns only not expired transactions + if (id > bound) { + transactions.push(txn); + } + (id, txn, success) = m_transactions.next(id); + } + } + + /// @dev Get-method that returns submitted transaction ids. + /// @return ids Array of transaction ids. + function getTransactionIds() public view returns (uint64[] ids) { + uint64 trId = 0; + bool success = false; + (trId, , success) = m_transactions.min(); + while (success) { + ids.push(trId); + (trId, , success) = m_transactions.next(trId); + } + } + + /// @dev Helper structure to return information about custodian. + /// Used in getCustodians(). + struct CustodianInfo { + uint8 index; + uint256 pubkey; + } + + /// @dev Get-method that returns info about wallet custodians. + /// @return custodians Array of custodians. + function getCustodians() public view returns (CustodianInfo[] custodians) { + (uint256 key, uint8 index, bool success) = m_custodians.min(); + while (success) { + custodians.push(CustodianInfo(index, key)); + (key, index, success) = m_custodians.next(key); + } + } + + /* + * Fallback and receive functions to receive simple transfers. + */ + + fallback () external payable {} + + receive () external payable {} +} \ No newline at end of file diff --git a/demo/TIP4_2/safemultisig/SafeMultisigWallet.tvc b/demo/TIP4_2/safemultisig/SafeMultisigWallet.tvc new file mode 100644 index 0000000..7584907 Binary files /dev/null and b/demo/TIP4_2/safemultisig/SafeMultisigWallet.tvc differ diff --git a/demo/TIP4_2/scripts/2-mint-nft.js b/demo/TIP4_2/scripts/2-mint-nft.js new file mode 100644 index 0000000..f61098e --- /dev/null +++ b/demo/TIP4_2/scripts/2-mint-nft.js @@ -0,0 +1,73 @@ +const { + isValidTonAddress +} = require('./utils'); +const prompts = require('prompts'); + +async function main() { + + const Collection = await locklift.factory.getContract('Collection'); + const [keyPair] = await locklift.keys.getKeyPairs(); + + const promptsData = []; + + promptsData.push({ + type: 'text', + name: 'collection', + message: 'Collection address', + validate: value => isValidTonAddress(value) ? true : 'Invalid TON address' + }); + + promptsData.push({ + type: 'text', + name: 'owner', + message: 'Owner address', + validate: value => isValidTonAddress(value) ? true : 'Invalid TON address' + }); + + promptsData.push({ + type: 'text', + name: 'json', + message: 'JSON', + validate: value => !!value + }) + + const response = await prompts(promptsData); + + const collectionOwner = await locklift.factory.getAccount('SafeMultisigWallet', 'safemultisig'); + collectionOwner.setAddress(response.owner); + + const collection = Collection; + collection.setAddress(response.collection); + + await collectionOwner.runTarget({ + contract: collection, + method: 'mintNft', + params: { + json: response.json, + }, + value: locklift.utils.convertCrystal(3, 'nano'), + keyPair + }); + + const totalSupply = await collection.call({ + method: 'totalSupply', + params: {}, + }); + + const nftAddr = await collection.call({ + method: 'nftAddress', + params: { + id: totalSupply - 1 + }, + }); + + console.log("Nft was successfully minted!"); + console.log("Address: " + nftAddr); +} + +main() + .then(() => process.exit(0)) + .catch(e => { + console.log(e); + process.exit(1); + }); diff --git a/demo/TIP4_2/scripts/utils.js b/demo/TIP4_2/scripts/utils.js new file mode 100644 index 0000000..d0e9922 --- /dev/null +++ b/demo/TIP4_2/scripts/utils.js @@ -0,0 +1,8 @@ +const isValidTonAddress = (address) => /^(?:-1|0):[0-9a-fA-F]{64}$/.test(address); + +const isNumeric = (value) => /^-?\d+$/.test(value); + +module.exports = { + isValidTonAddress, + isNumeric +} \ No newline at end of file diff --git a/demo/TIP4_3/locklift.config.js b/demo/TIP4_3/locklift.config.js deleted file mode 100644 index 3fb5ecd..0000000 --- a/demo/TIP4_3/locklift.config.js +++ /dev/null @@ -1,56 +0,0 @@ -module.exports = { - compiler: { - // Specify path to your TON-Solidity-Compiler - path: '$HOME/.everdev/solidity/solc', - }, - linker: { - // Path to your TVM Linker - path: '$HOME/.everdev/solidity/tvm_linker', - lib: '$HOME/.everdev/solidity/stdlib_sol.tvm', - }, - networks: { - // You can use TON labs graphql endpoints or local node - local: { - ton_client: { - // See the TON client specification for all available options - network: { - server_address: 'http://localhost', - }, - }, - // This giver is default local-node giver - giver: { - address: '0:841288ed3b55d9cdafa806807f02a0ae0c169aa5edfe88a789a6482429756a94', - abi: { "ABI version": 1, "functions": [ { "name": "constructor", "inputs": [], "outputs": [] }, { "name": "sendGrams", "inputs": [ {"name":"dest","type":"address"}, {"name":"amount","type":"uint64"} ], "outputs": [] } ], "events": [], "data": [] }, - key: '', - }, - // Use tonos-cli to generate your phrase - // $ tonos-cli genphrase - // !!! Never commit it in your repos !!! - keys: { - phrase: '', - amount: 20, - } - }, - devnet: { - ton_client: { - // See the TON client specification for all available options - network: { - server_address: 'http://net1.ton.dev', - }, - }, - // This giver is default local-node giver - giver: { - address: '0:f7597aecd0ecd2a78f220469f73a18585ad10a3f00391eeee337514a8f0b351e', - abi: {"ABI version":2,"version":"2.2","header":["pubkey","time","expire"],"functions":[{"name":"constructor","inputs":[{"name":"_owner","type":"uint256"}],"outputs":[]},{"name":"sendGrams","inputs":[{"name":"dest","type":"address"},{"name":"amount","type":"uint64"}],"outputs":[]},{"name":"transferOwnership","inputs":[{"name":"newOwner","type":"uint256"}],"outputs":[]},{"name":"owner","inputs":[],"outputs":[{"name":"owner","type":"uint256"}]},{"name":"_randomNonce","inputs":[],"outputs":[{"name":"_randomNonce","type":"uint256"}]}],"data":[{"key":1,"name":"_randomNonce","type":"uint256"}],"events":[{"name":"OwnershipTransferred","inputs":[{"name":"previousOwner","type":"uint256"},{"name":"newOwner","type":"uint256"}],"outputs":[]}],"fields":[{"name":"_pubkey","type":"uint256"},{"name":"_timestamp","type":"uint64"},{"name":"_constructorFlag","type":"bool"},{"name":"owner","type":"uint256"},{"name":"_randomNonce","type":"uint256"}]}, - key: '327caeff7c4727d76d3b2a82410e12c699c174796a5c7dd024ca5bed865c980c', - }, - // Use tonos-cli to generate your phrase - // $ tonos-cli genphrase - // !!! Never commit it in your repos !!! - keys: { - phrase: '', - amount: 20, - } - }, - } -}; diff --git a/demo/TIP4_2/locklift.config.js b/demo/TIP4_3/locklift.config.template.js similarity index 100% rename from demo/TIP4_2/locklift.config.js rename to demo/TIP4_3/locklift.config.template.js diff --git a/demo/TIP4_3/package-lock.json b/demo/TIP4_3/package-lock.json index 2a19bb1..d2ea0ac 100644 --- a/demo/TIP4_3/package-lock.json +++ b/demo/TIP4_3/package-lock.json @@ -1393,6 +1393,11 @@ "json-buffer": "3.0.1" } }, + "kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==" + }, "locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -1700,6 +1705,15 @@ "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==" }, + "prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "requires": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + } + }, "pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", @@ -1844,6 +1858,11 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, + "sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" + }, "slice-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", diff --git a/demo/TIP4_3/package.json b/demo/TIP4_3/package.json index 2c8bd85..e062a9b 100644 --- a/demo/TIP4_3/package.json +++ b/demo/TIP4_3/package.json @@ -4,12 +4,14 @@ "description": "TIP4_3 demo", "scripts": { "build": "locklift build --config locklift.config.js", - "deploy": "locklift run --config locklift.config.js --network devnet --script scripts/1-deploy-collection.js" + "deploy": "locklift run --config locklift.config.js --network local --script scripts/1-deploy-collection.js", + "mint": "locklift run --config locklift.config.js --network local --script scripts/2-mint-nft.js" }, "author": "itgold.io", "license": "MIT", "dependencies": { "@itgold/everscale-tip": "^1.1.3", - "locklift": "git+https://github.com/broxus/ton-locklift.git" + "locklift": "git+https://github.com/broxus/ton-locklift.git", + "prompts": "^2.4.2" } -} \ No newline at end of file +} diff --git a/demo/TIP4_3/safemultisig/SafeMultisigWallet.abi.json b/demo/TIP4_3/safemultisig/SafeMultisigWallet.abi.json new file mode 100644 index 0000000..bd0d131 --- /dev/null +++ b/demo/TIP4_3/safemultisig/SafeMultisigWallet.abi.json @@ -0,0 +1,123 @@ +{ + "ABI version": 2, + "header": ["pubkey", "time", "expire"], + "functions": [ + { + "name": "constructor", + "inputs": [ + {"name":"owners","type":"uint256[]"}, + {"name":"reqConfirms","type":"uint8"} + ], + "outputs": [ + ] + }, + { + "name": "acceptTransfer", + "inputs": [ + {"name":"payload","type":"bytes"} + ], + "outputs": [ + ] + }, + { + "name": "sendTransaction", + "inputs": [ + {"name":"dest","type":"address"}, + {"name":"value","type":"uint128"}, + {"name":"bounce","type":"bool"}, + {"name":"flags","type":"uint8"}, + {"name":"payload","type":"cell"} + ], + "outputs": [ + ] + }, + { + "name": "submitTransaction", + "inputs": [ + {"name":"dest","type":"address"}, + {"name":"value","type":"uint128"}, + {"name":"bounce","type":"bool"}, + {"name":"allBalance","type":"bool"}, + {"name":"payload","type":"cell"} + ], + "outputs": [ + {"name":"transId","type":"uint64"} + ] + }, + { + "name": "confirmTransaction", + "inputs": [ + {"name":"transactionId","type":"uint64"} + ], + "outputs": [ + ] + }, + { + "name": "isConfirmed", + "inputs": [ + {"name":"mask","type":"uint32"}, + {"name":"index","type":"uint8"} + ], + "outputs": [ + {"name":"confirmed","type":"bool"} + ] + }, + { + "name": "getParameters", + "inputs": [ + ], + "outputs": [ + {"name":"maxQueuedTransactions","type":"uint8"}, + {"name":"maxCustodianCount","type":"uint8"}, + {"name":"expirationTime","type":"uint64"}, + {"name":"minValue","type":"uint128"}, + {"name":"requiredTxnConfirms","type":"uint8"} + ] + }, + { + "name": "getTransaction", + "inputs": [ + {"name":"transactionId","type":"uint64"} + ], + "outputs": [ + {"components":[{"name":"id","type":"uint64"},{"name":"confirmationsMask","type":"uint32"},{"name":"signsRequired","type":"uint8"},{"name":"signsReceived","type":"uint8"},{"name":"creator","type":"uint256"},{"name":"index","type":"uint8"},{"name":"dest","type":"address"},{"name":"value","type":"uint128"},{"name":"sendFlags","type":"uint16"},{"name":"payload","type":"cell"},{"name":"bounce","type":"bool"}],"name":"trans","type":"tuple"} + ] + }, + { + "name": "getTransactions", + "inputs": [ + ], + "outputs": [ + {"components":[{"name":"id","type":"uint64"},{"name":"confirmationsMask","type":"uint32"},{"name":"signsRequired","type":"uint8"},{"name":"signsReceived","type":"uint8"},{"name":"creator","type":"uint256"},{"name":"index","type":"uint8"},{"name":"dest","type":"address"},{"name":"value","type":"uint128"},{"name":"sendFlags","type":"uint16"},{"name":"payload","type":"cell"},{"name":"bounce","type":"bool"}],"name":"transactions","type":"tuple[]"} + ] + }, + { + "name": "getTransactionIds", + "inputs": [ + ], + "outputs": [ + {"name":"ids","type":"uint64[]"} + ] + }, + { + "name": "getCustodians", + "inputs": [ + ], + "outputs": [ + {"components":[{"name":"index","type":"uint8"},{"name":"pubkey","type":"uint256"}],"name":"custodians","type":"tuple[]"} + ] + } + ], + "data": [ + ], + "events": [ + { + "name": "TransferAccepted", + "inputs": [ + {"name":"payload","type":"bytes"} + ], + "outputs": [ + ] + } + ] +} diff --git a/demo/TIP4_3/safemultisig/SafeMultisigWallet.base64 b/demo/TIP4_3/safemultisig/SafeMultisigWallet.base64 new file mode 100644 index 0000000..f4e9ac0 --- /dev/null +++ b/demo/TIP4_3/safemultisig/SafeMultisigWallet.base64 @@ -0,0 +1 @@ +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 diff --git a/demo/TIP4_3/safemultisig/SafeMultisigWallet.sol b/demo/TIP4_3/safemultisig/SafeMultisigWallet.sol new file mode 100644 index 0000000..dd5871a --- /dev/null +++ b/demo/TIP4_3/safemultisig/SafeMultisigWallet.sol @@ -0,0 +1,412 @@ +pragma solidity >=0.6.0; +pragma experimental ABIEncoderV2; +pragma ignoreIntOverflow; +pragma AbiHeader expire; +pragma AbiHeader pubkey; +pragma AbiHeader time; + +interface IAccept { + function acceptTransfer(bytes payload) external payable; +} + +/// @title Multisignature wallet +/// @author Tonlabs (https://tonlabs.io) +contract MultisigWallet is IAccept { + + /* + * Storage + */ + + struct Transaction { + // Transaction Id. + uint64 id; + // Transaction confirmations from custodians. + uint32 confirmationsMask; + // Number of required confirmations. + uint8 signsRequired; + // Number of confirmations already received. + uint8 signsReceived; + // Public key of custodian queued transaction. + uint256 creator; + // Index of custodian. + uint8 index; + // Destination address of gram transfer. + address payable dest; + // Amount of nanograms to transfer. + uint128 value; + // Flags for sending internal message (see SENDRAWMSG in TVM spec). + uint16 sendFlags; + // Payload used as body of outbound internal message. + TvmCell payload; + // Bounce flag for header of outbound internal message. + bool bounce; + } + + /* + * Constants + */ + uint8 constant MAX_QUEUED_REQUESTS = 5; + uint64 constant EXPIRATION_TIME = 3600; // lifetime is 1 hour + uint8 constant MAX_CUSTODIAN_COUNT = 32; + uint128 constant MIN_VALUE = 1e6; + uint constant MAX_CLEANUP_TXNS = 40; + + // Send flags. + // Forward fees for message will be paid from contract balance. + uint8 constant FLAG_PAY_FWD_FEE_FROM_BALANCE = 1; + // Tells node to ignore errors in action phase while outbound messages are sent. + uint8 constant FLAG_IGNORE_ERRORS = 2; + // Tells node to send all remaining balance. + uint8 constant FLAG_SEND_ALL_REMAINING = 128; + + /* + * Variables + */ + + // Public key of custodian who deployed a contract. + uint256 m_ownerKey; + // Binary mask with custodian requests (max 32 custodians). + uint256 m_requestsMask; + // Dictionary of queued transactions waiting confirmations. + mapping(uint64 => Transaction) m_transactions; + // Set of custodians, initiated in constructor, but values can be changed later in code. + mapping(uint256 => uint8) m_custodians; // pub_key -> custodian_index + // Read-only custodian count, initiated in constructor. + uint8 m_custodianCount; + // Default number of confirmations needed to execute transaction. + uint8 m_defaultRequiredConfirmations; + + /* + Exception codes: + 100 - message sender is not a custodian; + 102 - transaction does not exist; + 103 - operation is already confirmed by this custodian; + 107 - input value is too low; + 108 - wallet should have only one custodian; + 113 - Too many requests for one custodian; + 117 - invalid number of custodians; + 121 - payload size is too big; + */ + + /* + * Events + */ + event TransferAccepted(bytes payload); + + /* + * Runtime functions + */ + function tvm_ctos(TvmCell cell) private pure returns (uint /* slice */) {} + function tvm_tree_cell_size(uint slice) private pure returns (uint, uint) {} + + /* + * Constructor + */ + + /// @dev Internal function called from constructor to initialize custodians. + function _initialize(uint256[] owners, uint8 reqConfirms) inline private { + uint8 ownerCount = 0; + m_ownerKey = owners[0]; + + uint256 len = owners.length; + for (uint256 i = 0; (i < len && ownerCount < MAX_CUSTODIAN_COUNT); i++) { + uint256 key = owners[i]; + if (!m_custodians.exists(key)) { + m_custodians[key] = ownerCount++; + } + } + m_defaultRequiredConfirmations = ownerCount <= reqConfirms ? ownerCount : reqConfirms; + m_custodianCount = ownerCount; + } + + /// @dev Contract constructor. + /// @param owners Array of custodian keys. + /// @param reqConfirms Default number of confirmations required for executing transaction. + constructor(uint256[] owners, uint8 reqConfirms) public { + require(msg.pubkey() == tvm.pubkey(), 100); + require(owners.length > 0 && owners.length <= MAX_CUSTODIAN_COUNT, 117); + tvm.accept(); + _initialize(owners, reqConfirms); + } + + /* + * Inline helper macros + */ + + /// @dev Returns queued transaction count by custodian with defined index. + function _getMaskValue(uint256 mask, uint8 index) inline private pure returns (uint8) { + return uint8((mask >> (8 * uint256(index))) & 0xFF); + } + + /// @dev Increment queued transaction count by custodian with defined index. + function _incMaskValue(uint256 mask, uint8 index) inline private pure returns (uint256) { + return mask + (1 << (8 * uint256(index))); + } + + /// @dev Decrement queued transaction count by custodian with defined index. + function _decMaskValue(uint256 mask, uint8 index) inline private pure returns (uint256) { + return mask - (1 << (8 * uint256(index))); + } + + /// @dev Checks bit with defined index in the mask. + function _checkBit(uint32 mask, uint8 index) inline private pure returns (bool) { + return (mask & (uint32(1) << index)) != 0; + } + + /// @dev Checks if object is confirmed by custodian. + function _isConfirmed(uint32 mask, uint8 custodianIndex) inline private pure returns (bool) { + return _checkBit(mask, custodianIndex); + } + + /// @dev Sets custodian confirmation bit in the mask. + function _setConfirmed(uint32 mask, uint8 custodianIndex) inline private pure returns (uint32) { + mask |= (uint32(1) << custodianIndex); + return mask; + } + + /// @dev Checks that custodian with supplied public key exists in custodian set. + function _findCustodian(uint256 senderKey) inline private view returns (uint8) { + (bool exists, uint8 index) = m_custodians.fetch(senderKey); + require(exists, 100); + return index; + } + + /// @dev Generates new id for object. + function _generateId() inline private view returns (uint64) { + return (uint64(now) << 32) | (tvm.transLT() & 0xFFFFFFFF); + } + + /// @dev Returns timestamp after which transactions are treated as expired. + function _getExpirationBound() inline private view returns (uint64) { + return (uint64(now) - EXPIRATION_TIME) << 32; + } + + /// @dev Returns transfer flags according to input value and `allBalance` flag. + function _getSendFlags(uint128 value, bool allBalance) inline private pure returns (uint8, uint128) { + uint8 flags = FLAG_IGNORE_ERRORS | FLAG_PAY_FWD_FEE_FROM_BALANCE; + if (allBalance) { + flags = FLAG_IGNORE_ERRORS | FLAG_SEND_ALL_REMAINING; + value = uint128(address(this).balance); + } + return (flags, value); + } + + /* + * Public functions + */ + + /// @dev A payable method for accepting incoming funds. Generates + /// an event with incoming payload. + /// @param payload Payload from message body. + function acceptTransfer(bytes payload) external override payable { + emit TransferAccepted(payload); + } + + /// @dev Allows custodian if she is the only owner of multisig to transfer funds with minimal fees. + /// @param dest Transfer target address. + /// @param value Amount of funds to transfer. + /// @param bounce Bounce flag. Set true if need to transfer funds to existing account; + /// set false to create new account. + /// @param flags `sendmsg` flags. + /// @param payload Tree of cells used as body of outbound internal message. + function sendTransaction( + address payable dest, + uint128 value, + bool bounce, + uint8 flags, + TvmCell payload) public view + { + require(m_custodianCount == 1, 108); + require(msg.pubkey() == m_ownerKey, 100); + tvm.accept(); + dest.transfer(value, bounce, flags, payload); + } + + /// @dev Allows custodian to submit and confirm new transaction. + /// @param dest Transfer target address. + /// @param value Nanograms value to transfer. + /// @param bounce Bounce flag. Set true if need to transfer grams to existing account; set false to create new account. + /// @param allBalance Set true if need to transfer all remaining balance. + /// @param payload Tree of cells used as body of outbound internal message. + /// @return transId Transaction ID. + function submitTransaction( + address payable dest, + uint128 value, + bool bounce, + bool allBalance, + TvmCell payload) + public returns (uint64 transId) + { + uint256 senderKey = msg.pubkey(); + uint8 index = _findCustodian(senderKey); + require(value >= MIN_VALUE, 107); + (uint bits, uint cells) = tvm_tree_cell_size(tvm_ctos(payload)); + require(bits < 8192 && cells < 8, 121); + _removeExpiredTransactions(); + require(_getMaskValue(m_requestsMask, index) < MAX_QUEUED_REQUESTS, 113); + tvm.accept(); + + (uint8 flags, uint128 realValue) = _getSendFlags(value, allBalance); + uint8 requiredSigns = m_defaultRequiredConfirmations; + + if (requiredSigns == 1) { + dest.transfer(realValue, bounce, flags, payload); + return 0; + } else { + m_requestsMask = _incMaskValue(m_requestsMask, index); + uint64 trId = _generateId(); + Transaction txn = Transaction(trId, 0/*mask*/, requiredSigns, 0/*signsReceived*/, + senderKey, index, dest, realValue, flags, payload, bounce); + + _confirmTransaction(trId, txn, index); + return trId; + } + } + + /// @dev Allows custodian to confirm a transaction. + /// @param transactionId Transaction ID. + function confirmTransaction(uint64 transactionId) public { + uint8 index = _findCustodian(msg.pubkey()); + _removeExpiredTransactions(); + (bool trexists, Transaction txn) = m_transactions.fetch(transactionId); + require(trexists, 102); + require(!_isConfirmed(txn.confirmationsMask, index), 103); + tvm.accept(); + + _confirmTransaction(transactionId, txn, index); + } + + /* + * Internal functions + */ + + /// @dev Confirms transaction by custodian with defined index. + /// @param transactionId Transaction id to confirm. + /// @param txn Transaction object to confirm. + /// @param custodianIndex Index of custodian. + function _confirmTransaction(uint64 transactionId, Transaction txn, uint8 custodianIndex) inline private { + if ((txn.signsReceived + 1) >= txn.signsRequired) { + txn.dest.transfer(txn.value, txn.bounce, txn.sendFlags, txn.payload); + m_requestsMask = _decMaskValue(m_requestsMask, txn.index); + delete m_transactions[transactionId]; + } else { + txn.confirmationsMask = _setConfirmed(txn.confirmationsMask, custodianIndex); + txn.signsReceived++; + m_transactions[transactionId] = txn; + } + } + + /// @dev Removes expired transactions from storage. + function _removeExpiredTransactions() inline private { + uint64 marker = _getExpirationBound(); + (uint64 trId, Transaction txn, bool success) = m_transactions.min(); + + bool needCleanup = success && (trId <= marker); + if (!needCleanup) { return; } + + tvm.accept(); + uint i = 0; + while (needCleanup && i < MAX_CLEANUP_TXNS) { + // transaction is expired, remove it + i++; + m_requestsMask = _decMaskValue(m_requestsMask, txn.index); + delete m_transactions[trId]; + + (trId, txn, success) = m_transactions.next(trId); + needCleanup = success && (trId <= marker); + } + tvm.commit(); + } + + /* + * Get methods + */ + + /// @dev Helper get-method for checking if custodian confirmation bit is set. + /// @return confirmed True if confirmation bit is set. + function isConfirmed(uint32 mask, uint8 index) public pure returns (bool confirmed) { + confirmed = _isConfirmed(mask, index); + } + + /// @dev Get-method that returns wallet configuration parameters. + /// @return maxQueuedTransactions The maximum number of unconfirmed transactions that a custodian can submit. + /// @return maxCustodianCount The maximum allowed number of wallet custodians. + /// @return expirationTime Transaction lifetime in seconds. + /// @return minValue The minimum value allowed to transfer in one transaction. + /// @return requiredTxnConfirms The minimum number of confirmations required to execute transaction. + function getParameters() public view + returns (uint8 maxQueuedTransactions, + uint8 maxCustodianCount, + uint64 expirationTime, + uint128 minValue, + uint8 requiredTxnConfirms) { + + maxQueuedTransactions = MAX_QUEUED_REQUESTS; + maxCustodianCount = MAX_CUSTODIAN_COUNT; + expirationTime = EXPIRATION_TIME; + minValue = MIN_VALUE; + requiredTxnConfirms = m_defaultRequiredConfirmations; + } + + /// @dev Get-method that returns transaction info by id. + /// @return trans Transaction structure. + /// Throws exception if transaction does not exist. + function getTransaction(uint64 transactionId) public view + returns (Transaction trans) { + (bool exists, Transaction txn) = m_transactions.fetch(transactionId); + require(exists, 102); + trans = txn; + } + + /// @dev Get-method that returns array of pending transactions. + /// Returns not expired transactions only. + /// @return transactions Array of queued transactions. + function getTransactions() public view returns (Transaction[] transactions) { + uint64 bound = _getExpirationBound(); + (uint64 id, Transaction txn, bool success) = m_transactions.min(); + while (success) { + // returns only not expired transactions + if (id > bound) { + transactions.push(txn); + } + (id, txn, success) = m_transactions.next(id); + } + } + + /// @dev Get-method that returns submitted transaction ids. + /// @return ids Array of transaction ids. + function getTransactionIds() public view returns (uint64[] ids) { + uint64 trId = 0; + bool success = false; + (trId, , success) = m_transactions.min(); + while (success) { + ids.push(trId); + (trId, , success) = m_transactions.next(trId); + } + } + + /// @dev Helper structure to return information about custodian. + /// Used in getCustodians(). + struct CustodianInfo { + uint8 index; + uint256 pubkey; + } + + /// @dev Get-method that returns info about wallet custodians. + /// @return custodians Array of custodians. + function getCustodians() public view returns (CustodianInfo[] custodians) { + (uint256 key, uint8 index, bool success) = m_custodians.min(); + while (success) { + custodians.push(CustodianInfo(index, key)); + (key, index, success) = m_custodians.next(key); + } + } + + /* + * Fallback and receive functions to receive simple transfers. + */ + + fallback () external payable {} + + receive () external payable {} +} \ No newline at end of file diff --git a/demo/TIP4_3/safemultisig/SafeMultisigWallet.tvc b/demo/TIP4_3/safemultisig/SafeMultisigWallet.tvc new file mode 100644 index 0000000..7584907 Binary files /dev/null and b/demo/TIP4_3/safemultisig/SafeMultisigWallet.tvc differ diff --git a/demo/TIP4_3/scripts/2-mint-nft.js b/demo/TIP4_3/scripts/2-mint-nft.js new file mode 100644 index 0000000..de41014 --- /dev/null +++ b/demo/TIP4_3/scripts/2-mint-nft.js @@ -0,0 +1,64 @@ +const { + isValidTonAddress +} = require('./utils'); +const prompts = require('prompts'); + +async function main() { + + const Collection = await locklift.factory.getContract('Collection'); + const [keyPair] = await locklift.keys.getKeyPairs(); + + const promptsData = []; + + promptsData.push({ + type: 'text', + name: 'collection', + message: 'Collection address', + validate: value => isValidTonAddress(value) ? true : 'Invalid TON address' + }); + + promptsData.push({ + type: 'text', + name: 'owner', + message: 'Owner address', + validate: value => isValidTonAddress(value) ? true : 'Invalid TON address' + }); + + const response = await prompts(promptsData); + + const collectionOwner = await locklift.factory.getAccount('SafeMultisigWallet', 'safemultisig'); + collectionOwner.setAddress(response.owner); + + const collection = Collection; + collection.setAddress(response.collection); + + await collectionOwner.runTarget({ + contract: collection, + method: 'mintNft', + params: {}, + value: locklift.utils.convertCrystal(3, 'nano'), + keyPair + }); + + const totalSupply = await collection.call({ + method: 'totalSupply', + params: {}, + }); + + const nftAddr = await collection.call({ + method: 'nftAddress', + params: { + id: totalSupply - 1 + }, + }); + + console.log("Nft was successfully minted!"); + console.log("Address: " + nftAddr); +} + +main() + .then(() => process.exit(0)) + .catch(e => { + console.log(e); + process.exit(1); + }); diff --git a/demo/TIP4_3/scripts/utils.js b/demo/TIP4_3/scripts/utils.js new file mode 100644 index 0000000..d0e9922 --- /dev/null +++ b/demo/TIP4_3/scripts/utils.js @@ -0,0 +1,8 @@ +const isValidTonAddress = (address) => /^(?:-1|0):[0-9a-fA-F]{64}$/.test(address); + +const isNumeric = (value) => /^-?\d+$/.test(value); + +module.exports = { + isValidTonAddress, + isNumeric +} \ No newline at end of file