chore(wallet)_: ens resolver identified under ens api
New EnsResolver type identified and will be responsible for network calls, while ens api will use it (until mobile app switches to a new sending flow) and continue managing other (db) interactions.
This commit is contained in:
parent
11cf42bedd
commit
b4f819d85c
|
@ -593,7 +593,7 @@ func (b *StatusNode) walletService(accountsDB *accounts.Database, appDB *sql.DB,
|
|||
if b.walletSrvc == nil {
|
||||
b.walletSrvc = wallet.NewService(
|
||||
b.walletDB, accountsDB, appDB, b.rpcClient, accountsFeed, settingsFeed, b.gethAccountManager, b.transactor, b.config,
|
||||
b.ensService(b.timeSourceNow()),
|
||||
b.ensService(b.timeSourceNow()).API().EnsResolver(),
|
||||
b.pendingTracker,
|
||||
walletFeed,
|
||||
b.httpServer,
|
||||
|
|
|
@ -9,50 +9,41 @@ import (
|
|||
"math/big"
|
||||
"net/url"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/multiformats/go-multibase"
|
||||
"github.com/multiformats/go-multihash"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/wealdtech/go-ens/v3"
|
||||
"github.com/wealdtech/go-multicodec"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/ethereum/go-ethereum"
|
||||
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/status-im/status-go/account"
|
||||
gocommon "github.com/status-im/status-go/common"
|
||||
"github.com/status-im/status-go/contracts"
|
||||
"github.com/status-im/status-go/contracts/registrar"
|
||||
"github.com/status-im/status-go/contracts/resolver"
|
||||
"github.com/status-im/status-go/contracts/snt"
|
||||
"github.com/status-im/status-go/logutils"
|
||||
"github.com/status-im/status-go/params"
|
||||
"github.com/status-im/status-go/rpc"
|
||||
"github.com/status-im/status-go/services/ens/ensresolver"
|
||||
"github.com/status-im/status-go/services/utils"
|
||||
wcommon "github.com/status-im/status-go/services/wallet/common"
|
||||
"github.com/status-im/status-go/transactions"
|
||||
)
|
||||
|
||||
const StatusDomain = "stateofus.eth"
|
||||
|
||||
func NewAPI(rpcClient *rpc.Client, accountsManager *account.GethManager, pendingTracker *transactions.PendingTxTracker, config *params.NodeConfig, appDb *sql.DB, timeSource func() time.Time, syncUserDetailFunc *syncUsernameDetail) *API {
|
||||
return &API{
|
||||
contractMaker: &contracts.ContractMaker{
|
||||
RPCClient: rpcClient,
|
||||
},
|
||||
ensResolver: ensresolver.NewEnsResolver(rpcClient),
|
||||
|
||||
accountsManager: accountsManager,
|
||||
pendingTracker: pendingTracker,
|
||||
config: config,
|
||||
addrPerChain: make(map[uint64]common.Address),
|
||||
db: NewEnsDatabase(appDb),
|
||||
|
||||
quit: make(chan struct{}),
|
||||
timeSource: timeSource,
|
||||
syncUserDetailFunc: syncUserDetailFunc,
|
||||
}
|
||||
|
@ -68,17 +59,11 @@ type URI struct {
|
|||
type syncUsernameDetail func(context.Context, *UsernameDetail) error
|
||||
|
||||
type API struct {
|
||||
contractMaker *contracts.ContractMaker
|
||||
ensResolver *ensresolver.EnsResolver
|
||||
accountsManager *account.GethManager
|
||||
pendingTracker *transactions.PendingTxTracker
|
||||
config *params.NodeConfig
|
||||
|
||||
addrPerChain map[uint64]common.Address
|
||||
addrPerChainMutex sync.Mutex
|
||||
|
||||
quitOnce sync.Once
|
||||
quit chan struct{}
|
||||
|
||||
db *Database
|
||||
syncUserDetailFunc *syncUsernameDetail
|
||||
|
||||
|
@ -86,9 +71,11 @@ type API struct {
|
|||
}
|
||||
|
||||
func (api *API) Stop() {
|
||||
api.quitOnce.Do(func() {
|
||||
close(api.quit)
|
||||
})
|
||||
api.ensResolver.Stop()
|
||||
}
|
||||
|
||||
func (api *API) EnsResolver() *ensresolver.EnsResolver {
|
||||
return api.ensResolver
|
||||
}
|
||||
|
||||
func (api *API) unixTime() uint64 {
|
||||
|
@ -122,236 +109,52 @@ func (api *API) Remove(ctx context.Context, chainID uint64, username string) err
|
|||
}
|
||||
|
||||
func (api *API) GetRegistrarAddress(ctx context.Context, chainID uint64) (common.Address, error) {
|
||||
return api.usernameRegistrarAddr(ctx, chainID)
|
||||
return api.ensResolver.GetRegistrarAddress(ctx, chainID)
|
||||
}
|
||||
|
||||
func (api *API) Resolver(ctx context.Context, chainID uint64, username string) (*common.Address, error) {
|
||||
err := ValidateENSUsername(username)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
registry, err := api.contractMaker.NewRegistry(chainID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
callOpts := &bind.CallOpts{Context: ctx, Pending: false}
|
||||
resolver, err := registry.Resolver(callOpts, NameHash(username))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &resolver, nil
|
||||
return api.ensResolver.Resolver(ctx, chainID, username)
|
||||
}
|
||||
|
||||
func (api *API) GetName(ctx context.Context, chainID uint64, address common.Address) (string, error) {
|
||||
backend, err := api.contractMaker.RPCClient.EthClient(chainID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return ens.ReverseResolve(backend, address)
|
||||
return api.ensResolver.GetName(ctx, chainID, address)
|
||||
}
|
||||
|
||||
func (api *API) OwnerOf(ctx context.Context, chainID uint64, username string) (*common.Address, error) {
|
||||
err := ValidateENSUsername(username)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
registry, err := api.contractMaker.NewRegistry(chainID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
callOpts := &bind.CallOpts{Context: ctx, Pending: false}
|
||||
owner, err := registry.Owner(callOpts, NameHash(username))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &owner, nil
|
||||
return api.ensResolver.OwnerOf(ctx, chainID, username)
|
||||
}
|
||||
|
||||
func (api *API) ContentHash(ctx context.Context, chainID uint64, username string) ([]byte, error) {
|
||||
err := ValidateENSUsername(username)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resolverAddress, err := api.Resolver(ctx, chainID, username)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resolver, err := api.contractMaker.NewPublicResolver(chainID, resolverAddress)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
callOpts := &bind.CallOpts{Context: ctx, Pending: false}
|
||||
contentHash, err := resolver.Contenthash(callOpts, NameHash(username))
|
||||
if err != nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return contentHash, nil
|
||||
return api.ensResolver.ContentHash(ctx, chainID, username)
|
||||
}
|
||||
|
||||
func (api *API) PublicKeyOf(ctx context.Context, chainID uint64, username string) (string, error) {
|
||||
err := ValidateENSUsername(username)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
resolverAddress, err := api.Resolver(ctx, chainID, username)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
resolver, err := api.contractMaker.NewPublicResolver(chainID, resolverAddress)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
callOpts := &bind.CallOpts{Context: ctx, Pending: false}
|
||||
pubKey, err := resolver.Pubkey(callOpts, NameHash(username))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return "0x04" + hex.EncodeToString(pubKey.X[:]) + hex.EncodeToString(pubKey.Y[:]), nil
|
||||
return api.ensResolver.PublicKeyOf(ctx, chainID, username)
|
||||
}
|
||||
|
||||
func (api *API) AddressOf(ctx context.Context, chainID uint64, username string) (*common.Address, error) {
|
||||
err := ValidateENSUsername(username)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resolverAddress, err := api.Resolver(ctx, chainID, username)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resolver, err := api.contractMaker.NewPublicResolver(chainID, resolverAddress)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
callOpts := &bind.CallOpts{Context: ctx, Pending: false}
|
||||
addr, err := resolver.Addr(callOpts, NameHash(username))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &addr, nil
|
||||
}
|
||||
|
||||
func (api *API) usernameRegistrarAddr(ctx context.Context, chainID uint64) (common.Address, error) {
|
||||
logutils.ZapLogger().Info("obtaining username registrar address")
|
||||
api.addrPerChainMutex.Lock()
|
||||
defer api.addrPerChainMutex.Unlock()
|
||||
addr, ok := api.addrPerChain[chainID]
|
||||
if ok {
|
||||
return addr, nil
|
||||
}
|
||||
|
||||
registryAddr, err := api.OwnerOf(ctx, chainID, StatusDomain)
|
||||
if err != nil {
|
||||
return common.Address{}, err
|
||||
}
|
||||
|
||||
api.addrPerChain[chainID] = *registryAddr
|
||||
|
||||
go func() {
|
||||
defer gocommon.LogOnPanic()
|
||||
registry, err := api.contractMaker.NewRegistry(chainID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
logs := make(chan *resolver.ENSRegistryWithFallbackNewOwner)
|
||||
|
||||
sub, err := registry.WatchNewOwner(&bind.WatchOpts{}, logs, nil, nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-api.quit:
|
||||
logutils.ZapLogger().Info("quitting ens contract subscription")
|
||||
sub.Unsubscribe()
|
||||
return
|
||||
case err := <-sub.Err():
|
||||
if err != nil {
|
||||
logutils.ZapLogger().Error("ens contract subscription error: " + err.Error())
|
||||
}
|
||||
return
|
||||
case vLog := <-logs:
|
||||
api.addrPerChainMutex.Lock()
|
||||
api.addrPerChain[chainID] = vLog.Owner
|
||||
api.addrPerChainMutex.Unlock()
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return *registryAddr, nil
|
||||
return api.ensResolver.AddressOf(ctx, chainID, username)
|
||||
}
|
||||
|
||||
func (api *API) ExpireAt(ctx context.Context, chainID uint64, username string) (string, error) {
|
||||
registryAddr, err := api.usernameRegistrarAddr(ctx, chainID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
registrar, err := api.contractMaker.NewUsernameRegistrar(chainID, registryAddr)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
callOpts := &bind.CallOpts{Context: ctx, Pending: false}
|
||||
expTime, err := registrar.GetExpirationTime(callOpts, UsernameToLabel(username))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%x", expTime), nil
|
||||
return api.ensResolver.ExpireAt(ctx, chainID, username)
|
||||
}
|
||||
|
||||
func (api *API) Price(ctx context.Context, chainID uint64) (string, error) {
|
||||
registryAddr, err := api.usernameRegistrarAddr(ctx, chainID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
registrar, err := api.contractMaker.NewUsernameRegistrar(chainID, registryAddr)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
callOpts := &bind.CallOpts{Context: ctx, Pending: false}
|
||||
price, err := registrar.GetPrice(callOpts)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%x", price), nil
|
||||
return api.ensResolver.Price(ctx, chainID)
|
||||
}
|
||||
|
||||
// Deprecated: `Release` was used before introducing a new, uniform, sending flow that uses router.
|
||||
// Releasing ens username should start from calling `wallet_getSuggestedRoutesAsync`
|
||||
// TODO: remove once mobile switches to a new sending flow.
|
||||
func (api *API) Release(ctx context.Context, chainID uint64, txArgs transactions.SendTxArgs, password string, username string) (string, error) {
|
||||
registryAddr, err := api.usernameRegistrarAddr(ctx, chainID)
|
||||
registryAddr, err := api.ensResolver.GetRegistrarAddress(ctx, chainID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
registrar, err := api.contractMaker.NewUsernameRegistrar(chainID, registryAddr)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
txOpts := txArgs.ToTransactOpts(utils.GetSigner(chainID, api.accountsManager, api.config.KeyStoreDir, txArgs.From, password))
|
||||
tx, err := registrar.Release(txOpts, UsernameToLabel(username))
|
||||
signFn := utils.GetSigner(chainID, api.accountsManager, api.config.KeyStoreDir, txArgs.From, password)
|
||||
tx, err := api.ensResolver.Release(ctx, chainID, registryAddr, txArgs, username, signFn)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -370,7 +173,7 @@ func (api *API) Release(ctx context.Context, chainID uint64, txArgs transactions
|
|||
return "", err
|
||||
}
|
||||
|
||||
err = api.Remove(ctx, chainID, fullDomainName(username))
|
||||
err = api.Remove(ctx, chainID, wcommon.FullDomainName(username))
|
||||
|
||||
if err != nil {
|
||||
logutils.ZapLogger().Warn("Releasing ENS username: transaction successful, but removing failed")
|
||||
|
@ -379,13 +182,16 @@ func (api *API) Release(ctx context.Context, chainID uint64, txArgs transactions
|
|||
return tx.Hash().String(), nil
|
||||
}
|
||||
|
||||
// Deprecated: `ReleasePrepareTxCallMsg` was used before introducing a new, uniform, sending flow that uses router.
|
||||
// Releasing ens username should start from calling `wallet_getSuggestedRoutesAsync`
|
||||
// TODO: remove once mobile switches to a new sending flow.
|
||||
func (api *API) ReleasePrepareTxCallMsg(ctx context.Context, chainID uint64, txArgs transactions.SendTxArgs, username string) (ethereum.CallMsg, error) {
|
||||
registrarABI, err := abi.JSON(strings.NewReader(registrar.UsernameRegistrarABI))
|
||||
if err != nil {
|
||||
return ethereum.CallMsg{}, err
|
||||
}
|
||||
|
||||
data, err := registrarABI.Pack("release", UsernameToLabel(username))
|
||||
data, err := registrarABI.Pack("release", wcommon.UsernameToLabel(username))
|
||||
if err != nil {
|
||||
return ethereum.CallMsg{}, err
|
||||
}
|
||||
|
@ -402,6 +208,9 @@ func (api *API) ReleasePrepareTxCallMsg(ctx context.Context, chainID uint64, txA
|
|||
}, nil
|
||||
}
|
||||
|
||||
// Deprecated: `ReleasePrepareTx` was used before introducing a new, uniform, sending flow that uses router.
|
||||
// Releasing ens username should start from calling `wallet_getSuggestedRoutesAsync`
|
||||
// TODO: remove once mobile switches to a new sending flow.
|
||||
func (api *API) ReleasePrepareTx(ctx context.Context, chainID uint64, txArgs transactions.SendTxArgs, username string) (interface{}, error) {
|
||||
callMsg, err := api.ReleasePrepareTxCallMsg(ctx, chainID, txArgs, username)
|
||||
if err != nil {
|
||||
|
@ -411,76 +220,30 @@ func (api *API) ReleasePrepareTx(ctx context.Context, chainID uint64, txArgs tra
|
|||
return toCallArg(callMsg), nil
|
||||
}
|
||||
|
||||
// Deprecated: `ReleaseEstimate` was used before introducing a new, uniform, sending flow that uses router.
|
||||
// Releasing ens username should start from calling `wallet_getSuggestedRoutesAsync`
|
||||
// TODO: remove once mobile switches to a new sending flow.
|
||||
func (api *API) ReleaseEstimate(ctx context.Context, chainID uint64, txArgs transactions.SendTxArgs, username string) (uint64, error) {
|
||||
registrarABI, err := abi.JSON(strings.NewReader(registrar.UsernameRegistrarABI))
|
||||
callMsg, err := api.ReleasePrepareTxCallMsg(ctx, chainID, txArgs, username)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
data, err := registrarABI.Pack("release", UsernameToLabel(username))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
ethClient, err := api.contractMaker.RPCClient.EthClient(chainID)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
registryAddr, err := api.usernameRegistrarAddr(ctx, chainID)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
estimate, err := ethClient.EstimateGas(ctx, ethereum.CallMsg{
|
||||
From: common.Address(txArgs.From),
|
||||
To: ®istryAddr,
|
||||
Value: big.NewInt(0),
|
||||
Data: data,
|
||||
})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return estimate + 1000, nil
|
||||
return api.ensResolver.ReleaseEstimate(ctx, chainID, callMsg)
|
||||
}
|
||||
|
||||
// Deprecated: `Register` was used before introducing a new, uniform, sending flow that uses router.
|
||||
// Releasing ens username should start from calling `wallet_getSuggestedRoutesAsync`
|
||||
// TODO: remove once mobile switches to a new sending flow.
|
||||
func (api *API) Register(ctx context.Context, chainID uint64, txArgs transactions.SendTxArgs, password string, username string, pubkey string) (string, error) {
|
||||
snt, err := api.contractMaker.NewSNT(chainID)
|
||||
registryAddr, err := api.ensResolver.GetRegistrarAddress(ctx, chainID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
priceHex, err := api.Price(ctx, chainID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
price := new(big.Int)
|
||||
price.SetString(priceHex, 16)
|
||||
|
||||
registrarABI, err := abi.JSON(strings.NewReader(registrar.UsernameRegistrarABI))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
x, y := ExtractCoordinates(pubkey)
|
||||
extraData, err := registrarABI.Pack("register", UsernameToLabel(username), common.Address(txArgs.From), x, y)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
registryAddr, err := api.usernameRegistrarAddr(ctx, chainID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
txOpts := txArgs.ToTransactOpts(utils.GetSigner(chainID, api.accountsManager, api.config.KeyStoreDir, txArgs.From, password))
|
||||
tx, err := snt.ApproveAndCall(
|
||||
txOpts,
|
||||
registryAddr,
|
||||
price,
|
||||
extraData,
|
||||
)
|
||||
signFn := utils.GetSigner(chainID, api.accountsManager, api.config.KeyStoreDir, txArgs.From, password)
|
||||
|
||||
tx, err := api.ensResolver.Register(ctx, chainID, registryAddr, txArgs, username, pubkey, signFn)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -499,7 +262,7 @@ func (api *API) Register(ctx context.Context, chainID uint64, txArgs transaction
|
|||
return "", err
|
||||
}
|
||||
|
||||
err = api.Add(ctx, chainID, fullDomainName(username))
|
||||
err = api.Add(ctx, chainID, wcommon.FullDomainName(username))
|
||||
if err != nil {
|
||||
logutils.ZapLogger().Warn("Registering ENS username: transaction successful, but adding failed")
|
||||
}
|
||||
|
@ -507,6 +270,9 @@ func (api *API) Register(ctx context.Context, chainID uint64, txArgs transaction
|
|||
return tx.Hash().String(), nil
|
||||
}
|
||||
|
||||
// Deprecated: `RegisterPrepareTxCallMsg` was used before introducing a new, uniform, sending flow that uses router.
|
||||
// Releasing ens username should start from calling `wallet_getSuggestedRoutesAsync`
|
||||
// TODO: remove once mobile switches to a new sending flow.
|
||||
func (api *API) RegisterPrepareTxCallMsg(ctx context.Context, chainID uint64, txArgs transactions.SendTxArgs, username string, pubkey string) (ethereum.CallMsg, error) {
|
||||
priceHex, err := api.Price(ctx, chainID)
|
||||
if err != nil {
|
||||
|
@ -520,8 +286,8 @@ func (api *API) RegisterPrepareTxCallMsg(ctx context.Context, chainID uint64, tx
|
|||
return ethereum.CallMsg{}, err
|
||||
}
|
||||
|
||||
x, y := ExtractCoordinates(pubkey)
|
||||
extraData, err := registrarABI.Pack("register", UsernameToLabel(username), common.Address(txArgs.From), x, y)
|
||||
x, y := wcommon.ExtractCoordinates(pubkey)
|
||||
extraData, err := registrarABI.Pack("register", wcommon.UsernameToLabel(username), common.Address(txArgs.From), x, y)
|
||||
if err != nil {
|
||||
return ethereum.CallMsg{}, err
|
||||
}
|
||||
|
@ -531,7 +297,7 @@ func (api *API) RegisterPrepareTxCallMsg(ctx context.Context, chainID uint64, tx
|
|||
return ethereum.CallMsg{}, err
|
||||
}
|
||||
|
||||
registryAddr, err := api.usernameRegistrarAddr(ctx, chainID)
|
||||
registryAddr, err := api.ensResolver.GetRegistrarAddress(ctx, chainID)
|
||||
if err != nil {
|
||||
return ethereum.CallMsg{}, err
|
||||
}
|
||||
|
@ -553,6 +319,9 @@ func (api *API) RegisterPrepareTxCallMsg(ctx context.Context, chainID uint64, tx
|
|||
}, nil
|
||||
}
|
||||
|
||||
// Deprecated: `RegisterPrepareTx` was used before introducing a new, uniform, sending flow that uses router.
|
||||
// Releasing ens username should start from calling `wallet_getSuggestedRoutesAsync`
|
||||
// TODO: remove once mobile switches to a new sending flow.
|
||||
func (api *API) RegisterPrepareTx(ctx context.Context, chainID uint64, txArgs transactions.SendTxArgs, username string, pubkey string) (interface{}, error) {
|
||||
callMsg, err := api.RegisterPrepareTxCallMsg(ctx, chainID, txArgs, username, pubkey)
|
||||
if err != nil {
|
||||
|
@ -562,43 +331,29 @@ func (api *API) RegisterPrepareTx(ctx context.Context, chainID uint64, txArgs tr
|
|||
return toCallArg(callMsg), nil
|
||||
}
|
||||
|
||||
// Deprecated: `RegisterEstimate` was used before introducing a new, uniform, sending flow that uses router.
|
||||
// Releasing ens username should start from calling `wallet_getSuggestedRoutesAsync`
|
||||
// TODO: remove once mobile switches to a new sending flow.
|
||||
func (api *API) RegisterEstimate(ctx context.Context, chainID uint64, txArgs transactions.SendTxArgs, username string, pubkey string) (uint64, error) {
|
||||
ethClient, err := api.contractMaker.RPCClient.EthClient(chainID)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
callMsg, err := api.RegisterPrepareTxCallMsg(ctx, chainID, txArgs, username, pubkey)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
estimate, err := ethClient.EstimateGas(ctx, callMsg)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return estimate + 1000, nil
|
||||
return api.ensResolver.RegisterEstimate(ctx, chainID, callMsg)
|
||||
}
|
||||
|
||||
// Deprecated: `SetPubKey` was used before introducing a new, uniform, sending flow that uses router.
|
||||
// Releasing ens username should start from calling `wallet_getSuggestedRoutesAsync`
|
||||
// TODO: remove once mobile switches to a new sending flow.
|
||||
func (api *API) SetPubKey(ctx context.Context, chainID uint64, txArgs transactions.SendTxArgs, password string, username string, pubkey string) (string, error) {
|
||||
err := ValidateENSUsername(username)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
resolverAddress, err := api.Resolver(ctx, chainID, username)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
resolver, err := api.contractMaker.NewPublicResolver(chainID, resolverAddress)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
x, y := ExtractCoordinates(pubkey)
|
||||
txOpts := txArgs.ToTransactOpts(utils.GetSigner(chainID, api.accountsManager, api.config.KeyStoreDir, txArgs.From, password))
|
||||
tx, err := resolver.SetPubkey(txOpts, NameHash(username), x, y)
|
||||
signFn := utils.GetSigner(chainID, api.accountsManager, api.config.KeyStoreDir, txArgs.From, password)
|
||||
tx, err := api.ensResolver.SetPubKey(ctx, chainID, resolverAddress, txArgs, username, pubkey, signFn)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -617,7 +372,7 @@ func (api *API) SetPubKey(ctx context.Context, chainID uint64, txArgs transactio
|
|||
return "", err
|
||||
}
|
||||
|
||||
err = api.Add(ctx, chainID, fullDomainName(username))
|
||||
err = api.Add(ctx, chainID, wcommon.FullDomainName(username))
|
||||
|
||||
if err != nil {
|
||||
logutils.ZapLogger().Warn("Registering ENS username: transaction successful, but adding failed")
|
||||
|
@ -626,19 +381,22 @@ func (api *API) SetPubKey(ctx context.Context, chainID uint64, txArgs transactio
|
|||
return tx.Hash().String(), nil
|
||||
}
|
||||
|
||||
// Deprecated: `SetPubKeyPrepareTxCallMsg` was used before introducing a new, uniform, sending flow that uses router.
|
||||
// Releasing ens username should start from calling `wallet_getSuggestedRoutesAsync`
|
||||
// TODO: remove once mobile switches to a new sending flow.
|
||||
func (api *API) SetPubKeyPrepareTxCallMsg(ctx context.Context, chainID uint64, txArgs transactions.SendTxArgs, username string, pubkey string) (ethereum.CallMsg, error) {
|
||||
err := ValidateENSUsername(username)
|
||||
err := wcommon.ValidateENSUsername(username)
|
||||
if err != nil {
|
||||
return ethereum.CallMsg{}, err
|
||||
}
|
||||
x, y := ExtractCoordinates(pubkey)
|
||||
x, y := wcommon.ExtractCoordinates(pubkey)
|
||||
|
||||
resolverABI, err := abi.JSON(strings.NewReader(resolver.PublicResolverABI))
|
||||
if err != nil {
|
||||
return ethereum.CallMsg{}, err
|
||||
}
|
||||
|
||||
data, err := resolverABI.Pack("setPubkey", NameHash(username), x, y)
|
||||
data, err := resolverABI.Pack("setPubkey", wcommon.NameHash(username), x, y)
|
||||
if err != nil {
|
||||
return ethereum.CallMsg{}, err
|
||||
}
|
||||
|
@ -656,6 +414,9 @@ func (api *API) SetPubKeyPrepareTxCallMsg(ctx context.Context, chainID uint64, t
|
|||
}, nil
|
||||
}
|
||||
|
||||
// Deprecated: `SetPubKeyPrepareTx` was used before introducing a new, uniform, sending flow that uses router.
|
||||
// Releasing ens username should start from calling `wallet_getSuggestedRoutesAsync`
|
||||
// TODO: remove once mobile switches to a new sending flow.
|
||||
func (api *API) SetPubKeyPrepareTx(ctx context.Context, chainID uint64, txArgs transactions.SendTxArgs, username string, pubkey string) (interface{}, error) {
|
||||
callMsg, err := api.SetPubKeyPrepareTxCallMsg(ctx, chainID, txArgs, username, pubkey)
|
||||
if err != nil {
|
||||
|
@ -665,22 +426,16 @@ func (api *API) SetPubKeyPrepareTx(ctx context.Context, chainID uint64, txArgs t
|
|||
return toCallArg(callMsg), nil
|
||||
}
|
||||
|
||||
// Deprecated: `SetPubKeyEstimate` was used before introducing a new, uniform, sending flow that uses router.
|
||||
// Releasing ens username should start from calling `wallet_getSuggestedRoutesAsync`
|
||||
// TODO: remove once mobile switches to a new sending flow.
|
||||
func (api *API) SetPubKeyEstimate(ctx context.Context, chainID uint64, txArgs transactions.SendTxArgs, username string, pubkey string) (uint64, error) {
|
||||
ethClient, err := api.contractMaker.RPCClient.EthClient(chainID)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
callMsg, err := api.SetPubKeyPrepareTxCallMsg(ctx, chainID, txArgs, username, pubkey)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
estimate, err := ethClient.EstimateGas(ctx, callMsg)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return estimate + 1000, nil
|
||||
return api.ensResolver.SetPubKeyEstimate(ctx, chainID, callMsg)
|
||||
}
|
||||
|
||||
func (api *API) ResourceURL(ctx context.Context, chainID uint64, username string) (*URI, error) {
|
||||
|
@ -773,7 +528,3 @@ func toCallArg(msg ethereum.CallMsg) interface{} {
|
|||
}
|
||||
return arg
|
||||
}
|
||||
|
||||
func fullDomainName(username string) string {
|
||||
return username + "." + StatusDomain
|
||||
}
|
||||
|
|
|
@ -0,0 +1,369 @@
|
|||
package ensresolver
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/wealdtech/go-ens/v3"
|
||||
|
||||
"github.com/ethereum/go-ethereum"
|
||||
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
gocommon "github.com/status-im/status-go/common"
|
||||
"github.com/status-im/status-go/contracts"
|
||||
"github.com/status-im/status-go/contracts/registrar"
|
||||
"github.com/status-im/status-go/contracts/resolver"
|
||||
"github.com/status-im/status-go/logutils"
|
||||
"github.com/status-im/status-go/rpc"
|
||||
walletCommon "github.com/status-im/status-go/services/wallet/common"
|
||||
"github.com/status-im/status-go/transactions"
|
||||
)
|
||||
|
||||
func NewEnsResolver(rpcClient *rpc.Client) *EnsResolver {
|
||||
return &EnsResolver{
|
||||
contractMaker: &contracts.ContractMaker{
|
||||
RPCClient: rpcClient,
|
||||
},
|
||||
addrPerChain: make(map[uint64]common.Address),
|
||||
|
||||
quit: make(chan struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
type EnsResolver struct {
|
||||
contractMaker *contracts.ContractMaker
|
||||
|
||||
addrPerChain map[uint64]common.Address
|
||||
addrPerChainMutex sync.Mutex
|
||||
|
||||
quitOnce sync.Once
|
||||
quit chan struct{}
|
||||
}
|
||||
|
||||
func (e *EnsResolver) Stop() {
|
||||
e.quitOnce.Do(func() {
|
||||
close(e.quit)
|
||||
})
|
||||
}
|
||||
|
||||
func (e *EnsResolver) GetRegistrarAddress(ctx context.Context, chainID uint64) (common.Address, error) {
|
||||
return e.usernameRegistrarAddr(ctx, chainID)
|
||||
}
|
||||
|
||||
func (e *EnsResolver) Resolver(ctx context.Context, chainID uint64, username string) (*common.Address, error) {
|
||||
err := walletCommon.ValidateENSUsername(username)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
registry, err := e.contractMaker.NewRegistry(chainID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
callOpts := &bind.CallOpts{Context: ctx, Pending: false}
|
||||
resolver, err := registry.Resolver(callOpts, walletCommon.NameHash(username))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &resolver, nil
|
||||
}
|
||||
|
||||
func (e *EnsResolver) GetName(ctx context.Context, chainID uint64, address common.Address) (string, error) {
|
||||
backend, err := e.contractMaker.RPCClient.EthClient(chainID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return ens.ReverseResolve(backend, address)
|
||||
}
|
||||
|
||||
func (e *EnsResolver) OwnerOf(ctx context.Context, chainID uint64, username string) (*common.Address, error) {
|
||||
err := walletCommon.ValidateENSUsername(username)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
registry, err := e.contractMaker.NewRegistry(chainID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
callOpts := &bind.CallOpts{Context: ctx, Pending: false}
|
||||
owner, err := registry.Owner(callOpts, walletCommon.NameHash(username))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &owner, nil
|
||||
}
|
||||
|
||||
func (e *EnsResolver) ContentHash(ctx context.Context, chainID uint64, username string) ([]byte, error) {
|
||||
err := walletCommon.ValidateENSUsername(username)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resolverAddress, err := e.Resolver(ctx, chainID, username)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resolver, err := e.contractMaker.NewPublicResolver(chainID, resolverAddress)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
callOpts := &bind.CallOpts{Context: ctx, Pending: false}
|
||||
contentHash, err := resolver.Contenthash(callOpts, walletCommon.NameHash(username))
|
||||
if err != nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return contentHash, nil
|
||||
}
|
||||
|
||||
func (e *EnsResolver) PublicKeyOf(ctx context.Context, chainID uint64, username string) (string, error) {
|
||||
err := walletCommon.ValidateENSUsername(username)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
resolverAddress, err := e.Resolver(ctx, chainID, username)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
resolver, err := e.contractMaker.NewPublicResolver(chainID, resolverAddress)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
callOpts := &bind.CallOpts{Context: ctx, Pending: false}
|
||||
pubKey, err := resolver.Pubkey(callOpts, walletCommon.NameHash(username))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return "0x04" + hex.EncodeToString(pubKey.X[:]) + hex.EncodeToString(pubKey.Y[:]), nil
|
||||
}
|
||||
|
||||
func (e *EnsResolver) AddressOf(ctx context.Context, chainID uint64, username string) (*common.Address, error) {
|
||||
err := walletCommon.ValidateENSUsername(username)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resolverAddress, err := e.Resolver(ctx, chainID, username)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resolver, err := e.contractMaker.NewPublicResolver(chainID, resolverAddress)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
callOpts := &bind.CallOpts{Context: ctx, Pending: false}
|
||||
addr, err := resolver.Addr(callOpts, walletCommon.NameHash(username))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &addr, nil
|
||||
}
|
||||
|
||||
func (e *EnsResolver) usernameRegistrarAddr(ctx context.Context, chainID uint64) (common.Address, error) {
|
||||
logutils.ZapLogger().Info("obtaining username registrar address")
|
||||
e.addrPerChainMutex.Lock()
|
||||
defer e.addrPerChainMutex.Unlock()
|
||||
addr, ok := e.addrPerChain[chainID]
|
||||
if ok {
|
||||
return addr, nil
|
||||
}
|
||||
|
||||
registryAddr, err := e.OwnerOf(ctx, chainID, walletCommon.StatusDomain)
|
||||
if err != nil {
|
||||
return common.Address{}, err
|
||||
}
|
||||
|
||||
e.addrPerChain[chainID] = *registryAddr
|
||||
|
||||
go func() {
|
||||
defer gocommon.LogOnPanic()
|
||||
registry, err := e.contractMaker.NewRegistry(chainID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
logs := make(chan *resolver.ENSRegistryWithFallbackNewOwner)
|
||||
|
||||
sub, err := registry.WatchNewOwner(&bind.WatchOpts{}, logs, nil, nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-e.quit:
|
||||
logutils.ZapLogger().Info("quitting ens contract subscription")
|
||||
sub.Unsubscribe()
|
||||
return
|
||||
case err := <-sub.Err():
|
||||
if err != nil {
|
||||
logutils.ZapLogger().Error("ens contract subscription error: " + err.Error())
|
||||
}
|
||||
return
|
||||
case vLog := <-logs:
|
||||
e.addrPerChainMutex.Lock()
|
||||
e.addrPerChain[chainID] = vLog.Owner
|
||||
e.addrPerChainMutex.Unlock()
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return *registryAddr, nil
|
||||
}
|
||||
|
||||
func (e *EnsResolver) ExpireAt(ctx context.Context, chainID uint64, username string) (string, error) {
|
||||
registryAddr, err := e.usernameRegistrarAddr(ctx, chainID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
registrar, err := e.contractMaker.NewUsernameRegistrar(chainID, registryAddr)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
callOpts := &bind.CallOpts{Context: ctx, Pending: false}
|
||||
expTime, err := registrar.GetExpirationTime(callOpts, walletCommon.UsernameToLabel(username))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%x", expTime), nil
|
||||
}
|
||||
|
||||
func (e *EnsResolver) Price(ctx context.Context, chainID uint64) (string, error) {
|
||||
registryAddr, err := e.usernameRegistrarAddr(ctx, chainID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
registrar, err := e.contractMaker.NewUsernameRegistrar(chainID, registryAddr)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
callOpts := &bind.CallOpts{Context: ctx, Pending: false}
|
||||
price, err := registrar.GetPrice(callOpts)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%x", price), nil
|
||||
}
|
||||
|
||||
func (e *EnsResolver) Release(ctx context.Context, chainID uint64, registryAddress common.Address, txArgs transactions.SendTxArgs, username string, signFn bind.SignerFn) (*types.Transaction, error) {
|
||||
registrar, err := e.contractMaker.NewUsernameRegistrar(chainID, registryAddress)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
txOpts := txArgs.ToTransactOpts(signFn)
|
||||
return registrar.Release(txOpts, walletCommon.UsernameToLabel(username))
|
||||
}
|
||||
|
||||
func (e *EnsResolver) ReleaseEstimate(ctx context.Context, chainID uint64, callMsg ethereum.CallMsg) (uint64, error) {
|
||||
ethClient, err := e.contractMaker.RPCClient.EthClient(chainID)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
estimate, err := ethClient.EstimateGas(ctx, callMsg)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return estimate + 1000, nil
|
||||
}
|
||||
|
||||
func (e *EnsResolver) Register(ctx context.Context, chainID uint64, registryAddress common.Address, txArgs transactions.SendTxArgs, username string, pubkey string, signFn bind.SignerFn) (*types.Transaction, error) {
|
||||
snt, err := e.contractMaker.NewSNT(chainID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
priceHex, err := e.Price(ctx, chainID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
price := new(big.Int)
|
||||
price.SetString(priceHex, 16)
|
||||
|
||||
registrarABI, err := abi.JSON(strings.NewReader(registrar.UsernameRegistrarABI))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
x, y := walletCommon.ExtractCoordinates(pubkey)
|
||||
extraData, err := registrarABI.Pack("register", walletCommon.UsernameToLabel(username), common.Address(txArgs.From), x, y)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
txOpts := txArgs.ToTransactOpts(signFn)
|
||||
return snt.ApproveAndCall(
|
||||
txOpts,
|
||||
registryAddress,
|
||||
price,
|
||||
extraData,
|
||||
)
|
||||
}
|
||||
|
||||
func (e *EnsResolver) RegisterEstimate(ctx context.Context, chainID uint64, callMsg ethereum.CallMsg) (uint64, error) {
|
||||
ethClient, err := e.contractMaker.RPCClient.EthClient(chainID)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
estimate, err := ethClient.EstimateGas(ctx, callMsg)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return estimate + 1000, nil
|
||||
}
|
||||
|
||||
func (e *EnsResolver) SetPubKey(ctx context.Context, chainID uint64, resolverAddress *common.Address, txArgs transactions.SendTxArgs, username string, pubkey string, signFn bind.SignerFn) (*types.Transaction, error) {
|
||||
err := walletCommon.ValidateENSUsername(username)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resolver, err := e.contractMaker.NewPublicResolver(chainID, resolverAddress)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
x, y := walletCommon.ExtractCoordinates(pubkey)
|
||||
txOpts := txArgs.ToTransactOpts(signFn)
|
||||
return resolver.SetPubkey(txOpts, walletCommon.NameHash(username), x, y)
|
||||
}
|
||||
|
||||
func (e *EnsResolver) SetPubKeyEstimate(ctx context.Context, chainID uint64, callMsg ethereum.CallMsg) (uint64, error) {
|
||||
ethClient, err := e.contractMaker.RPCClient.EthClient(chainID)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
estimate, err := ethClient.EstimateGas(ctx, callMsg)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return estimate + 1000, nil
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
package ens
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
)
|
||||
|
||||
func NameHash(name string) common.Hash {
|
||||
node := common.Hash{}
|
||||
|
||||
if len(name) > 0 {
|
||||
labels := strings.Split(name, ".")
|
||||
|
||||
for i := len(labels) - 1; i >= 0; i-- {
|
||||
labelSha := crypto.Keccak256Hash([]byte(labels[i]))
|
||||
node = crypto.Keccak256Hash(node.Bytes(), labelSha.Bytes())
|
||||
}
|
||||
}
|
||||
|
||||
return node
|
||||
}
|
||||
|
||||
func ValidateENSUsername(username string) error {
|
||||
if !strings.HasSuffix(username, ".eth") {
|
||||
return fmt.Errorf("username must end with .eth")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func UsernameToLabel(username string) [32]byte {
|
||||
usernameHashed := crypto.Keccak256([]byte(username))
|
||||
var label [32]byte
|
||||
copy(label[:], usernameHashed)
|
||||
|
||||
return label
|
||||
}
|
||||
|
||||
func ExtractCoordinates(pubkey string) ([32]byte, [32]byte) {
|
||||
x, _ := hex.DecodeString(pubkey[4:68])
|
||||
y, _ := hex.DecodeString(pubkey[68:132])
|
||||
|
||||
var xByte [32]byte
|
||||
copy(xByte[:], x)
|
||||
|
||||
var yByte [32]byte
|
||||
copy(yByte[:], y)
|
||||
|
||||
return xByte, yByte
|
||||
}
|
|
@ -13,6 +13,7 @@ type MultiTransactionIDType int64
|
|||
const (
|
||||
NoMultiTransactionID = MultiTransactionIDType(0)
|
||||
HexAddressLength = 42
|
||||
StatusDomain = "stateofus.eth"
|
||||
)
|
||||
|
||||
type ChainID uint64
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"strings"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/status-im/status-go/contracts/ierc20"
|
||||
)
|
||||
|
||||
|
@ -30,3 +32,51 @@ func GetTokenIdFromSymbol(symbol string) (*big.Int, error) {
|
|||
}
|
||||
return id, nil
|
||||
}
|
||||
|
||||
func FullDomainName(username string) string {
|
||||
return username + "." + StatusDomain
|
||||
}
|
||||
|
||||
func ExtractCoordinates(pubkey string) ([32]byte, [32]byte) {
|
||||
x, _ := hex.DecodeString(pubkey[4:68])
|
||||
y, _ := hex.DecodeString(pubkey[68:132])
|
||||
|
||||
var xByte [32]byte
|
||||
copy(xByte[:], x)
|
||||
|
||||
var yByte [32]byte
|
||||
copy(yByte[:], y)
|
||||
|
||||
return xByte, yByte
|
||||
}
|
||||
|
||||
func NameHash(name string) common.Hash {
|
||||
node := common.Hash{}
|
||||
|
||||
if len(name) > 0 {
|
||||
labels := strings.Split(name, ".")
|
||||
|
||||
for i := len(labels) - 1; i >= 0; i-- {
|
||||
labelSha := crypto.Keccak256Hash([]byte(labels[i]))
|
||||
node = crypto.Keccak256Hash(node.Bytes(), labelSha.Bytes())
|
||||
}
|
||||
}
|
||||
|
||||
return node
|
||||
}
|
||||
|
||||
func ValidateENSUsername(username string) error {
|
||||
if !strings.HasSuffix(username, ".eth") {
|
||||
return fmt.Errorf("username must end with .eth")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func UsernameToLabel(username string) [32]byte {
|
||||
usernameHashed := crypto.Keccak256([]byte(username))
|
||||
var label [32]byte
|
||||
copy(label[:], usernameHashed)
|
||||
|
||||
return label
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@ import (
|
|||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/status-im/status-go/errors"
|
||||
"github.com/status-im/status-go/services/ens"
|
||||
walletCommon "github.com/status-im/status-go/services/wallet/common"
|
||||
"github.com/status-im/status-go/services/wallet/router/fees"
|
||||
"github.com/status-im/status-go/services/wallet/router/pathprocessor"
|
||||
|
@ -103,7 +102,7 @@ func (i *RouteInputParams) Validate() error {
|
|||
return ErrENSSetPubKeyRequiresUsernameAndPubKey
|
||||
}
|
||||
|
||||
if ens.ValidateENSUsername(i.Username) != nil {
|
||||
if walletCommon.ValidateENSUsername(i.Username) != nil {
|
||||
return ErrENSSetPubKeyInvalidUsername
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ import (
|
|||
"github.com/status-im/status-go/contracts/resolver"
|
||||
"github.com/status-im/status-go/eth-node/types"
|
||||
"github.com/status-im/status-go/rpc"
|
||||
"github.com/status-im/status-go/services/ens"
|
||||
"github.com/status-im/status-go/services/ens/ensresolver"
|
||||
walletCommon "github.com/status-im/status-go/services/wallet/common"
|
||||
"github.com/status-im/status-go/transactions"
|
||||
)
|
||||
|
@ -22,16 +22,16 @@ import (
|
|||
type ENSPublicKeyProcessor struct {
|
||||
contractMaker *contracts.ContractMaker
|
||||
transactor transactions.TransactorIface
|
||||
ensService *ens.Service
|
||||
ensResolver *ensresolver.EnsResolver
|
||||
}
|
||||
|
||||
func NewENSPublicKeyProcessor(rpcClient *rpc.Client, transactor transactions.TransactorIface, ensService *ens.Service) *ENSPublicKeyProcessor {
|
||||
func NewENSPublicKeyProcessor(rpcClient *rpc.Client, transactor transactions.TransactorIface, ensResolver *ensresolver.EnsResolver) *ENSPublicKeyProcessor {
|
||||
return &ENSPublicKeyProcessor{
|
||||
contractMaker: &contracts.ContractMaker{
|
||||
RPCClient: rpcClient,
|
||||
},
|
||||
transactor: transactor,
|
||||
ensService: ensService,
|
||||
ensResolver: ensResolver,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -57,8 +57,8 @@ func (s *ENSPublicKeyProcessor) PackTxInputData(params ProcessorInputParams) ([]
|
|||
return []byte{}, createENSPublicKeyErrorResponse(err)
|
||||
}
|
||||
|
||||
x, y := ens.ExtractCoordinates(params.PublicKey)
|
||||
return resolverABI.Pack("setPubkey", ens.NameHash(params.Username), x, y)
|
||||
x, y := walletCommon.ExtractCoordinates(params.PublicKey)
|
||||
return resolverABI.Pack("setPubkey", walletCommon.NameHash(params.Username), x, y)
|
||||
}
|
||||
|
||||
func (s *ENSPublicKeyProcessor) EstimateGas(params ProcessorInputParams) (uint64, error) {
|
||||
|
@ -120,7 +120,7 @@ func (s *ENSPublicKeyProcessor) CalculateAmountOut(params ProcessorInputParams)
|
|||
}
|
||||
|
||||
func (s *ENSPublicKeyProcessor) GetContractAddress(params ProcessorInputParams) (common.Address, error) {
|
||||
addr, err := s.ensService.API().Resolver(context.Background(), params.FromChain.ChainID, params.Username)
|
||||
addr, err := s.ensResolver.Resolver(context.Background(), params.FromChain.ChainID, params.Username)
|
||||
if err != nil {
|
||||
return common.Address{}, createENSPublicKeyErrorResponse(err)
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ import (
|
|||
"github.com/status-im/status-go/contracts/snt"
|
||||
"github.com/status-im/status-go/eth-node/types"
|
||||
"github.com/status-im/status-go/rpc"
|
||||
"github.com/status-im/status-go/services/ens"
|
||||
"github.com/status-im/status-go/services/ens/ensresolver"
|
||||
walletCommon "github.com/status-im/status-go/services/wallet/common"
|
||||
"github.com/status-im/status-go/transactions"
|
||||
)
|
||||
|
@ -24,16 +24,16 @@ import (
|
|||
type ENSRegisterProcessor struct {
|
||||
contractMaker *contracts.ContractMaker
|
||||
transactor transactions.TransactorIface
|
||||
ensService *ens.Service
|
||||
ensResolver *ensresolver.EnsResolver
|
||||
}
|
||||
|
||||
func NewENSRegisterProcessor(rpcClient *rpc.Client, transactor transactions.TransactorIface, ensService *ens.Service) *ENSRegisterProcessor {
|
||||
func NewENSRegisterProcessor(rpcClient *rpc.Client, transactor transactions.TransactorIface, ensResolver *ensresolver.EnsResolver) *ENSRegisterProcessor {
|
||||
return &ENSRegisterProcessor{
|
||||
contractMaker: &contracts.ContractMaker{
|
||||
RPCClient: rpcClient,
|
||||
},
|
||||
transactor: transactor,
|
||||
ensService: ensService,
|
||||
ensResolver: ensResolver,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -46,7 +46,7 @@ func (s *ENSRegisterProcessor) Name() string {
|
|||
}
|
||||
|
||||
func (s *ENSRegisterProcessor) GetPriceForRegisteringEnsName(chainID uint64) (*big.Int, error) {
|
||||
registryAddr, err := s.ensService.API().GetRegistrarAddress(context.Background(), chainID)
|
||||
registryAddr, err := s.ensResolver.GetRegistrarAddress(context.Background(), chainID)
|
||||
if err != nil {
|
||||
return nil, createENSRegisterProcessorErrorResponse(err)
|
||||
}
|
||||
|
@ -78,8 +78,8 @@ func (s *ENSRegisterProcessor) PackTxInputData(params ProcessorInputParams) ([]b
|
|||
return []byte{}, createENSRegisterProcessorErrorResponse(err)
|
||||
}
|
||||
|
||||
x, y := ens.ExtractCoordinates(params.PublicKey)
|
||||
extraData, err := registrarABI.Pack("register", ens.UsernameToLabel(params.Username), params.FromAddr, x, y)
|
||||
x, y := walletCommon.ExtractCoordinates(params.PublicKey)
|
||||
extraData, err := registrarABI.Pack("register", walletCommon.UsernameToLabel(params.Username), params.FromAddr, x, y)
|
||||
if err != nil {
|
||||
return []byte{}, createENSRegisterProcessorErrorResponse(err)
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ func (s *ENSRegisterProcessor) PackTxInputData(params ProcessorInputParams) ([]b
|
|||
return []byte{}, createENSRegisterProcessorErrorResponse(err)
|
||||
}
|
||||
|
||||
registryAddr, err := s.ensService.API().GetRegistrarAddress(context.Background(), params.FromChain.ChainID)
|
||||
registryAddr, err := s.ensResolver.GetRegistrarAddress(context.Background(), params.FromChain.ChainID)
|
||||
if err != nil {
|
||||
return []byte{}, createENSRegisterProcessorErrorResponse(err)
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ import (
|
|||
"github.com/status-im/status-go/contracts/registrar"
|
||||
"github.com/status-im/status-go/eth-node/types"
|
||||
"github.com/status-im/status-go/rpc"
|
||||
"github.com/status-im/status-go/services/ens"
|
||||
"github.com/status-im/status-go/services/ens/ensresolver"
|
||||
walletCommon "github.com/status-im/status-go/services/wallet/common"
|
||||
"github.com/status-im/status-go/transactions"
|
||||
)
|
||||
|
@ -22,16 +22,16 @@ import (
|
|||
type ENSReleaseProcessor struct {
|
||||
contractMaker *contracts.ContractMaker
|
||||
transactor transactions.TransactorIface
|
||||
ensService *ens.Service
|
||||
ensResolver *ensresolver.EnsResolver
|
||||
}
|
||||
|
||||
func NewENSReleaseProcessor(rpcClient *rpc.Client, transactor transactions.TransactorIface, ensService *ens.Service) *ENSReleaseProcessor {
|
||||
func NewENSReleaseProcessor(rpcClient *rpc.Client, transactor transactions.TransactorIface, ensResolver *ensresolver.EnsResolver) *ENSReleaseProcessor {
|
||||
return &ENSReleaseProcessor{
|
||||
contractMaker: &contracts.ContractMaker{
|
||||
RPCClient: rpcClient,
|
||||
},
|
||||
transactor: transactor,
|
||||
ensService: ensService,
|
||||
ensResolver: ensResolver,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -58,7 +58,7 @@ func (s *ENSReleaseProcessor) PackTxInputData(params ProcessorInputParams) ([]by
|
|||
}
|
||||
|
||||
name := getNameFromEnsUsername(params.Username)
|
||||
return registrarABI.Pack("release", ens.UsernameToLabel(name))
|
||||
return registrarABI.Pack("release", walletCommon.UsernameToLabel(name))
|
||||
}
|
||||
|
||||
func (s *ENSReleaseProcessor) EstimateGas(params ProcessorInputParams) (uint64, error) {
|
||||
|
@ -120,7 +120,7 @@ func (s *ENSReleaseProcessor) CalculateAmountOut(params ProcessorInputParams) (*
|
|||
}
|
||||
|
||||
func (s *ENSReleaseProcessor) GetContractAddress(params ProcessorInputParams) (common.Address, error) {
|
||||
addr, err := s.ensService.API().GetRegistrarAddress(context.Background(), params.FromChain.ChainID)
|
||||
addr, err := s.ensResolver.GetRegistrarAddress(context.Background(), params.FromChain.ChainID)
|
||||
if err != nil {
|
||||
return common.Address{}, err
|
||||
}
|
||||
|
|
|
@ -16,7 +16,6 @@ import (
|
|||
"github.com/status-im/status-go/logutils"
|
||||
"github.com/status-im/status-go/params"
|
||||
"github.com/status-im/status-go/rpc"
|
||||
"github.com/status-im/status-go/services/ens"
|
||||
"github.com/status-im/status-go/services/wallet/async"
|
||||
"github.com/status-im/status-go/services/wallet/collectibles"
|
||||
walletCommon "github.com/status-im/status-go/services/wallet/common"
|
||||
|
@ -68,7 +67,6 @@ type Router struct {
|
|||
marketManager *market.Manager
|
||||
collectiblesService *collectibles.Service
|
||||
collectiblesManager *collectibles.Manager
|
||||
ensService *ens.Service
|
||||
feesManager *fees.FeeManager
|
||||
pathProcessors map[string]pathprocessor.PathProcessor
|
||||
scheduler *async.Scheduler
|
||||
|
@ -88,7 +86,7 @@ type Router struct {
|
|||
}
|
||||
|
||||
func NewRouter(rpcClient *rpc.Client, transactor *transactions.Transactor, tokenManager *token.Manager, marketManager *market.Manager,
|
||||
collectibles *collectibles.Service, collectiblesManager *collectibles.Manager, ensService *ens.Service) *Router {
|
||||
collectibles *collectibles.Service, collectiblesManager *collectibles.Manager) *Router {
|
||||
processors := make(map[string]pathprocessor.PathProcessor)
|
||||
|
||||
return &Router{
|
||||
|
@ -97,7 +95,6 @@ func NewRouter(rpcClient *rpc.Client, transactor *transactions.Transactor, token
|
|||
marketManager: marketManager,
|
||||
collectiblesService: collectibles,
|
||||
collectiblesManager: collectiblesManager,
|
||||
ensService: ensService,
|
||||
feesManager: &fees.FeeManager{
|
||||
RPCClient: rpcClient,
|
||||
},
|
||||
|
|
|
@ -101,7 +101,7 @@ func setupRouter(t *testing.T) (*Router, func()) {
|
|||
}
|
||||
client, _ := rpc.NewClient(config)
|
||||
|
||||
router := NewRouter(client, nil, nil, nil, nil, nil, nil)
|
||||
router := NewRouter(client, nil, nil, nil, nil, nil)
|
||||
|
||||
transfer := pathprocessor.NewTransferProcessor(nil, nil)
|
||||
router.AddPathProcessor(transfer)
|
||||
|
|
|
@ -19,7 +19,7 @@ import (
|
|||
protocolCommon "github.com/status-im/status-go/protocol/common"
|
||||
"github.com/status-im/status-go/rpc"
|
||||
"github.com/status-im/status-go/server"
|
||||
"github.com/status-im/status-go/services/ens"
|
||||
"github.com/status-im/status-go/services/ens/ensresolver"
|
||||
"github.com/status-im/status-go/services/wallet/activity"
|
||||
"github.com/status-im/status-go/services/wallet/balance"
|
||||
"github.com/status-im/status-go/services/wallet/blockchainstate"
|
||||
|
@ -59,7 +59,7 @@ func NewService(
|
|||
gethManager *account.GethManager,
|
||||
transactor *transactions.Transactor,
|
||||
config *params.NodeConfig,
|
||||
ens *ens.Service,
|
||||
ensResolver *ensresolver.EnsResolver,
|
||||
pendingTxManager *transactions.PendingTxTracker,
|
||||
feed *event.Feed,
|
||||
mediaServer *server.MediaServer,
|
||||
|
@ -190,8 +190,8 @@ func NewService(
|
|||
}
|
||||
|
||||
router := router.NewRouter(rpcClient, transactor, tokenManager, marketManager, collectibles,
|
||||
collectiblesManager, ens)
|
||||
pathProcessors := buildPathProcessors(rpcClient, transactor, tokenManager, ens, featureFlags)
|
||||
collectiblesManager)
|
||||
pathProcessors := buildPathProcessors(rpcClient, transactor, tokenManager, ensResolver, featureFlags)
|
||||
for _, processor := range pathProcessors {
|
||||
router.AddPathProcessor(processor)
|
||||
}
|
||||
|
@ -214,7 +214,6 @@ func NewService(
|
|||
gethManager: gethManager,
|
||||
marketManager: marketManager,
|
||||
transactor: transactor,
|
||||
ens: ens,
|
||||
feed: feed,
|
||||
signals: signals,
|
||||
reader: reader,
|
||||
|
@ -235,7 +234,7 @@ func buildPathProcessors(
|
|||
rpcClient *rpc.Client,
|
||||
transactor *transactions.Transactor,
|
||||
tokenManager *token.Manager,
|
||||
ens *ens.Service,
|
||||
ensResolver *ensresolver.EnsResolver,
|
||||
featureFlags *protocolCommon.FeatureFlags,
|
||||
) []pathprocessor.PathProcessor {
|
||||
ret := make([]pathprocessor.PathProcessor, 0)
|
||||
|
@ -261,13 +260,13 @@ func buildPathProcessors(
|
|||
paraswap := pathprocessor.NewSwapParaswapProcessor(rpcClient, transactor, tokenManager)
|
||||
ret = append(ret, paraswap)
|
||||
|
||||
ensRegister := pathprocessor.NewENSRegisterProcessor(rpcClient, transactor, ens)
|
||||
ensRegister := pathprocessor.NewENSRegisterProcessor(rpcClient, transactor, ensResolver)
|
||||
ret = append(ret, ensRegister)
|
||||
|
||||
ensRelease := pathprocessor.NewENSReleaseProcessor(rpcClient, transactor, ens)
|
||||
ensRelease := pathprocessor.NewENSReleaseProcessor(rpcClient, transactor, ensResolver)
|
||||
ret = append(ret, ensRelease)
|
||||
|
||||
ensPublicKey := pathprocessor.NewENSPublicKeyProcessor(rpcClient, transactor, ens)
|
||||
ensPublicKey := pathprocessor.NewENSPublicKeyProcessor(rpcClient, transactor, ensResolver)
|
||||
ret = append(ret, ensPublicKey)
|
||||
|
||||
buyStickers := pathprocessor.NewStickersBuyProcessor(rpcClient, transactor)
|
||||
|
@ -294,7 +293,6 @@ type Service struct {
|
|||
collectibles *collectibles.Service
|
||||
gethManager *account.GethManager
|
||||
transactor *transactions.Transactor
|
||||
ens *ens.Service
|
||||
feed *event.Feed
|
||||
signals *walletevent.SignalsTransmitter
|
||||
reader *Reader
|
||||
|
@ -399,7 +397,3 @@ func (s *Service) GetCollectiblesService() *collectibles.Service {
|
|||
func (s *Service) GetCollectiblesManager() *collectibles.Manager {
|
||||
return s.collectiblesManager
|
||||
}
|
||||
|
||||
func (s *Service) GetEnsService() *ens.Service {
|
||||
return s.ens
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue