diff --git a/cmd/vega/commands/bridge/erc20.go b/cmd/vega/commands/bridge/erc20.go index 89c10d0a238..a89cdcc46c8 100644 --- a/cmd/vega/commands/bridge/erc20.go +++ b/cmd/vega/commands/bridge/erc20.go @@ -38,6 +38,7 @@ type ERC20Cmd struct { AddSigner ERC20AddSignerCmd `command:"add_signer" description:"Create signature to add a new signer to the erc20 bridge"` RemoveSigner ERC20RemoveSignerCmd `command:"remove_signer" description:"Create signature to remove a signer from the erc20 bridge"` + VerifyRemoveSigner ERC20VerifyRemoveSignerCmd `command:"verify_remove_signer" description:"Verify signatures to remove a signer from the erc20 bridge"` SetThreshold ERC20SetThresholdCmd `command:"set_threshold" description:"Create signature to change the threshold of required signature to apply changes to the bridge"` BurnNonce ERC20BurnNonceCmd `command:"burn_nonce" description:"Create signature to burn and existing nonce in order to prevent it to be used on the bridge"` ListAsset ERC20ListAssetCmd `command:"list_asset" description:"Add a new erc20 asset to the erc20 bridge"` @@ -91,6 +92,7 @@ func ERC20() *ERC20Cmd { erc20Cmd = &ERC20Cmd{ AddSigner: ERC20AddSignerCmd{}, RemoveSigner: ERC20RemoveSignerCmd{}, + VerifyRemoveSigner: ERC20VerifyRemoveSignerCmd{}, SetThreshold: ERC20SetThresholdCmd{}, ListAsset: ERC20ListAssetCmd{}, VerifyListAsset: ERC20VerifyListAssetCmd{}, @@ -398,6 +400,46 @@ func (opts *ERC20RemoveSignerCmd) Execute(_ []string) error { return nil } +type ERC20VerifyRemoveSignerCmd struct { + OldSigner string `description:"Ethereum address of signer to remove" long:"old-signer" required:"true"` + Submitter string `description:"Ethereum address of the submitter of the transaction" long:"submitter" required:"true"` + Nonce string `description:"A nonce for this signature" long:"nonce" required:"true"` + Signatures string `description:"The list of signatures from the validators" long:"signatures" required:"true"` +} + +func (opts *ERC20VerifyRemoveSignerCmd) Execute(_ []string) error { + if _, err := flags.NewParser(opts, flags.Default|flags.IgnoreUnknown).Parse(); err != nil { + return err + } + + nonce, overflowed := num.UintFromString(opts.Nonce, 10) + if overflowed { + return errors.New("invalid nonce, needs to be base 10 and not overflow") + } + + if len(opts.Signatures) <= 0 { + return errors.New("missing signatures") + } + + if (len(opts.Signatures)-2)%130 != 0 { + return errors.New("invalid signatures format") + } + + multiSigControl := bridges.NewERC20MultiSigControl(nil, erc20Cmd.ChainID, erc20Cmd.ChainID == "") + signers, err := multiSigControl.VerifyRemoveSigner( + opts.OldSigner, opts.Submitter, nonce, opts.Signatures, + ) + if err != nil { + return fmt.Errorf("unable to verify signature: %w", err) + } + + sort.Strings(signers) + for _, v := range signers { + fmt.Printf("%v\n", v) + } + return nil +} + type ERC20SetThresholdCmd struct { NewThreshold uint16 `description:"The new threshold to be used on the bridge" long:"new-threshold" required:"true"` Submitter string `description:"Ethereum address of the submitter of the transaction" long:"submitter" required:"true"` diff --git a/core/bridges/erc20_multisigcontrol.go b/core/bridges/erc20_multisigcontrol.go index 177c30a14aa..9f40a570f1f 100644 --- a/core/bridges/erc20_multisigcontrol.go +++ b/core/bridges/erc20_multisigcontrol.go @@ -16,6 +16,10 @@ package bridges import ( + "encoding/hex" + "fmt" + + crypto "code.vegaprotocol.io/vega/libs/crypto/signature" "code.vegaprotocol.io/vega/libs/num" "github.com/ethereum/go-ethereum/accounts/abi" @@ -164,10 +168,57 @@ func (e *ERC20MultiSigControl) AddSigner( return sign(e.signer, msg) } +func (e *ERC20MultiSigControl) VerifyRemoveSigner( + oldSigner, submitter string, + nonce *num.Uint, + signatures string, +) ([]string, error) { + msg, err := e.buildRemoveSignerMessage( + oldSigner, submitter, nonce, + ) + if err != nil { + return nil, err + } + + addresses := []string{} + var hexCurrent string + signatures = signatures[2:] + for len(signatures) > 0 { + hexCurrent, signatures = signatures[0:130], signatures[130:] + current, err := hex.DecodeString(hexCurrent) + if err != nil { + return nil, fmt.Errorf("invalid signature format: %w", err) + } + + address, err := crypto.RecoverEthereumAddress(msg, current) + if err != nil { + return nil, fmt.Errorf("error recovering ethereum address: %w", err) + } + + addresses = append(addresses, address.Hex()) + } + + return addresses, nil +} + func (e *ERC20MultiSigControl) RemoveSigner( oldSigner, submitter string, nonce *num.Uint, ) (*SignaturePayload, error) { + msg, err := e.buildRemoveSignerMessage( + oldSigner, submitter, nonce, + ) + if err != nil { + return nil, err + } + + return sign(e.signer, msg) +} + +func (e *ERC20MultiSigControl) buildRemoveSignerMessage( + oldSigner, submitter string, + nonce *num.Uint, +) ([]byte, error) { typAddr, err := abi.NewType("address", "", nil) if err != nil { return nil, err @@ -202,10 +253,7 @@ func (e *ERC20MultiSigControl) RemoveSigner( return nil, err } - msg, err := packScheme(buf, submitter, e.chainID, e.v1) - if err != nil { - return nil, err - } + fmt.Printf("%v - %v - %v\n", submitter, e.chainID, e.v1) - return sign(e.signer, msg) + return packScheme(buf, submitter, e.chainID, e.v1) }