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()));
        }