public void Execute(bool exist, int level, int monsterCollectionRound, int prevLevel, long blockIndex) { Address monsterCollectionAddress = MonsterCollectionState0.DeriveAddress(_signer, monsterCollectionRound); if (exist) { List <MonsterCollectionRewardSheet.RewardInfo> rewards = _tableSheets.MonsterCollectionRewardSheet[prevLevel].Rewards; MonsterCollectionState0 prevMonsterCollectionState = new MonsterCollectionState0(monsterCollectionAddress, prevLevel, 0, _tableSheets.MonsterCollectionRewardSheet); _initialState = _initialState.SetState(monsterCollectionAddress, prevMonsterCollectionState.Serialize()); Assert.All(prevMonsterCollectionState.RewardLevelMap, kv => Assert.Equal(rewards, kv.Value)); } AgentState prevAgentState = _initialState.GetAgentState(_signer); while (prevAgentState.MonsterCollectionRound < monsterCollectionRound) { prevAgentState.IncreaseCollectionRound(); } _initialState = _initialState.SetState(_signer, prevAgentState.Serialize()); Currency currency = _initialState.GetGoldCurrency(); for (int i = 1; i < level + 1; i++) { if (i > prevLevel) { MonsterCollectionSheet.Row row = _tableSheets.MonsterCollectionSheet[i]; _initialState = _initialState.MintAsset(_signer, row.RequiredGold * currency); } } MonsterCollect0 action = new MonsterCollect0 { level = level, collectionRound = monsterCollectionRound, }; IAccountStateDelta nextState = action.Execute(new ActionContext { PreviousStates = _initialState, Signer = _signer, BlockIndex = blockIndex, }); MonsterCollectionState0 nextMonsterCollectionState = new MonsterCollectionState0((Dictionary)nextState.GetState(monsterCollectionAddress)); AgentState nextAgentState = nextState.GetAgentState(_signer); Assert.Equal(level, nextMonsterCollectionState.Level); Assert.Equal(0 * currency, nextState.GetBalance(_signer, currency)); Assert.Equal(monsterCollectionRound, nextAgentState.MonsterCollectionRound); long rewardLevel = nextMonsterCollectionState.GetRewardLevel(blockIndex); for (long i = rewardLevel; i < 4; i++) { List <MonsterCollectionRewardSheet.RewardInfo> expected = _tableSheets.MonsterCollectionRewardSheet[level].Rewards; Assert.Equal(expected, nextMonsterCollectionState.RewardLevelMap[i + 1]); } }
public override IAccountStateDelta Execute(IActionContext context) { IAccountStateDelta states = context.PreviousStates; Address collectionAddress = MonsterCollectionState0.DeriveAddress(context.Signer, collectRound); if (context.Rehearsal) { return(states .SetState(collectionAddress, MarkChanged) .MarkBalanceChanged(GoldCurrencyMock, collectionAddress, context.Signer)); } CheckObsolete(BlockChain.Policy.BlockPolicySource.V100080ObsoleteIndex, context); AgentState agentState = states.GetAgentState(context.Signer); if (agentState is null) { throw new FailedLoadStateException("Aborted as the agent state 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); Currency currency = states.GetGoldCurrency(); FungibleAssetValue balance = 0 * currency; MonsterCollectionSheet monsterCollectionSheet = states.GetSheet <MonsterCollectionSheet>(); int currentLevel = monsterCollectionState.Level; if (currentLevel <= level || level <= 0) { throw new InvalidLevelException($"The level must be greater than 0 and less than {currentLevel}."); } if (monsterCollectionState.End) { throw new MonsterCollectionExpiredException($"{collectionAddress} has already expired on {monsterCollectionState.ExpiredBlockIndex}"); } long rewardLevel = monsterCollectionState.GetRewardLevel(context.BlockIndex); MonsterCollectionRewardSheet monsterCollectionRewardSheet = states.GetSheet <MonsterCollectionRewardSheet>(); monsterCollectionState.Update(level, rewardLevel, monsterCollectionRewardSheet); for (int i = currentLevel; i > level; i--) { balance += monsterCollectionSheet[i].RequiredGold * currency; } return(states .SetState(collectionAddress, monsterCollectionState.Serialize()) .TransferAsset(collectionAddress, context.Signer, balance)); }
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 )); }
public void Execute(int prevLevel, int collectionLevel, long blockIndex) { Address collectionAddress = MonsterCollectionState0.DeriveAddress(_signer, 0); List <MonsterCollectionRewardSheet.RewardInfo> rewardInfos = _tableSheets.MonsterCollectionRewardSheet[prevLevel].Rewards; MonsterCollectionState0 monsterCollectionState = new MonsterCollectionState0(collectionAddress, prevLevel, 0, _tableSheets.MonsterCollectionRewardSheet); Currency currency = _state.GetGoldCurrency(); FungibleAssetValue balance = 0 * currency; foreach (var row in _tableSheets.MonsterCollectionSheet) { if (collectionLevel < row.Level && row.Level <= prevLevel) { balance += row.RequiredGold * currency; } } Assert.All(monsterCollectionState.RewardLevelMap, kv => Assert.Equal(rewardInfos, kv.Value)); _state = _state .SetState(collectionAddress, monsterCollectionState.Serialize()) .MintAsset(collectionAddress, balance); CancelMonsterCollect action = new CancelMonsterCollect { collectRound = 0, level = collectionLevel, }; IAccountStateDelta nextState = action.Execute(new ActionContext { PreviousStates = _state, Signer = _signer, BlockIndex = blockIndex, }); MonsterCollectionState0 nextMonsterCollectionState = new MonsterCollectionState0((Dictionary)nextState.GetState(collectionAddress)); Assert.Equal(collectionLevel, nextMonsterCollectionState.Level); Assert.Equal(0 * currency, nextState.GetBalance(collectionAddress, currency)); Assert.Equal(balance, nextState.GetBalance(_signer, currency)); long rewardLevel = nextMonsterCollectionState.GetRewardLevel(blockIndex); List <MonsterCollectionRewardSheet.RewardInfo> nextRewardInfos = _tableSheets.MonsterCollectionRewardSheet[collectionLevel].Rewards; for (long i = rewardLevel; i < 4; i++) { Assert.Equal(nextRewardInfos, nextMonsterCollectionState.RewardLevelMap[i + 1]); } }
public void Execute() { var shopState = _initialState.GetShopState(); Assert.Empty(shopState.Products); var avatarState = _initialState.GetAvatarState(_avatarAddress); Assert.Single(avatarState.inventory.Equipments); var equipment = avatarState.inventory.Equipments.FirstOrDefault(); Assert.NotNull(equipment); var currencyState = _initialState.GetGoldCurrency(); var price = new FungibleAssetValue(currencyState, 100, 0); var sellAction = new Sell0 { itemId = equipment.ItemId, price = price, sellerAvatarAddress = _avatarAddress, }; var nextState = sellAction.Execute(new ActionContext { BlockIndex = 0, PreviousStates = _initialState, Rehearsal = false, Signer = _agentAddress, Random = new TestRandom(), }); var nextAvatarState = nextState.GetAvatarState(_avatarAddress); Assert.Empty(nextAvatarState.inventory.Equipments); var nextShopState = nextState.GetShopState(); Assert.Single(nextShopState.Products); var(_, shopItem) = nextShopState.Products.FirstOrDefault(); Assert.NotNull(shopItem); Assert.Equal(equipment.ItemId, shopItem.ItemUsable.ItemId); Assert.Equal(price, shopItem.Price); Assert.Equal(_agentAddress, shopItem.SellerAgentAddress); Assert.Equal(_avatarAddress, shopItem.SellerAvatarAddress); }
public void Execute(int balance, int?prevLevel, int level, long blockIndex, Type exc, int?expectedStakings) { Address monsterCollectionAddress = MonsterCollectionState.DeriveAddress(_signer, 0); Currency currency = _initialState.GetGoldCurrency(); FungibleAssetValue balanceFav = currency * balance; FungibleAssetValue staked = currency * 0; if (prevLevel is { } prevLevelNotNull) { List <MonsterCollectionRewardSheet.RewardInfo> rewards = _tableSheets.MonsterCollectionRewardSheet[prevLevelNotNull].Rewards; var prevMonsterCollectionState = new MonsterCollectionState( address: monsterCollectionAddress, level: prevLevelNotNull, blockIndex: 0, monsterCollectionRewardSheet: _tableSheets.MonsterCollectionRewardSheet ); _initialState = _initialState.SetState(monsterCollectionAddress, prevMonsterCollectionState.Serialize()); for (int i = 0; i < prevLevel; i++) { MonsterCollectionSheet.Row row = _tableSheets.MonsterCollectionSheet[i + 1]; staked += row.RequiredGold * currency; _initialState = _initialState.MintAsset(monsterCollectionAddress, row.RequiredGold * currency); } } balanceFav -= staked; _initialState = _initialState.MintAsset(_signer, balanceFav); var action = new MonsterCollect { level = level, }; if (exc is { } excType) { Assert.Throws(excType, () => action.Execute(new ActionContext { PreviousStates = _initialState, Signer = _signer, BlockIndex = blockIndex, })); }
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); }
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); }
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); }
public void Execute(int rewardLevel, int prevRewardLevel, int collectionLevel) { Address collectionAddress = MonsterCollectionState0.DeriveAddress(_signer, 0); List <MonsterCollectionRewardSheet.RewardInfo> rewards = _tableSheets.MonsterCollectionRewardSheet[1].Rewards; MonsterCollectionState0 monsterCollectionState = new MonsterCollectionState0(collectionAddress, 1, 0, _tableSheets.MonsterCollectionRewardSheet); for (int i = 0; i < prevRewardLevel; i++) { int level = i + 1; MonsterCollectionResult result = new MonsterCollectionResult(Guid.NewGuid(), _avatarAddress, rewards); monsterCollectionState.UpdateRewardMap(level, result, i * MonsterCollectionState0.RewardInterval); } List <MonsterCollectionRewardSheet.RewardInfo> collectionRewards = _tableSheets.MonsterCollectionRewardSheet[collectionLevel].Rewards; monsterCollectionState.Update(collectionLevel, rewardLevel, _tableSheets.MonsterCollectionRewardSheet); for (long i = rewardLevel; i < 4; i++) { Assert.Equal(collectionRewards, monsterCollectionState.RewardLevelMap[i + 1]); } Dictionary <int, int> rewardExpectedMap = new Dictionary <int, int>(); foreach (var(key, value) in monsterCollectionState.RewardLevelMap) { if (monsterCollectionState.RewardMap.ContainsKey(key) || key > rewardLevel) { continue; } foreach (var info in value) { if (rewardExpectedMap.ContainsKey(info.ItemId)) { rewardExpectedMap[info.ItemId] += info.Quantity; } else { rewardExpectedMap[info.ItemId] = info.Quantity; } } } AvatarState prevAvatarState = _state.GetAvatarState(_avatarAddress); Assert.Empty(prevAvatarState.mailBox); Currency currency = _state.GetGoldCurrency(); int collectionRound = _state.GetAgentState(_signer).MonsterCollectionRound; _state = _state .SetState(collectionAddress, monsterCollectionState.Serialize()); FungibleAssetValue balance = 0 * currency; if (rewardLevel == 4) { foreach (var row in _tableSheets.MonsterCollectionSheet) { if (row.Level <= collectionLevel) { balance += row.RequiredGold * currency; } } collectionRound += 1; _state = _state .MintAsset(collectionAddress, balance); } Assert.Equal(prevRewardLevel, monsterCollectionState.RewardLevel); Assert.Equal(0, _state.GetAgentState(_signer).MonsterCollectionRound); ClaimMonsterCollectionReward0 action = new ClaimMonsterCollectionReward0 { avatarAddress = _avatarAddress, collectionRound = 0, }; IAccountStateDelta nextState = action.Execute(new ActionContext { PreviousStates = _state, Signer = _signer, BlockIndex = rewardLevel * MonsterCollectionState0.RewardInterval, Random = new TestRandom(), }); MonsterCollectionState0 nextMonsterCollectionState = new MonsterCollectionState0((Dictionary)nextState.GetState(collectionAddress)); Assert.Equal(rewardLevel, nextMonsterCollectionState.RewardLevel); AvatarState nextAvatarState = nextState.GetAvatarState(_avatarAddress); foreach (var(itemId, qty) in rewardExpectedMap) { Assert.True(nextAvatarState.inventory.HasItem(itemId, qty)); } Assert.Equal(rewardLevel - prevRewardLevel, nextAvatarState.mailBox.Count); Assert.All(nextAvatarState.mailBox, mail => { Assert.IsType <MonsterCollectionMail>(mail); MonsterCollectionMail monsterCollectionMail = (MonsterCollectionMail)mail; Assert.IsType <MonsterCollectionResult>(monsterCollectionMail.attachment); MonsterCollectionResult result = (MonsterCollectionResult)monsterCollectionMail.attachment; Assert.Equal(result.id, mail.id); }); for (int i = 0; i < nextMonsterCollectionState.RewardLevel; i++) { int level = i + 1; List <MonsterCollectionRewardSheet.RewardInfo> rewardInfos = _tableSheets.MonsterCollectionRewardSheet[collectionLevel].Rewards; Assert.Contains(level, nextMonsterCollectionState.RewardMap.Keys); Assert.Equal(_avatarAddress, nextMonsterCollectionState.RewardMap[level].avatarAddress); } Assert.Equal(0 * currency, nextState.GetBalance(collectionAddress, currency)); Assert.Equal(balance, nextState.GetBalance(_signer, currency)); Assert.Equal(collectionRound, nextState.GetAgentState(_signer).MonsterCollectionRound); Assert.Equal(nextMonsterCollectionState.End, rewardLevel == 4); }
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); }
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); }
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())); }