1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0

use crate::families::FamilyHead;
use crate::{Gateway, IdentityKey, MixNode, MixNodeCostParams};
use contracts_common::signing::{
    ContractMessageContent, MessageType, Nonce, SignableMessage, SigningPurpose,
};
use cosmwasm_std::{Addr, Coin};
use serde::Serialize;

pub type SignableMixNodeBondingMsg = SignableMessage<ContractMessageContent<MixnodeBondingPayload>>;
pub type SignableGatewayBondingMsg = SignableMessage<ContractMessageContent<GatewayBondingPayload>>;
pub type SignableFamilyJoinPermitMsg = SignableMessage<FamilyJoinPermit>;

#[derive(Serialize)]
pub struct MixnodeBondingPayload {
    mix_node: MixNode,
    cost_params: MixNodeCostParams,
}

impl MixnodeBondingPayload {
    pub fn new(mix_node: MixNode, cost_params: MixNodeCostParams) -> Self {
        Self {
            mix_node,
            cost_params,
        }
    }
}

impl SigningPurpose for MixnodeBondingPayload {
    fn message_type() -> MessageType {
        MessageType::new("mixnode-bonding")
    }
}

pub fn construct_mixnode_bonding_sign_payload(
    nonce: Nonce,
    sender: Addr,
    proxy: Option<Addr>,
    pledge: Coin,
    mix_node: MixNode,
    cost_params: MixNodeCostParams,
) -> SignableMixNodeBondingMsg {
    let payload = MixnodeBondingPayload::new(mix_node, cost_params);
    let content = ContractMessageContent::new(sender, proxy, vec![pledge], payload);

    SignableMessage::new(nonce, content)
}

#[derive(Serialize)]
pub struct GatewayBondingPayload {
    gateway: Gateway,
}

impl GatewayBondingPayload {
    pub fn new(gateway: Gateway) -> Self {
        Self { gateway }
    }
}

impl SigningPurpose for GatewayBondingPayload {
    fn message_type() -> MessageType {
        MessageType::new("gateway-bonding")
    }
}

pub fn construct_gateway_bonding_sign_payload(
    nonce: Nonce,
    sender: Addr,
    proxy: Option<Addr>,
    pledge: Coin,
    gateway: Gateway,
) -> SignableGatewayBondingMsg {
    let payload = GatewayBondingPayload::new(gateway);
    let content = ContractMessageContent::new(sender, proxy, vec![pledge], payload);

    SignableMessage::new(nonce, content)
}

#[derive(Serialize)]
pub struct FamilyJoinPermit {
    // the granter of this permit
    family_head: FamilyHead,
    // whether the **member** will want to join via the proxy (i.e. vesting contract)
    proxy: Option<Addr>,
    // the actual member we want to permit to join
    member_node: IdentityKey,
}

impl FamilyJoinPermit {
    pub fn new(family_head: FamilyHead, proxy: Option<Addr>, member_node: IdentityKey) -> Self {
        Self {
            family_head,
            proxy,
            member_node,
        }
    }
}

impl SigningPurpose for FamilyJoinPermit {
    fn message_type() -> MessageType {
        MessageType::new("family-join-permit")
    }
}

pub fn construct_family_join_permit(
    nonce: Nonce,
    family_head: FamilyHead,
    proxy: Option<Addr>,
    member_node: IdentityKey,
) -> SignableFamilyJoinPermitMsg {
    let payload = FamilyJoinPermit::new(family_head, proxy, member_node);

    // note: we're NOT wrapping it in `ContractMessageContent` because the family head is not going to be the one
    // sending the message to the contract
    SignableMessage::new(nonce, payload)
}

// TODO: depending on our threat model, we should perhaps extend it to include all _on_behalf methods
// (update: but we trust our vesting contract since its compromise would be even more devastating so there's no need)