Last active
June 27, 2023 14:42
-
-
Save 0x19/1a0635d35bcb42f331f7692a424038d5 to your computer and use it in GitHub Desktop.
Golang IsEIP55
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package main | |
| import ( | |
| "fmt" | |
| "strings" | |
| "testing" | |
| "golang.org/x/crypto/sha3" | |
| ) | |
| // IsEIP55 checks if the given Ethereum address is EIP-55 compliant. | |
| // It does this by hashing the lowercase address and then checking if each character in the original address is correctly cased according to the EIP-55 specification. | |
| // If the address is EIP-55 compliant, the function returns nil. Otherwise, it returns an error that provides more information about why the address is not compliant. | |
| func IsEIP55(address string) error { | |
| // Check if the address has a '0x' prefix | |
| if !strings.HasPrefix(address, "0x") { | |
| return fmt.Errorf("address does not start with '0x'") | |
| } | |
| // Remove '0x' prefix | |
| address = address[2:] | |
| // Check if the address is the correct length | |
| if len(address) != 40 { | |
| return fmt.Errorf("address is not the correct length") | |
| } | |
| // Hash the lowercase address | |
| hash := sha3.NewLegacyKeccak256() | |
| hash.Write([]byte(strings.ToLower(address))) | |
| hashedAddress := hash.Sum(nil) | |
| // Iterate over each character in the address | |
| for i := 0; i < len(address); i++ { | |
| if address[i] >= '0' && address[i] <= '9' { | |
| // We can't upper-case the decimal digits | |
| continue | |
| } | |
| // Check if the corresponding hex digit (nibble) in the hash is 8 or higher | |
| hashedValue := hashedAddress[i/2] >> uint(4*(1-i%2)) & 0xf | |
| if hashedValue >= 8 { | |
| if address[i] < 'A' || address[i] > 'F' { | |
| // The character is not upper-case | |
| return fmt.Errorf("character at position %d should be upper-case", i) | |
| } | |
| } else { | |
| if address[i] < 'a' || address[i] > 'f' { | |
| // The character is not lower-case | |
| return fmt.Errorf("character at position %d should be lower-case", i) | |
| } | |
| } | |
| } | |
| return nil | |
| } | |
| func TestIsEIP55(t *testing.T) { | |
| // Define test cases | |
| testCases := []struct { | |
| name string | |
| address string | |
| wantErr bool | |
| }{ | |
| { | |
| name: "Valid EIP55 address", | |
| address: "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed", | |
| wantErr: false, | |
| }, | |
| { | |
| name: "Invalid EIP55 address", | |
| address: "0x5aaeb6053f3e94c9b9a09f33669435e7ef1beaed", | |
| wantErr: true, | |
| }, | |
| { | |
| name: "Address without 0x prefix", | |
| address: "5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed", | |
| wantErr: true, | |
| }, | |
| { | |
| name: "Address of incorrect length", | |
| address: "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1Be", | |
| wantErr: true, | |
| }, | |
| } | |
| for _, tc := range testCases { | |
| t.Run(tc.name, func(t *testing.T) { | |
| err := isEIP55(tc.address) | |
| if (err != nil) != tc.wantErr { | |
| t.Errorf("isEIP55() error = %v, wantErr %v", err, tc.wantErr) | |
| } | |
| }) | |
| } | |
| } | |
| func main() { | |
| fmt.Println(IsEIP55("0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed")) // Should print: <nil> | |
| fmt.Println(IsEIP55("0x5aaeb6053f3e94c9b9a09f33669435e7ef1beaed")) // Should print: character at position 1 should be upper-case | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment