public NativeExecutionContext(SmartContract contract)
 {
     this.Contract = contract;
 }
Example #2
0
        public void ApplyInflation(Address from)
        {
            Runtime.Expect(_inflationReady, "inflation not ready");

            Runtime.Expect(Runtime.IsRootChain(), "only on root chain");

            var currentSupply = Runtime.GetTokenSupply(DomainSettings.StakingTokenSymbol);

            var minExpectedSupply = UnitConversion.ToBigInteger(100000000, DomainSettings.StakingTokenDecimals);

            if (currentSupply < minExpectedSupply)
            {
                currentSupply = minExpectedSupply;
            }

            // NOTE this gives an approximate inflation of 3% per year (0.75% per season)
            var        inflationAmount = currentSupply / 133;
            BigInteger mintedAmount    = 0;

            Runtime.Expect(inflationAmount > 0, "invalid inflation amount");

            var masterOrg = Runtime.GetOrganization(DomainSettings.MastersOrganizationName);
            var masters   = masterOrg.GetMembers();

            var rewardList = new List <Address>();

            foreach (var addr in masters)
            {
                var masterDate = Runtime.CallNativeContext(NativeContractKind.Stake, nameof(StakeContract.GetMasterDate), addr).AsTimestamp();

                if (masterDate <= _lastInflationDate)
                {
                    rewardList.Add(addr);
                }
            }

            if (rewardList.Count > 0)
            {
                var rewardAmount = inflationAmount / 10;

                var rewardStake = rewardAmount / rewardList.Count;
                rewardAmount = rewardList.Count * rewardStake; // eliminate leftovers

                var rewardFuel = _rewardAccum / rewardList.Count;

                BigInteger stakeAmount;

                if (Runtime.ProtocolVersion > 5)
                {
                    stakeAmount = UnitConversion.ToBigInteger(2, DomainSettings.StakingTokenDecimals);
                }
                else
                {
                    stakeAmount = UnitConversion.ToBigInteger(1, DomainSettings.StakingTokenDecimals);
                }

                Runtime.MintTokens(DomainSettings.StakingTokenSymbol, this.Address, this.Address, rewardAmount);

                var crownAddress = TokenUtils.GetContractAddress(DomainSettings.RewardTokenSymbol);
                Runtime.MintTokens(DomainSettings.StakingTokenSymbol, this.Address, crownAddress, stakeAmount);
                Runtime.CallNativeContext(NativeContractKind.Stake, nameof(StakeContract.Stake), crownAddress, stakeAmount);

                foreach (var addr in rewardList)
                {
                    var reward  = new StakeReward(addr, Runtime.Time);
                    var rom     = Serialization.Serialize(reward);
                    var tokenID = Runtime.MintToken(DomainSettings.RewardTokenSymbol, this.Address, this.Address, rom, new byte[0], 0);
                    Runtime.InfuseToken(DomainSettings.RewardTokenSymbol, this.Address, tokenID, DomainSettings.FuelTokenSymbol, rewardFuel);
                    Runtime.InfuseToken(DomainSettings.RewardTokenSymbol, this.Address, tokenID, DomainSettings.StakingTokenSymbol, rewardStake);
                    Runtime.TransferToken(DomainSettings.RewardTokenSymbol, this.Address, addr, tokenID);
                }

                _rewardAccum -= rewardList.Count * rewardFuel;
                Runtime.Expect(_rewardAccum >= 0, "invalid reward leftover");

                inflationAmount -= rewardAmount;
                inflationAmount -= stakeAmount;
            }

            var refillAmount  = inflationAmount / 50;
            var cosmicAddress = SmartContract.GetAddressForNative(NativeContractKind.Swap);

            Runtime.MintTokens(DomainSettings.StakingTokenSymbol, this.Address, cosmicAddress, refillAmount);
            inflationAmount -= refillAmount;

            var phantomOrg = Runtime.GetOrganization(DomainSettings.PhantomForceOrganizationName);

            if (phantomOrg != null)
            {
                var phantomFunding = inflationAmount / 3;
                Runtime.MintTokens(DomainSettings.StakingTokenSymbol, this.Address, phantomOrg.Address, phantomFunding);
                inflationAmount -= phantomFunding;

                if (phantomOrg.Size == 1)
                {
                    Runtime.CallNativeContext(NativeContractKind.Stake, nameof(StakeContract.Stake), phantomOrg.Address, phantomFunding);
                }
            }

            var bpOrg = Runtime.GetOrganization(DomainSettings.ValidatorsOrganizationName);

            if (bpOrg != null)
            {
                Runtime.MintTokens(DomainSettings.StakingTokenSymbol, this.Address, bpOrg.Address, inflationAmount);

                if (bpOrg.Size == 1)
                {
                    Runtime.CallNativeContext(NativeContractKind.Stake, nameof(StakeContract.Stake), bpOrg.Address, inflationAmount);
                }
            }

            Runtime.Notify(EventKind.Inflation, from, new TokenEventData(DomainSettings.StakingTokenSymbol, mintedAmount, Runtime.Chain.Name));

            _lastInflationDate = Runtime.Time;
            _inflationReady    = false;
        }
        public void EditAuction(Address from, string baseSymbol, string quoteSymbol, BigInteger tokenID, BigInteger price, BigInteger endPrice, Timestamp startDate, Timestamp endDate, BigInteger extensionPeriod)
        {
            Runtime.Expect(Runtime.IsWitness(from), "invalid witness");

            Runtime.Expect(Runtime.TokenExists(quoteSymbol), "invalid quote token");
            var quoteToken = Runtime.GetToken(quoteSymbol);

            Runtime.Expect(quoteToken.Flags.HasFlag(TokenFlags.Fungible), "quote token must be fungible");

            var nft = Runtime.ReadToken(baseSymbol, tokenID);

            Runtime.Expect(nft.CurrentChain == Runtime.Chain.Name, "token not currently in this chain");
            var marketAddress = SmartContract.GetAddressForNative(NativeContractKind.Market);

            Runtime.Expect(nft.CurrentOwner == marketAddress, "invalid owner");

            var auctionID = baseSymbol + "." + tokenID;

            Runtime.Expect(_auctionMap.ContainsKey <string>(auctionID), "invalid auction");

            var auction = _auctionMap.Get <string, MarketAuction>(auctionID);

            Runtime.Expect(auction.Creator == from, "invalid auction creator");

            if (auction.Type != TypeAuction.Fixed) // prevent edit already started auctions
            {
                Runtime.Expect(auction.StartDate > Runtime.Time, "EditAuction can only be used before listing start");
            }

            if (price == 0)
            {
                price = auction.Price;
            }

            if (endPrice == 0)
            {
                endPrice = auction.EndPrice;
            }

            if (startDate == 0 || startDate == null)
            {
                startDate = auction.StartDate;
            }

            if (endDate == 0 || endDate == null)
            {
                endDate = auction.EndDate;
            }
            Runtime.Expect(endDate > startDate, "invalid end date");

            if (extensionPeriod == 0 || auction.Type == TypeAuction.Fixed)
            {
                extensionPeriod = auction.ExtensionPeriod;
            }

            if (auction.Type == TypeAuction.Classic || auction.Type == TypeAuction.Reserve)
            {
                Runtime.Expect(extensionPeriod <= oneHour, "extensionPeriod must be <= 1 hour");
            }

            var auctionNew = new MarketAuction(from, startDate, endDate, baseSymbol, quoteSymbol, tokenID, price, endPrice, extensionPeriod, auction.Type, auction.ListingFee, auction.ListingFeeAddress, auction.BuyingFee, auction.BuyingFeeAddress, auction.CurrentBidWinner);

            _auctionMap.Set(auctionID, auctionNew);

            Runtime.Notify(EventKind.OrderCancelled, auctionNew.Creator, new MarketEventData()
            {
                ID = auction.TokenID, BaseSymbol = auction.BaseSymbol, QuoteSymbol = auction.QuoteSymbol, Price = auction.Price, EndPrice = auction.EndPrice, Type = auction.Type
            });
            Runtime.Notify(EventKind.OrderCreated, auctionNew.Creator, new MarketEventData()
            {
                ID = auctionNew.TokenID, BaseSymbol = auctionNew.BaseSymbol, QuoteSymbol = auctionNew.QuoteSymbol, Price = auctionNew.Price, EndPrice = auctionNew.EndPrice, Type = auctionNew.Type
            });
        }
Example #4
0
        private void SpendGasV2(Address from)
        {
            var availableAmount = _allowanceMap.Get <Address, BigInteger>(from);

            var spentGas       = Runtime.UsedGas;
            var requiredAmount = spentGas * Runtime.GasPrice;

            Runtime.Expect(requiredAmount > 0, $"{Runtime.GasPrice} {spentGas} gas fee must exist");

            Runtime.Expect(availableAmount >= requiredAmount, "gas allowance is not enough");

            var leftoverAmount = availableAmount - requiredAmount;

            var        targetAddress = _allowanceTargets.Get <Address, Address>(from);
            BigInteger targetGas;

            Runtime.Notify(EventKind.GasPayment, from, new GasEventData(targetAddress, Runtime.GasPrice, spentGas));

            // return leftover escrowed gas to transaction creator
            if (leftoverAmount > 0)
            {
                Runtime.TransferTokens(DomainSettings.FuelTokenSymbol, this.Address, from, leftoverAmount);
            }

            Runtime.Expect(spentGas > 1, "gas spent too low");
            var burnGas = spentGas / 2;

            if (burnGas > 0)
            {
                BigInteger burnAmount;

                if (Runtime.ProtocolVersion >= 4)
                {
                    burnAmount = burnGas * Runtime.GasPrice;
                }
                else
                {
                    burnAmount = burnGas;
                }

                Runtime.BurnTokens(DomainSettings.FuelTokenSymbol, this.Address, burnAmount);
                spentGas -= burnGas;
            }

            targetGas = spentGas / 2; // 50% for dapps (or reward accum if dapp not specified)

            if (targetGas > 0)
            {
                var targetPayment = targetGas * Runtime.GasPrice;

                if (targetAddress == Runtime.Chain.Address)
                {
                    _rewardAccum += targetPayment;
                    Runtime.Notify(EventKind.CrownRewards, from, new TokenEventData(DomainSettings.FuelTokenSymbol, targetPayment, Runtime.Chain.Name));
                }
                else
                {
                    Runtime.TransferTokens(DomainSettings.FuelTokenSymbol, this.Address, targetAddress, targetPayment);
                }
                spentGas -= targetGas;
            }

            if (spentGas > 0)
            {
                var validatorPayment = spentGas * Runtime.GasPrice;
                var validatorAddress = SmartContract.GetAddressForNative(NativeContractKind.Block);
                Runtime.TransferTokens(DomainSettings.FuelTokenSymbol, this.Address, validatorAddress, validatorPayment);
                spentGas = 0;
            }

            _allowanceMap.Remove(from);
            _allowanceTargets.Remove(from);

            CheckInflation();
        }