Skip to content

Commit

Permalink
Merge pull request #24 from Brahma-fi/ft-1271
Browse files Browse the repository at this point in the history
add support for EIP-1271 signature validators
  • Loading branch information
rahul0tripathi authored Oct 18, 2024
2 parents 653204f + 4c66b7e commit 2b3fbb6
Show file tree
Hide file tree
Showing 5 changed files with 382 additions and 1 deletion.
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ gen-abis:
abigen --abi=./contracts/abis/safe.json --pkg=safe --out=contracts/safe/safe.go
abigen --abi=./contracts/abis/wallet_registry.json --pkg=walletregistry --out=contracts/walletregistry/wallet_registry.go
abigen --abi=./contracts/abis/multicall3.json --pkg=multicall --out=contracts/multicall/multicall.go
abigen --abi=./contracts/abis/eip_1271_validator.json --pkg=eip1271validator --out=contracts/validators/eip1271.go

build: build-common ## - build
@ $(GO) build ./...
Expand All @@ -31,7 +32,7 @@ build-common: ## - execute build common tasks clean and mod tidy

.PHONY: test
test: ## - execute go test command
@ go test -v -cover ./...
@ go test -v -cover ./... -skip 'TestVerifySignedSafeSignatureWithEIP1271'

.PHONY: scan
scan: ## - execute GOSEC static code analysis
Expand Down
26 changes: 26 additions & 0 deletions contracts/abis/eip_1271_validator.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
[
{
"inputs": [
{
"internalType": "bytes32",
"name": "_hash",
"type": "bytes32"
},
{
"internalType": "bytes",
"name": "_signature",
"type": "bytes"
}
],
"name": "isValidSignature",
"outputs": [
{
"internalType": "bytes4",
"name": "",
"type": "bytes4"
}
],
"stateMutability": "view",
"type": "function"
}
]
212 changes: 212 additions & 0 deletions contracts/validators/eip1271.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

110 changes: 110 additions & 0 deletions wallet/eip1271_validator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package wallet

import (
"context"
"fmt"

eip1271validator "github.com/Brahma-fi/go-safe/contracts/validators"
"github.com/Brahma-fi/go-safe/utils"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/signer/core/apitypes"
)

const (
//MagicValueHex bytes4(keccak256("isValidSignature(bytes32,bytes)")
MagicValueHex = "0x1626ba7e"
)

func isValidSignature(
ctx context.Context,
caller bind.ContractCaller,
signer common.Address,
hash common.Hash,
signature []byte,
) error {
validator, err := eip1271validator.NewEip1271validatorCaller(signer, caller)
if err != nil {
return err
}

magicValue, err := validator.IsValidSignature(&bind.CallOpts{Context: ctx}, hash, signature)
switch {
case err != nil:
return err
case hexutil.Encode(magicValue[:]) != MagicValueHex:
return fmt.Errorf("failed to verify magicValue want=%s found=%s", MagicValueHex, hexutil.Encode(magicValue[:]))
}

return nil
}

func VerifyTypedDataSignatureWithEIP1271(
ctx context.Context,
caller bind.ContractCaller,
signer common.Address,
request apitypes.TypedData,
signature []byte,
) error {
hash, err := utils.GetTypedDataHash(request)
if err != nil {
return err
}

return isValidSignature(ctx, caller, signer, hash, signature)
}

func VerifyPersonalSignatureWithEIP1271(
ctx context.Context,
caller bind.ContractCaller,
signer common.Address,
message string,
signature []byte,
) error {
return isValidSignature(ctx, caller, signer, utils.GetMessageHash(message), signature)
}

func GetSafeMessageDigest(
message common.Hash,
chainID int64,
safeAddress common.Address,
) (*common.Hash, error) {
safeTransactionTypedData := &apitypes.TypedData{
Types: apitypes.Types{
"EIP712Domain": []apitypes.Type{
{Name: "chainId", Type: "uint256"},
{Name: "verifyingContract", Type: "address"},
},
"SafeMessage": []apitypes.Type{
{Name: "message", Type: "bytes"},
},
},
PrimaryType: "SafeMessage",
Domain: apitypes.TypedDataDomain{
ChainId: math.NewHexOrDecimal256(chainID),
VerifyingContract: safeAddress.Hex(),
},
Message: map[string]interface{}{
"message": message.Hex(),
},
}

domainSeparator, err := safeTransactionTypedData.HashStruct("EIP712Domain", safeTransactionTypedData.Domain.Map())
if err != nil {
return nil, fmt.Errorf("eip712domain hash struct: %w", err)
}

typedDataHash, err := safeTransactionTypedData.HashStruct(
safeTransactionTypedData.PrimaryType,
safeTransactionTypedData.Message,
)
if err != nil {
return nil, fmt.Errorf("primary type hash struct: %w", err)
}

sigHash := crypto.Keccak256Hash([]byte(fmt.Sprintf("\x19\x01%s%s", string(domainSeparator), string(typedDataHash))))
return &sigHash, nil
}
Loading

0 comments on commit 2b3fbb6

Please sign in to comment.