Skip to content

Commit

Permalink
Added optional signer for wallet
Browse files Browse the repository at this point in the history
  • Loading branch information
nayutalienx committed Sep 18, 2024
1 parent d4afeb1 commit 5a73e3f
Show file tree
Hide file tree
Showing 7 changed files with 93 additions and 14 deletions.
6 changes: 5 additions & 1 deletion ton/wallet/highloadv2r2.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 6 additions & 1 deletion ton/wallet/highloadv3.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down
6 changes: 5 additions & 1 deletion ton/wallet/v3.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 5 additions & 1 deletion ton/wallet/v4r2.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 5 additions & 1 deletion ton/wallet/v5beta.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 5 additions & 1 deletion ton/wallet/v5r1.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
70 changes: 62 additions & 8 deletions ton/wallet/wallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,21 +143,45 @@ 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.
subwallet uint32

// 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
Expand All @@ -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)
Expand All @@ -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:
Expand Down Expand Up @@ -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
Expand All @@ -270,17 +322,19 @@ 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
}

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)
Expand Down Expand Up @@ -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)
}
Expand Down

0 comments on commit 5a73e3f

Please sign in to comment.