예제 #1
0
        public IAccountStateDelta MinerReward(IActionContext ctx, IAccountStateDelta states)
        {
            // 마이닝 보상
            // https://www.notion.so/planetarium/Mining-Reward-b7024ef463c24ebca40a2623027d497d
            BigInteger defaultMiningReward = 10;
            var        countOfHalfLife     = Convert.ToInt64(ctx.BlockIndex / 12614400) + 1;
            var        miningReward        = defaultMiningReward / countOfHalfLife;

            return(states.TransferAsset(
                       GoldCurrencyState.Address,
                       ctx.Miner,
                       states.GetGoldCurrency() * miningReward
                       ));
        }
예제 #2
0
        public void ExecuteThrowNotEnoughFungibleAssetValueException()
        {
            var previousWeeklyArenaState = _initialState.GetWeeklyArenaState(_weeklyArenaAddress);
            var arenaInfo = previousWeeklyArenaState.GetArenaInfo(_avatar1Address);

            previousWeeklyArenaState.Update(new ArenaInfo(arenaInfo));

            var previousState = _initialState.SetState(
                _weeklyArenaAddress,
                previousWeeklyArenaState.Serialize());

            var goldCurrency           = new Currency("NCG", 2, Addresses.GoldCurrency);
            var previousAgentGoldState = _initialState.GetBalance(
                _agent1Address,
                goldCurrency);

            if (previousAgentGoldState.Sign > 0)
            {
                previousState = _initialState.TransferAsset(
                    _agent1Address,
                    Addresses.GoldCurrency,
                    previousAgentGoldState);
            }

            var action = new RankingBattle4
            {
                AvatarAddress      = _avatar1Address,
                EnemyAddress       = _avatar2Address,
                WeeklyArenaAddress = _weeklyArenaAddress,
                costumeIds         = new List <int>(),
                equipmentIds       = new List <Guid>(),
                consumableIds      = new List <Guid>(),
            };

            Assert.Throws <NotEnoughFungibleAssetValueException>(() =>
            {
                action.Execute(new ActionContext()
                {
                    PreviousStates = previousState,
                    Signer         = _agent1Address,
                    Random         = new TestRandom(),
                    Rehearsal      = false,
                });
            });
        }
        public override void TransferAsset()
        {
            base.TransferAsset();
            Assert.IsType <AccountStateDeltaImpl>(_init);

            IAccountStateDelta a = _init.TransferAsset(
                _addr[0],
                _addr[1],
                Value(0, 6),
                allowNegativeBalance: true
                );

            Assert.IsType <AccountStateDeltaImpl>(a);
            Assert.Equal(Value(0, 6), a.GetBalance(_addr[1], _currencies[0]));
            a = a.TransferAsset(_addr[1], _addr[1], Value(0, 5));
            Assert.IsType <AccountStateDeltaImpl>(a);
            Assert.Equal(Value(0, 6), a.GetBalance(_addr[1], _currencies[0]));
        }
예제 #4
0
        public IAccountStateDelta MinerReward(IActionContext ctx, IAccountStateDelta states)
        {
            // 마이닝 보상
            // https://www.notion.so/planetarium/Mining-Reward-b7024ef463c24ebca40a2623027d497d
            Currency           currency            = states.GetGoldCurrency();
            FungibleAssetValue defaultMiningReward = currency * 10;
            var countOfHalfLife             = (int)Math.Pow(2, Convert.ToInt64((ctx.BlockIndex - 1) / 12614400));
            FungibleAssetValue miningReward =
                defaultMiningReward.DivRem(countOfHalfLife, out FungibleAssetValue _);

            if (miningReward >= FungibleAssetValue.Parse(currency, "1.25"))
            {
                states = states.TransferAsset(
                    GoldCurrencyState.Address,
                    ctx.Miner,
                    miningReward
                    );
            }

            return(states);
        }
예제 #5
0
        public static IAccountStateDelta MarkBalanceChanged(
            this IAccountStateDelta states,
            Currency currency,
            params Address[] accounts
            )
        {
            if (accounts.Length == 1)
            {
                return(states.MintAsset(accounts[0], currency * 1));
            }
            else if (accounts.Length < 1)
            {
                return(states);
            }

            for (int i = 1; i < accounts.Length; i++)
            {
                states = states.TransferAsset(accounts[i - 1], accounts[i], currency * 1, true);
            }

            return(states);
        }
예제 #6
0
        public IAccountStateDelta GenesisGoldDistribution(IActionContext ctx, IAccountStateDelta states)
        {
            IEnumerable <GoldDistribution> goldDistributions = states.GetGoldDistribution();
            var      index        = ctx.BlockIndex;
            Currency goldCurrency = states.GetGoldCurrency();
            Address  fund         = GoldCurrencyState.Address;

            foreach (GoldDistribution distribution in goldDistributions)
            {
                BigInteger amount = distribution.GetAmount(index);
                if (amount <= 0)
                {
                    continue;
                }
                states = states.TransferAsset(
                    fund,
                    distribution.Address,
                    goldCurrency * amount
                    );
            }
            return(states);
        }
예제 #7
0
        public IAccountStateDelta GenesisGoldDistribution(IActionContext ctx, IAccountStateDelta states)
        {
            IEnumerable <GoldDistribution> goldDistributions = states.GetGoldDistribution();
            var      index        = ctx.BlockIndex;
            Currency goldCurrency = states.GetGoldCurrency();
            Address  fund         = GoldCurrencyState.Address;

            foreach (GoldDistribution distribution in goldDistributions)
            {
                BigInteger amount = distribution.GetAmount(index);
                if (amount <= 0)
                {
                    continue;
                }

                // We should divide by 100 for only mainnet distributions.
                // See also: https://github.com/planetarium/lib9c/pull/170#issuecomment-713380172
                FungibleAssetValue fav = goldCurrency * amount;
                var testAddresses      = new HashSet <Address>(
                    new []
                {
                    new Address("F9A15F870701268Bd7bBeA6502eB15F4997f32f9"),
                    new Address("Fb90278C67f9b266eA309E6AE8463042f5461449"),
                }
                    );
                if (!testAddresses.Contains(distribution.Address))
                {
                    fav = fav.DivRem(100, out FungibleAssetValue _);
                }
                states = states.TransferAsset(
                    fund,
                    distribution.Address,
                    fav
                    );
            }
            return(states);
        }
예제 #8
0
        public override IAccountStateDelta Execute(IActionContext context)
        {
            IAccountStateDelta states = context.PreviousStates;
            Address            monsterCollectionAddress = MonsterCollectionState0.DeriveAddress(context.Signer, collectionRound);

            if (context.Rehearsal)
            {
                return(states
                       .SetState(monsterCollectionAddress, MarkChanged)
                       .SetState(context.Signer, MarkChanged)
                       .MarkBalanceChanged(GoldCurrencyMock, context.Signer, monsterCollectionAddress));
            }

            CheckObsolete(BlockChain.Policy.BlockPolicySource.V100080ObsoleteIndex, context);

            MonsterCollectionSheet monsterCollectionSheet = states.GetSheet <MonsterCollectionSheet>();

            AgentState agentState = states.GetAgentState(context.Signer);

            if (agentState is null)
            {
                throw new FailedLoadStateException("Aborted as the agent state failed to load.");
            }

            if (agentState.MonsterCollectionRound != collectionRound)
            {
                throw new InvalidMonsterCollectionRoundException(
                          $"Expected collection round is {agentState.MonsterCollectionRound}, but actual collection round is {collectionRound}.");
            }

            if (!monsterCollectionSheet.TryGetValue(level, out MonsterCollectionSheet.Row _))
            {
                throw new SheetRowNotFoundException(nameof(MonsterCollectionSheet), level);
            }

            Currency currency = states.GetGoldCurrency();
            // Set default gold value.
            FungibleAssetValue requiredGold = currency * 0;
            FungibleAssetValue balance      = states.GetBalance(context.Signer, states.GetGoldCurrency());

            MonsterCollectionState0 monsterCollectionState;
            int currentLevel = 1;
            MonsterCollectionRewardSheet monsterCollectionRewardSheet = states.GetSheet <MonsterCollectionRewardSheet>();

            if (states.TryGetState(monsterCollectionAddress, out Dictionary stateDict))
            {
                monsterCollectionState = new MonsterCollectionState0(stateDict);

                if (monsterCollectionState.ExpiredBlockIndex < context.BlockIndex)
                {
                    throw new MonsterCollectionExpiredException(
                              $"{monsterCollectionAddress} has already expired on {monsterCollectionState.ExpiredBlockIndex}");
                }

                if (monsterCollectionState.Level >= level)
                {
                    throw new InvalidLevelException($"The level must be greater than {monsterCollectionState.Level}.");
                }

                currentLevel = monsterCollectionState.Level + 1;
                long rewardLevel = monsterCollectionState.GetRewardLevel(context.BlockIndex);
                monsterCollectionState.Update(level, rewardLevel, monsterCollectionRewardSheet);
            }
            else
            {
                monsterCollectionState = new MonsterCollectionState0(monsterCollectionAddress, level, context.BlockIndex, monsterCollectionRewardSheet);
            }

            for (int i = currentLevel; i < level + 1; i++)
            {
                requiredGold += currency * monsterCollectionSheet[i].RequiredGold;
            }

            if (balance < requiredGold)
            {
                throw new InsufficientBalanceException(context.Signer, requiredGold,
                                                       $"There is no sufficient balance for {context.Signer}: {balance} < {requiredGold}");
            }
            states = states.TransferAsset(context.Signer, monsterCollectionAddress, requiredGold);
            states = states.SetState(monsterCollectionAddress, monsterCollectionState.Serialize());
            return(states);
        }
예제 #9
0
        public override IAccountStateDelta Execute(IActionContext context)
        {
            IAccountStateDelta states = context.PreviousStates;

            if (context.Rehearsal)
            {
                return(states
                       .SetState(MonsterCollectionState.DeriveAddress(context.Signer, 0), MarkChanged)
                       .SetState(MonsterCollectionState.DeriveAddress(context.Signer, 1), MarkChanged)
                       .SetState(MonsterCollectionState.DeriveAddress(context.Signer, 2), MarkChanged)
                       .SetState(MonsterCollectionState.DeriveAddress(context.Signer, 3), MarkChanged)
                       .SetState(context.Signer, MarkChanged)
                       .MarkBalanceChanged(GoldCurrencyMock, context.Signer, MonsterCollectionState.DeriveAddress(context.Signer, 0))
                       .MarkBalanceChanged(GoldCurrencyMock, context.Signer, MonsterCollectionState.DeriveAddress(context.Signer, 1))
                       .MarkBalanceChanged(GoldCurrencyMock, context.Signer, MonsterCollectionState.DeriveAddress(context.Signer, 2))
                       .MarkBalanceChanged(GoldCurrencyMock, context.Signer, MonsterCollectionState.DeriveAddress(context.Signer, 3)));
            }

            MonsterCollectionSheet monsterCollectionSheet = states.GetSheet <MonsterCollectionSheet>();

            AgentState agentState = states.GetAgentState(context.Signer);

            if (agentState is null)
            {
                throw new FailedLoadStateException("Aborted as the agent state failed to load.");
            }

            if (level < 0 || level > 0 && !monsterCollectionSheet.TryGetValue(level, out MonsterCollectionSheet.Row _))
            {
                throw new MonsterCollectionLevelException();
            }

            Currency currency = states.GetGoldCurrency();
            // Set default gold value.
            FungibleAssetValue requiredGold             = currency * 0;
            Address            monsterCollectionAddress = MonsterCollectionState.DeriveAddress(
                context.Signer,
                agentState.MonsterCollectionRound
                );

            if (states.TryGetState(monsterCollectionAddress, out Dictionary stateDict))
            {
                var existingStates = new MonsterCollectionState(stateDict);
                int previousLevel  = existingStates.Level;
                // Check collection level and required block index
                if (level < previousLevel && existingStates.IsLocked(context.BlockIndex))
                {
                    throw new RequiredBlockIndexException();
                }

                if (level == previousLevel)
                {
                    throw new MonsterCollectionLevelException();
                }

                if (existingStates.CalculateStep(context.BlockIndex) > 0)
                {
                    throw new MonsterCollectionExistingClaimableException();
                }

                // Refund holding NCG to user
                FungibleAssetValue gold = states.GetBalance(monsterCollectionAddress, currency);
                states = states.TransferAsset(monsterCollectionAddress, context.Signer, gold);
            }

            if (level == 0)
            {
                return(states.SetState(monsterCollectionAddress, new Null()));
            }

            FungibleAssetValue balance = states.GetBalance(context.Signer, currency);
            var monsterCollectionState = new MonsterCollectionState(monsterCollectionAddress, level, context.BlockIndex);

            for (int i = 0; i < level; i++)
            {
                requiredGold += currency * monsterCollectionSheet[i + 1].RequiredGold;
            }

            if (balance < requiredGold)
            {
                throw new InsufficientBalanceException(context.Signer, requiredGold,
                                                       $"There is no sufficient balance for {context.Signer}: {balance} < {requiredGold}");
            }
            states = states.TransferAsset(context.Signer, monsterCollectionAddress, requiredGold);
            states = states.SetState(monsterCollectionAddress, monsterCollectionState.Serialize());
            return(states);
        }
예제 #10
0
        public override IAccountStateDelta Execute(IActionContext context)
        {
            IAccountStateDelta states            = context.PreviousStates;
            Address            collectionAddress = MonsterCollectionState0.DeriveAddress(context.Signer, collectionRound);

            if (context.Rehearsal)
            {
                return(states
                       .SetState(context.Signer, MarkChanged)
                       .SetState(avatarAddress, MarkChanged)
                       .SetState(collectionAddress, MarkChanged));
            }

            CheckObsolete(BlockChain.Policy.BlockPolicySource.V100080ObsoleteIndex, context);

            if (!states.TryGetAgentAvatarStates(context.Signer, avatarAddress, out AgentState agentState, out AvatarState avatarState))
            {
                throw new FailedLoadStateException($"Aborted as the avatar state of the signer failed to load.");
            }

            if (!states.TryGetState(collectionAddress, out Dictionary stateDict))
            {
                throw new FailedLoadStateException($"Aborted as the monster collection state failed to load.");
            }

            MonsterCollectionState0 monsterCollectionState = new MonsterCollectionState0(stateDict);

            if (monsterCollectionState.End)
            {
                throw new MonsterCollectionExpiredException($"{collectionAddress} has already expired on {monsterCollectionState.ExpiredBlockIndex}");
            }

            if (!monsterCollectionState.CanReceive(context.BlockIndex))
            {
                throw new RequiredBlockIndexException(
                          $"{collectionAddress} is not available yet; it will be available after {Math.Max(monsterCollectionState.StartedBlockIndex, monsterCollectionState.ReceivedBlockIndex) + MonsterCollectionState0.RewardInterval}");
            }

            long      rewardLevel = monsterCollectionState.GetRewardLevel(context.BlockIndex);
            ItemSheet itemSheet   = states.GetItemSheet();

            for (int i = 0; i < rewardLevel; i++)
            {
                int level = i + 1;
                if (level <= monsterCollectionState.RewardLevel)
                {
                    continue;
                }

                List <MonsterCollectionRewardSheet.RewardInfo> rewards = monsterCollectionState.RewardLevelMap[level];
                Guid id = context.Random.GenerateRandomGuid();
                MonsterCollectionResult result = new MonsterCollectionResult(id, avatarAddress, rewards);
                MonsterCollectionMail   mail   = new MonsterCollectionMail(result, context.BlockIndex, id, context.BlockIndex);
                avatarState.Update(mail);
                foreach (var rewardInfo in rewards)
                {
                    var row  = itemSheet[rewardInfo.ItemId];
                    var item = row is MaterialItemSheet.Row materialRow
                        ? ItemFactory.CreateTradableMaterial(materialRow)
                        : ItemFactory.CreateItem(row, context.Random);
                    avatarState.inventory.AddItem2(item, rewardInfo.Quantity);
                }
                monsterCollectionState.UpdateRewardMap(level, result, context.BlockIndex);
            }

            // Return gold at the end of monster collect.
            if (rewardLevel == 4)
            {
                MonsterCollectionSheet monsterCollectionSheet = states.GetSheet <MonsterCollectionSheet>();
                Currency currency = states.GetGoldCurrency();
                // Set default gold value.
                FungibleAssetValue gold = currency * 0;
                for (int i = 0; i < monsterCollectionState.Level; i++)
                {
                    int level = i + 1;
                    gold += currency * monsterCollectionSheet[level].RequiredGold;
                }
                agentState.IncreaseCollectionRound();
                states = states.SetState(context.Signer, agentState.Serialize());
                if (gold > currency * 0)
                {
                    states = states.TransferAsset(collectionAddress, context.Signer, gold);
                }
            }

            return(states
                   .SetState(avatarAddress, avatarState.Serialize())
                   .SetState(collectionAddress, monsterCollectionState.Serialize()));
        }