From 5a73e3fa92f089e88455f3be88e4bbc2e2435723 Mon Sep 17 00:00:00 2001 From: nayutalienx Date: Tue, 17 Sep 2024 23:47:30 +0700 Subject: [PATCH] Added optional signer for wallet --- ton/wallet/highloadv2r2.go | 6 +++- ton/wallet/highloadv3.go | 7 +++- ton/wallet/v3.go | 6 +++- ton/wallet/v4r2.go | 6 +++- ton/wallet/v5beta.go | 6 +++- ton/wallet/v5r1.go | 6 +++- ton/wallet/wallet.go | 70 +++++++++++++++++++++++++++++++++----- 7 files changed, 93 insertions(+), 14 deletions(-) diff --git a/ton/wallet/highloadv2r2.go b/ton/wallet/highloadv2r2.go index 9d47e289..898f79d1 100644 --- a/ton/wallet/highloadv2r2.go +++ b/ton/wallet/highloadv2r2.go @@ -62,7 +62,11 @@ func (s *SpecHighloadV2R2) BuildMessage(ctx context.Context, messages []*Message MustStoreUInt(boundedID, 64). MustStoreDict(dict) - sign := payload.EndCell().Sign(s.wallet.key) + sign, err := s.wallet.sign(payload.EndCell().Hash()) + if err != nil { + return nil, fmt.Errorf("failed to sign: %w", err) + } + msg := cell.BeginCell().MustStoreSlice(sign, 512).MustStoreBuilder(payload).EndCell() return msg, nil diff --git a/ton/wallet/highloadv3.go b/ton/wallet/highloadv3.go index 821bf034..3b8b67f6 100644 --- a/ton/wallet/highloadv3.go +++ b/ton/wallet/highloadv3.go @@ -83,8 +83,13 @@ func (s *SpecHighloadV3) BuildMessage(ctx context.Context, messages []*Message) MustStoreUInt(uint64(s.config.MessageTTL), 22). EndCell() + sign, err := s.wallet.sign(payload.Hash()) + if err != nil { + return nil, fmt.Errorf("failed to sign: %w", err) + } + return cell.BeginCell(). - MustStoreSlice(payload.Sign(s.wallet.key), 512). + MustStoreSlice(sign, 512). MustStoreRef(payload).EndCell(), nil } diff --git a/ton/wallet/v3.go b/ton/wallet/v3.go index 770481bf..6b7d842f 100644 --- a/ton/wallet/v3.go +++ b/ton/wallet/v3.go @@ -47,7 +47,11 @@ func (s *SpecV3) BuildMessage(ctx context.Context, _ bool, _ *ton.BlockIDExt, me payload.MustStoreUInt(uint64(message.Mode), 8).MustStoreRef(intMsg) } - sign := payload.EndCell().Sign(s.wallet.key) + sign, err := s.wallet.sign(payload.EndCell().Hash()) + if err != nil { + return nil, fmt.Errorf("failed to sign: %w", err) + } + msg := cell.BeginCell().MustStoreSlice(sign, 512).MustStoreBuilder(payload).EndCell() return msg, nil diff --git a/ton/wallet/v4r2.go b/ton/wallet/v4r2.go index fc861cb0..7e1d5546 100644 --- a/ton/wallet/v4r2.go +++ b/ton/wallet/v4r2.go @@ -48,7 +48,11 @@ func (s *SpecV4R2) BuildMessage(ctx context.Context, _ bool, _ *ton.BlockIDExt, payload.MustStoreUInt(uint64(message.Mode), 8).MustStoreRef(intMsg) } - sign := payload.EndCell().Sign(s.wallet.key) + sign, err := s.wallet.sign(payload.EndCell().Hash()) + if err != nil { + return nil, fmt.Errorf("failed to sign: %w", err) + } + msg := cell.BeginCell().MustStoreSlice(sign, 512).MustStoreBuilder(payload).EndCell() return msg, nil diff --git a/ton/wallet/v5beta.go b/ton/wallet/v5beta.go index f31db570..e5f1faf6 100644 --- a/ton/wallet/v5beta.go +++ b/ton/wallet/v5beta.go @@ -58,7 +58,11 @@ func (s *SpecV5R1Beta) BuildMessage(ctx context.Context, _ bool, _ *ton.BlockIDE MustStoreUInt(uint64(seq), 32). MustStoreBuilder(actions) - sign := payload.EndCell().Sign(s.wallet.key) + sign, err := s.wallet.sign(payload.EndCell().Hash()) + if err != nil { + return nil, fmt.Errorf("failed to sign: %w", err) + } + msg := cell.BeginCell().MustStoreBuilder(payload).MustStoreSlice(sign, 512).EndCell() return msg, nil diff --git a/ton/wallet/v5r1.go b/ton/wallet/v5r1.go index 1e97fc16..5ee6dba1 100644 --- a/ton/wallet/v5r1.go +++ b/ton/wallet/v5r1.go @@ -85,7 +85,11 @@ func (s *SpecV5R1Final) BuildMessage(ctx context.Context, _ bool, _ *ton.BlockID MustStoreUInt(uint64(seq), 32). // seq (block) MustStoreBuilder(actions) // Action list - sign := payload.EndCell().Sign(s.wallet.key) + sign, err := s.wallet.sign(payload.EndCell().Hash()) + if err != nil { + return nil, fmt.Errorf("failed to sign: %w", err) + } + msg := cell.BeginCell().MustStoreBuilder(payload).MustStoreSlice(sign, 512).EndCell() return msg, nil diff --git a/ton/wallet/wallet.go b/ton/wallet/wallet.go index 84a272df..6727dc04 100644 --- a/ton/wallet/wallet.go +++ b/ton/wallet/wallet.go @@ -143,11 +143,14 @@ type Message struct { InternalMessage *tlb.InternalMessage } +type Signer func(message []byte) ([]byte, error) + type Wallet struct { - api TonAPI - key ed25519.PrivateKey - addr *address.Address - ver VersionConfig + api TonAPI + key ed25519.PrivateKey + pubKey ed25519.PublicKey + addr *address.Address + ver VersionConfig // Can be used to operate multiple wallets with the same key and version. // use GetSubwallet if you need it. @@ -155,9 +158,30 @@ type Wallet struct { // Stores a pointer to implementation of the version related functionality spec any + + // Optional signer + signer Signer } +type walletOption func(*Wallet) + func FromPrivateKey(api TonAPI, key ed25519.PrivateKey, version VersionConfig) (*Wallet, error) { + return newWallet( + api, + key.Public().(ed25519.PublicKey), + version, + withPrivateKey(key)) +} + +func FromSigner(api TonAPI, publicKey ed25519.PublicKey, version VersionConfig, signer Signer) (*Wallet, error) { + return newWallet( + api, + publicKey, + version, + withSigner(signer)) +} + +func newWallet(api TonAPI, publicKey ed25519.PublicKey, version VersionConfig, options ...walletOption) (*Wallet, error) { var subwallet uint32 = DefaultSubwallet // default subwallet depends on wallet type @@ -167,17 +191,21 @@ func FromPrivateKey(api TonAPI, key ed25519.PrivateKey, version VersionConfig) ( subwallet = 0 } - addr, err := AddressFromPubKey(key.Public().(ed25519.PublicKey), version, subwallet) + addr, err := AddressFromPubKey(publicKey, version, subwallet) if err != nil { return nil, err } w := &Wallet{ api: api, - key: key, addr: addr, ver: version, subwallet: subwallet, + pubKey: publicKey, + } + + for _, opt := range options { + opt(w) } w.spec, err = getSpec(w) @@ -188,6 +216,18 @@ func FromPrivateKey(api TonAPI, key ed25519.PrivateKey, version VersionConfig) ( return w, nil } +func withPrivateKey(privateKey ed25519.PrivateKey) walletOption { + return func(w *Wallet) { + w.key = privateKey + } +} + +func withSigner(signer Signer) walletOption { + return func(w *Wallet) { + w.signer = signer + } +} + func getSpec(w *Wallet) (any, error) { switch v := w.ver.(type) { case Version, ConfigV5R1Beta, ConfigV5R1Final: @@ -253,6 +293,18 @@ func getSpec(w *Wallet) (any, error) { return nil, fmt.Errorf("cannot init spec: %w", ErrUnsupportedWalletVersion) } +func (w *Wallet) sign(message []byte) ([]byte, error) { + if w.key == nil && w.signer == nil { + return nil, fmt.Errorf("cannot sign: private key and signer is nil") + } + + if w.key != nil { + return ed25519.Sign(w.key, message), nil + } + + return w.signer(message) +} + // Address - returns old (bounce) version of wallet address // DEPRECATED: because of address reform, use WalletAddress, // it will return UQ format @@ -270,7 +322,7 @@ func (w *Wallet) PrivateKey() ed25519.PrivateKey { } func (w *Wallet) GetSubwallet(subwallet uint32) (*Wallet, error) { - addr, err := AddressFromPubKey(w.key.Public().(ed25519.PublicKey), w.ver, subwallet) + addr, err := AddressFromPubKey(w.pubKey, w.ver, subwallet) if err != nil { return nil, err } @@ -278,9 +330,11 @@ func (w *Wallet) GetSubwallet(subwallet uint32) (*Wallet, error) { sub := &Wallet{ api: w.api, key: w.key, + pubKey: w.pubKey, addr: addr, ver: w.ver, subwallet: subwallet, + signer: w.signer, } sub.spec, err = getSpec(sub) @@ -341,7 +395,7 @@ func (w *Wallet) BuildExternalMessageForMany(ctx context.Context, messages []*Me func (w *Wallet) PrepareExternalMessageForMany(ctx context.Context, withStateInit bool, messages []*Message) (_ *tlb.ExternalMessage, err error) { var stateInit *tlb.StateInit if withStateInit { - stateInit, err = GetStateInit(w.key.Public().(ed25519.PublicKey), w.ver, w.subwallet) + stateInit, err = GetStateInit(w.pubKey, w.ver, w.subwallet) if err != nil { return nil, fmt.Errorf("failed to get state init: %w", err) }