From 48d2c7077c598f3195a3f0a73dcda6d9838e08d1 Mon Sep 17 00:00:00 2001 From: failfmi Date: Thu, 22 Apr 2021 11:38:13 +0300 Subject: [PATCH 01/14] feat: sign and store router address Signed-off-by: failfmi --- app/domain/service/contracts.go | 2 + app/domain/service/transfers.go | 13 ++--- app/model/auth-message/auth-message.go | 7 ++- app/model/message/message.go | 13 ++--- app/model/transfer/transfer.go | 4 +- app/persistence/entity/transfer.go | 1 + app/persistence/transfer/transfer.go | 1 + app/process/recovery/recovery.go | 3 +- app/process/watcher/transfer/watcher.go | 2 +- app/services/contracts/service.go | 3 +- app/services/messages/service.go | 5 +- app/services/transfers/service.go | 16 +++--- e2e/e2e_test.go | 8 +-- e2e/service/database/service.go | 8 +-- e2e/setup/config.go | 2 + proto/topic_eth_signature_message.pb.go | 68 ++++++++++++++----------- proto/topic_eth_signature_message.proto | 11 ++-- 17 files changed, 98 insertions(+), 69 deletions(-) diff --git a/app/domain/service/contracts.go b/app/domain/service/contracts.go index cb5366e12..0ee77010d 100644 --- a/app/domain/service/contracts.go +++ b/app/domain/service/contracts.go @@ -25,6 +25,8 @@ import ( // Contracts interface is implemented by the Contracts Service providing business logic access to the Ethereum SmartContracts and other related utility functions type Contracts interface { + // Address returns the address of the contract instance + Address() common.Address // GetMembers returns the array of bridge members currently set in the Bridge contract GetMembers() []string // IsMember returns true/false depending on whether the provided address is a Bridge member or not diff --git a/app/domain/service/transfers.go b/app/domain/service/transfers.go index cff3ac629..996b95f96 100644 --- a/app/domain/service/transfers.go +++ b/app/domain/service/transfers.go @@ -41,10 +41,11 @@ type Transfers interface { } type TransferData struct { - Recipient string `json:"recipient"` - Amount string `json:"amount"` - NativeAsset string `json:"nativeAsset"` - WrappedAsset string `json:"wrappedAsset"` - Signatures []string `json:"signatures"` - Majority bool `json:"majority"` + Recipient string `json:"recipient"` + RouterAddress string `json:"routerAddress"` + Amount string `json:"amount"` + NativeAsset string `json:"nativeAsset"` + WrappedAsset string `json:"wrappedAsset"` + Signatures []string `json:"signatures"` + Majority bool `json:"majority"` } diff --git a/app/model/auth-message/auth-message.go b/app/model/auth-message/auth-message.go index ea1526bad..a813f2c4b 100644 --- a/app/model/auth-message/auth-message.go +++ b/app/model/auth-message/auth-message.go @@ -25,7 +25,7 @@ import ( // EncodeBytesFrom returns the array of bytes representing an // authorisation signature ready to be signed by Ethereum Private Key -func EncodeBytesFrom(txId, wrappedAsset, receiverEthAddress, amount string) ([]byte, error) { +func EncodeBytesFrom(txId, routerAddress, wrappedAsset, receiverEthAddress, amount string) ([]byte, error) { args, err := generateArguments() if err != nil { return nil, err @@ -35,7 +35,7 @@ func EncodeBytesFrom(txId, wrappedAsset, receiverEthAddress, amount string) ([]b return nil, err } - bytesToHash, err := args.Pack([]byte(txId), common.HexToAddress(wrappedAsset), common.HexToAddress(receiverEthAddress), amountBn) + bytesToHash, err := args.Pack([]byte(txId), common.HexToAddress(routerAddress), common.HexToAddress(wrappedAsset), common.HexToAddress(receiverEthAddress), amountBn) return keccak(bytesToHash), nil } @@ -65,6 +65,9 @@ func generateArguments() (abi.Arguments, error) { { Type: addressType, }, + { + Type: addressType, + }, { Type: uint256Type, }}, nil diff --git a/app/model/message/message.go b/app/model/message/message.go index 484731f07..f31928d23 100644 --- a/app/model/message/message.go +++ b/app/model/message/message.go @@ -64,13 +64,14 @@ func FromString(data, ts string) (*Message, error) { } // NewSignatureMessage instantiates Signature Message struct ready for submission to the Bridge Topic -func NewSignature(transferID, receiver, amount, signature, wrappedAsset string) *Message { +func NewSignature(transferID, routerAddress, receiver, amount, signature, wrappedAsset string) *Message { topicMsg := &model.TopicEthSignatureMessage{ - TransferID: transferID, - Receiver: receiver, - Amount: amount, - Signature: signature, - WrappedAsset: wrappedAsset, + TransferID: transferID, + RouterAddress: routerAddress, + Receiver: receiver, + Amount: amount, + Signature: signature, + WrappedAsset: wrappedAsset, } return &Message{topicMsg} } diff --git a/app/model/transfer/transfer.go b/app/model/transfer/transfer.go index 3b8d6471f..061ae396a 100644 --- a/app/model/transfer/transfer.go +++ b/app/model/transfer/transfer.go @@ -23,15 +23,17 @@ type Transfer struct { Amount string NativeAsset string WrappedAsset string + RouterAddress string } // New instantiates Transfer struct ready for submission to the handler -func New(txId, receiver, nativeAsset, wrappedAsset, amount string) *Transfer { +func New(txId, receiver, nativeAsset, wrappedAsset, amount, routerAddress string) *Transfer { return &Transfer{ TransactionId: txId, Receiver: receiver, Amount: amount, NativeAsset: nativeAsset, WrappedAsset: wrappedAsset, + RouterAddress: routerAddress, } } diff --git a/app/persistence/entity/transfer.go b/app/persistence/entity/transfer.go index 29056bd34..355027b00 100644 --- a/app/persistence/entity/transfer.go +++ b/app/persistence/entity/transfer.go @@ -22,6 +22,7 @@ type Transfer struct { NativeAsset string WrappedAsset string Amount string + RouterAddress string Status string SignatureMsgStatus string Messages []Message `gorm:"foreignKey:TransferID"` diff --git a/app/persistence/transfer/transfer.go b/app/persistence/transfer/transfer.go index c34bcf888..972acd4e5 100644 --- a/app/persistence/transfer/transfer.go +++ b/app/persistence/transfer/transfer.go @@ -145,6 +145,7 @@ func (tr Repository) create(ct *model.Transfer, status string) (*entity.Transfer Status: status, NativeAsset: ct.NativeAsset, WrappedAsset: ct.WrappedAsset, + RouterAddress: ct.RouterAddress, } err := tr.dbClient.Create(tx).Error diff --git a/app/process/recovery/recovery.go b/app/process/recovery/recovery.go index 10f050ec0..7a8252f3e 100644 --- a/app/process/recovery/recovery.go +++ b/app/process/recovery/recovery.go @@ -229,7 +229,8 @@ func (r Recovery) processUnfinishedOperations() error { t.Receiver, t.NativeAsset, t.WrappedAsset, - t.Amount) + t.Amount, + r.contracts.Address().String()) err = r.transfers.ProcessTransfer(*transferMsg) if err != nil { diff --git a/app/process/watcher/transfer/watcher.go b/app/process/watcher/transfer/watcher.go index e0792e97f..09e11dcfc 100644 --- a/app/process/watcher/transfer/watcher.go +++ b/app/process/watcher/transfer/watcher.go @@ -159,7 +159,7 @@ func (ctw Watcher) processTransaction(tx mirror_node.Transaction, q *pair.Queue) return } - transferMessage := transfer.New(tx.TransactionID, ethAddress, nativeAsset, wrappedAsset, amount) + transferMessage := transfer.New(tx.TransactionID, ethAddress, nativeAsset, wrappedAsset, amount, ctw.contractService.Address().String()) q.Push(&pair.Message{Payload: transferMessage}) } diff --git a/app/services/contracts/service.go b/app/services/contracts/service.go index d0c888f09..9b9840306 100644 --- a/app/services/contracts/service.go +++ b/app/services/contracts/service.go @@ -74,7 +74,8 @@ func (bsc *Service) ToNative(wrappedAsset common.Address) (string, error) { return string(common.TrimRightZeroes(native)), nil } -func (bsc *Service) GetBridgeContractAddress() common.Address { +// Address returns the address of the contract instance +func (bsc *Service) Address() common.Address { return bsc.address } diff --git a/app/services/messages/service.go b/app/services/messages/service.go index 9c02ba5ff..01b4e70d4 100644 --- a/app/services/messages/service.go +++ b/app/services/messages/service.go @@ -106,7 +106,8 @@ func (ss *Service) SanityCheckSignature(topicMessage message.Message) (bool, err return false, err } - match := t.Receiver == topicMessage.Receiver && + match := topicMessage.Receiver == t.Receiver && + topicMessage.RouterAddress == t.RouterAddress && topicMessage.Amount == signedAmount && topicMessage.WrappedAsset == wrappedAsset return match, nil @@ -115,7 +116,7 @@ func (ss *Service) SanityCheckSignature(topicMessage message.Message) (bool, err // ProcessSignature processes the signature message, verifying and updating all necessary fields in the DB func (ss *Service) ProcessSignature(tsm message.Message) error { // Parse incoming message - authMsgBytes, err := auth_message.EncodeBytesFrom(tsm.TransferID, tsm.WrappedAsset, tsm.Receiver, tsm.Amount) + authMsgBytes, err := auth_message.EncodeBytesFrom(tsm.TransferID, tsm.RouterAddress, tsm.WrappedAsset, tsm.Receiver, tsm.Amount) if err != nil { ss.logger.Errorf("[%s] - Failed to encode the authorisation signature. Error: [%s]", tsm.TransferID, err) return err diff --git a/app/services/transfers/service.go b/app/services/transfers/service.go index 94d07c31d..b2d8eb0c0 100644 --- a/app/services/transfers/service.go +++ b/app/services/transfers/service.go @@ -194,7 +194,7 @@ func (ts *Service) ProcessTransfer(tm model.Transfer) error { wrappedAmount := strconv.FormatInt(remainder, 10) - authMsgHash, err := auth_message.EncodeBytesFrom(tm.TransactionId, tm.WrappedAsset, tm.Receiver, wrappedAmount) + authMsgHash, err := auth_message.EncodeBytesFrom(tm.TransactionId, tm.RouterAddress, tm.WrappedAsset, tm.Receiver, wrappedAmount) if err != nil { ts.logger.Errorf("[%s] - Failed to encode the authorisation signature. Error: [%s]", tm.TransactionId, err) return err @@ -209,6 +209,7 @@ func (ts *Service) ProcessTransfer(tm model.Transfer) error { signatureMessage := message.NewSignature( tm.TransactionId, + tm.RouterAddress, tm.Receiver, wrappedAmount, signature, @@ -352,11 +353,12 @@ func (ts *Service) TransferData(txId string) (service.TransferData, error) { reachedMajority := len(t.Messages) >= requiredSigCount return service.TransferData{ - Recipient: t.Receiver, - Amount: signedAmount, - NativeAsset: t.NativeAsset, - WrappedAsset: t.WrappedAsset, - Signatures: signatures, - Majority: reachedMajority, + Recipient: t.Receiver, + RouterAddress: t.RouterAddress, + Amount: signedAmount, + NativeAsset: t.NativeAsset, + WrappedAsset: t.WrappedAsset, + Signatures: signatures, + Majority: reachedMajority, }, nil } diff --git a/e2e/e2e_test.go b/e2e/e2e_test.go index 44080570f..6bec6216e 100644 --- a/e2e/e2e_test.go +++ b/e2e/e2e_test.go @@ -87,7 +87,7 @@ func Test_HBAR(t *testing.T) { }, t) // Step 8 - Verify Database Records - verifyDatabaseRecords(setupEnv.DbValidation, expectedTxRecord, strconv.FormatInt(mintAmount, 10), receivedSignatures, t) + verifyDatabaseRecords(setupEnv.DbValidation, expectedTxRecord, setupEnv.RouterAddress.String(), strconv.FormatInt(mintAmount, 10), receivedSignatures, t) } func Test_E2E_Token_Transfer(t *testing.T) { @@ -128,7 +128,7 @@ func Test_E2E_Token_Transfer(t *testing.T) { }, t) // Step 8 - Verify Database Records - verifyDatabaseRecords(setupEnv.DbValidation, expectedTxRecord, strconv.FormatInt(mintAmount, 10), receivedSignatures, t) + verifyDatabaseRecords(setupEnv.DbValidation, expectedTxRecord, setupEnv.RouterAddress.String(), strconv.FormatInt(mintAmount, 10), receivedSignatures, t) } func submitMintTransaction(setupEnv *setup.Setup, transactionResponse hedera.TransactionResponse, transactionData *service.TransferData, tokenAddress *common.Address, t *testing.T) string { @@ -223,8 +223,8 @@ func verifyTransferFromValidatorAPI(setupEnv *setup.Setup, txResponse hedera.Tra return transactionData, tokenAddress } -func verifyDatabaseRecords(dbValidation *database.Service, expectedRecord *entity.Transfer, mintAmount string, signatures []string, t *testing.T) { - exist, err := dbValidation.VerifyDatabaseRecords(expectedRecord, mintAmount, signatures) +func verifyDatabaseRecords(dbValidation *database.Service, expectedRecord *entity.Transfer, routerAddress, mintAmount string, signatures []string, t *testing.T) { + exist, err := dbValidation.VerifyDatabaseRecords(expectedRecord, routerAddress, mintAmount, signatures) if err != nil { t.Fatalf("[%s] - Verification of database records failed - Error: [%s].", expectedRecord.TransactionID, err) } diff --git a/e2e/service/database/service.go b/e2e/service/database/service.go index 47dbbf0d4..10c7b224b 100644 --- a/e2e/service/database/service.go +++ b/e2e/service/database/service.go @@ -39,7 +39,7 @@ func NewService(dbConfigs []config.Database) *Service { } } -func (s *Service) VerifyDatabaseRecords(expectedTransferRecord *entity.Transfer, mintAmount string, signatures []string) (bool, error) { +func (s *Service) VerifyDatabaseRecords(expectedTransferRecord *entity.Transfer, routerAddress, mintAmount string, signatures []string) (bool, error) { valid, record, err := s.validTransactionRecord(expectedTransferRecord) if err != nil { return false, err @@ -48,7 +48,7 @@ func (s *Service) VerifyDatabaseRecords(expectedTransferRecord *entity.Transfer, return false, nil } - valid, err = s.validSignatureMessages(record, mintAmount, signatures) + valid, err = s.validSignatureMessages(record, routerAddress, mintAmount, signatures) if err != nil { return false, err } @@ -71,10 +71,10 @@ func (s *Service) validTransactionRecord(expectedTransferRecord *entity.Transfer return true, expectedTransferRecord, nil } -func (s *Service) validSignatureMessages(record *entity.Transfer, mintAmount string, signatures []string) (bool, error) { +func (s *Service) validSignatureMessages(record *entity.Transfer, routerAddress, mintAmount string, signatures []string) (bool, error) { var expectedMessageRecords []entity.Message - authMsgBytes, err := auth_message.EncodeBytesFrom(record.TransactionID, record.WrappedAsset, record.Receiver, mintAmount) + authMsgBytes, err := auth_message.EncodeBytesFrom(record.TransactionID, routerAddress, record.WrappedAsset, record.Receiver, mintAmount) if err != nil { s.logger.Errorf("[%s] - Failed to encode the authorisation signature. Error: [%s]", record.TransactionID, err) return false, err diff --git a/e2e/setup/config.go b/e2e/setup/config.go index 8c507f3f7..b8b3a689f 100644 --- a/e2e/setup/config.go +++ b/e2e/setup/config.go @@ -83,6 +83,7 @@ type Setup struct { Receiver common.Address BridgeAccount hederaSDK.AccountID SenderAccount hederaSDK.AccountID + RouterAddress common.Address TopicID hederaSDK.TopicID TokenID hederaSDK.TokenID FeePercentage int64 @@ -141,6 +142,7 @@ func newSetup(config Config) (*Setup, error) { FeePercentage: config.Hedera.FeePercentage, Members: members, Clients: clients, + RouterAddress: common.HexToAddress(config.Ethereum.RouterContractAddress), DbValidation: db_validation.NewService(config.Hedera.DbValidationProps), Receiver: common.HexToAddress(clients.Signer.Address()), }, nil diff --git a/proto/topic_eth_signature_message.pb.go b/proto/topic_eth_signature_message.pb.go index bc15f07bc..70dc0ca4c 100644 --- a/proto/topic_eth_signature_message.pb.go +++ b/proto/topic_eth_signature_message.pb.go @@ -26,11 +26,12 @@ type TopicEthSignatureMessage struct { unknownFields protoimpl.UnknownFields TransferID string `protobuf:"bytes,1,opt,name=transferID,proto3" json:"transferID,omitempty"` // The transaction Id of the initial Hedera Transfer - Receiver string `protobuf:"bytes,2,opt,name=receiver,proto3" json:"receiver,omitempty"` // The receiver of the initial Hedera Transfer Memo - Amount string `protobuf:"bytes,3,opt,name=amount,proto3" json:"amount,omitempty"` // The amount of the initial Hedera Transfer - Signature string `protobuf:"bytes,4,opt,name=signature,proto3" json:"signature,omitempty"` // The signature of the validator - WrappedAsset string `protobuf:"bytes,5,opt,name=wrappedAsset,proto3" json:"wrappedAsset,omitempty"` // The wrapped eth token - TransactionTimestamp int64 `protobuf:"varint,6,opt,name=transactionTimestamp,proto3" json:"transactionTimestamp,omitempty"` // The timestamp of the Hedera Transfer + RouterAddress string `protobuf:"bytes,2,opt,name=routerAddress,proto3" json:"routerAddress,omitempty"` // The router address to which the message will be submitted + WrappedAsset string `protobuf:"bytes,3,opt,name=wrappedAsset,proto3" json:"wrappedAsset,omitempty"` // The wrapped eth token + Receiver string `protobuf:"bytes,4,opt,name=receiver,proto3" json:"receiver,omitempty"` // The receiver of the initial Hedera Transfer Memo + Amount string `protobuf:"bytes,5,opt,name=amount,proto3" json:"amount,omitempty"` // The amount of the initial Hedera Transfer + Signature string `protobuf:"bytes,6,opt,name=signature,proto3" json:"signature,omitempty"` // The signature of the validator + TransactionTimestamp int64 `protobuf:"varint,7,opt,name=transactionTimestamp,proto3" json:"transactionTimestamp,omitempty"` // The timestamp of the Hedera Transfer } func (x *TopicEthSignatureMessage) Reset() { @@ -72,6 +73,20 @@ func (x *TopicEthSignatureMessage) GetTransferID() string { return "" } +func (x *TopicEthSignatureMessage) GetRouterAddress() string { + if x != nil { + return x.RouterAddress + } + return "" +} + +func (x *TopicEthSignatureMessage) GetWrappedAsset() string { + if x != nil { + return x.WrappedAsset + } + return "" +} + func (x *TopicEthSignatureMessage) GetReceiver() string { if x != nil { return x.Receiver @@ -93,13 +108,6 @@ func (x *TopicEthSignatureMessage) GetSignature() string { return "" } -func (x *TopicEthSignatureMessage) GetWrappedAsset() string { - if x != nil { - return x.WrappedAsset - } - return "" -} - func (x *TopicEthSignatureMessage) GetTransactionTimestamp() int64 { if x != nil { return x.TransactionTimestamp @@ -112,26 +120,28 @@ var File_topic_eth_signature_message_proto protoreflect.FileDescriptor var file_topic_eth_signature_message_proto_rawDesc = []byte{ 0x0a, 0x21, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x5f, 0x65, 0x74, 0x68, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x12, 0x05, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xe4, 0x01, 0x0a, 0x18, 0x54, + 0x6f, 0x74, 0x6f, 0x12, 0x05, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x8a, 0x02, 0x0a, 0x18, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x45, 0x74, 0x68, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x72, 0x61, - 0x6e, 0x73, 0x66, 0x65, 0x72, 0x49, 0x44, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x63, 0x65, 0x69, - 0x76, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x63, 0x65, 0x69, - 0x76, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x73, - 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, - 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x77, 0x72, 0x61, - 0x70, 0x70, 0x65, 0x64, 0x41, 0x73, 0x73, 0x65, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0c, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x64, 0x41, 0x73, 0x73, 0x65, 0x74, 0x12, 0x32, 0x0a, - 0x14, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x69, 0x6d, 0x65, - 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x14, 0x74, 0x72, 0x61, - 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, - 0x70, 0x42, 0x38, 0x5a, 0x36, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, - 0x6c, 0x69, 0x6d, 0x65, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x2f, 0x68, 0x65, 0x64, 0x65, 0x72, 0x61, - 0x2d, 0x65, 0x74, 0x68, 0x2d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x2d, 0x76, 0x61, 0x6c, 0x69, - 0x64, 0x61, 0x74, 0x6f, 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x33, + 0x6e, 0x73, 0x66, 0x65, 0x72, 0x49, 0x44, 0x12, 0x24, 0x0a, 0x0d, 0x72, 0x6f, 0x75, 0x74, 0x65, + 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, + 0x72, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x22, 0x0a, + 0x0c, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x64, 0x41, 0x73, 0x73, 0x65, 0x74, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0c, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x64, 0x41, 0x73, 0x73, 0x65, + 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x12, 0x16, 0x0a, + 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, + 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, + 0x72, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, + 0x75, 0x72, 0x65, 0x12, 0x32, 0x0a, 0x14, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x07, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x14, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x42, 0x38, 0x5a, 0x36, 0x67, 0x69, 0x74, 0x68, 0x75, + 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x69, 0x6d, 0x65, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x2f, + 0x68, 0x65, 0x64, 0x65, 0x72, 0x61, 0x2d, 0x65, 0x74, 0x68, 0x2d, 0x62, 0x72, 0x69, 0x64, 0x67, + 0x65, 0x2d, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/proto/topic_eth_signature_message.proto b/proto/topic_eth_signature_message.proto index 7a95b7e7b..6c013842f 100644 --- a/proto/topic_eth_signature_message.proto +++ b/proto/topic_eth_signature_message.proto @@ -6,9 +6,10 @@ option go_package = "github.com/limechain/hedera-eth-bridge-validator/proto"; message TopicEthSignatureMessage { string transferID = 1; // The transaction Id of the initial Hedera Transfer - string receiver = 2; // The receiver of the initial Hedera Transfer Memo - string amount = 3; // The amount of the initial Hedera Transfer - string signature = 4; // The signature of the validator - string wrappedAsset = 5; // The wrapped eth token - int64 transactionTimestamp = 6; // The timestamp of the Hedera Transfer + string routerAddress = 2; // The router address to which the message will be submitted + string wrappedAsset = 3; // The wrapped eth token + string receiver = 4; // The receiver of the initial Hedera Transfer Memo + string amount = 5; // The amount of the initial Hedera Transfer + string signature = 6; // The signature of the validator + int64 transactionTimestamp = 7; // The timestamp of the Hedera Transfer } \ No newline at end of file From f97bda1c836a68a6a4b4054161bceb1b42075bac Mon Sep 17 00:00:00 2001 From: failfmi Date: Fri, 23 Apr 2021 10:29:48 +0300 Subject: [PATCH 02/14] fix: transfer data check Signed-off-by: failfmi --- app/persistence/transfer/transfer.go | 14 +++++++++++--- app/services/transfers/service.go | 4 ++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/app/persistence/transfer/transfer.go b/app/persistence/transfer/transfer.go index 972acd4e5..3193242d9 100644 --- a/app/persistence/transfer/transfer.go +++ b/app/persistence/transfer/transfer.go @@ -57,13 +57,21 @@ func (tr Repository) GetByTransactionId(txId string) (*entity.Transfer, error) { func (tr Repository) GetWithPreloads(txId string) (*entity.Transfer, error) { tx := &entity.Transfer{} - err := tr.dbClient. + result := tr.dbClient. Preload("Fee"). Preload("Messages"). Model(entity.Transfer{}). Where("transaction_id = ?", txId). - Find(tx).Error - return tx, err + Find(tx) + + if result.Error != nil { + if errors.Is(result.Error, gorm.ErrRecordNotFound) { + return nil, nil + } + return nil, result.Error + } + + return tx, nil } // Returns Transfer with preloaded Fee table. Returns nil if not found diff --git a/app/services/transfers/service.go b/app/services/transfers/service.go index b2d8eb0c0..f98e1a685 100644 --- a/app/services/transfers/service.go +++ b/app/services/transfers/service.go @@ -331,6 +331,10 @@ func (ts *Service) TransferData(txId string) (service.TransferData, error) { return service.TransferData{}, err } + if t == nil { + return service.TransferData{}, err + } + amount, err := strconv.ParseInt(t.Amount, 10, 64) if err != nil { ts.logger.Errorf("[%s] - Failed to parse transfer amount. Error [%s]", t.TransactionID, err) From c5895216d18f95ec2cde4aeee3f12d93ae24353f Mon Sep 17 00:00:00 2001 From: failfmi Date: Fri, 23 Apr 2021 10:42:28 +0300 Subject: [PATCH 03/14] fix: check if fee exists Signed-off-by: failfmi --- app/services/transfers/service.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/services/transfers/service.go b/app/services/transfers/service.go index f98e1a685..76ef1f7f3 100644 --- a/app/services/transfers/service.go +++ b/app/services/transfers/service.go @@ -330,8 +330,7 @@ func (ts *Service) TransferData(txId string) (service.TransferData, error) { ts.logger.Errorf("[%s] - Failed to query Transfer with messages. Error: [%s].", txId, err) return service.TransferData{}, err } - - if t == nil { + if t == nil || t.Fee.Amount == "" { return service.TransferData{}, err } From b3ad373ca9baa3fdff4eecc8d8c67ef117ec30d6 Mon Sep 17 00:00:00 2001 From: failfmi Date: Fri, 23 Apr 2021 10:45:41 +0300 Subject: [PATCH 04/14] e2e: add router address to expected transfer Signed-off-by: failfmi --- e2e/e2e_test.go | 13 ++++++++----- e2e/service/database/service.go | 8 ++++---- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/e2e/e2e_test.go b/e2e/e2e_test.go index 6bec6216e..6870cabbb 100644 --- a/e2e/e2e_test.go +++ b/e2e/e2e_test.go @@ -79,6 +79,7 @@ func Test_HBAR(t *testing.T) { setupEnv.Clients.RouterContract, transactionResponse.TransactionID, constants.Hbar, + setupEnv.RouterAddress.String(), strconv.FormatInt(hBarSendAmount.AsTinybar(), 10), setupEnv.Receiver.String(), database.ExpectedStatuses{ @@ -87,7 +88,7 @@ func Test_HBAR(t *testing.T) { }, t) // Step 8 - Verify Database Records - verifyDatabaseRecords(setupEnv.DbValidation, expectedTxRecord, setupEnv.RouterAddress.String(), strconv.FormatInt(mintAmount, 10), receivedSignatures, t) + verifyDatabaseRecords(setupEnv.DbValidation, expectedTxRecord, strconv.FormatInt(mintAmount, 10), receivedSignatures, t) } func Test_E2E_Token_Transfer(t *testing.T) { @@ -120,6 +121,7 @@ func Test_E2E_Token_Transfer(t *testing.T) { setupEnv.Clients.RouterContract, transactionResponse.TransactionID, setupEnv.TokenID.String(), + setupEnv.RouterAddress.String(), strconv.FormatInt(amount, 10), setupEnv.Receiver.String(), database.ExpectedStatuses{ @@ -128,7 +130,7 @@ func Test_E2E_Token_Transfer(t *testing.T) { }, t) // Step 8 - Verify Database Records - verifyDatabaseRecords(setupEnv.DbValidation, expectedTxRecord, setupEnv.RouterAddress.String(), strconv.FormatInt(mintAmount, 10), receivedSignatures, t) + verifyDatabaseRecords(setupEnv.DbValidation, expectedTxRecord, strconv.FormatInt(mintAmount, 10), receivedSignatures, t) } func submitMintTransaction(setupEnv *setup.Setup, transactionResponse hedera.TransactionResponse, transactionData *service.TransferData, tokenAddress *common.Address, t *testing.T) string { @@ -223,8 +225,8 @@ func verifyTransferFromValidatorAPI(setupEnv *setup.Setup, txResponse hedera.Tra return transactionData, tokenAddress } -func verifyDatabaseRecords(dbValidation *database.Service, expectedRecord *entity.Transfer, routerAddress, mintAmount string, signatures []string, t *testing.T) { - exist, err := dbValidation.VerifyDatabaseRecords(expectedRecord, routerAddress, mintAmount, signatures) +func verifyDatabaseRecords(dbValidation *database.Service, expectedRecord *entity.Transfer, mintAmount string, signatures []string, t *testing.T) { + exist, err := dbValidation.VerifyDatabaseRecords(expectedRecord, mintAmount, signatures) if err != nil { t.Fatalf("[%s] - Verification of database records failed - Error: [%s].", expectedRecord.TransactionID, err) } @@ -233,7 +235,7 @@ func verifyDatabaseRecords(dbValidation *database.Service, expectedRecord *entit } } -func prepareExpectedTransfer(routerContract *routerContract.Router, transactionID hedera.TransactionID, nativeAsset, amount, receiver string, statuses database.ExpectedStatuses, t *testing.T) *entity.Transfer { +func prepareExpectedTransfer(routerContract *routerContract.Router, transactionID hedera.TransactionID, nativeAsset, routerAddress, amount, receiver string, statuses database.ExpectedStatuses, t *testing.T) *entity.Transfer { expectedTxId := hederahelper.FromHederaTransactionID(&transactionID) wrappedAsset, err := setup.WrappedAsset(routerContract, nativeAsset) @@ -245,6 +247,7 @@ func prepareExpectedTransfer(routerContract *routerContract.Router, transactionI Receiver: receiver, NativeAsset: nativeAsset, WrappedAsset: wrappedAsset.String(), + RouterAddress: routerAddress, Amount: amount, Status: statuses.Status, SignatureMsgStatus: statuses.StatusSignature, diff --git a/e2e/service/database/service.go b/e2e/service/database/service.go index 10c7b224b..bfeda79b9 100644 --- a/e2e/service/database/service.go +++ b/e2e/service/database/service.go @@ -39,7 +39,7 @@ func NewService(dbConfigs []config.Database) *Service { } } -func (s *Service) VerifyDatabaseRecords(expectedTransferRecord *entity.Transfer, routerAddress, mintAmount string, signatures []string) (bool, error) { +func (s *Service) VerifyDatabaseRecords(expectedTransferRecord *entity.Transfer, mintAmount string, signatures []string) (bool, error) { valid, record, err := s.validTransactionRecord(expectedTransferRecord) if err != nil { return false, err @@ -48,7 +48,7 @@ func (s *Service) VerifyDatabaseRecords(expectedTransferRecord *entity.Transfer, return false, nil } - valid, err = s.validSignatureMessages(record, routerAddress, mintAmount, signatures) + valid, err = s.validSignatureMessages(record, mintAmount, signatures) if err != nil { return false, err } @@ -71,10 +71,10 @@ func (s *Service) validTransactionRecord(expectedTransferRecord *entity.Transfer return true, expectedTransferRecord, nil } -func (s *Service) validSignatureMessages(record *entity.Transfer, routerAddress, mintAmount string, signatures []string) (bool, error) { +func (s *Service) validSignatureMessages(record *entity.Transfer, mintAmount string, signatures []string) (bool, error) { var expectedMessageRecords []entity.Message - authMsgBytes, err := auth_message.EncodeBytesFrom(record.TransactionID, routerAddress, record.WrappedAsset, record.Receiver, mintAmount) + authMsgBytes, err := auth_message.EncodeBytesFrom(record.TransactionID, record.RouterAddress, record.WrappedAsset, record.Receiver, mintAmount) if err != nil { s.logger.Errorf("[%s] - Failed to encode the authorisation signature. Error: [%s]", record.TransactionID, err) return false, err From 8c45592f503cc7bbbcd0f62482930148acfbb7ab Mon Sep 17 00:00:00 2001 From: failfmi Date: Fri, 23 Apr 2021 12:23:53 +0300 Subject: [PATCH 05/14] fix(transfer-data): nil return Signed-off-by: failfmi --- app/services/transfers/service.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/services/transfers/service.go b/app/services/transfers/service.go index 76ef1f7f3..879531ef1 100644 --- a/app/services/transfers/service.go +++ b/app/services/transfers/service.go @@ -331,7 +331,7 @@ func (ts *Service) TransferData(txId string) (service.TransferData, error) { return service.TransferData{}, err } if t == nil || t.Fee.Amount == "" { - return service.TransferData{}, err + return service.TransferData{}, nil } amount, err := strconv.ParseInt(t.Amount, 10, 64) From f5ea49831780bd88d589bcd241655227c68e1e60 Mon Sep 17 00:00:00 2001 From: failfmi Date: Fri, 23 Apr 2021 13:16:09 +0300 Subject: [PATCH 06/14] feat(event): get hedera tx from id Signed-off-by: failfmi --- app/domain/repository/burn-event.go | 3 ++ app/domain/service/burn-event.go | 2 ++ app/persistence/burn-event/burn-event.go | 18 +++++++++++ app/router/burn-event/burn-event.go | 40 ++++++++++++++++++++++++ app/services/burn-event/service.go | 15 +++++++++ cmd/main.go | 2 ++ 6 files changed, 80 insertions(+) create mode 100644 app/router/burn-event/burn-event.go diff --git a/app/domain/repository/burn-event.go b/app/domain/repository/burn-event.go index f749b22f6..a027fb8a5 100644 --- a/app/domain/repository/burn-event.go +++ b/app/domain/repository/burn-event.go @@ -16,9 +16,12 @@ package repository +import "github.com/limechain/hedera-eth-bridge-validator/app/persistence/entity" + type BurnEvent interface { Create(id string, amount int64, recipient string) error UpdateStatusSubmitted(id, scheduleID, transactionId string) error UpdateStatusCompleted(txId string) error UpdateStatusFailed(txId string) error + Get(txId string) (*entity.BurnEvent, error) } diff --git a/app/domain/service/burn-event.go b/app/domain/service/burn-event.go index d0ade3cf4..bcfe18d3c 100644 --- a/app/domain/service/burn-event.go +++ b/app/domain/service/burn-event.go @@ -23,4 +23,6 @@ type BurnEvent interface { // ProcessEvent processes the burn event by submitting the appropriate // scheduled transaction, leaving the synchronization of the actual transfer on HCS ProcessEvent(event burn_event.BurnEvent) + // ScheduledTxID returns from the database the corresponding scheduled transaction id + ScheduledTxID(id string) (string, error) } diff --git a/app/persistence/burn-event/burn-event.go b/app/persistence/burn-event/burn-event.go index edfa31185..56f007be8 100644 --- a/app/persistence/burn-event/burn-event.go +++ b/app/persistence/burn-event/burn-event.go @@ -18,6 +18,7 @@ package burn_event import ( "database/sql" + "errors" "github.com/limechain/hedera-eth-bridge-validator/app/persistence/entity" burn_event "github.com/limechain/hedera-eth-bridge-validator/app/persistence/entity/burn-event" "gorm.io/gorm" @@ -68,3 +69,20 @@ func (sr Repository) updateStatus(id string, status string) error { UpdateColumn("status", status). Error } + +func (sr Repository) Get(id string) (*entity.BurnEvent, error) { + burnEvent := &entity.BurnEvent{} + result := sr.dbClient. + Model(entity.BurnEvent{}). + Where("id = ?", id). + First(burnEvent) + + if result.Error != nil { + if errors.Is(result.Error, gorm.ErrRecordNotFound) { + return nil, nil + } + return nil, result.Error + } + + return burnEvent, nil +} diff --git a/app/router/burn-event/burn-event.go b/app/router/burn-event/burn-event.go new file mode 100644 index 000000000..d33a7c19c --- /dev/null +++ b/app/router/burn-event/burn-event.go @@ -0,0 +1,40 @@ +package burn_event + +import ( + "fmt" + "github.com/go-chi/chi" + "github.com/go-chi/render" + "github.com/limechain/hedera-eth-bridge-validator/app/domain/service" + "github.com/limechain/hedera-eth-bridge-validator/app/router/response" + "github.com/limechain/hedera-eth-bridge-validator/config" + "net/http" +) + +var ( + Route = "/events" + logger = config.GetLoggerFor(fmt.Sprintf("Router [%s]", Route)) +) + +// GET: .../events/:id/tx +func getTx(burnService service.BurnEvent) func(w http.ResponseWriter, r *http.Request) { + return func(w http.ResponseWriter, r *http.Request) { + eventID := chi.URLParam(r, "id") + + scheduledID, err := burnService.ScheduledTxID(eventID) + if err != nil { + render.Status(r, http.StatusInternalServerError) + render.JSON(w, r, response.ErrorResponse(response.ErrorInternalServerError)) + + logger.Errorf("Router resolved with an error. Error [%s].", err) + return + } + + render.JSON(w, r, scheduledID) + } +} + +func NewRouter(service service.BurnEvent) chi.Router { + r := chi.NewRouter() + r.Get("/{id}/tx", getTx(service)) + return r +} diff --git a/app/services/burn-event/service.go b/app/services/burn-event/service.go index 3c2b18ebf..3003c8cc1 100644 --- a/app/services/burn-event/service.go +++ b/app/services/burn-event/service.go @@ -109,6 +109,21 @@ func (s *Service) prepareTransfers(event burn_event.BurnEvent) (recipientAmount return remainder, validFee, transfers, nil } +// ScheduledTxID returns from the database the corresponding scheduled transaction id +func (s *Service) ScheduledTxID(id string) (string, error) { + event, err := s.repository.Get(id) + if err != nil { + s.logger.Errorf("[%s] - failed to get event.", id) + return "", err + } + + if event == nil { + return "", nil + } + + return event.TransactionId.String, nil +} + func (s *Service) scheduledTxExecutionCallbacks(id string, feeAmount string) (onExecutionSuccess func(transactionID, scheduleID string), onExecutionFail func(transactionID string)) { onExecutionSuccess = func(transactionID, scheduleID string) { s.logger.Debugf("[%s] - Updating db status to Submitted with TransactionID [%s].", diff --git a/cmd/main.go b/cmd/main.go index 5482e1532..70ec722cd 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -30,6 +30,7 @@ import ( cmw "github.com/limechain/hedera-eth-bridge-validator/app/process/watcher/message" tw "github.com/limechain/hedera-eth-bridge-validator/app/process/watcher/transfer" apirouter "github.com/limechain/hedera-eth-bridge-validator/app/router" + burn_event "github.com/limechain/hedera-eth-bridge-validator/app/router/burn-event" "github.com/limechain/hedera-eth-bridge-validator/app/router/healthcheck" "github.com/limechain/hedera-eth-bridge-validator/app/router/transfer" "github.com/limechain/hedera-eth-bridge-validator/config" @@ -103,6 +104,7 @@ func initializeAPIRouter(services *Services) *apirouter.APIRouter { apiRouter := apirouter.NewAPIRouter() apiRouter.AddV1Router(healthcheck.Route, healthcheck.NewRouter()) apiRouter.AddV1Router(transfer.Route, transfer.NewRouter(services.transfers)) + apiRouter.AddV1Router(burn_event.Route, burn_event.NewRouter(services.burnEvents)) return apiRouter } From 562dfeae7b06afe9482eb05898e90a1fc6561e3e Mon Sep 17 00:00:00 2001 From: failfmi Date: Mon, 26 Apr 2021 15:16:52 +0300 Subject: [PATCH 07/14] fix(recovery): add router address Signed-off-by: failfmi --- app/services/transfers/service.go | 1 + 1 file changed, 1 insertion(+) diff --git a/app/services/transfers/service.go b/app/services/transfers/service.go index 879531ef1..06fcee6de 100644 --- a/app/services/transfers/service.go +++ b/app/services/transfers/service.go @@ -142,6 +142,7 @@ func (ts *Service) InitiateNewTransfer(tm model.Transfer) (*entity.Transfer, err func (ts *Service) SaveRecoveredTxn(txId, amount, nativeAsset, wrappedAsset string, memo string) error { err := ts.transferRepository.SaveRecoveredTxn(&model.Transfer{ TransactionId: txId, + RouterAddress: ts.contractsService.Address().String(), Receiver: memo, Amount: amount, NativeAsset: nativeAsset, From 1568165446dfb1104b4e91856891dde7e7fdc095 Mon Sep 17 00:00:00 2001 From: failfmi Date: Tue, 27 Apr 2021 15:31:02 +0300 Subject: [PATCH 08/14] feat(contracts): update contract wrappers Signed-off-by: failfmi --- .../ethereum/contracts/router/router.go | 85 ++++++++++++------- .../ethereum/contracts/wtoken/wtoken.go | 85 ++++++++++++++++++- 2 files changed, 137 insertions(+), 33 deletions(-) diff --git a/app/clients/ethereum/contracts/router/router.go b/app/clients/ethereum/contracts/router/router.go index 3a2c1a7f4..6287ca004 100644 --- a/app/clients/ethereum/contracts/router/router.go +++ b/app/clients/ethereum/contracts/router/router.go @@ -27,7 +27,7 @@ var ( ) // RouterABI is the input ABI used to generate the binding from. -const RouterABI = "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_controller\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"wrappedAsset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"receiver\",\"type\":\"bytes\"}],\"name\":\"Burn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"member\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"status\",\"type\":\"bool\"}],\"name\":\"MemberUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"wrappedAsset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bytes\",\"name\":\"transactionId\",\"type\":\"bytes\"}],\"name\":\"Mint\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"native\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"wrapped\",\"type\":\"address\"}],\"name\":\"PairAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"native\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"wrapped\",\"type\":\"address\"}],\"name\":\"PairRemoved\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"native\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"wrapped\",\"type\":\"address\"}],\"name\":\"addPair\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"receiver\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"wrappedAsset\",\"type\":\"address\"}],\"name\":\"burn\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"controller\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_member\",\"type\":\"address\"}],\"name\":\"isMember\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"wrappedAsset\",\"type\":\"address\"}],\"name\":\"isSupportedAsset\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"memberAt\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"membersCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"transactionId\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"wrappedAsset\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes[]\",\"name\":\"signatures\",\"type\":\"bytes[]\"}],\"name\":\"mint\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"mintTransfers\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"isExecuted\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"nativeToWrapped\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"native\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"wrapped\",\"type\":\"address\"}],\"name\":\"removePair\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"isMember\",\"type\":\"bool\"}],\"name\":\"updateMember\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"wrappedAssetAt\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wrappedAssetsCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"wrappedToNative\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]" +const RouterABI = "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_controller\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"wrappedAsset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"receiver\",\"type\":\"bytes\"}],\"name\":\"Burn\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"member\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"status\",\"type\":\"bool\"}],\"name\":\"MemberUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"wrappedAsset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"bytes\",\"name\":\"transactionId\",\"type\":\"bytes\"}],\"name\":\"Mint\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"native\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"wrapped\",\"type\":\"address\"}],\"name\":\"PairAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"native\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"wrapped\",\"type\":\"address\"}],\"name\":\"PairRemoved\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"native\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"wrapped\",\"type\":\"address\"}],\"name\":\"addPair\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"receiver\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"wrappedAsset\",\"type\":\"address\"}],\"name\":\"burn\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"wrappedAsset\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"receiver\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"name\":\"burnWithPermit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"controller\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"executedTransactions\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_member\",\"type\":\"address\"}],\"name\":\"isMember\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"wrappedAsset\",\"type\":\"address\"}],\"name\":\"isSupportedAsset\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"memberAt\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"membersCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"transactionId\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"wrappedAsset\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes[]\",\"name\":\"signatures\",\"type\":\"bytes[]\"}],\"name\":\"mint\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"nativeToWrapped\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"native\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"wrapped\",\"type\":\"address\"}],\"name\":\"removePair\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"isMember\",\"type\":\"bool\"}],\"name\":\"updateMember\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"wrappedAssetAt\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"wrappedAssetsCount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"wrappedToNative\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]" // Router is an auto generated Go binding around an Ethereum contract. type Router struct { @@ -202,6 +202,37 @@ func (_Router *RouterCallerSession) Controller() (common.Address, error) { return _Router.Contract.Controller(&_Router.CallOpts) } +// ExecutedTransactions is a free data retrieval call binding the contract method 0x4c2c7559. +// +// Solidity: function executedTransactions(bytes ) view returns(bool) +func (_Router *RouterCaller) ExecutedTransactions(opts *bind.CallOpts, arg0 []byte) (bool, error) { + var out []interface{} + err := _Router.contract.Call(opts, &out, "executedTransactions", arg0) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// ExecutedTransactions is a free data retrieval call binding the contract method 0x4c2c7559. +// +// Solidity: function executedTransactions(bytes ) view returns(bool) +func (_Router *RouterSession) ExecutedTransactions(arg0 []byte) (bool, error) { + return _Router.Contract.ExecutedTransactions(&_Router.CallOpts, arg0) +} + +// ExecutedTransactions is a free data retrieval call binding the contract method 0x4c2c7559. +// +// Solidity: function executedTransactions(bytes ) view returns(bool) +func (_Router *RouterCallerSession) ExecutedTransactions(arg0 []byte) (bool, error) { + return _Router.Contract.ExecutedTransactions(&_Router.CallOpts, arg0) +} + // IsMember is a free data retrieval call binding the contract method 0xa230c524. // // Solidity: function isMember(address _member) view returns(bool) @@ -326,37 +357,6 @@ func (_Router *RouterCallerSession) MembersCount() (*big.Int, error) { return _Router.Contract.MembersCount(&_Router.CallOpts) } -// MintTransfers is a free data retrieval call binding the contract method 0xed1018ad. -// -// Solidity: function mintTransfers(bytes ) view returns(bool isExecuted) -func (_Router *RouterCaller) MintTransfers(opts *bind.CallOpts, arg0 []byte) (bool, error) { - var out []interface{} - err := _Router.contract.Call(opts, &out, "mintTransfers", arg0) - - if err != nil { - return *new(bool), err - } - - out0 := *abi.ConvertType(out[0], new(bool)).(*bool) - - return out0, err - -} - -// MintTransfers is a free data retrieval call binding the contract method 0xed1018ad. -// -// Solidity: function mintTransfers(bytes ) view returns(bool isExecuted) -func (_Router *RouterSession) MintTransfers(arg0 []byte) (bool, error) { - return _Router.Contract.MintTransfers(&_Router.CallOpts, arg0) -} - -// MintTransfers is a free data retrieval call binding the contract method 0xed1018ad. -// -// Solidity: function mintTransfers(bytes ) view returns(bool isExecuted) -func (_Router *RouterCallerSession) MintTransfers(arg0 []byte) (bool, error) { - return _Router.Contract.MintTransfers(&_Router.CallOpts, arg0) -} - // NativeToWrapped is a free data retrieval call binding the contract method 0x1104296b. // // Solidity: function nativeToWrapped(bytes ) view returns(address) @@ -554,6 +554,27 @@ func (_Router *RouterTransactorSession) Burn(amount *big.Int, receiver []byte, w return _Router.Contract.Burn(&_Router.TransactOpts, amount, receiver, wrappedAsset) } +// BurnWithPermit is a paid mutator transaction binding the contract method 0x63f4c78a. +// +// Solidity: function burnWithPermit(address wrappedAsset, bytes receiver, uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s) returns() +func (_Router *RouterTransactor) BurnWithPermit(opts *bind.TransactOpts, wrappedAsset common.Address, receiver []byte, amount *big.Int, deadline *big.Int, v uint8, r [32]byte, s [32]byte) (*types.Transaction, error) { + return _Router.contract.Transact(opts, "burnWithPermit", wrappedAsset, receiver, amount, deadline, v, r, s) +} + +// BurnWithPermit is a paid mutator transaction binding the contract method 0x63f4c78a. +// +// Solidity: function burnWithPermit(address wrappedAsset, bytes receiver, uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s) returns() +func (_Router *RouterSession) BurnWithPermit(wrappedAsset common.Address, receiver []byte, amount *big.Int, deadline *big.Int, v uint8, r [32]byte, s [32]byte) (*types.Transaction, error) { + return _Router.Contract.BurnWithPermit(&_Router.TransactOpts, wrappedAsset, receiver, amount, deadline, v, r, s) +} + +// BurnWithPermit is a paid mutator transaction binding the contract method 0x63f4c78a. +// +// Solidity: function burnWithPermit(address wrappedAsset, bytes receiver, uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s) returns() +func (_Router *RouterTransactorSession) BurnWithPermit(wrappedAsset common.Address, receiver []byte, amount *big.Int, deadline *big.Int, v uint8, r [32]byte, s [32]byte) (*types.Transaction, error) { + return _Router.Contract.BurnWithPermit(&_Router.TransactOpts, wrappedAsset, receiver, amount, deadline, v, r, s) +} + // Mint is a paid mutator transaction binding the contract method 0x9949e912. // // Solidity: function mint(bytes transactionId, address wrappedAsset, address receiver, uint256 amount, bytes[] signatures) returns() diff --git a/app/clients/ethereum/contracts/wtoken/wtoken.go b/app/clients/ethereum/contracts/wtoken/wtoken.go index 9aea67100..f15fa558d 100644 --- a/app/clients/ethereum/contracts/wtoken/wtoken.go +++ b/app/clients/ethereum/contracts/wtoken/wtoken.go @@ -27,7 +27,7 @@ var ( ) // WtokenABI is the input ABI used to generate the binding from. -const WtokenABI = "[{\"inputs\":[{\"internalType\":\"string\",\"name\":\"tokenName\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"tokenSymbol\",\"type\":\"string\"},{\"internalType\":\"uint8\",\"name\":\"decimals\",\"type\":\"uint8\"},{\"internalType\":\"address\",\"name\":\"_controller\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newController\",\"type\":\"address\"}],\"name\":\"ControllerSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"burnFrom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"controller\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"subtractedValue\",\"type\":\"uint256\"}],\"name\":\"decreaseAllowance\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"addedValue\",\"type\":\"uint256\"}],\"name\":\"increaseAllowance\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"mint\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"paused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_controller\",\"type\":\"address\"}],\"name\":\"setController\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unpause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]" +const WtokenABI = "[{\"inputs\":[{\"internalType\":\"string\",\"name\":\"tokenName\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"tokenSymbol\",\"type\":\"string\"},{\"internalType\":\"uint8\",\"name\":\"decimals\",\"type\":\"uint8\"},{\"internalType\":\"address\",\"name\":\"_controller\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newController\",\"type\":\"address\"}],\"name\":\"ControllerSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Paused\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"Unpaused\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"burnFrom\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"controller\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"subtractedValue\",\"type\":\"uint256\"}],\"name\":\"decreaseAllowance\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"domainSeparators\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"addedValue\",\"type\":\"uint256\"}],\"name\":\"increaseAllowance\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"mint\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"nonces\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"paused\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"deadline\",\"type\":\"uint256\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"name\":\"permit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_controller\",\"type\":\"address\"}],\"name\":\"setController\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"unpause\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]" // Wtoken is an auto generated Go binding around an Ethereum contract. type Wtoken struct { @@ -295,6 +295,37 @@ func (_Wtoken *WtokenCallerSession) Decimals() (uint8, error) { return _Wtoken.Contract.Decimals(&_Wtoken.CallOpts) } +// DomainSeparators is a free data retrieval call binding the contract method 0x99740a18. +// +// Solidity: function domainSeparators(uint256 ) view returns(bytes32) +func (_Wtoken *WtokenCaller) DomainSeparators(opts *bind.CallOpts, arg0 *big.Int) ([32]byte, error) { + var out []interface{} + err := _Wtoken.contract.Call(opts, &out, "domainSeparators", arg0) + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// DomainSeparators is a free data retrieval call binding the contract method 0x99740a18. +// +// Solidity: function domainSeparators(uint256 ) view returns(bytes32) +func (_Wtoken *WtokenSession) DomainSeparators(arg0 *big.Int) ([32]byte, error) { + return _Wtoken.Contract.DomainSeparators(&_Wtoken.CallOpts, arg0) +} + +// DomainSeparators is a free data retrieval call binding the contract method 0x99740a18. +// +// Solidity: function domainSeparators(uint256 ) view returns(bytes32) +func (_Wtoken *WtokenCallerSession) DomainSeparators(arg0 *big.Int) ([32]byte, error) { + return _Wtoken.Contract.DomainSeparators(&_Wtoken.CallOpts, arg0) +} + // Name is a free data retrieval call binding the contract method 0x06fdde03. // // Solidity: function name() view returns(string) @@ -326,6 +357,37 @@ func (_Wtoken *WtokenCallerSession) Name() (string, error) { return _Wtoken.Contract.Name(&_Wtoken.CallOpts) } +// Nonces is a free data retrieval call binding the contract method 0x7ecebe00. +// +// Solidity: function nonces(address owner) view returns(uint256) +func (_Wtoken *WtokenCaller) Nonces(opts *bind.CallOpts, owner common.Address) (*big.Int, error) { + var out []interface{} + err := _Wtoken.contract.Call(opts, &out, "nonces", owner) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// Nonces is a free data retrieval call binding the contract method 0x7ecebe00. +// +// Solidity: function nonces(address owner) view returns(uint256) +func (_Wtoken *WtokenSession) Nonces(owner common.Address) (*big.Int, error) { + return _Wtoken.Contract.Nonces(&_Wtoken.CallOpts, owner) +} + +// Nonces is a free data retrieval call binding the contract method 0x7ecebe00. +// +// Solidity: function nonces(address owner) view returns(uint256) +func (_Wtoken *WtokenCallerSession) Nonces(owner common.Address) (*big.Int, error) { + return _Wtoken.Contract.Nonces(&_Wtoken.CallOpts, owner) +} + // Owner is a free data retrieval call binding the contract method 0x8da5cb5b. // // Solidity: function owner() view returns(address) @@ -576,6 +638,27 @@ func (_Wtoken *WtokenTransactorSession) Pause() (*types.Transaction, error) { return _Wtoken.Contract.Pause(&_Wtoken.TransactOpts) } +// Permit is a paid mutator transaction binding the contract method 0xd505accf. +// +// Solidity: function permit(address owner, address spender, uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s) returns() +func (_Wtoken *WtokenTransactor) Permit(opts *bind.TransactOpts, owner common.Address, spender common.Address, amount *big.Int, deadline *big.Int, v uint8, r [32]byte, s [32]byte) (*types.Transaction, error) { + return _Wtoken.contract.Transact(opts, "permit", owner, spender, amount, deadline, v, r, s) +} + +// Permit is a paid mutator transaction binding the contract method 0xd505accf. +// +// Solidity: function permit(address owner, address spender, uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s) returns() +func (_Wtoken *WtokenSession) Permit(owner common.Address, spender common.Address, amount *big.Int, deadline *big.Int, v uint8, r [32]byte, s [32]byte) (*types.Transaction, error) { + return _Wtoken.Contract.Permit(&_Wtoken.TransactOpts, owner, spender, amount, deadline, v, r, s) +} + +// Permit is a paid mutator transaction binding the contract method 0xd505accf. +// +// Solidity: function permit(address owner, address spender, uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s) returns() +func (_Wtoken *WtokenTransactorSession) Permit(owner common.Address, spender common.Address, amount *big.Int, deadline *big.Int, v uint8, r [32]byte, s [32]byte) (*types.Transaction, error) { + return _Wtoken.Contract.Permit(&_Wtoken.TransactOpts, owner, spender, amount, deadline, v, r, s) +} + // RenounceOwnership is a paid mutator transaction binding the contract method 0x715018a6. // // Solidity: function renounceOwnership() returns() From cceb8b4fd88d18a2ea74e1759350665be90b6626 Mon Sep 17 00:00:00 2001 From: failfmi Date: Wed, 28 Apr 2021 10:23:26 +0300 Subject: [PATCH 09/14] refactor: clarify variable namings Signed-off-by: failfmi --- app/router/burn-event/burn-event.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/router/burn-event/burn-event.go b/app/router/burn-event/burn-event.go index d33a7c19c..a885ef5cb 100644 --- a/app/router/burn-event/burn-event.go +++ b/app/router/burn-event/burn-event.go @@ -16,11 +16,11 @@ var ( ) // GET: .../events/:id/tx -func getTx(burnService service.BurnEvent) func(w http.ResponseWriter, r *http.Request) { +func getTxID(burnService service.BurnEvent) func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) { eventID := chi.URLParam(r, "id") - scheduledID, err := burnService.ScheduledTxID(eventID) + txID, err := burnService.ScheduledTxID(eventID) if err != nil { render.Status(r, http.StatusInternalServerError) render.JSON(w, r, response.ErrorResponse(response.ErrorInternalServerError)) @@ -29,12 +29,12 @@ func getTx(burnService service.BurnEvent) func(w http.ResponseWriter, r *http.Re return } - render.JSON(w, r, scheduledID) + render.JSON(w, r, txID) } } func NewRouter(service service.BurnEvent) chi.Router { r := chi.NewRouter() - r.Get("/{id}/tx", getTx(service)) + r.Get("/{id}/tx", getTxID(service)) return r } From 13060c04b425ddcf3bdcc0a7ce04e377ce307b79 Mon Sep 17 00:00:00 2001 From: failfmi Date: Wed, 28 Apr 2021 10:39:48 +0300 Subject: [PATCH 10/14] fix(e2e): add missing expected transfer check Signed-off-by: failfmi --- e2e/service/database/compare.go | 1 + 1 file changed, 1 insertion(+) diff --git a/e2e/service/database/compare.go b/e2e/service/database/compare.go index 9e830d5e3..58b843e1d 100644 --- a/e2e/service/database/compare.go +++ b/e2e/service/database/compare.go @@ -22,6 +22,7 @@ import ( func transfersFieldsMatch(comparing, comparable entity.Transfer) bool { return comparable.TransactionID == comparing.TransactionID && + comparable.RouterAddress == comparing.RouterAddress && comparable.Receiver == comparing.Receiver && comparable.NativeAsset == comparing.NativeAsset && comparable.WrappedAsset == comparing.WrappedAsset && From 0206a3493afa63565a25194facbe1ad61e2af120 Mon Sep 17 00:00:00 2001 From: failfmi Date: Wed, 28 Apr 2021 10:55:29 +0300 Subject: [PATCH 11/14] e2e(evm->hedera): validate event api call Signed-off-by: failfmi --- app/domain/service/burn-event.go | 4 ++-- app/router/burn-event/burn-event.go | 2 +- app/services/burn-event/service.go | 4 ++-- e2e/clients/validator.go | 36 +++++++++++++++++++++++++---- e2e/e2e_test.go | 33 +++++++++++++++++++------- 5 files changed, 61 insertions(+), 18 deletions(-) diff --git a/app/domain/service/burn-event.go b/app/domain/service/burn-event.go index bcfe18d3c..ec4777d5c 100644 --- a/app/domain/service/burn-event.go +++ b/app/domain/service/burn-event.go @@ -23,6 +23,6 @@ type BurnEvent interface { // ProcessEvent processes the burn event by submitting the appropriate // scheduled transaction, leaving the synchronization of the actual transfer on HCS ProcessEvent(event burn_event.BurnEvent) - // ScheduledTxID returns from the database the corresponding scheduled transaction id - ScheduledTxID(id string) (string, error) + // TransactionID returns the corresponding transaction id + TransactionID(id string) (string, error) } diff --git a/app/router/burn-event/burn-event.go b/app/router/burn-event/burn-event.go index a885ef5cb..8a9246e01 100644 --- a/app/router/burn-event/burn-event.go +++ b/app/router/burn-event/burn-event.go @@ -20,7 +20,7 @@ func getTxID(burnService service.BurnEvent) func(w http.ResponseWriter, r *http. return func(w http.ResponseWriter, r *http.Request) { eventID := chi.URLParam(r, "id") - txID, err := burnService.ScheduledTxID(eventID) + txID, err := burnService.TransactionID(eventID) if err != nil { render.Status(r, http.StatusInternalServerError) render.JSON(w, r, response.ErrorResponse(response.ErrorInternalServerError)) diff --git a/app/services/burn-event/service.go b/app/services/burn-event/service.go index 3003c8cc1..804192013 100644 --- a/app/services/burn-event/service.go +++ b/app/services/burn-event/service.go @@ -109,8 +109,8 @@ func (s *Service) prepareTransfers(event burn_event.BurnEvent) (recipientAmount return remainder, validFee, transfers, nil } -// ScheduledTxID returns from the database the corresponding scheduled transaction id -func (s *Service) ScheduledTxID(id string) (string, error) { +// TransactionID returns the corresponding transaction id +func (s *Service) TransactionID(id string) (string, error) { event, err := s.repository.Get(id) if err != nil { s.logger.Errorf("[%s] - failed to get event.", id) diff --git a/e2e/clients/validator.go b/e2e/clients/validator.go index 429ba355a..d7b861caa 100644 --- a/e2e/clients/validator.go +++ b/e2e/clients/validator.go @@ -38,15 +38,12 @@ func NewValidatorClient(url string) *Validator { func (v *Validator) GetTransferData(transactionID string) (*transfers.TransferData, error) { url := v.baseUrl + "/api/v1/transfers/" + transactionID - response, err := v.Client.Get(url) + + bodyBytes, err := v.get(url) if err != nil { return nil, err } - if response.StatusCode != http.StatusOK { - return nil, errors.New(fmt.Sprintf("Get Transfer Data resolved with status [%d].", response.StatusCode)) - } - bodyBytes, err := ioutil.ReadAll(response.Body) var transferDataResponse *transfers.TransferData err = json.Unmarshal(bodyBytes, &transferDataResponse) if err != nil { @@ -55,3 +52,32 @@ func (v *Validator) GetTransferData(transactionID string) (*transfers.TransferDa return transferDataResponse, nil } + +func (v *Validator) GetEventTransactionID(eventId string) (string, error) { + url := fmt.Sprintf("%s/api/v1/events/%s/tx", v.baseUrl, eventId) + + bodyBytes, err := v.get(url) + if err != nil { + return "", err + } + + var txID string + err = json.Unmarshal(bodyBytes, &txID) + if err != nil { + return "", err + } + + return txID, nil +} + +func (v *Validator) get(url string) ([]byte, error) { + response, err := v.Client.Get(url) + if err != nil { + return nil, err + } + if response.StatusCode != http.StatusOK { + return nil, errors.New(fmt.Sprintf("GET resolved with status [%d].", response.StatusCode)) + } + + return ioutil.ReadAll(response.Body) +} diff --git a/e2e/e2e_test.go b/e2e/e2e_test.go index 7da0d3b2a..696d81ccb 100644 --- a/e2e/e2e_test.go +++ b/e2e/e2e_test.go @@ -182,10 +182,13 @@ func Test_Ethereum_Hedera_HBAR(t *testing.T) { // 4. Validate that a scheduled transaction was submitted transactionID, scheduleID := validateSubmittedScheduledTx(setupEnv, constants.Hbar, generateMirrorNodeExpectedTransfersForBurnEvent(setupEnv, constants.Hbar, expectedReceiveAmount, fee), t) - // 5. Validate that the balance of the receiver account (hedera) was changed with the correct amount + // 5. Validate Event Transaction ID retrieved from Validator API + validateEventTransactionIDFromValidatorAPI(setupEnv, expectedId, transactionID, t) + + // 6. Validate that the balance of the receiver account (hedera) was changed with the correct amount validateReceiverAccountBalance(setupEnv, uint64(expectedReceiveAmount), accountBalanceBefore, constants.Hbar, t) - // 6. Prepare Expected Database Records + // 7. Prepare Expected Database Records expectedBurnEventRecord := util.PrepareExpectedBurnEventRecord( scheduleID, receiveAmount, @@ -195,10 +198,10 @@ func Test_Ethereum_Hedera_HBAR(t *testing.T) { // and: expectedFeeRecord := util.PrepareExpectedFeeRecord(transactionID, scheduleID, fee, "", expectedId) - // 7. Wait for validators to update DB state after Scheduled TX is mined + // 8. Wait for validators to update DB state after Scheduled TX is mined time.Sleep(10 * time.Second) - // 8. Validate Database Records + // 9. Validate Database Records verifyBurnEventRecord(setupEnv.DbValidator, expectedBurnEventRecord, t) // and: verifyFeeRecord(setupEnv.DbValidator, expectedFeeRecord, t) @@ -221,10 +224,13 @@ func Test_Ethereum_Hedera_Token(t *testing.T) { // 4. Validate that a scheduled transaction was submitted transactionID, scheduleID := validateSubmittedScheduledTx(setupEnv, setupEnv.TokenID.String(), generateMirrorNodeExpectedTransfersForBurnEvent(setupEnv, setupEnv.TokenID.String(), expectedReceiveAmount, fee), t) - // 5. Validate that the balance of the receiver account (hedera) was changed with the correct amount + // 5. Validate Event Transaction ID retrieved from Validator API + validateEventTransactionIDFromValidatorAPI(setupEnv, expectedId, transactionID, t) + + // 6. Validate that the balance of the receiver account (hedera) was changed with the correct amount validateReceiverAccountBalance(setupEnv, uint64(expectedReceiveAmount), accountBalanceBefore, setupEnv.TokenID.String(), t) - // 6. Prepare Expected Database Records + // 7. Prepare Expected Database Records expectedBurnEventRecord := util.PrepareExpectedBurnEventRecord( scheduleID, receiveAmount, @@ -234,10 +240,10 @@ func Test_Ethereum_Hedera_Token(t *testing.T) { // and: expectedFeeRecord := util.PrepareExpectedFeeRecord(transactionID, scheduleID, fee, "", expectedId) - // 7. Wait for validators to update DB state after Scheduled TX is mined + // 8. Wait for validators to update DB state after Scheduled TX is mined time.Sleep(10 * time.Second) - // 8. Validate Database Records + // 9. Validate Database Records verifyBurnEventRecord(setupEnv.DbValidator, expectedBurnEventRecord, t) // and: verifyFeeRecord(setupEnv.DbValidator, expectedFeeRecord, t) @@ -590,6 +596,17 @@ func verifyWrappedAssetBalance(setupEnv *setup.Setup, nativeAsset string, mintAm } } +func validateEventTransactionIDFromValidatorAPI(setupEnv *setup.Setup, eventID, expectedTxID string, t *testing.T) { + actualTxID, err := setupEnv.Clients.ValidatorClient.GetEventTransactionID(eventID) + if err != nil { + t.Fatalf("Failed to get event transaction ID. Error: [%s]", err) + } + + if actualTxID != expectedTxID { + t.Fatalf("Expected Event TX ID [%s] did not match actual TX ID [%s]", expectedTxID, actualTxID) + } +} + func verifyTransferFromValidatorAPI(setupEnv *setup.Setup, txResponse hedera.TransactionResponse, tokenID string, expectedSendAmount int64, t *testing.T) (*service.TransferData, *common.Address) { tokenAddress, err := setup.WrappedAsset(setupEnv.Clients.RouterContract, tokenID) if err != nil { From b4799352b51019103c82fc1de3eef85c9c2f7db7 Mon Sep 17 00:00:00 2001 From: failfmi Date: Wed, 28 Apr 2021 12:10:11 +0300 Subject: [PATCH 12/14] e2e: clarify fatal error Signed-off-by: failfmi --- e2e/e2e_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e/e2e_test.go b/e2e/e2e_test.go index 696d81ccb..e83282554 100644 --- a/e2e/e2e_test.go +++ b/e2e/e2e_test.go @@ -599,7 +599,7 @@ func verifyWrappedAssetBalance(setupEnv *setup.Setup, nativeAsset string, mintAm func validateEventTransactionIDFromValidatorAPI(setupEnv *setup.Setup, eventID, expectedTxID string, t *testing.T) { actualTxID, err := setupEnv.Clients.ValidatorClient.GetEventTransactionID(eventID) if err != nil { - t.Fatalf("Failed to get event transaction ID. Error: [%s]", err) + t.Fatalf("[%s] - Failed to get event transaction ID. Error: [%s]", eventID, err) } if actualTxID != expectedTxID { From 7d3ddaa160daa4789cc3a906b1caacaed82c0575 Mon Sep 17 00:00:00 2001 From: failfmi Date: Wed, 28 Apr 2021 16:55:56 +0300 Subject: [PATCH 13/14] fix(router): return 404 if not found Signed-off-by: failfmi --- app/domain/service/errors.go | 21 +++++++++++++++++++++ app/router/transfer/transfer.go | 12 +++++++++--- app/services/transfers/service.go | 2 +- 3 files changed, 31 insertions(+), 4 deletions(-) create mode 100644 app/domain/service/errors.go diff --git a/app/domain/service/errors.go b/app/domain/service/errors.go new file mode 100644 index 000000000..dde0845a1 --- /dev/null +++ b/app/domain/service/errors.go @@ -0,0 +1,21 @@ +/* + * Copyright 2021 LimeChain Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package service + +import "errors" + +var ErrNotFound = errors.New("not found") diff --git a/app/router/transfer/transfer.go b/app/router/transfer/transfer.go index 36f3f6985..76d7f71e0 100644 --- a/app/router/transfer/transfer.go +++ b/app/router/transfer/transfer.go @@ -22,10 +22,16 @@ func getTransfer(transfersService service.Transfers) func(w http.ResponseWriter, transferData, err := transfersService.TransferData(transferID) if err != nil { - render.Status(r, http.StatusInternalServerError) - render.JSON(w, r, response.ErrorResponse(response.ErrorInternalServerError)) - logger.Errorf("Router resolved with an error. Error [%s].", err) + switch err { + case service.ErrNotFound: + render.Status(r, http.StatusNotFound) + render.JSON(w, r, response.ErrorResponse(err)) + default: + render.Status(r, http.StatusInternalServerError) + render.JSON(w, r, response.ErrorResponse(response.ErrorInternalServerError)) + } + return } diff --git a/app/services/transfers/service.go b/app/services/transfers/service.go index 06fcee6de..0636164da 100644 --- a/app/services/transfers/service.go +++ b/app/services/transfers/service.go @@ -332,7 +332,7 @@ func (ts *Service) TransferData(txId string) (service.TransferData, error) { return service.TransferData{}, err } if t == nil || t.Fee.Amount == "" { - return service.TransferData{}, nil + return service.TransferData{}, service.ErrNotFound } amount, err := strconv.ParseInt(t.Amount, 10, 64) From 17be4ff58ce6ee69c5902a001eff731e5d1cce40 Mon Sep 17 00:00:00 2001 From: failfmi Date: Wed, 28 Apr 2021 16:59:01 +0300 Subject: [PATCH 14/14] fix(router-event): return 404 if not found Signed-off-by: failfmi --- app/domain/service/burn-event.go | 3 ++- app/router/burn-event/burn-event.go | 12 +++++++++--- app/services/burn-event/service.go | 5 +++-- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/app/domain/service/burn-event.go b/app/domain/service/burn-event.go index ec4777d5c..8f8c62806 100644 --- a/app/domain/service/burn-event.go +++ b/app/domain/service/burn-event.go @@ -23,6 +23,7 @@ type BurnEvent interface { // ProcessEvent processes the burn event by submitting the appropriate // scheduled transaction, leaving the synchronization of the actual transfer on HCS ProcessEvent(event burn_event.BurnEvent) - // TransactionID returns the corresponding transaction id + // TransactionID returns the corresponding Scheduled Transaction paying out the + // fees to validators and the amount being bridged to the receiver address TransactionID(id string) (string, error) } diff --git a/app/router/burn-event/burn-event.go b/app/router/burn-event/burn-event.go index 8a9246e01..cc02f32a1 100644 --- a/app/router/burn-event/burn-event.go +++ b/app/router/burn-event/burn-event.go @@ -22,10 +22,16 @@ func getTxID(burnService service.BurnEvent) func(w http.ResponseWriter, r *http. txID, err := burnService.TransactionID(eventID) if err != nil { - render.Status(r, http.StatusInternalServerError) - render.JSON(w, r, response.ErrorResponse(response.ErrorInternalServerError)) - logger.Errorf("Router resolved with an error. Error [%s].", err) + switch err { + case service.ErrNotFound: + render.Status(r, http.StatusNotFound) + render.JSON(w, r, response.ErrorResponse(err)) + default: + render.Status(r, http.StatusInternalServerError) + render.JSON(w, r, response.ErrorResponse(response.ErrorInternalServerError)) + } + return } diff --git a/app/services/burn-event/service.go b/app/services/burn-event/service.go index 804192013..797c7a686 100644 --- a/app/services/burn-event/service.go +++ b/app/services/burn-event/service.go @@ -109,7 +109,8 @@ func (s *Service) prepareTransfers(event burn_event.BurnEvent) (recipientAmount return remainder, validFee, transfers, nil } -// TransactionID returns the corresponding transaction id +// TransactionID returns the corresponding Scheduled Transaction paying out the +// fees to validators and the amount being bridged to the receiver address func (s *Service) TransactionID(id string) (string, error) { event, err := s.repository.Get(id) if err != nil { @@ -118,7 +119,7 @@ func (s *Service) TransactionID(id string) (string, error) { } if event == nil { - return "", nil + return "", service.ErrNotFound } return event.TransactionId.String, nil