Multisig prover contract

Not used on the XRPL side. XRPL outbound transactions are built by the XRPL Multisig Prover, which builds XRPL-native transactions (Payment, SignerListSet, TicketCreate, TrustSet), manages tickets and the XRP fee reserve, and uses the XRPL SMT\0-prefixed SHA-512-half multi-signing digest. The generic multisig-prover documented here is the template deployed for most other connected amplifier chains.

The prover contract is responsible for transforming gateway messages into a payload that is ready to be sent to the destination gateway. It calls the multisig contract to generate the signature proof and finally encodes both the data and proof so that relayers can take it and send it to the destination chain gateway.

Interface

pub enum ExecuteMsg {
    // Start building a proof that includes specified messages. Permission: Any.
    // Queries the gateway for actual message contents.
    ConstructProof(Vec<CrossChainId>),

    // Triggers a verifier set rotation if the registered set has diverged from the current
    // one by more than `verifier_set_diff_threshold`. Permission: Elevated (admin or governance).
    UpdateVerifierSet,

    // Promotes a previously-prepared NextVerifierSet to be the current set, once a poll on
    // the destination chain's SignersRotated event has confirmed it. Permission: Any.
    ConfirmVerifierSet,

    // Updates the signing threshold used for future verifier sets. The threshold currently
    // in use does not change; the verifier set must be updated and confirmed for the change
    // to take effect. Permission: Governance.
    UpdateSigningThreshold {
        new_signing_threshold: MajorityThreshold,
    },

    // Replaces the contract's admin address. Permission: Governance.
    UpdateAdmin {
        new_admin_address: String,
    },
}

#[derive(QueryResponses)]
pub enum QueryMsg {
    // Returns the current proof for a given multisig session, including the encoded
    // execute_data once signing completes.
    #[returns(ProofResponse)]
    Proof { multisig_session_id: Uint64 },

    // Returns the current active verifier set, or None if uninitialized.
    #[returns(Option<VerifierSetResponse>)]
    CurrentVerifierSet,

    // Returns the next (pending) verifier set, or None if no rotation is in progress.
    #[returns(Option<VerifierSetResponse>)]
    NextVerifierSet,
}

pub enum ProofStatus {
    Pending,
    Completed { execute_data: HexBinary }, // encoded data and proof sent to destination gateway
}

pub struct ProofResponse {
    pub multisig_session_id: Uint64,
    pub message_ids: Vec<CrossChainId>,
    pub payload: Payload,
    pub status: ProofStatus,
}

pub struct VerifierSetResponse {
    pub id: String,
    pub verifier_set: multisig::verifier_set::VerifierSet,
}

Events

pub enum Event {
    ProofUnderConstruction {
        destination_chain: ChainName,
        payload_id: PayloadId,
        multisig_session_id: Uint64,
        msg_ids: Vec<CrossChainId>,
    },
}

Proof construction graph

graph TD

r[Relayer]
subgraph Axelar
b[Prover]
g[Gateway]
m[Multisig]
end
s[Signer]

r--ConstructProof-->b
b--OutgoingMessages-->g
g-.->b
b--StartSigningSession-->m
b--Multisig-->m
s--SubmitSignature-->m

Proof construction sequence diagram

sequenceDiagram
autonumber
participant Relayer
box LightYellow Axelar
participant Prover
participant Gateway
participant Multisig
end
actor Signers

Relayer->>+Prover: ExecuteMsg::ConstructProof
alt payload not created previously
  Prover->>+Gateway: QueryMsg::OutgoingMessages
  Gateway-->>-Prover: query result
  alt newer VerifierSet exists
    Prover->>Prover: update next VerifierSet
  end
else previously created payload found
  Prover->>Prover: retrieves payload from storage
end
Prover->>+Multisig: ExecuteMsg::StartSigningSession
Multisig-->>Signers: emit SigningStarted event
Multisig->>-Prover: reply with session ID
Prover-->>Relayer: emit ProofUnderConstruction event
deactivate Prover
loop Collect signatures
	Signers->>+Multisig: signature collection
end
Multisig-->>-Relayer: emit SigningCompleted event
Relayer->>+Prover: QueryMsg::Proof
Prover->>+Multisig: QueryMsg::Multisig
Multisig-->>-Prover: reply with status, current signatures vector and snapshot
Prover-->>-Relayer: returns ProofResponse
  1. Relayer asks Prover contract to construct proof providing a list of cross chain ids.
  2. If no payload for the given messages was previously created, it queries the gateway for the messages to construct it.
  3. With the retrieved messages, the Prover contract transforms them into a payload digest that needs to be signed by the multisig.
  4. If a previous payload was found for the given message ids, the Prover retrieves it from storage instead of querying the gateway and building it again.
  5. The Multisig contract is called asking to sign the payload digest.
  6. Multisig emits event SigningStarted indicating a new multisig session has started.
  7. Multisig triggers a reply in Prover returning the newly created session ID which is then stored with the payload for reference.
  8. Prover contract emits event ProofUnderConstruction which includes the ID of the proof being constructed.
  9. Signers submit their signatures until threshold is reached.
  10. Multisig emits event indicating the multisig session has been completed.
  11. Relayer queries Prover for the proof, using the multisig session ID.
  12. Prover queries Multisig for the multisig session.
  13. Multisig replies with the multisig state, the list of collected signatures so far and the snapshot of participants.
  14. If the Multisig state is Completed, the Prover finalizes constructing the proof and returns the ProofResponse struct which includes the proof itself and the data to be sent to the destination gateway. If the state is not completed, the Prover returns the ProofResponse struct with the status field set to Pending.

Update and confirm VerifierSet graph

graph TD

r[Relayer]
subgraph Axelar
b[Prover]
v[Voting Verifier]
m[Multisig]
s[Service Registry]
end

r--UpdateVerifierSet-->b
b--ActiveVerifiers-->s
b--RegisterVerifierSet-->m
r--ConfirmVerifierSet-->b
b--VerifierSetStatus-->v

Update and confirm VerifierSet sequence diagram

sequenceDiagram
autonumber
participant External Gateway
participant Relayer
box LightYellow Axelar
participant Prover
participant Service Registry
participant Voting Verifier
participant Multisig
end
actor Verifier
actor Signers
Relayer->>+Prover: ExecuteMsg::UpdateVerifierSet
alt existing VerifierSet stored
  Prover->>+Service Registry: QueryMsg::ActiveVerifiers
  Service Registry-->>-Prover: save new VerifierSet as next VerifierSet
  Prover->>+Multisig: ExecuteMsg::StartSigningSession (for rotate signers message)
  loop Collect signatures
	  Signers->>+Multisig: signature collection
  end
end
Relayer->>+Prover: QueryMsg::Proof
Prover-->>-Relayer: returns ProofResponse (new verifier set signed by old verifier set)
Relayer-->>External Gateway: send new VerifierSet to the gateway, signed by old VerifierSet
External Gateway-->>+Relayer: emit SignersRotated event
Relayer->>+Voting Verifier: ExecuteMsg::VerifyVerifierSet
Verifier->>+External Gateway: look up SignersRotated event, verify event matches verifier set in poll
Verifier->>+Voting Verifier: ExecuteMsg::Vote
Relayer->>+Voting Verifier: ExecuteMsg::EndPoll
Relayer->>+Prover: ExecuteMsg::ConfirmVerifierSet
Prover->>+Voting Verifier: QueryMsg::VerifierSetStatus
Voting Verifier-->>-Prover: true
Prover->>+Multisig: ExecuteMsg::RegisterVerifierSet
  1. The Relayer calls Prover to update the VerifierSet.
  2. The Prover calls Service Registry to get a VerifierSet.
  3. If a newer VerifierSet was found, the new VerifierSet is stored as the next VerifierSet. The prover creates payload for the new verifier set.
  4. The Multisig contract is called asking to sign the binary message.
  5. Signers submit their signatures until threshold is reached.
  6. Relayer queries Prover for the proof, using the multisig session id.
  7. If the Multisig state is Completed, the Prover finalizes constructing the proof and returns the ProofResponse struct which includes the proof itself and the data to be sent to the External Chain's gateway. If the state is not completed, the Prover returns the ProofResponse struct with the status field set to Pending.
  8. Relayer sends proof and data to the External Gateway.
  9. The gateway on the External Gateway processes the commands in the data and emits event SignersRotated.
  10. The event SignersRotated picked up by the Relayer, the Relayer calls Voting Verifier to create a poll.
  11. The Verifiers see the PollStarted event and look up the SignersRotated event on the External Gateway and verify the event matches the verifier set in the poll.
  12. The Verifiers then vote on whether the event matches the verifiers or not.
  13. The Relayer calls the Voting Verifier to end the poll and emit PollEnded event.
  14. Once the poll is completed, the Relayer calls the Prover to confirm if the VerifierSet was updated.
  15. The Prover queries the Voting Verifier to check if the VerifierSet is confirmed.
  16. The Voting Verifier returns that the VerifierSet is confirmed.
  17. The Prover stores the VerifierSet in itself and in Multisig.