Shop system in 2d game

Hello everyone. I am a newbie and I am trying to make a 2D farm game and I am following a tutorial on how to make it, where unfortunately many steps are missing. I have encountered a problem in developing a store in the game. My store works on the principle that the player drags an object to the playing field and the object is placed if the player has enough money (money is taken away) or the object disappears if the player does not have enough money. I already have one similar mechanism for opening new territories in my game and I wanted to use its likeness this time. I found the most suitable option to put this check (if the player has enough money or not) in public void CheckPlacement() - all scripts will be below. But when I implement a similar system for buying from the store, either the installation of objects gives bugs (multiple installation, or items disappear) or I just get the error “KeyNotFoundException: The given key ‘EnoughCurrencyGameEvent’ was not present in the dictionary.
System.Collections.Generic.Dictionary2[TKey,TValue].get_Item (TKey key)”, although it seems to me that I register events and listeners correctly. In any case, I will be very grateful if someone helps me fix my mistake or suggests a more suitable solution for the store. Thanks!

Part of Territory sctipt, which I used like expample:

public class Territory : MonoBehaviour, IPointerClickHandler
{
    ...
    //amount of currency needed to unlock the territory
    public int gemsAmount;
     ....
   
   public void OnPointerClick(PointerEventData eventData)
    {
        ...

        window.Find("Buy Button").GetComponent<Button>().onClick.AddListener(delegate
        {
            EventManager.Instance.AddListenerOnce<EnoughCurrencyGameEvent>(OnEnoughCurrency);
            EventManager.Instance.AddListenerOnce<NotEnoughCurrencyGameEvent>(OnNotEnoughCurrency);

            CurrencyChangeGameEvent info = new CurrencyChangeGameEvent(-gemsAmount, CurrencyType.Gems);
            EventManager.Instance.QueueEvent(info);

            Destroy(holder);
            isWindowOpen = false;
            Deselect();
        });

        
        window.Find("Amount Text").GetComponent<TextMeshProUGUI>().text = gemsAmount.ToString();

        
        PanZoom.current.Focus(transform.position);
        Select();
    }

   ...
    }

    private void OnEnoughCurrency(EnoughCurrencyGameEvent info)
    {
        //unlock territory if the player has enough currency
        UnlockTerritory();
        //remove listener of the opposite event
        EventManager.Instance.RemoveListener<NotEnoughCurrencyGameEvent>(OnNotEnoughCurrency);
    }

    private void OnNotEnoughCurrency(NotEnoughCurrencyGameEvent info)
    {
        //remove listener of the opposite event
        EventManager.Instance.RemoveListener<EnoughCurrencyGameEvent>(OnEnoughCurrency);
    }
    
    ...
}

Here a script of PlaceableObject, where I tried implemet similar system but bugs were everywhere :confused:

public class PlaceableObject : MonoBehaviour
{
    //if the building is placed or not
    public bool Placed { get; private set; }
    //position on which an object was placed
    //(save it if the new position is not available)
    private Vector3 origin;

    //area under the house - stores position and building size
    public BoundsInt area;

    public int Price;
    public CurrencyType Currency;

    //Check if the building can be placed at its current position

    public bool CanBePlaced()
    {
        //create an area under the building
        Vector3Int positionInt = BuildingSystem.current.gridLayout.LocalToCell(transform.position);
        BoundsInt areaTemp = area;
        areaTemp.position = positionInt;

        //call the GridBuildingSystem to check the area
        return BuildingSystem.current.CanTakeArea(areaTemp);
    }


    //Make the building placed

    public void Place()
    {
        //create an area under the building
        Vector3Int positionInt = BuildingSystem.current.gridLayout.LocalToCell(transform.position);
        BoundsInt areaTemp = area;
        areaTemp.position = positionInt;

        //set the bool
        Placed = true;
        //save position
        origin = transform.position;

        //call the system to 
        BuildingSystem.current.TakeArea(areaTemp);

        PanZoom.current.UnfollowObject();
    }

    public void CheckPlacement()
    {
    // If the object is new and hasn't been placed yet
    if (!Placed)
    {            
        // Subscribe to the event if there is enough currency
        EventManager.Instance.AddListenerOnce<EnoughCurrencyGameEvent>(OnEnoughCurrency);

        // Subscribe to the event if there isn't enough currency
        EventManager.Instance.AddListenerOnce<NotEnoughCurrencyGameEvent>(OnNotEnoughCurrency);

        // Create an event to attempt spending currency
        CurrencyChangeGameEvent currencyChangeEvent = new CurrencyChangeGameEvent(-Price, Currency);

        // Trigger the event to change the amount of currency
        EventManager.Instance.QueueEvent(currencyChangeEvent);

        // Check if the object still exists and can be placed
        if (this != null && CanBePlaced())
        {
            // Place the object at the desired location
            Place();
        }
        else if (this != null)
        {
            // If the placement is not possible, destroy the object
            Destroy(transform.gameObject);
        }

        // After placing the object or destroying it, open the shop
        ShopManager.current.ShopButton_Click();
    }
    // If the object was previously placed and is now being edited
    else
    {
        // If the object cannot be placed at the new location
        if (!CanBePlaced())
        {
            // Check if the object still exists
            if (this != null)
            {
                // Return the object to its original position
                transform.position = origin;
            }
        }

        // Place the object again (at the new location)
        if (this != null)
        {
            Place();
        }
    }
}

private void OnEnoughCurrency(EnoughCurrencyGameEvent info)
{
    // Check if the object still exists and can be placed
    if (this != null && CanBePlaced())
    {
        // Place the object at the desired location
        Place();
    }
    else if (this != null)
    {
        // If the placement is not possible, destroy the object
        Destroy(transform.gameObject);
    }

    // Unsubscribe from events after the operation is completed
    EventManager.Instance.RemoveListener<EnoughCurrencyGameEvent>(OnEnoughCurrency);
    EventManager.Instance.RemoveListener<NotEnoughCurrencyGameEvent>(OnNotEnoughCurrency);
}

private void OnNotEnoughCurrency(NotEnoughCurrencyGameEvent info)
{
    // Check if the object still exists before destroying it
    if (this != null)
    {
        // Destroy the object because there isn't enough currency
        Destroy(transform.gameObject);
    }

    // Unsubscribe from events after the operation is completed
    EventManager.Instance.RemoveListener<EnoughCurrencyGameEvent>(OnEnoughCurrency);
    EventManager.Instance.RemoveListener<NotEnoughCurrencyGameEvent>(OnNotEnoughCurrency);
}
       ....
}

and the last one is a script of CurrencySystem, where, I guess, also could be a problem:

public class CurrencySystem : MonoBehaviour
{
    //all player's treasures
    private static Dictionary<CurrencyType, int> CurrencyAmounts = new Dictionary<CurrencyType, int>();

    //currency texts
    [SerializeField] private List<GameObject> texts;

    //currency texts in a dictionary (for easier access)
    private Dictionary<CurrencyType, TextMeshProUGUI> currencyTexts =
        new Dictionary<CurrencyType, TextMeshProUGUI>();


    private void Awake()
    {
        //initialize dictionaries
        for (int i = 0; i < texts.Count; i++)
        {
            CurrencyAmounts.Add((CurrencyType)i, 0);
            currencyTexts.Add((CurrencyType)i, texts[i].transform.GetChild(1).GetComponent<TextMeshProUGUI>());
        }
    }

    private void Start()
    {

        //give the player some currency
        CurrencyAmounts[CurrencyType.Mana] = 200;
        CurrencyAmounts[CurrencyType.Coins] = 1000;
        CurrencyAmounts[CurrencyType.Gems] = 10;

        //update UI texts to reflect the right amount
        UpdateUI();

        //add listeners for currency change events and not enough currency
        EventManager.Instance.AddListener<CurrencyChangeGameEvent>(OnCurrencyChange);
        EventManager.Instance.AddListener<NotEnoughCurrencyGameEvent>(OnNotEnough);
    }

    private void UpdateUI()
    {
        //set new currency amounts
        for (int i = 0; i < texts.Count; i++)
        {
            currencyTexts[(CurrencyType)i].text = CurrencyAmounts[(CurrencyType)i].ToString();
        }
    }

    private void OnCurrencyChange(CurrencyChangeGameEvent info)
    {

        //if the player's trying to spend currency
        if (info.amount < 0)
        {
            if (CurrencyAmounts[info.currencyType] < Math.Abs(info.amount))
            {
                EventManager.Instance.QueueEvent(new NotEnoughCurrencyGameEvent(info.amount, info.currencyType));
                return;
            }

            EventManager.Instance.QueueEvent(new EnoughCurrencyGameEvent());
        }

        //change currency amount
        CurrencyAmounts[info.currencyType] += info.amount;
        //update currency texts
        currencyTexts[info.currencyType].text = CurrencyAmounts[info.currencyType].ToString();

        UpdateUI();
    }

    private void OnNotEnough(NotEnoughCurrencyGameEvent info)
    {
        //display that the player doesn't have any currency
        Debug.Log($"You don't have enough of {info.amount} {info.currencyType}");
    }

}


public enum CurrencyType
{
    Mana,
    Coins,
    Gems
}

If you have scrolled all the way to the end of my question, then thank you very much for your patience!

Problem Solved! Here is correct script:

public class PlaceableObject : MonoBehaviour
{
    //if the building is placed or not
    public bool Placed { get; private set; }
    //position on which an object was placed
    //(save it if the new position is not available)
    private Vector3 origin;

    //area under the house - stores position and building size
    public BoundsInt area;

    public int Price;
    public CurrencyType Currency;



    //Check if the building can be placed at its current position

    public bool CanBePlaced()
    {
        //create an area under the building
        Vector3Int positionInt = BuildingSystem.current.gridLayout.LocalToCell(transform.position);
        BoundsInt areaTemp = area;
        areaTemp.position = positionInt;

        //call the GridBuildingSystem to check the area
        return BuildingSystem.current.CanTakeArea(areaTemp);
    }


    //Make the building placed

    public void Place()
    {
        //create an area under the building
        Vector3Int positionInt = BuildingSystem.current.gridLayout.LocalToCell(transform.position);
        BoundsInt areaTemp = area;
        areaTemp.position = positionInt;

        //set the bool
        Placed = true;
        //save position
        origin = transform.position;

        //call the system to 
        BuildingSystem.current.TakeArea(areaTemp);

        PanZoom.current.UnfollowObject();
    }

    public void CheckPlacement()
    {
        //object is new an haven't been placed before
        if (!Placed)
        {
            //if it can be placed
            if (CanBePlaced())
            {
                //add listeners for both events
                EventManager.Instance.AddListenerOnce<EnoughCurrencyGameEvent>(OnEnoughCurrency);
                EventManager.Instance.AddListenerOnce<NotEnoughCurrencyGameEvent>(OnNotEnoughCurrency);

                //initialize event infor
                CurrencyChangeGameEvent info = new CurrencyChangeGameEvent(-Price, Currency);
                //invoke the event of currency change

                EventManager.Instance.QueueEvent(info);

                
            }
            else
            {
                //destroy this object (because it is new)
                Destroy(transform.gameObject);
            }

            //open the shop afterwards
            ShopManager.current.ShopButton_Click();
        }
        //editing the map, object has been placed before
        else
        {
            //if cannot be placed
            if (!CanBePlaced())
            {
                //reset the position to origin
                transform.position = origin;
            }

            Place();
        }

    }

    private void OnEnoughCurrency(EnoughCurrencyGameEvent info)
    {
        Place();
        //remove listener so the object doesn't listen to this event anymore
        EventManager.Instance.RemoveListener<NotEnoughCurrencyGameEvent>(OnNotEnoughCurrency);
    }

    //if the player doesn't have enough currency
    private void OnNotEnoughCurrency(NotEnoughCurrencyGameEvent info)
    {
        PanZoom.current.UnfollowObject();
        Destroy(transform.gameObject);

        //remove listener so the object doesn't listen to this event anymore
        EventManager.Instance.RemoveListener<EnoughCurrencyGameEvent>(OnEnoughCurrency);
    }


  ...

    private void Update()
    {
        ...
    }
}