0

I'm having some trouble getting events and emit to work as I expect in my archetype contract. I must be messing something up with the syntax. I have no problem if I am emitting a single value in the event, but I want to emit several values.

I have:

asset challengers_big_map to big_map {
  challenger_id : address;
  chosen_fighter_id : nat;
  fightHistory : list<fight_record> = [];
  fightCount: nat = 0
}

entry register_challenger(fighter_id_requested : nat) {
  require {
    register_challenger_r1: fighters_map.contains(fighter_id_requested) otherwise "There is no fighter with the requested id.";
  }
  effect {
  challengers_big_map.add_update( caller, {
    chosen_fighter_id = fighter_id_requested
  });
  const this_new_challenger_record ?= challengers_big_map[caller];
  emit<new_challenger_registered>({
      caller;
      this_new_challenger_record.chosen_fighter_id;
      this_new_challenger_record.fightHistory;
      this_new_challenger_record.fightCount
      })
  }

event new_challenger_registered {
  new_challenger_address: address;
  new_chosen_fighter_id: nat;
  new_fightHistory : list<fight_record> = [];
  new_fightCount: nat
}

If I only emit the caller address, I get no error. But I can't figure out how to emit multiple items - even if I package them into a single record.

The error message in my frontend console:

battlemaster.ts:18 Uncaught (in promise) TypeError: Cannot read properties of undefined (reading '0')
    at new_challenger_registered.from_mich (battlemaster.ts:18:89)
    at battlemaster.ts:265:58
    at Object.process (battlemaster.ts:266:21)
    at @completium_event-listener.js?v=f4b1b41d:2513:15
    at Array.forEach (<anonymous>)
    at @completium_event-listener.js?v=f4b1b41d:2512:14
    at Generator.next (<anonymous>)
    at fulfilled (@completium_event-listener.js?v=f4b1b41d:2417:28)

Extract from the dapp bindings where the error is found - the line with the error is the "static from mich.... " line toward the end of the following excerpt

export class new_challenger_registered implements att.ArchetypeType {
    constructor(public new_challenger_address: att.Address, public new_chosen_fighter_id: att.Nat, public new_fightHistory: Array<fight_record>, public new_fightCount: att.Nat) { }
    toString(): string {
        return JSON.stringify(this, null, 2);
    }
    to_mich(): att.Micheline {
        return att.pair_to_mich([this.new_challenger_address.to_mich(), this.new_chosen_fighter_id.to_mich(), att.list_to_mich(this.new_fightHistory, x => {
                return x.to_mich();
            }), this.new_fightCount.to_mich()]);
    }
    equals(v: new_challenger_registered): boolean {
        return att.micheline_equals(this.to_mich(), v.to_mich());
    }
    static from_mich(input: att.Micheline): new_challenger_registered {
        return new new_challenger_registered(att.Address.from_mich((input as att.Mpair).args[0]), att.Nat.from_mich((input as att.Mpair).args[1]), att.mich_to_list((input as att.Mpair).args[2], x => { return fight_record.from_mich(x); }), att.Nat.from_mich((input as att.Mpair).args[3]));
    }

Help appreciated! Thanks


EDIT + HACKY FIX: The problem, as best I can tell, is that the from_mich static in the new_challenger_registered class in the dapp bindings expects an Mpair but recieves an Array of micheline objects in the form of Mstring, Mint etc (see the achetype types library). My current workaround is to edit the event classes directly in the bindings so if they receieve an array of this type the process it correctly, until this is addressed.

Example of a working class in the bindings:

export class new_challenger_registered implements att.ArchetypeType {
    constructor(public new_challenger_address: att.Address, public new_challenger_fighter_id: att.Nat, public new_challenger_fight_history: Array<fight_record>, public new_challenger_fight_count: att.Nat, public new_challenger_c_mode: att.Nat) { }
    toString(): string {
        return JSON.stringify(this, null, 2);
    }
    to_mich(): att.Micheline {
        return att.pair_to_mich([this.new_challenger_address.to_mich(), this.new_challenger_fighter_id.to_mich(), att.list_to_mich(this.new_challenger_fight_history, x => {
                return x.to_mich();
            }), this.new_challenger_fight_count.to_mich(), this.new_challenger_c_mode.to_mich()]);
    }
    equals(v: new_challenger_registered): boolean {
        return att.micheline_equals(this.to_mich(), v.to_mich());
    }
    static from_mich(input: att.Micheline): new_challenger_registered {
        let args: att.Micheline[];
        if (Array.isArray(input)) {
            args = input;
        } else {
            args = (input as att.Mpair).args;
        }

        const new_challenger_address = att.Address.from_mich(args[0]);
        const new_challenger_fighter_id = att.Nat.from_mich(args[1]);
        const new_challenger_fight_history = att.mich_to_list(args[2], x => fight_record.from_mich(x));
        const new_challenger_fight_count = att.Nat.from_mich(args[3]);
        const new_challenger_c_mode = att.Nat.from_mich(args[4]);

        return new new_challenger_registered(
            new_challenger_address,
            new_challenger_fighter_id,
            new_challenger_fight_history,
            new_challenger_fight_count,
            new_challenger_c_mode
        );
    }
}

FURTHER EDIT:

The completium team have let me know that this issue is caused by inconsistent payload returned by the octez-client transfer command. Basically, the problem is beyond the scope of completium. They recommend avoiding the use of tuples or records (only use simple types) in events until this is fixed.

1 Answer 1

0

There's a slight mismatch in your event parameter matching, this should work:

emit<new_challenger_registered>({
  caller;  // This should be new_challenger_address
  this_new_challenger_record.chosen_fighter_id;
  this_new_challenger_record.fightHistory;
  this_new_challenger_record.fightCount
})

event new_challenger_registered {
  new_challenger_address: address;
  new_chosen_fighter_id: nat;
  new_fightHistory : list<fight_record> = [];
  new_fightCount: nat
}

Then update your emit statement to match the event parameters

emit<new_challenger_registered>({
  new_challenger_address: caller;
  new_chosen_fighter_id: this_new_challenger_record.chosen_fighter_id;
  new_fightHistory: this_new_challenger_record.fightHistory;
  new_fightCount: this_new_challenger_record.fightCount
})

I hope this helps

4
  • Thanks for the response, but in this case the caller address is the new_challenger_address, so that is not an error. Also, if I try to structure the emit properties like that (key colon entry semicolon) I get a linting error and cannot compile - I think it has to just be the list of entries seperated by semicolons.
    – Grum
    Commented Jun 29 at 10:39
  • Did you try separating the list of entries?
    – Amethyst
    Commented Jul 1 at 0:34
  • I'm not sure exactly what you mean by that, but I have a similar problem with other events as well that have a different structure. I've now posted my "fix" as an edit to the original post. I don't think it really counts as a solution so I didn't post it as a seperate answer My current guess is that the issue is with the way the bindings are generated.
    – Grum
    Commented Jul 1 at 2:11
  • 1
    Good to know you were able to solve your problem then.
    – Amethyst
    Commented Jul 1 at 22:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.