Repository: xuperchain/xuperchain (language: python)

Issue:
xchain-cli utxo 指令操作合约账号不符合预期
**Brief of the issue**

使用 xchain-cli 对合约账号的 UTXO 进行 `merge`|`split` 始终报错

**Your environment**

- XuperChain: v5.3.0
- OS: MacOS 12.0.1 (21A559)
- Go:  go1.17.2 darwin/amd64
- gcc: 4.2.1
<details>
<summary>gcc</summary>

```
Configured with: --prefix=/Library/Developer/CommandLineTools/usr --with-gxx-include-dir=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/4.2.1
Apple clang version 13.0.0 (clang-1300.0.29.30)
Target: x86_64-apple-darwin21.1.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
```
</details>

**Repo steps**

1. create a contract account `XC1111111111111111@xuper`
2. transfer to the `XC1111111111111111@xuper` more than twice
3. (optional) list and check UTXO
`bin/xchain-cli utxo list -N 10 -A XC1111111111111111@xuper`
4. merge or split UTXO
``` shell
bin/xchain-cli utxo merge -A XC1111111111111111@xuper -P data
bin/xchain-cli utxo split -N 2 -A XC1111111111111111@xuper
```

**Expected behaviours**

- no error
- option usage
  - `-A <ak>`
  - `-A <contract account> -P <auth accounts path>`

**What actually happened**

- split: parse account error
- merge: genAuthRequire error
![36a2a38861b5962329974f6ddd1200e2](https://user-images.githubusercontent.com/4128595/206516637-50f6a01d-cddc-41fb-87cf-741e511f6c5f.png)

**Additional information**

None yet

xchain-cli utxo 指令操作合约账号不符合预期
**Brief of the issue**

使用 xchain-cli 对合约账号的 UTXO 进行 `merge`|`split` 始终报错

**Your environment**

- XuperChain: v5.3.0
- OS: MacOS 12.0.1 (21A559)
- Go:  go1.17.2 darwin/amd64
- gcc: 4.2.1
<details>
<summary>gcc</summary>

```
Configured with: --prefix=/Library/Developer/CommandLineTools/usr --with-gxx-include-dir=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/4.2.1
Apple clang version 13.0.0 (clang-1300.0.29.30)
Target: x86_64-apple-darwin21.1.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
```
</details>

**Repo steps**

1. create a contract account `XC1111111111111111@xuper`
2. transfer to the `XC1111111111111111@xuper` more than twice
3. (optional) list and check UTXO
`bin/xchain-cli utxo list -N 10 -A XC1111111111111111@xuper`
4. merge or split UTXO
``` shell
bin/xchain-cli utxo merge -A XC1111111111111111@xuper -P data
bin/xchain-cli utxo split -N 2 -A XC1111111111111111@xuper
```

**Expected behaviours**

- no error
- option usage
  - `-A <ak>`
  - `-A <contract account> -P <auth accounts path>`

**What actually happened**

- split: parse account error
- merge: genAuthRequire error
![36a2a38861b5962329974f6ddd1200e2](https://user-images.githubusercontent.com/4128595/206516637-50f6a01d-cddc-41fb-87cf-741e511f6c5f.png)

**Additional information**

None yet

xchain-cli utxo 指令操作合约账号不符合预期
**Brief of the issue**

使用 xchain-cli 对合约账号的 UTXO 进行 `merge`|`split` 始终报错

**Your environment**

- XuperChain: v5.3.0
- OS: MacOS 12.0.1 (21A559)
- Go:  go1.17.2 darwin/amd64
- gcc: 4.2.1
<details>
<summary>gcc</summary>

```
Configured with: --prefix=/Library/Developer/CommandLineTools/usr --with-gxx-include-dir=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/4.2.1
Apple clang version 13.0.0 (clang-1300.0.29.30)
Target: x86_64-apple-darwin21.1.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
```
</details>

**Repo steps**

1. create a contract account `XC1111111111111111@xuper`
2. transfer to the `XC1111111111111111@xuper` more than twice
3. (optional) list and check UTXO
`bin/xchain-cli utxo list -N 10 -A XC1111111111111111@xuper`
4. merge or split UTXO
``` shell
bin/xchain-cli utxo merge -A XC1111111111111111@xuper -P data
bin/xchain-cli utxo split -N 2 -A XC1111111111111111@xuper
```

**Expected behaviours**

- no error
- option usage
  - `-A <ak>`
  - `-A <contract account> -P <auth accounts path>`

**What actually happened**

- split: parse account error
- merge: genAuthRequire error
![36a2a38861b5962329974f6ddd1200e2](https://user-images.githubusercontent.com/4128595/206516637-50f6a01d-cddc-41fb-87cf-741e511f6c5f.png)

**Additional information**

None yet

优化代码实现
- 优化代码实现效率
- 提升可维护性
  - 去除重复代码，抽取类、函数
  - Error 处理规范化
  - 去除无用代码
- 优化可读性
  - 变量名优化
  - 函数原型优化
  - 长函数拆解
- 代码规范
  - Import
优化代码实现
- 优化代码实现效率
- 提升可维护性
  - 去除重复代码，抽取类、函数
  - Error 处理规范化
  - 去除无用代码
- 优化可读性
  - 变量名优化
  - 函数原型优化
  - 长函数拆解
- 代码规范
  - Import
xchain-cli utxo 指令操作合约账号不符合预期
**Brief of the issue**

使用 xchain-cli 对合约账号的 UTXO 进行 `merge`|`split` 始终报错

**Your environment**

- XuperChain: v5.3.0
- OS: MacOS 12.0.1 (21A559)
- Go:  go1.17.2 darwin/amd64
- gcc: 4.2.1
<details>
<summary>gcc</summary>

```
Configured with: --prefix=/Library/Developer/CommandLineTools/usr --with-gxx-include-dir=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/4.2.1
Apple clang version 13.0.0 (clang-1300.0.29.30)
Target: x86_64-apple-darwin21.1.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
```
</details>

**Repo steps**

1. create a contract account `XC1111111111111111@xuper`
2. transfer to the `XC1111111111111111@xuper` more than twice
3. (optional) list and check UTXO
`bin/xchain-cli utxo list -N 10 -A XC1111111111111111@xuper`
4. merge or split UTXO
``` shell
bin/xchain-cli utxo merge -A XC1111111111111111@xuper -P data
bin/xchain-cli utxo split -N 2 -A XC1111111111111111@xuper
```

**Expected behaviours**

- no error
- option usage
  - `-A <ak>`
  - `-A <contract account> -P <auth accounts path>`

**What actually happened**

- split: parse account error
- merge: genAuthRequire error
![36a2a38861b5962329974f6ddd1200e2](https://user-images.githubusercontent.com/4128595/206516637-50f6a01d-cddc-41fb-87cf-741e511f6c5f.png)

**Additional information**

None yet



Discussion / hints:

Fix patch:
diff --git a/auto/ci_pipeline.sh b/auto/ci_pipeline.sh
index fe0d2cfb7..a1c1de36b 100644
--- a/auto/ci_pipeline.sh
+++ b/auto/ci_pipeline.sh
@@ -34,7 +34,7 @@ function testnet() {
 
   cd "$WorkPath" || exit
 
-  info "start testnet path=$(pwd)"
+  echo "start testnet path=$(pwd)"
   sleep 3s && ./bin/xchain-cli status || \
   sleep 3s && ./bin/xchain-cli status || \
   sleep 3s && ./bin/xchain-cli status || \
@@ -49,44 +49,44 @@ function account() {
   ./bin/xchain-cli account newkeys --output data/alice || exit
   ./bin/xchain-cli transfer --to "$(cat data/alice/address)" --amount 10000000 || exit
   balance=$(./bin/xchain-cli account balance --keys data/alice)
-  info "account $(cat data/alice/address) balance $balance"
+  echo "account $(cat data/alice/address) balance $balance"
 
   ## 合约账户
   ./bin/xchain-cli account new --account 1111111111111111 --fee 1000 || exit
   ./bin/xchain-cli transfer --to XC1111111111111111@xuper --amount 100000001 || exit
   balance=$(./bin/xchain-cli account balance XC1111111111111111@xuper)
-  info "account XC1111111111111111@xuper balance $balance"
+  echo "account XC1111111111111111@xuper balance $balance"
 
   ## 合约账户：desc 文件
   ./bin/xchain-cli account new --desc $WorkRoot/data/desc/NewAccount.json --fee 1000 || exit
   ./bin/xchain-cli transfer --to XC2222222222222222@xuper --amount 100000002 || exit
   balance=$(./bin/xchain-cli account balance XC2222222222222222@xuper)
-  info "account XC2222222222222222@xuper balance $balance"
+  echo "account XC2222222222222222@xuper balance $balance"
 }
 
 # contract
 function contract() {
   cp $WorkRoot/auto/counter.wasm $WorkPath
   # wasm
-  info "contract wasm"
+  echo "contract wasm"
   ./bin/xchain-cli wasm deploy $WorkPath/counter.wasm --cname counter.wasm \
             --account XC1111111111111111@xuper \
             --runtime c -a '{"creator": "xuper"}' --fee 155537 || exit
-  info "contract wasm invoke"
+  echo "contract wasm invoke"
   ./bin/xchain-cli wasm invoke --method increase -a '{"key":"test"}' counter.wasm --fee 100
   ./bin/xchain-cli wasm query --method get -a '{"key":"test"}' counter.wasm
 
   # 查询用户部署的合约
-  info "contract XC1111111111111111@xuper"
+  echo "contract XC1111111111111111@xuper"
   ./bin/xchain-cli account contracts --account XC1111111111111111@xuper
-  info "contract $(cat data/keys/address)"
+  echo "contract $(cat data/keys/address)"
   ./bin/xchain-cli account contracts --address $(cat data/keys/address)
 }
 
 # 内置合约
 function builtin() {
       # reserved_contracts
-  info "contract reserved unified_check"
+  echo "contract reserved unified_check"
   ./bin/xchain-cli wasm deploy $WorkPath/build/unified_check --cname unified_check \
             --account XC1111111111111111@xuper \
             --runtime c -a '{"creator": "TeyyPLpp9L7QAcxHangtcHTu7HUZ6iydY"}' --fee 164735 || exit
@@ -94,7 +94,7 @@ function builtin() {
             -a '{"aks":"SmJG3rH2ZzYQ9ojxhbRCPwFiE9y6pD1Co,iYjtLcW6SVCiousAb5DFKWtWroahhEj4u"}' --fee 155 || exit
 
   # forbidden_contract
-  info "contract forbidden"
+  echo "contract forbidden"
   ./bin/xchain-cli wasm deploy $WorkPath/build/forbidden --cname forbidden \
             --account XC1111111111111111@xuper \
             --runtime c -a '{"creator": "TeyyPLpp9L7QAcxHangtcHTu7HUZ6iydY"}' --fee 155679 || exit
@@ -106,7 +106,7 @@ function acl() {
   mkdir -p data/acl
 
   # 设置合约账户acl
-  info "acl account"
+  echo "acl account"
   echo "XC1111111111111111@xuper/$(cat $TestNet/node1/data/keys/address)" > data/acl/addrs
   ./bin/xchain-cli acl query --account XC1111111111111111@xuper
   ./bin/xchain-cli multisig gen --desc $WorkRoot/data/desc/SetAccountACL.json --fee 100
@@ -116,7 +116,7 @@ function acl() {
   ./bin/xchain-cli acl query --account XC1111111111111111@xuper
 
   # 设置合约方法acl
-  info "acl contract method"
+  echo "acl contract method"
   echo "XC1111111111111111@xuper/$(cat $TestNet/node2/data/keys/address)" >> data/acl/addrs
   ./bin/xchain-cli multisig gen --desc $WorkRoot/data/desc/SetMethodACL.json --fee 100
   ./bin/xchain-cli multisig sign --keys $TestNet/node1/data/keys --output sign1.out
@@ -126,13 +126,13 @@ function acl() {
   ./bin/xchain-cli acl query --contract counter.wasm --method increase
 
   # 调用合约方法
-  info "acl invoke contract method"
+  echo "acl invoke contract method"
   ./bin/xchain-cli transfer --to "$(cat $TestNet/node2/data/keys/address)" --amount 10000000 || exit
   ./bin/xchain-cli transfer --to "$(cat $TestNet/node3/data/keys/address)" --amount 10000000 || exit
   ./bin/xchain-cli wasm invoke --method increase -a '{"key":"test"}' counter.wasm --fee 100 --keys $TestNet/node1/data/keys || exit
   ./bin/xchain-cli wasm invoke --method increase -a '{"key":"test"}' counter.wasm --fee 100 --keys $TestNet/node2/data/keys || exit
   # node3节点无权限，应该调用失败
-  info "acl node3 invoke contract method: should 'ACL not enough'"
+  echo "acl node3 invoke contract method: should 'ACL not enough'"
   ./bin/xchain-cli wasm invoke --method increase -a '{"key":"test"}' counter.wasm --fee 100 --keys $TestNet/node3/data/keys && exit
 }
 
@@ -141,7 +141,7 @@ function height() {
   height2=$(./bin/xchain-cli status -H:37102 | grep trunkHeight | awk '{print $2}')
   height3=$(./bin/xchain-cli status -H:37103 | grep trunkHeight | awk '{print $2}')
 
-  info "height1=$height1 height2=$height2 height3=$height3"
+  echo "height1=$height1 height2=$height2 height3=$height3"
   diff=$((2*height1-height2-height3))
   if [ $diff -gt 3 ]; then
 		error "height inconsistency: height1=$height1 height2=$height2 height3=$height3" && exit
@@ -158,26 +158,26 @@ function clean() {
 }
 
 function main() {
-  info "test start"
+  echo "test start"
   clean
 
-  info "test install"
+  echo "test install"
   testnet
 
-  info "test account"
+  echo "test account"
   account
 
-  info "test contract"
+  echo "test contract"
   contract
   #builtin
 
-  info "test acl"
+  echo "test acl"
   acl
 
-  info "test height"
+  echo "test height"
   height
 
-  info "test done"
+  echo "test done"
 }
 
 case X$1 in
diff --git a/cmd/client/cmd/account_new.go b/cmd/client/cmd/account_new.go
index 50a6185d2..942329142 100644
--- a/cmd/client/cmd/account_new.go
+++ b/cmd/client/cmd/account_new.go
@@ -137,7 +137,7 @@ func (c *AccountNewCommand) printRealAccountName(name string) error {
 }
 
 func (c *AccountNewCommand) readPreExeParamWithDesc(buf []byte) (*pb.InvokeRequest, error) {
-	params := new(invokeRequestWraper)
+	params := new(invokeRequestWrapper)
 	err := json.Unmarshal(buf, params)
 	if err != nil {
 		return nil, fmt.Errorf("unmarshal json error:%s", err)
diff --git a/cmd/client/cmd/ak.go b/cmd/client/cmd/ak.go
new file mode 100644
index 000000000..605d08a9e
--- /dev/null
+++ b/cmd/client/cmd/ak.go
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2022. Baidu Inc. All Rights Reserved.
+ */
+
+package cmd
+
+import (
+	"io/ioutil"
+	"math/big"
+	"os"
+	"path/filepath"
+	"strconv"
+
+	"github.com/xuperchain/xupercore/lib/crypto/client/base"
+	"github.com/xuperchain/xupercore/lib/crypto/hash"
+
+	"github.com/xuperchain/xuperchain/service/common"
+	"github.com/xuperchain/xuperchain/service/pb"
+)
+
+// file names in AK directory
+const (
+	FileAddress    = "address"
+	FilePublicKey  = "public.key"
+	FilePrivateKey = "private.key"
+)
+
+/* AK with its directory like:
+
+└── <AK name>
+	├── address
+	├── private.key
+	└── public.key
+
+*/
+type AK struct {
+	path string
+}
+
+// create AK with path
+// Params:
+// 	path: path refers to <AK name>
+func newAK(path string) AK {
+	return AK{
+		path: path,
+	}
+}
+
+/* listAKs lists all AK by root, which could be like:
+
+ └── <root>	// normally as `data`
+	├── keys	// default AK name
+	│	├── address
+	│	├── private.key
+	│	└── public.key
+	├── <AK name>
+	│	├── address
+	│	├── private.key
+	│	└── public.key
+	└── <other dir>
+
+Params:
+	root: root path refers to <root>
+*/
+func listAKs(root string) ([]AK, error) {
+	dirs, err := ioutil.ReadDir(root)
+	if err != nil {
+		return nil, err
+	}
+
+	akList := make([]AK, 0)
+	for _, dir := range dirs {
+		if !dir.IsDir() {
+			continue
+		}
+
+		akPath := filepath.Join(root, dir.Name())
+		ak := newAK(akPath)
+		if ak.IsAKDir() {
+			akList = append(akList, ak)
+		}
+	}
+	return akList, nil
+}
+
+// IsAKDir return true for AK directory
+func (ak AK) IsAKDir() bool {
+	// if `address` file not exists, it isn't an AK directory
+	address := filepath.Join(ak.path, FileAddress)
+	_, err := os.Stat(address)
+	return err == nil
+}
+
+// AuthRequirementFrom return an auth require text for the source account
+func (ak *AK) AuthRequirementFrom(account string) (string, error) {
+	address, err := readAddress(ak.path)
+	if err != nil {
+		return "", err
+	}
+
+	authRequirement := account + "/" + address
+	return authRequirement, nil
+}
+
+// Info gets AK info from its directory,
+// includes: address, key pair
+func (ak *AK) Info() (info AKInfo, err error) {
+	info.address, err = readAddress(ak.path)
+	if err != nil {
+		return AKInfo{}, err
+	}
+
+	info.KeyPair, err = ak.keyPair()
+	if err != nil {
+		return AKInfo{}, err
+	}
+
+	return info, nil
+}
+
+// keyPair gets key pair for AK
+func (ak *AK) keyPair() (KeyPair, error) {
+
+	pk, err := readPublicKey(ak.path)
+	if err != nil {
+		return KeyPair{}, err
+	}
+	sk, err := readPrivateKey(ak.path)
+	if err != nil {
+		return KeyPair{}, err
+	}
+
+	return KeyPair{
+		publicKey: pk,
+		secretKey: sk,
+	}, nil
+}
+
+// SignTx signs for a transaction with given crypto client
+func (ak *AK) SignTx(tx *pb.Transaction, crypto base.CryptoClient) (*pb.SignatureInfo, error) {
+	pk, err := ak.keyPair()
+	if err != nil {
+		return nil, err
+	}
+	return pk.SignTx(tx, crypto)
+}
+
+// AK information which is store in files
+type AKInfo struct {
+	address string
+	KeyPair // public & private key pair
+}
+
+// SignUtxo self signs for an UTXO with given crypto client
+// Params:
+// 	bcName: UTXO blockchain name
+// 	amount: UTXO amount
+// 	crypto: crypto client
+func (i *AKInfo) SignUtxo(bcName string, amount *big.Int, crypto base.CryptoClient) (pb.SignatureInfo, error) {
+	return i.KeyPair.SignUtxo(bcName, i.address, amount, crypto)
+}
+
+// KeyPair is key-pair for crypto
+type KeyPair struct {
+	publicKey, secretKey string
+}
+
+// SignTx signs for a transaction with given crypto client by AK key pair
+func (p *KeyPair) SignTx(tx *pb.Transaction, crypto base.CryptoClient) (*pb.SignatureInfo, error) {
+	sign, err := common.ComputeTxSign(crypto, tx, []byte(p.secretKey))
+	if err != nil {
+		return nil, err
+	}
+	return &pb.SignatureInfo{
+		PublicKey: p.publicKey,
+		Sign:      sign,
+	}, nil
+}
+
+// SignUtxo signs for an UTXO with given crypto client by AK key pair
+// Params:
+// 	bcName: UTXO blockchain name
+// 	account: UTXO account
+// 	amount: UTXO amount
+// 	crypto: crypto client
+func (p *KeyPair) SignUtxo(bcName, account string, amount *big.Int, crypto base.CryptoClient) (pb.SignatureInfo, error) {
+
+	// prepare raw content
+	hashKey := bcName + account + amount.String() + strconv.FormatBool(true)
+	hashValue := hash.DoubleSha256([]byte(hashKey))
+
+	// prepare private key
+	ecdsaPrivateKey, err := crypto.GetEcdsaPrivateKeyFromJsonStr(p.secretKey)
+	if err != nil {
+		return pb.SignatureInfo{}, err
+	}
+
+	// sign
+	sign, err := crypto.SignECDSA(ecdsaPrivateKey, hashValue)
+	if err != nil {
+		return pb.SignatureInfo{}, err
+	}
+	return pb.SignatureInfo{
+		PublicKey: p.publicKey,
+		Sign:      sign,
+	}, nil
+}
diff --git a/cmd/client/cmd/cli.go b/cmd/client/cmd/cli.go
index c85abf70e..9484bcc72 100644
--- a/cmd/client/cmd/cli.go
+++ b/cmd/client/cmd/cli.go
@@ -15,20 +15,18 @@ import (
 	"io/ioutil"
 	"math/big"
 	"os"
-	"strconv"
 	"time"
 
 	"github.com/spf13/cobra"
 	"github.com/spf13/viper"
+	"github.com/xuperchain/xupercore/lib/crypto/client"
+	"github.com/xuperchain/xupercore/lib/crypto/client/base"
+	"github.com/xuperchain/xupercore/lib/utils"
 	"google.golang.org/grpc"
 	"google.golang.org/grpc/credentials"
 
 	"github.com/xuperchain/xuperchain/service/common"
 	"github.com/xuperchain/xuperchain/service/pb"
-	crypto_client "github.com/xuperchain/xupercore/lib/crypto/client"
-	crypto_base "github.com/xuperchain/xupercore/lib/crypto/client/base"
-	cryptoHash "github.com/xuperchain/xupercore/lib/crypto/hash"
-	"github.com/xuperchain/xupercore/lib/utils"
 )
 
 // CommandFunc 代表了一个子命令，用于往Cli注册子命令
@@ -247,59 +245,51 @@ func (c *Cli) RangeNodes(ctx context.Context, f func(addr string, client pb.Xcha
 
 // Transfer transfer cli entrance
 func (c *Cli) Transfer(ctx context.Context, opt *TransferOptions) (string, error) {
-	fromAddr, err := readAddress(opt.KeyPath)
-	if err != nil {
-		return "", err
-	}
-	fromPubkey, err := readPublicKey(opt.KeyPath)
-	if err != nil {
-		return "", err
-	}
 
-	fromScrkey, err := readPrivateKey(opt.KeyPath)
+	from := newAK(opt.KeyPath)
+	fromInfo, err := from.Info()
 	if err != nil {
 		return "", err
 	}
 
 	// create crypto client
-	cryptoClient, cryptoErr := crypto_client.CreateCryptoClient(opt.CryptoType)
+	crypto, cryptoErr := client.CreateCryptoClient(opt.CryptoType)
 	if cryptoErr != nil {
 		fmt.Println("fail to create crypto client, err=", cryptoErr)
 		return "", cryptoErr
 	}
 
-	return c.transfer(ctx, c.xclient, opt, fromAddr, fromPubkey, fromScrkey, cryptoClient)
+	return c.transfer(ctx, c.xclient, opt, fromInfo, crypto)
 }
 
-func (c *Cli) transfer(ctx context.Context, client pb.XchainClient, opt *TransferOptions, fromAddr,
-	fromPubkey, fromScrkey string, cryptoClient crypto_base.CryptoClient) (string, error) {
+func (c *Cli) transfer(ctx context.Context, client pb.XchainClient, opt *TransferOptions, initiator AKInfo,
+	cryptoClient base.CryptoClient) (string, error) {
+
 	if opt.From == "" {
-		opt.From = fromAddr
+		opt.From = initiator.address
 	}
-	return c.tansferSupportAccount(ctx, client, opt, fromAddr, fromPubkey, fromScrkey, cryptoClient)
+	return c.transferSupportAccount(ctx, client, opt, initiator, cryptoClient)
 }
 
-func (c *Cli) tansferSupportAccount(ctx context.Context, client pb.XchainClient, opt *TransferOptions,
-	initAddr, initPubkey, initScrkey string, cryptoClient crypto_base.CryptoClient) (string, error) {
+func (c *Cli) transferSupportAccount(ctx context.Context, client pb.XchainClient, opt *TransferOptions,
+	initiator AKInfo, cryptoClient base.CryptoClient) (string, error) {
+
 	// 组装交易
-	txStatus, err := assembleTxSupportAccount(ctx, client, opt, initAddr, initPubkey, initScrkey, cryptoClient)
+	txStatus, err := assembleTxSupportAccount(ctx, client, opt, initiator, cryptoClient)
 	if err != nil {
 		return "", err
 	}
 
-	// 签名和生成txid
-	signTx, err := common.ComputeTxSign(cryptoClient, txStatus.Tx, []byte(initScrkey))
+	// 签名和生成 Tx ID
+	signInfo, err := initiator.KeyPair.SignTx(txStatus.Tx, cryptoClient)
 	if err != nil {
 		return "", err
 	}
-	signInfo := &pb.SignatureInfo{
-		PublicKey: initPubkey,
-		Sign:      signTx,
-	}
+
 	txStatus.Tx.InitiatorSigns = append(txStatus.Tx.InitiatorSigns, signInfo)
-	txStatus.Tx.AuthRequireSigns, err = genAuthRequireSigns(opt, cryptoClient, txStatus.Tx, initScrkey, initPubkey)
+	txStatus.Tx.AuthRequireSigns, err = signTx(opt, cryptoClient, txStatus.Tx, initiator.KeyPair)
 	if err != nil {
-		return "", fmt.Errorf("Failed to genAuthRequireSigns %s", err)
+		return "", fmt.Errorf("Failed to signTx %s", err)
 	}
 	txStatus.Tx.Txid, err = common.MakeTxId(txStatus.Tx)
 	if err != nil {
@@ -325,8 +315,9 @@ func (c *Cli) tansferSupportAccount(ctx context.Context, client pb.XchainClient,
 	return hex.EncodeToString(txStatus.GetTxid()), nil
 }
 
-func assembleTxSupportAccount(ctx context.Context, client pb.XchainClient, opt *TransferOptions, initAddr, initPubkey,
-	initScrkey string, cryptoClient crypto_base.CryptoClient) (*pb.TxStatus, error) {
+func assembleTxSupportAccount(ctx context.Context, client pb.XchainClient, opt *TransferOptions, initiator AKInfo,
+	cryptoClient base.CryptoClient) (*pb.TxStatus, error) {
+
 	bigZero := big.NewInt(0)
 	totalNeed := big.NewInt(0)
 	tx := &pb.Transaction{
@@ -335,7 +326,7 @@ func assembleTxSupportAccount(ctx context.Context, client pb.XchainClient, opt *
 		Desc:      opt.Desc,
 		Nonce:     utils.GenNonce(),
 		Timestamp: time.Now().UnixNano(),
-		Initiator: initAddr,
+		Initiator: initiator.address,
 	}
 	account := &pb.TxDataAccount{
 		Address:      opt.To,
@@ -363,8 +354,7 @@ func assembleTxSupportAccount(ctx context.Context, client pb.XchainClient, opt *
 		tx.TxOutputs = append(tx.TxOutputs, txOutput)
 	}
 	// 组装input 和 剩余output
-	txInputs, deltaTxOutput, err := assembleTxInputsSupportAccount(ctx, client, opt, totalNeed, initAddr,
-		initPubkey, initScrkey, cryptoClient)
+	txInputs, deltaTxOutput, err := assembleTxInputsSupportAccount(ctx, client, opt, totalNeed, initiator, cryptoClient)
 	if err != nil {
 		return nil, err
 	}
@@ -373,7 +363,7 @@ func assembleTxSupportAccount(ctx context.Context, client pb.XchainClient, opt *
 		tx.TxOutputs = append(tx.TxOutputs, deltaTxOutput)
 	}
 	// 设置auth require
-	tx.AuthRequire, err = genAuthRequire(opt.From, opt.AccountPath)
+	tx.AuthRequire, err = genAuthRequirement(opt.From, opt.AccountPath)
 	if err != nil {
 		return nil, err
 	}
@@ -384,7 +374,7 @@ func assembleTxSupportAccount(ctx context.Context, client pb.XchainClient, opt *
 		Header: &pb.Header{
 			Logid: utils.GenLogId(),
 		},
-		Initiator:   initAddr,
+		Initiator:   initiator.address,
 		AuthRequire: tx.AuthRequire,
 	}
 
@@ -408,86 +398,92 @@ func assembleTxSupportAccount(ctx context.Context, client pb.XchainClient, opt *
 	return txStatus, nil
 }
 
-func genAuthRequire(from, path string) ([]string, error) {
-	authRequire := []string{}
+// genAuthRequirement generates auth requirement for AK or Account
+func genAuthRequirement(from, path string) (authRequirements []string, err error) {
+
+	// generate auth requirement for AK: require self
 	if path == "" {
-		authRequire = append(authRequire, from)
-		return authRequire, nil
+		authRequirements = []string{from}
+		return
 	}
-	dir, err := ioutil.ReadDir(path)
+
+	// generate auth requirements for account: require all AK in account path
+	// TODO: is that necessary for all AK
+	akList, err := listAKs(path)
 	if err != nil {
 		return nil, err
 	}
-	for _, fi := range dir {
-		if fi.IsDir() {
-			addr, err := readAddress(path + "/" + fi.Name())
-			if err != nil {
-				return nil, err
-			}
-			authRequire = append(authRequire, from+"/"+addr)
+	for _, ak := range akList {
+		authRequirement, err := ak.AuthRequirementFrom(from)
+		if err != nil {
+			return nil, fmt.Errorf("requires auth error: %s", err)
 		}
+		authRequirements = append(authRequirements, authRequirement)
 	}
-	return authRequire, nil
+	return authRequirements, nil
 }
 
-func genAuthRequireSigns(opt *TransferOptions, cryptoClient crypto_base.CryptoClient, tx *pb.Transaction, initScrkey, initPubkey string) ([]*pb.SignatureInfo, error) {
-	authRequireSigns := []*pb.SignatureInfo{}
+// signTx generates Tx signatures for AK or Account
+func signTx(opt *TransferOptions, crypto base.CryptoClient, tx *pb.Transaction,
+	initiator KeyPair) ([]*pb.SignatureInfo, error) {
+
+	// generate for AK
 	if opt.AccountPath == "" {
-		signTx, err := common.ComputeTxSign(cryptoClient, tx, []byte(initScrkey))
-		if err != nil {
-			return nil, err
-		}
-		signInfo := &pb.SignatureInfo{
-			PublicKey: initPubkey,
-			Sign:      signTx,
-		}
-		authRequireSigns = append(authRequireSigns, signInfo)
-		return authRequireSigns, nil
+		return signTxForAK(tx, initiator, crypto)
+	}
+
+	// generate for account
+	return signTxForAccount(tx, opt.AccountPath, crypto)
+}
+
+// signTxForAK generates transaction signature for AK with its key pair
+func signTxForAK(tx *pb.Transaction, keyPair KeyPair, crypto base.CryptoClient) ([]*pb.SignatureInfo, error) {
+	sign, err := keyPair.SignTx(tx, crypto)
+	if err != nil {
+		return nil, err
 	}
+	return []*pb.SignatureInfo{sign}, nil
+}
+
+// signTxForAccount generates transaction signatures for account: signed by each AK in account path
+// Params:
+// 	tx: transaction
+//	path: root path for accounts
+// 	crypto: crypto client
+// TODO: is that necessary for all AK
+func signTxForAccount(tx *pb.Transaction, path string, crypto base.CryptoClient) ([]*pb.SignatureInfo, error) {
+	signs := []*pb.SignatureInfo{}
 
-	dir, err := ioutil.ReadDir(opt.AccountPath)
+	akList, err := listAKs(path)
 	if err != nil {
 		return nil, err
 	}
-	for _, fi := range dir {
-		if fi.IsDir() {
-			sk, err := readPrivateKey(opt.AccountPath + "/" + fi.Name())
-			if err != nil {
-				return nil, err
-			}
-			pk, err := readPublicKey(opt.AccountPath + "/" + fi.Name())
-			if err != nil {
-				return nil, err
-			}
-			signTx, err := common.ComputeTxSign(cryptoClient, tx, []byte(sk))
-			if err != nil {
-				return nil, err
-			}
-			signInfo := &pb.SignatureInfo{
-				PublicKey: pk,
-				Sign:      signTx,
-			}
-			authRequireSigns = append(authRequireSigns, signInfo)
+	for _, ak := range akList {
+		sign, err := ak.SignTx(tx, crypto)
+		if err != nil {
+			return nil, fmt.Errorf("sign error: %s", err)
 		}
+		signs = append(signs, sign)
 	}
-	return authRequireSigns, nil
+	return signs, nil
 }
 
-func assembleTxInputsSupportAccount(ctx context.Context, client pb.XchainClient, opt *TransferOptions, totalNeed *big.Int,
-	initAddr, initPubkey, initScrkey string, cryptoClient crypto_base.CryptoClient) ([]*pb.TxInput, *pb.TxOutput, error) {
+func assembleTxInputsSupportAccount(ctx context.Context, client pb.XchainClient, opt *TransferOptions,
+	totalNeed *big.Int, initiator AKInfo, crypto base.CryptoClient) ([]*pb.TxInput, *pb.TxOutput, error) {
+
 	ui := &pb.UtxoInput{
 		Bcname:    opt.BlockchainName,
 		Address:   opt.From,
 		TotalNeed: totalNeed.String(),
 		NeedLock:  true,
-		Publickey: initPubkey,
+		Publickey: initiator.publicKey,
 	}
 
-	sign, err := computeSelectUtxoSign(opt.BlockchainName, initAddr, totalNeed.String(), initScrkey, strconv.FormatBool(true), cryptoClient)
+	sign, err := initiator.SignUtxo(opt.BlockchainName, totalNeed, crypto)
 	if err != nil {
 		return nil, nil, err
 	}
-	ui.UserSign = sign
+	ui.UserSign = sign.Sign
 	utxoRes, selectErr := client.SelectUTXO(ctx, ui)
 	if selectErr != nil || utxoRes.Header.Error != pb.XChainErrorEnum_SUCCESS {
 		return nil, nil, ErrSelectUtxo
@@ -517,21 +513,6 @@ func assembleTxInputsSupportAccount(ctx context.Context, client pb.XchainClient,
 	return txTxInputs, txOutput, nil
 }
 
-func computeSelectUtxoSign(bcName, account, need, initScrKey, isLock string, cryptoClient crypto_base.CryptoClient) ([]byte, error) {
-	privateKey, err := cryptoClient.GetEcdsaPrivateKeyFromJsonStr(initScrKey)
-	if err != nil {
-		return nil, err
-	}
-
-	hashStr := bcName + account + need + isLock
-	doubleHash := cryptoHash.DoubleSha256([]byte(hashStr))
-	signResult, err := cryptoClient.SignECDSA(privateKey, doubleHash)
-	if err != nil {
-		return nil, err
-	}
-	return signResult, nil
-}
-
 // AddCommand add sub cmd
 func AddCommand(cmd CommandFunc) {
 	Commands = append(Commands, cmd)
diff --git a/cmd/client/cmd/comm_trans.go b/cmd/client/cmd/comm_trans.go
index 8864e2302..7ffe04072 100644
--- a/cmd/client/cmd/comm_trans.go
+++ b/cmd/client/cmd/comm_trans.go
@@ -18,15 +18,14 @@ import (
 	"time"
 
 	"github.com/golang/protobuf/proto"
+	"github.com/xuperchain/xupercore/bcs/ledger/xledger/state/utxo"
+	"github.com/xuperchain/xupercore/kernel/contract"
+	"github.com/xuperchain/xupercore/lib/crypto/client"
+	"github.com/xuperchain/xupercore/lib/utils"
 	"google.golang.org/grpc"
 
 	"github.com/xuperchain/xuperchain/service/common"
 	"github.com/xuperchain/xuperchain/service/pb"
-	"github.com/xuperchain/xupercore/bcs/ledger/xledger/state/utxo"
-	"github.com/xuperchain/xupercore/kernel/contract"
-	crypto_client "github.com/xuperchain/xupercore/lib/crypto/client"
-	cryptoHash "github.com/xuperchain/xupercore/lib/crypto/hash"
-	"github.com/xuperchain/xupercore/lib/utils"
 )
 
 const (
@@ -65,45 +64,45 @@ type CommTrans struct {
 }
 
 // GenerateTx generate raw tx
-func (c *CommTrans) GenerateTx(ctx context.Context) (*pb.Transaction, error) {
-	preExeRPCRes, preExeReqs, err := c.GenPreExeRes(ctx)
+func (t *CommTrans) GenerateTx(ctx context.Context) (*pb.Transaction, error) {
+	preExeRPCRes, preExeReqs, err := t.GenPreExeRes(ctx)
 	if err != nil {
 		return nil, err
 	}
 
-	desc, _ := c.GetDesc()
+	desc, _ := t.GetDesc()
 
-	tx, err := c.GenRawTx(ctx, desc, preExeRPCRes.GetResponse(), preExeReqs)
+	tx, err := t.GenRawTx(ctx, desc, preExeRPCRes.GetResponse(), preExeReqs)
 	return tx, err
 }
 
 // GenPreExeRes 得到预执行的结果
-func (c *CommTrans) GenPreExeRes(ctx context.Context) (
+func (t *CommTrans) GenPreExeRes(ctx context.Context) (
 	*pb.InvokeRPCResponse, []*pb.InvokeRequest, error) {
 	preExeReqs := []*pb.InvokeRequest{}
-	if c.ModuleName != "" {
-		if c.ModuleName == "xkernel" {
+	if t.ModuleName != "" {
+		if t.ModuleName == "xkernel" {
 			preExeReqs = append(preExeReqs, &pb.InvokeRequest{
-				ModuleName:   c.ModuleName,
-				ContractName: c.ContractName,
-				MethodName:   c.MethodName,
-				Args:         c.Args,
+				ModuleName:   t.ModuleName,
+				ContractName: t.ContractName,
+				MethodName:   t.MethodName,
+				Args:         t.Args,
 			})
 		} else {
 			invokeReq := &pb.InvokeRequest{
-				ModuleName:   c.ModuleName,
-				ContractName: c.ContractName,
-				MethodName:   c.MethodName,
-				Args:         c.Args,
+				ModuleName:   t.ModuleName,
+				ContractName: t.ContractName,
+				MethodName:   t.MethodName,
+				Args:         t.Args,
 			}
 			// transfer to contract
-			if c.To == c.ContractName {
-				invokeReq.Amount = c.Amount
+			if t.To == t.ContractName {
+				invokeReq.Amount = t.Amount
 			}
 			preExeReqs = append(preExeReqs, invokeReq)
 		}
 	} else {
-		tmpReq, err := c.GetInvokeRequestFromDesc()
+		tmpReq, err := t.GetInvokeRequestFromDesc()
 		if err != nil {
 			return nil, nil, fmt.Errorf("Get pb.InvokeRPCRequest error:%s", err)
 		}
@@ -113,31 +112,31 @@ func (c *CommTrans) GenPreExeRes(ctx context.Context) (
 	}
 
 	preExeRPCReq := &pb.InvokeRPCRequest{
-		Bcname: c.ChainName,
+		Bcname: t.ChainName,
 		Header: &pb.Header{
 			Logid: utils.GenLogId(),
 		},
 		Requests: preExeReqs,
 	}
 
-	initiator, err := c.genInitiator()
+	initiator, err := t.genInitiator()
 	if err != nil {
 		return nil, nil, fmt.Errorf("Get initiator error: %s", err.Error())
 	}
 
 	preExeRPCReq.Initiator = initiator
-	if !c.IsQuick {
-		preExeRPCReq.AuthRequire, err = c.genAuthRequireQuick()
+	if !t.IsQuick {
+		preExeRPCReq.AuthRequire, err = t.genAuthRequireQuick()
 		if err != nil {
 			return nil, nil, fmt.Errorf("Get auth require quick error: %s", err.Error())
 		}
 	} else {
-		preExeRPCReq.AuthRequire, err = c.GenAuthRequire(c.MultiAddrs)
+		preExeRPCReq.AuthRequire, err = t.GenAuthRequire(t.MultiAddrs)
 		if err != nil {
 			return nil, nil, fmt.Errorf("Get auth require error: %s", err.Error())
 		}
 	}
-	preExeRPCRes, err := c.XchainClient.PreExec(ctx, preExeRPCReq)
+	preExeRPCRes, err := t.XchainClient.PreExec(ctx, preExeRPCReq)
 	if err != nil {
 		return nil, nil, fmt.Errorf("PreExe contract response : %v, logid:%s", err, preExeRPCReq.Header.Logid)
 	}
@@ -151,14 +150,14 @@ func (c *CommTrans) GenPreExeRes(ctx context.Context) (
 }
 
 // GetInvokeRequestFromDesc get invokerequest from desc file
-func (c *CommTrans) GetInvokeRequestFromDesc() (*pb.InvokeRequest, error) {
-	desc, err := c.GetDesc()
+func (t *CommTrans) GetInvokeRequestFromDesc() (*pb.InvokeRequest, error) {
+	desc, err := t.GetDesc()
 	if err != nil {
 		return nil, fmt.Errorf("get desc error:%s", err)
 	}
 
 	var preExeReq *pb.InvokeRequest
-	preExeReq, err = c.ReadPreExeReq(desc)
+	preExeReq, err = t.ReadPreExeReq(desc)
 	if err != nil {
 		return nil, err
 	}
@@ -167,16 +166,16 @@ func (c *CommTrans) GetInvokeRequestFromDesc() (*pb.InvokeRequest, error) {
 }
 
 // GetDesc 解析desc字段，主要是针对合约
-func (c *CommTrans) GetDesc() ([]byte, error) {
-	if c.Descfile == "" {
+func (t *CommTrans) GetDesc() ([]byte, error) {
+	if t.Descfile == "" {
 		return []byte(defaultDesc), nil
 	}
-	return ioutil.ReadFile(c.Descfile)
+	return ioutil.ReadFile(t.Descfile)
 }
 
 // ReadPreExeReq 从desc中填充出发起合约调用的结构体
-func (c *CommTrans) ReadPreExeReq(buf []byte) (*pb.InvokeRequest, error) {
-	params := new(invokeRequestWraper)
+func (t *CommTrans) ReadPreExeReq(buf []byte) (*pb.InvokeRequest, error) {
+	params := new(invokeRequestWrapper)
 	err := json.Unmarshal(buf, params)
 	if err != nil {
 		return nil, nil
@@ -194,7 +193,7 @@ func (c *CommTrans) ReadPreExeReq(buf []byte) (*pb.InvokeRequest, error) {
 }
 
 // GenRawTx 生成一个完整raw的交易
-func (c *CommTrans) GenRawTx(ctx context.Context, desc []byte, preExeRes *pb.InvokeResponse,
+func (t *CommTrans) GenRawTx(ctx context.Context, desc []byte, preExeRes *pb.InvokeResponse,
 	preExeReqs []*pb.InvokeRequest) (*pb.Transaction, error) {
 	tx := &pb.Transaction{
 		Desc:      desc,
@@ -217,13 +216,13 @@ func (c *CommTrans) GenRawTx(ctx context.Context, desc []byte, preExeRes *pb.Inv
 		tx.TxOutputs = append(tx.TxOutputs, preExeRes.GetUtxoOutputs()...)
 	}
 
-	txOutputs, totalNeed, err := c.GenTxOutputs(gasUsed)
+	txOutputs, totalNeed, err := t.GenTxOutputs(gasUsed)
 	if err != nil {
 		return nil, err
 	}
 	tx.TxOutputs = append(tx.TxOutputs, txOutputs...)
 
-	txInputs, deltaTxOutput, err := c.GenTxInputs(ctx, totalNeed)
+	txInputs, deltaTxOutput, err := t.GenTxInputs(ctx, totalNeed)
 	if err != nil {
 		return nil, err
 	}
@@ -241,7 +240,7 @@ func (c *CommTrans) GenRawTx(ctx context.Context, desc []byte, preExeRes *pb.Inv
 	}
 
 	// 填充交易发起者的addr
-	fromAddr, err := c.genInitiator()
+	fromAddr, err := t.genInitiator()
 	if err != nil {
 		return nil, err
 	}
@@ -251,11 +250,11 @@ func (c *CommTrans) GenRawTx(ctx context.Context, desc []byte, preExeRes *pb.Inv
 }
 
 // genInitiator generate initiator of transaction
-func (c *CommTrans) genInitiator() (string, error) {
-	if c.From != "" {
-		return c.From, nil
+func (t *CommTrans) genInitiator() (string, error) {
+	if t.From != "" {
+		return t.From, nil
 	}
-	fromAddr, err := readAddress(c.Keys)
+	fromAddr, err := readAddress(t.Keys)
 	if err != nil {
 		return "", err
 	}
@@ -263,35 +262,35 @@ func (c *CommTrans) genInitiator() (string, error) {
 }
 
 // GenTxOutputs 填充得到transaction的repeated TxOutput tx_outputs
-func (c *CommTrans) GenTxOutputs(gasUsed int64) ([]*pb.TxOutput, *big.Int, error) {
+func (t *CommTrans) GenTxOutputs(gasUsed int64) ([]*pb.TxOutput, *big.Int, error) {
 	// 组装转账的账户信息
 	account := &pb.TxDataAccount{
-		Address:      c.To,
-		Amount:       c.Amount,
-		FrozenHeight: c.FrozenHeight,
+		Address:      t.To,
+		Amount:       t.Amount,
+		FrozenHeight: t.FrozenHeight,
 	}
 
 	accounts := []*pb.TxDataAccount{}
-	if c.To != "" {
+	if t.To != "" {
 		accounts = append(accounts, account)
 	}
 
 	// 如果有小费,增加转个小费地址的账户
 	// 如果有合约，需要支付gas
 	if gasUsed > 0 {
-		if c.Fee != "" && c.Fee != "0" {
-			fee, _ := strconv.ParseInt(c.Fee, 10, 64)
+		if t.Fee != "" && t.Fee != "0" {
+			fee, _ := strconv.ParseInt(t.Fee, 10, 64)
 			if fee < gasUsed {
 				return nil, nil, errors.New("Fee not enough")
 			}
 		} else {
 			return nil, nil, errors.New("You need add fee")
 		}
-		fmt.Printf("The fee you pay is: %v\n", c.Fee)
-		accounts = append(accounts, newFeeAccount(c.Fee))
-	} else if c.Fee != "" && c.Fee != "0" && gasUsed <= 0 {
-		fmt.Printf("The fee you pay is: %v\n", c.Fee)
-		accounts = append(accounts, newFeeAccount(c.Fee))
+		fmt.Printf("The fee you pay is: %v\n", t.Fee)
+		accounts = append(accounts, newFeeAccount(t.Fee))
+	} else if t.Fee != "" && t.Fee != "0" && gasUsed <= 0 {
+		fmt.Printf("The fee you pay is: %v\n", t.Fee)
+		accounts = append(accounts, newFeeAccount(t.Fee))
 	}
 
 	// 组装txOutputs
@@ -325,27 +324,27 @@ func (c *CommTrans) GenTxOutputs(gasUsed int64) ([]*pb.TxOutput, *big.Int, error
 
 // GenTxInputs 填充得到transaction的repeated TxInput tx_inputs,
 // 如果输入大于输出，增加一个转给自己(data/keys/)的输入-输出的交易
-func (c *CommTrans) GenTxInputs(ctx context.Context, totalNeed *big.Int) (
+func (t *CommTrans) GenTxInputs(ctx context.Context, totalNeed *big.Int) (
 	[]*pb.TxInput, *pb.TxOutput, error) {
 	var fromAddr string
 	var err error
-	if c.From != "" {
-		fromAddr = c.From
+	if t.From != "" {
+		fromAddr = t.From
 	} else {
-		fromAddr, err = readAddress(c.Keys)
+		fromAddr, err = readAddress(t.Keys)
 		if err != nil {
 			return nil, nil, err
 		}
 	}
 
 	utxoInput := &pb.UtxoInput{
-		Bcname:    c.ChainName,
+		Bcname:    t.ChainName,
 		Address:   fromAddr,
 		TotalNeed: totalNeed.String(),
 		NeedLock:  false,
 	}
 
-	utxoOutputs, err := c.XchainClient.SelectUTXO(ctx, utxoInput)
+	utxoOutputs, err := t.XchainClient.SelectUTXO(ctx, utxoInput)
 	if err != nil {
 		return nil, nil, fmt.Errorf("%v, details:%v", ErrSelectUtxo, err)
 	}
@@ -384,48 +383,48 @@ func (c *CommTrans) GenTxInputs(ctx context.Context, totalNeed *big.Int) (
 }
 
 // Transfer quick access to transfer
-func (c *CommTrans) Transfer(ctx context.Context) error {
+func (t *CommTrans) Transfer(ctx context.Context) error {
 	var err error
 	tx := &pb.Transaction{}
-	if c.RootOptions.ComplianceCheck.IsNeedComplianceCheck == true {
-		preSelectUTXORes, err := c.GenPreExeWithSelectUtxoRes(ctx)
+	if t.RootOptions.ComplianceCheck.IsNeedComplianceCheck == true {
+		preSelectUTXORes, err := t.GenPreExeWithSelectUtxoRes(ctx)
 		if err != nil {
 			return err
 		}
-		return c.GenCompleteTxAndPost(ctx, preSelectUTXORes)
+		return t.GenCompleteTxAndPost(ctx, preSelectUTXORes)
 	} else {
-		tx, err = c.GenerateTx(ctx)
+		tx, err = t.GenerateTx(ctx)
 		if err != nil {
 			return err
 		}
 
-		if c.DebugTx {
+		if t.DebugTx {
 			ttx := FromPBTx(tx)
 			out, _ := json.MarshalIndent(ttx, "", "  ")
 			fmt.Println(string(out))
 			return nil
 		}
 
-		return c.SendTx(ctx, tx)
+		return t.SendTx(ctx, tx)
 	}
 }
 
 // SendTx post tx
-func (c *CommTrans) SendTx(ctx context.Context, tx *pb.Transaction) error {
-	fromAddr, err := readAddress(c.Keys)
+func (t *CommTrans) SendTx(ctx context.Context, tx *pb.Transaction) error {
+	fromAddr, err := readAddress(t.Keys)
 	if err != nil {
 		return err
 	}
 
 	var authRequire string
-	if c.From != "" {
-		authRequire = c.From + "/" + fromAddr
+	if t.From != "" {
+		authRequire = t.From + "/" + fromAddr
 	} else {
 		authRequire = fromAddr
 	}
 	tx.AuthRequire = append(tx.AuthRequire, authRequire)
 
-	signInfos, err := c.genInitSign(tx)
+	signInfos, err := t.signTxForInitiator(tx)
 	if err != nil {
 		return err
 	}
@@ -434,107 +433,63 @@ func (c *CommTrans) SendTx(ctx context.Context, tx *pb.Transaction) error {
 
 	tx.Txid, err = common.MakeTxId(tx)
 	if err != nil {
-		return errors.New("MakeTxDigesthash txid error")
+		return errors.New("MakeTxId error")
 	}
 
-	txid, err := c.postTx(ctx, tx)
+	txID, err := t.postTx(ctx, tx)
 	if err != nil {
 		return err
 	}
-	fmt.Printf("Tx id: %s\n", txid)
+	fmt.Printf("Tx id: %s\n", txID)
 
 	return nil
 }
 
-func (c *CommTrans) genInitSign(tx *pb.Transaction) ([]*pb.SignatureInfo, error) {
-	fromPubkey, err := readPublicKey(c.Keys)
-	if err != nil {
-		return nil, err
-	}
+// signTx generates auth required signatures for transaction according to path
+func (t *CommTrans) signTx(tx *pb.Transaction, path string) ([]*pb.SignatureInfo, error) {
 
-	cryptoClient, err := crypto_client.CreateCryptoClient(c.CryptoType)
-	if err != nil {
-		return nil, errors.New("Create crypto client error")
-	}
-	fromScrkey, err := readPrivateKey(c.Keys)
-	if err != nil {
-		return nil, err
+	// generate signature for AK: signed by initiator
+	if path == "" {
+		return t.signTxForInitiator(tx)
 	}
-	signTx, err := common.ComputeTxSign(cryptoClient, tx, []byte(fromScrkey))
+
+	// generate signatures for account: signed by all AK in account path
+	return t.signTxForAccount(tx, path)
+}
+
+// signTxForInitiator generates initiator's signature for this Tx
+func (t *CommTrans) signTxForInitiator(tx *pb.Transaction) ([]*pb.SignatureInfo, error) {
+	initiator := newAK(t.Keys)
+	keyPair, err := initiator.keyPair()
 	if err != nil {
 		return nil, err
 	}
 
-	signInfo := &pb.SignatureInfo{
-		PublicKey: fromPubkey,
-		Sign:      signTx,
+	// create crypto client
+	crypto, err := client.CreateCryptoClient(t.CryptoType)
+	if err != nil {
+		return nil, errors.New("Create crypto client error")
 	}
 
-	signInfos := []*pb.SignatureInfo{}
-	signInfos = append(signInfos, signInfo)
-
-	return signInfos, nil
+	// sign by initiator
+	return signTxForAK(tx, keyPair, crypto)
 }
 
-func (c *CommTrans) genAuthRequireSignsFromPath(tx *pb.Transaction, path string) ([]*pb.SignatureInfo, error) {
-	cryptoClient, err := crypto_client.CreateCryptoClient(c.CryptoType)
+// signTxForAccount generates transaction signatures for account
+func (t *CommTrans) signTxForAccount(tx *pb.Transaction, path string) ([]*pb.SignatureInfo, error) {
+
+	// create crypto client
+	crypto, err := client.CreateCryptoClient(t.CryptoType)
 	if err != nil {
 		return nil, errors.New("Create crypto client error")
 	}
 
-	authRequireSigns := []*pb.SignatureInfo{}
-	if path == "" {
-		initPubkey, err := readPublicKey(c.Keys)
-		if err != nil {
-			return nil, err
-		}
-
-		initScrkey, err := readPrivateKey(c.Keys)
-		if err != nil {
-			return nil, err
-		}
-		signTx, err := common.ComputeTxSign(cryptoClient, tx, []byte(initScrkey))
-		if err != nil {
-			return nil, err
-		}
-		signInfo := &pb.SignatureInfo{
-			PublicKey: initPubkey,
-			Sign:      signTx,
-		}
-		authRequireSigns = append(authRequireSigns, signInfo)
-		return authRequireSigns, nil
-	}
-	dir, err := ioutil.ReadDir(path)
-	if err != nil {
-		return nil, err
-	}
-	for _, fi := range dir {
-		if fi.IsDir() {
-			sk, err := readPrivateKey(path + "/" + fi.Name())
-			if err != nil {
-				return nil, err
-			}
-			pk, err := readPublicKey(path + "/" + fi.Name())
-			if err != nil {
-				return nil, err
-			}
-			signTx, err := common.ComputeTxSign(cryptoClient, tx, []byte(sk))
-			if err != nil {
-				return nil, err
-			}
-			signInfo := &pb.SignatureInfo{
-				PublicKey: pk,
-				Sign:      signTx,
-			}
-			authRequireSigns = append(authRequireSigns, signInfo)
-		}
-	}
-	return authRequireSigns, nil
+	return signTxForAccount(tx, path, crypto)
 }
 
-func (c *CommTrans) postTx(ctx context.Context, tx *pb.Transaction) (string, error) {
+func (t *CommTrans) postTx(ctx context.Context, tx *pb.Transaction) (string, error) {
 	txStatus := &pb.TxStatus{
-		Bcname: c.ChainName,
+		Bcname: t.ChainName,
 		Status: pb.TransactionStatus_UNCONFIRM,
 		Tx:     tx,
 		Header: &pb.Header{
@@ -543,7 +498,7 @@ func (c *CommTrans) postTx(ctx context.Context, tx *pb.Transaction) (string, err
 		Txid: tx.Txid,
 	}
 
-	reply, err := c.XchainClient.PostTx(ctx, txStatus)
+	reply, err := t.XchainClient.PostTx(ctx, txStatus)
 	if err != nil {
 		return "", err
 	}
@@ -554,32 +509,32 @@ func (c *CommTrans) postTx(ctx context.Context, tx *pb.Transaction) (string, err
 	return hex.EncodeToString(txStatus.Txid), nil
 }
 
-// GenerateMultisigGenRawTx for mulitisig gen cmd
-func (c *CommTrans) GenerateMultisigGenRawTx(ctx context.Context) error {
-	tx, err := c.GenerateTx(ctx)
+// GenerateMultisigGenRawTx for multisig gen cmd
+func (t *CommTrans) GenerateMultisigGenRawTx(ctx context.Context) error {
+	tx, err := t.GenerateTx(ctx)
 	if err != nil {
 		return err
 	}
 
 	// 填充需要多重签名的addr
-	multiAddrs, err := c.GenAuthRequire(c.MultiAddrs)
+	multiAddrs, err := t.GenAuthRequire(t.MultiAddrs)
 	if err != nil {
 		return err
 	}
 	tx.AuthRequire = multiAddrs
 
-	return c.GenTxFile(tx)
+	return t.GenTxFile(tx)
 }
 
-func (c *CommTrans) genAuthRequireQuick() ([]string, error) {
+func (t *CommTrans) genAuthRequireQuick() ([]string, error) {
 
-	fromAddr, err := readAddress(c.Keys)
+	fromAddr, err := readAddress(t.Keys)
 	if err != nil {
 		return nil, err
 	}
 	authRequires := []string{}
-	if c.From != "" {
-		authRequires = append(authRequires, c.From+"/"+fromAddr)
+	if t.From != "" {
+		authRequires = append(authRequires, t.From+"/"+fromAddr)
 	} else {
 		authRequires = append(authRequires, fromAddr)
 	}
@@ -587,7 +542,7 @@ func (c *CommTrans) genAuthRequireQuick() ([]string, error) {
 }
 
 // GenAuthRequire get auth require aks from file
-func (c *CommTrans) GenAuthRequire(filename string) ([]string, error) {
+func (t *CommTrans) GenAuthRequire(filename string) ([]string, error) {
 	var addrs []string
 
 	fileIn, err := os.Open(filename)
@@ -613,17 +568,17 @@ func (c *CommTrans) GenAuthRequire(filename string) ([]string, error) {
 }
 
 // GenTxFile generate raw tx file
-func (c *CommTrans) GenTxFile(tx *pb.Transaction) error {
+func (t *CommTrans) GenTxFile(tx *pb.Transaction) error {
 	data, err := proto.Marshal(tx)
 	if err != nil {
 		return errors.New("Tx marshal error")
 	}
-	err = ioutil.WriteFile(c.Output, data, 0755)
+	err = ioutil.WriteFile(t.Output, data, 0755)
 	if err != nil {
 		return errors.New("WriteFile error")
 	}
 
-	if c.IsPrint {
+	if t.IsPrint {
 		return printTx(tx)
 	}
 
@@ -643,31 +598,31 @@ func printTx(tx *pb.Transaction) error {
 }
 
 // GenTxInputsWithMergeUTXO generate tx with merge utxo
-func (c *CommTrans) GenTxInputsWithMergeUTXO(ctx context.Context) ([]*pb.TxInput, *pb.TxOutput, error) {
+func (t *CommTrans) GenTxInputsWithMergeUTXO(ctx context.Context) ([]*pb.TxInput, *pb.TxOutput, error) {
 	var fromAddr string
 	var err error
-	if c.From != "" {
-		fromAddr = c.From
+	if t.From != "" {
+		fromAddr = t.From
 	} else {
-		fromAddr, err = readAddress(c.Keys)
+		fromAddr, err = readAddress(t.Keys)
 		if err != nil {
 			return nil, nil, err
 		}
 	}
 
 	utxoInput := &pb.UtxoInput{
-		Bcname:   c.ChainName,
+		Bcname:   t.ChainName,
 		Address:  fromAddr,
 		NeedLock: true,
 	}
 
-	pubKey, signature, err := signForLockUtxo(c.ChainName, fromAddr, c.Keys, c.CryptoType, big.NewInt(0))
+	signature, err := t.signLockUtxo(t.ChainName, fromAddr, big.NewInt(0))
 	if err != nil {
 		return nil, nil, err
 	}
-	utxoInput.Publickey = pubKey
-	utxoInput.UserSign = signature
-	utxoOutputs, err := c.XchainClient.SelectUTXOBySize(ctx, utxoInput)
+	utxoInput.Publickey = signature.PublicKey
+	utxoInput.UserSign = signature.Sign
+	utxoOutputs, err := t.XchainClient.SelectUTXOBySize(ctx, utxoInput)
 	if err != nil {
 		return nil, nil, fmt.Errorf("%v, details:%v", ErrSelectUtxo, err)
 	}
@@ -700,32 +655,32 @@ func (c *CommTrans) GenTxInputsWithMergeUTXO(ctx context.Context) ([]*pb.TxInput
 	return txInputs, txOutput, nil
 }
 
-func (c *CommTrans) GenPreExeWithSelectUtxoRes(ctx context.Context) (
+func (t *CommTrans) GenPreExeWithSelectUtxoRes(ctx context.Context) (
 	*pb.PreExecWithSelectUTXOResponse, error) {
 	preExeReqs := []*pb.InvokeRequest{}
-	if c.ModuleName != "" {
-		if c.ModuleName == "xkernel" {
+	if t.ModuleName != "" {
+		if t.ModuleName == "xkernel" {
 			preExeReqs = append(preExeReqs, &pb.InvokeRequest{
-				ModuleName:   c.ModuleName,
-				ContractName: c.ContractName,
-				MethodName:   c.MethodName,
-				Args:         c.Args,
+				ModuleName:   t.ModuleName,
+				ContractName: t.ContractName,
+				MethodName:   t.MethodName,
+				Args:         t.Args,
 			})
 		} else {
 			invokeReq := &pb.InvokeRequest{
-				ModuleName:   c.ModuleName,
-				ContractName: c.ContractName,
-				MethodName:   c.MethodName,
-				Args:         c.Args,
+				ModuleName:   t.ModuleName,
+				ContractName: t.ContractName,
+				MethodName:   t.MethodName,
+				Args:         t.Args,
 			}
 			// transfer to contract
-			if c.To == c.ContractName {
-				invokeReq.Amount = c.Amount
+			if t.To == t.ContractName {
+				invokeReq.Amount = t.Amount
 			}
 			preExeReqs = append(preExeReqs, invokeReq)
 		}
 	} else {
-		tmpReq, err := c.GetInvokeRequestFromDesc()
+		tmpReq, err := t.GetInvokeRequestFromDesc()
 		if err != nil {
 			return nil, fmt.Errorf("Get pb.InvokeRPCRequest error:%s", err)
 		}
@@ -735,55 +690,55 @@ func (c *CommTrans) GenPreExeWithSelectUtxoRes(ctx context.Context) (
 	}
 
 	preExeRPCReq := &pb.InvokeRPCRequest{
-		Bcname: c.ChainName,
+		Bcname: t.ChainName,
 		Header: &pb.Header{
 			Logid: utils.GenLogId(),
 		},
 		Requests: preExeReqs,
 	}
 
-	initiator, err := c.genInitiator()
+	initiator, err := t.genInitiator()
 	if err != nil {
 		return nil, fmt.Errorf("Get initiator error: %s", err.Error())
 	}
 
 	preExeRPCReq.Initiator = initiator
-	if !c.IsQuick {
-		preExeRPCReq.AuthRequire, err = c.genAuthRequireQuick()
+	if !t.IsQuick {
+		preExeRPCReq.AuthRequire, err = t.genAuthRequireQuick()
 		if err != nil {
 			return nil, fmt.Errorf("Get auth require quick error: %s", err.Error())
 		}
 	} else {
-		preExeRPCReq.AuthRequire, err = c.GenAuthRequire(c.MultiAddrs)
+		preExeRPCReq.AuthRequire, err = t.GenAuthRequire(t.MultiAddrs)
 		if err != nil {
 			return nil, fmt.Errorf("Get auth require error: %s", err.Error())
 		}
 	}
-	extraAmount := int64(c.RootOptions.ComplianceCheck.ComplianceCheckEndorseServiceFee)
-	if c.Fee != "" && c.Fee != "0" {
-		fee, err := strconv.ParseInt(c.Fee, 10, 64)
+	extraAmount := int64(t.RootOptions.ComplianceCheck.ComplianceCheckEndorseServiceFee)
+	if t.Fee != "" && t.Fee != "0" {
+		fee, err := strconv.ParseInt(t.Fee, 10, 64)
 		if err != nil {
-			return nil, fmt.Errorf("Invalid Fee: %s", c.Fee)
+			return nil, fmt.Errorf("Invalid Fee: %s", t.Fee)
 		}
 		extraAmount += fee
 	}
-	if c.Amount != "" {
-		amount, err := strconv.ParseInt(c.Amount, 10, 64)
+	if t.Amount != "" {
+		amount, err := strconv.ParseInt(t.Amount, 10, 64)
 		if err != nil {
-			return nil, fmt.Errorf("invalid Amount: %s", c.Amount)
+			return nil, fmt.Errorf("invalid Amount: %s", t.Amount)
 		}
 		extraAmount += amount
 	}
-	preExeRPCReq.AuthRequire = append(preExeRPCReq.AuthRequire, c.RootOptions.ComplianceCheck.ComplianceCheckEndorseServiceAddr)
+	preExeRPCReq.AuthRequire = append(preExeRPCReq.AuthRequire, t.RootOptions.ComplianceCheck.ComplianceCheckEndorseServiceAddr)
 	preSelUTXOReq := &pb.PreExecWithSelectUTXORequest{
-		Bcname:      c.ChainName,
+		Bcname:      t.ChainName,
 		Address:     initiator,
 		TotalAmount: extraAmount,
 		Request:     preExeRPCReq,
 	}
 
 	// preExe
-	preExecWithSelectUTXOResponse, err := c.XchainClient.PreExecWithSelectUTXO(ctx, preSelUTXOReq)
+	preExecWithSelectUTXOResponse, err := t.XchainClient.PreExecWithSelectUTXO(ctx, preSelUTXOReq)
 	if err != nil {
 		return nil, err
 	}
@@ -798,43 +753,43 @@ func (c *CommTrans) GenPreExeWithSelectUtxoRes(ctx context.Context) (
 	gasUsed := preExecWithSelectUTXOResponse.GetResponse().GetGasUsed()
 	fmt.Printf("The gas you cousume is: %v\n", gasUsed)
 	if gasUsed > 0 {
-		if c.Fee != "" && c.Fee != "0" {
-			fee, _ := strconv.ParseInt(c.Fee, 10, 64)
+		if t.Fee != "" && t.Fee != "0" {
+			fee, _ := strconv.ParseInt(t.Fee, 10, 64)
 			if fee < gasUsed {
 				return nil, errors.New("Fee not enough")
 			}
 		} else {
 			return nil, errors.New("You need add fee")
 		}
-		fmt.Printf("The fee you pay is: %v\n", c.Fee)
-	} else if c.Fee != "" && c.Fee != "0" && gasUsed <= 0 {
-		fmt.Printf("The fee you pay is: %v\n", c.Fee)
+		fmt.Printf("The fee you pay is: %v\n", t.Fee)
+	} else if t.Fee != "" && t.Fee != "0" && gasUsed <= 0 {
+		fmt.Printf("The fee you pay is: %v\n", t.Fee)
 	}
 
 	return preExecWithSelectUTXOResponse, nil
 }
 
-func (c *CommTrans) GenCompleteTxAndPost(ctx context.Context, preExeResp *pb.PreExecWithSelectUTXOResponse) error {
-	complianceCheckTx, err := c.GenComplianceCheckTx(preExeResp.GetUtxoOutput())
+func (t *CommTrans) GenCompleteTxAndPost(ctx context.Context, preExeResp *pb.PreExecWithSelectUTXOResponse) error {
+	complianceCheckTx, err := t.GenComplianceCheckTx(preExeResp.GetUtxoOutput())
 	if err != nil {
 		fmt.Printf("GenCompleteTxAndPost GenComplianceCheckTx failed, err: %v", err)
 		return err
 	}
 	fmt.Printf("ComplianceCheck txid: %v\n", hex.EncodeToString(complianceCheckTx.Txid))
 
-	tx, err := c.GenRealTx(preExeResp, complianceCheckTx)
+	tx, err := t.GenRealTx(preExeResp, complianceCheckTx)
 	if err != nil {
 		fmt.Printf("GenRealTx failed, err: %v", err)
 		return err
 	}
-	endorserSign, err := c.ComplianceCheck(tx, complianceCheckTx)
+	endorserSign, err := t.ComplianceCheck(tx, complianceCheckTx)
 	if err != nil {
 		return err
 	}
 	tx.AuthRequireSigns = append(tx.AuthRequireSigns, endorserSign)
 	tx.Txid, _ = common.MakeTxId(tx)
 
-	txid, err := c.postTx(ctx, tx)
+	txid, err := t.postTx(ctx, tx)
 	if err != nil {
 		return err
 	}
@@ -843,11 +798,11 @@ func (c *CommTrans) GenCompleteTxAndPost(ctx context.Context, preExeResp *pb.Pre
 	return nil
 }
 
-func (c *CommTrans) GenRealTx(response *pb.PreExecWithSelectUTXOResponse,
+func (t *CommTrans) GenRealTx(response *pb.PreExecWithSelectUTXOResponse,
 	complianceCheckTx *pb.Transaction) (*pb.Transaction, error) {
 	utxolist := []*pb.Utxo{}
 	totalSelected := big.NewInt(0)
-	initiator, err := c.genInitiator()
+	initiator, err := t.genInitiator()
 	if err != nil {
 		return nil, err
 	}
@@ -871,19 +826,19 @@ func (c *CommTrans) GenRealTx(response *pb.PreExecWithSelectUTXOResponse,
 
 	totalNeed := big.NewInt(0)
 
-	// no need to double check
+	// no need to double-check
 	amount, ok := big.NewInt(0).SetString("0", 10)
 	if !ok {
 		return nil, ErrInvalidAmount
 	}
-	fee, ok := big.NewInt(0).SetString(c.Fee, 10)
+	fee, ok := big.NewInt(0).SetString(t.Fee, 10)
 	if !ok {
 		return nil, ErrInvalidAmount
 	}
 	amount.Add(amount, fee)
 	totalNeed.Add(totalNeed, amount)
-	if c.Amount != "" {
-		amount, ok := big.NewInt(0).SetString(c.Amount, 10)
+	if t.Amount != "" {
+		amount, ok := big.NewInt(0).SetString(t.Amount, 10)
 		if !ok {
 			return nil, ErrInvalidAmount
 		}
@@ -891,13 +846,13 @@ func (c *CommTrans) GenRealTx(response *pb.PreExecWithSelectUTXOResponse,
 	}
 
 	selfAmount := totalSelected.Sub(totalSelected, totalNeed)
-	txOutputs, err := c.GenerateMultiTxOutputs(selfAmount.String(), c.Fee)
+	txOutputs, err := t.GenerateMultiTxOutputs(selfAmount.String(), t.Fee)
 	if err != nil {
 		fmt.Printf("GenRealTx GenerateTxOutput failed.")
 		return nil, fmt.Errorf("GenRealTx GenerateTxOutput err: %v", err)
 	}
 
-	txInputs, err := c.GeneratePureTxInputs(utxoOutput)
+	txInputs, err := t.GeneratePureTxInputs(utxoOutput)
 	if err != nil {
 		fmt.Printf("GenRealTx GenerateTxInput failed.")
 		return nil, fmt.Errorf("GenRealTx GenerateTxInput err: %v", err)
@@ -920,60 +875,39 @@ func (c *CommTrans) GenRealTx(response *pb.PreExecWithSelectUTXOResponse,
 		tx.TxOutputs = append(tx.TxOutputs, response.GetResponse().GetUtxoOutputs()...)
 	}
 
-	desc, _ := c.GetDesc()
+	desc, _ := t.GetDesc()
 	tx.Desc = desc
 	tx.TxInputsExt = response.GetResponse().GetInputs()
 	tx.TxOutputsExt = response.GetResponse().GetOutputs()
 	tx.ContractRequests = response.GetResponse().GetRequests()
 
-	fromAddr, err := readAddress(c.Keys)
+	fromAddr, err := readAddress(t.Keys)
 	if err != nil {
 		return nil, err
 	}
 	var authRequire string
-	if c.From != "" {
-		authRequire = c.From + "/" + fromAddr
+	if t.From != "" {
+		authRequire = t.From + "/" + fromAddr
 	} else {
 		authRequire = fromAddr
 	}
 	tx.AuthRequire = append(tx.AuthRequire, authRequire)
-	tx.AuthRequire = append(tx.AuthRequire, c.RootOptions.ComplianceCheck.ComplianceCheckEndorseServiceAddr)
+	tx.AuthRequire = append(tx.AuthRequire, t.RootOptions.ComplianceCheck.ComplianceCheckEndorseServiceAddr)
 
-	cryptoClient, err := crypto_client.CreateCryptoClient(c.CryptoType)
-	if err != nil {
-		return nil, errors.New("Create crypto client error")
-	}
-	fromPubkey, err := readPublicKey(c.Keys)
-	if err != nil {
-		return nil, err
-	}
-	fromScrkey, err := readPrivateKey(c.Keys)
-	if err != nil {
-		return nil, err
-	}
-	signTx, err := common.ComputeTxSign(cryptoClient, tx, []byte(fromScrkey))
+	signInfos, err := t.signTxForInitiator(tx)
 	if err != nil {
 		return nil, err
 	}
-
-	signatureInfo := &pb.SignatureInfo{
-		PublicKey: fromPubkey,
-		Sign:      signTx,
-	}
-
-	var signatureInfos []*pb.SignatureInfo
-	signatureInfos = append(signatureInfos, signatureInfo)
-
-	tx.InitiatorSigns = signatureInfos
-	tx.AuthRequireSigns = signatureInfos
+	tx.InitiatorSigns = signInfos
+	tx.AuthRequireSigns = signInfos
 
 	// make txid
 	tx.Txid, _ = common.MakeTxId(tx)
 	return tx, nil
 }
 
-func (c *CommTrans) GenerateMultiTxOutputs(selfAmount string, gasUsed string) ([]*pb.TxOutput, error) {
-	selfAddr, err := c.genInitiator()
+func (t *CommTrans) GenerateMultiTxOutputs(selfAmount string, gasUsed string) ([]*pb.TxOutput, error) {
+	selfAddr, err := t.genInitiator()
 	if err != nil {
 		return nil, err
 	}
@@ -1004,13 +938,13 @@ func (c *CommTrans) GenerateMultiTxOutputs(selfAmount string, gasUsed string) ([
 		txOutputs = append(txOutputs, txOutputFee)
 	}
 
-	if c.Amount != "" {
-		amount, ok := new(big.Int).SetString(c.Amount, 10)
+	if t.Amount != "" {
+		amount, ok := new(big.Int).SetString(t.Amount, 10)
 		if !ok {
 			return nil, ErrInvalidAmount
 		}
 		txOutputCountractAmount := new(pb.TxOutput)
-		txOutputCountractAmount.ToAddr = []byte(c.ContractName)
+		txOutputCountractAmount.ToAddr = []byte(t.ContractName)
 		txOutputCountractAmount.Amount = amount.Bytes()
 		txOutputs = append(txOutputs, txOutputCountractAmount)
 	}
@@ -1018,7 +952,7 @@ func (c *CommTrans) GenerateMultiTxOutputs(selfAmount string, gasUsed string) ([
 	return txOutputs, nil
 }
 
-func (c *CommTrans) GeneratePureTxInputs(utxoOutputs *pb.UtxoOutput) (
+func (t *CommTrans) GeneratePureTxInputs(utxoOutputs *pb.UtxoOutput) (
 	[]*pb.TxInput, error) {
 	// gen txInputs
 	var txInputs []*pb.TxInput
@@ -1034,10 +968,10 @@ func (c *CommTrans) GeneratePureTxInputs(utxoOutputs *pb.UtxoOutput) (
 	return txInputs, nil
 }
 
-func (c *CommTrans) ComplianceCheck(tx *pb.Transaction, fee *pb.Transaction) (
+func (t *CommTrans) ComplianceCheck(tx *pb.Transaction, fee *pb.Transaction) (
 	*pb.SignatureInfo, error) {
 	txStatus := &pb.TxStatus{
-		Bcname: c.ChainName,
+		Bcname: t.ChainName,
 		Tx:     tx,
 	}
 
@@ -1049,12 +983,12 @@ func (c *CommTrans) ComplianceCheck(tx *pb.Transaction, fee *pb.Transaction) (
 
 	endorserRequest := &pb.EndorserRequest{
 		RequestName: "ComplianceCheck",
-		BcName:      c.ChainName,
+		BcName:      t.ChainName,
 		Fee:         fee,
 		RequestData: requestData,
 	}
 
-	conn, err := grpc.Dial(c.RootOptions.EndorseServiceHost, grpc.WithInsecure(), grpc.WithMaxMsgSize(64<<20-1))
+	conn, err := grpc.Dial(t.RootOptions.EndorseServiceHost, grpc.WithInsecure(), grpc.WithMaxMsgSize(64<<20-1))
 	if err != nil {
 		fmt.Printf("ComplianceCheck connect EndorseServiceHost err: %v", err)
 		return nil, err
@@ -1073,16 +1007,16 @@ func (c *CommTrans) ComplianceCheck(tx *pb.Transaction, fee *pb.Transaction) (
 	return endorserResponse.GetEndorserSign(), nil
 }
 
-func (c *CommTrans) GenComplianceCheckTx(utxoOutput *pb.UtxoOutput) (*pb.Transaction, error) {
-	totalNeed := new(big.Int).SetInt64(int64(c.RootOptions.ComplianceCheck.ComplianceCheckEndorseServiceFee))
-	txInputs, deltaTxOutput, err := c.GenerateTxInput(utxoOutput, totalNeed)
+func (t *CommTrans) GenComplianceCheckTx(utxoOutput *pb.UtxoOutput) (*pb.Transaction, error) {
+	totalNeed := new(big.Int).SetInt64(int64(t.RootOptions.ComplianceCheck.ComplianceCheckEndorseServiceFee))
+	txInputs, deltaTxOutput, err := t.GenerateTxInput(utxoOutput, totalNeed)
 	if err != nil {
 		fmt.Printf("GenerateComplianceTx GenerateTxInput failed.")
 		return nil, fmt.Errorf("GenerateComplianceTx GenerateTxInput err: %v", err)
 	}
 
-	checkAmount := strconv.Itoa(c.RootOptions.ComplianceCheck.ComplianceCheckEndorseServiceFee)
-	txOutputs, err := c.GenerateTxOutput(c.RootOptions.ComplianceCheck.ComplianceCheckEndorseServiceFeeAddr, checkAmount, "0")
+	checkAmount := strconv.Itoa(t.RootOptions.ComplianceCheck.ComplianceCheckEndorseServiceFee)
+	txOutputs, err := t.GenerateTxOutput(t.RootOptions.ComplianceCheck.ComplianceCheckEndorseServiceFeeAddr, checkAmount, "0")
 	if err != nil {
 		fmt.Printf("GenerateComplianceTx GenerateTxOutput failed.")
 		return nil, fmt.Errorf("GenerateComplianceTx GenerateTxOutput err: %v", err)
@@ -1090,7 +1024,7 @@ func (c *CommTrans) GenComplianceCheckTx(utxoOutput *pb.UtxoOutput) (*pb.Transac
 	if deltaTxOutput != nil {
 		txOutputs = append(txOutputs, deltaTxOutput)
 	}
-	// populates fields
+	// populate fields
 	tx := &pb.Transaction{
 		Desc:      []byte(""),
 		Version:   utxo.TxVersion,
@@ -1100,59 +1034,38 @@ func (c *CommTrans) GenComplianceCheckTx(utxoOutput *pb.UtxoOutput) (*pb.Transac
 		TxOutputs: txOutputs,
 		Nonce:     utils.GenNonce(),
 	}
-	initiator, err := c.genInitiator()
+	initiator, err := t.genInitiator()
 	if err != nil {
 		return nil, err
 	}
 	tx.Initiator = initiator
 
-	cryptoClient, err := crypto_client.CreateCryptoClient(c.CryptoType)
-	if err != nil {
-		return nil, errors.New("Create crypto client error")
-	}
-	fromPubkey, err := readPublicKey(c.Keys)
-	if err != nil {
-		return nil, err
-	}
-	fromScrkey, err := readPrivateKey(c.Keys)
-	if err != nil {
-		return nil, err
-	}
-	fromAddr, err := readAddress(c.Keys)
+	fromAddr, err := readAddress(t.Keys)
 	if err != nil {
 		return nil, err
 	}
 
 	var authRequire string
-	if c.From != "" {
-		authRequire = c.From + "/" + fromAddr
+	if t.From != "" {
+		authRequire = t.From + "/" + fromAddr
 	} else {
 		authRequire = fromAddr
 	}
 	tx.AuthRequire = append(tx.AuthRequire, authRequire)
 
-	signTx, err := common.ComputeTxSign(cryptoClient, tx, []byte(fromScrkey))
+	signInfos, err := t.signTxForInitiator(tx)
 	if err != nil {
 		return nil, err
 	}
+	tx.InitiatorSigns = signInfos
+	tx.AuthRequireSigns = signInfos
 
-	signatureInfo := &pb.SignatureInfo{
-		PublicKey: fromPubkey,
-		Sign:      signTx,
-	}
-
-	var signatureInfos []*pb.SignatureInfo
-	signatureInfos = append(signatureInfos, signatureInfo)
-
-	tx.InitiatorSigns = signatureInfos
-	tx.AuthRequireSigns = signatureInfos
-
-	// make txid
+	// make Tx ID
 	tx.Txid, _ = common.MakeTxId(tx)
 	return tx, nil
 }
 
-func (c *CommTrans) GenerateTxInput(utxoOutputs *pb.UtxoOutput, totalNeed *big.Int) (
+func (t *CommTrans) GenerateTxInput(utxoOutputs *pb.UtxoOutput, totalNeed *big.Int) (
 	[]*pb.TxInput, *pb.TxOutput, error) {
 	var txInputs []*pb.TxInput
 	var txOutput *pb.TxOutput
@@ -1172,10 +1085,10 @@ func (c *CommTrans) GenerateTxInput(utxoOutputs *pb.UtxoOutput, totalNeed *big.I
 
 	var fromAddr string
 	var err error
-	if c.From != "" {
-		fromAddr = c.From
+	if t.From != "" {
+		fromAddr = t.From
 	} else {
-		fromAddr, err = readAddress(c.Keys)
+		fromAddr, err = readAddress(t.Keys)
 		if err != nil {
 			return nil, nil, err
 		}
@@ -1192,7 +1105,7 @@ func (c *CommTrans) GenerateTxInput(utxoOutputs *pb.UtxoOutput, totalNeed *big.I
 	return txInputs, txOutput, nil
 }
 
-func (xc *CommTrans) GenerateTxOutput(to, amount, fee string) ([]*pb.TxOutput, error) {
+func (t *CommTrans) GenerateTxOutput(to, amount, fee string) ([]*pb.TxOutput, error) {
 	accounts := []*pb.TxDataAccount{}
 	if to != "" {
 		account := &pb.TxDataAccount{
@@ -1233,32 +1146,18 @@ func (xc *CommTrans) GenerateTxOutput(to, amount, fee string) ([]*pb.TxOutput, e
 	return txOutputs, nil
 }
 
-func signForLockUtxo(bcName, account, keyPath, cryptoType string, need *big.Int) (string, []byte, error) {
-	hashStr := bcName + account + need.String() + strconv.FormatBool(true)
-	doubleHash := cryptoHash.DoubleSha256([]byte(hashStr))
+func (t *CommTrans) signLockUtxo(bcName, account string, need *big.Int) (pb.SignatureInfo, error) {
 
-	pubkey, err := readPublicKey(keyPath)
+	ak := newAK(t.Keys)
+	keyPair, err := ak.keyPair()
 	if err != nil {
-		return "", nil, err
+		return pb.SignatureInfo{}, err
 	}
 
-	initScrkey, err := readPrivateKey(keyPath)
+	crypto, err := client.CreateCryptoClient(t.CryptoType)
 	if err != nil {
-		return "", nil, err
+		return pb.SignatureInfo{}, errors.New("Create crypto client error")
 	}
 
-	cryptoClient, err := crypto_client.CreateCryptoClient(cryptoType)
-	if err != nil {
-		return "", nil, errors.New("Create crypto client error")
-	}
-	privateKey, err := cryptoClient.GetEcdsaPrivateKeyFromJsonStr(initScrkey)
-	if err != nil {
-		return "", nil, err
-	}
-
-	sign, sErr := cryptoClient.SignECDSA(privateKey, doubleHash)
-	if sErr != nil {
-		return "", nil, sErr
-	}
-	return pubkey, sign, nil
+	return keyPair.SignUtxo(bcName, account, need, crypto)
 }
diff --git a/cmd/client/cmd/multisig_sign.go b/cmd/client/cmd/multisig_sign.go
index 1117f7633..5cdd22bac 100644
--- a/cmd/client/cmd/multisig_sign.go
+++ b/cmd/client/cmd/multisig_sign.go
@@ -12,10 +12,10 @@ import (
 
 	"github.com/golang/protobuf/proto"
 	"github.com/spf13/cobra"
+	"github.com/xuperchain/xupercore/lib/crypto/client"
 
 	"github.com/xuperchain/xuperchain/service/common"
 	"github.com/xuperchain/xuperchain/service/pb"
-	crypto_client "github.com/xuperchain/xupercore/lib/crypto/client"
 )
 
 // MultisigSignCommand multisig sign struct
@@ -61,7 +61,8 @@ func (c *MultisigSignCommand) sign() error {
 		return err
 	}
 
-	fromPubkey, err := readPublicKey(c.cli.RootOptions.Keys)
+	ak := newAK(c.cli.RootOptions.Keys)
+	from, err := ak.keyPair()
 	if err != nil {
 		return err
 	}
@@ -77,16 +78,12 @@ func (c *MultisigSignCommand) sign() error {
 		if err != nil {
 			return err
 		}
-		fromScrkey, err := readPrivateKey(c.cli.RootOptions.Keys)
-		if err != nil {
-			return err
-		}
 
-		xcc, err := crypto_client.CreateCryptoClientFromJSONPrivateKey([]byte(fromScrkey))
+		crypto, err := client.CreateCryptoClientFromJSONPrivateKey([]byte(from.secretKey))
 		if err != nil {
 			return err
 		}
-		priv, err := xcc.GetEcdsaPrivateKeyFromJsonStr(fromScrkey)
+		ecdsaPrivateKey, err := crypto.GetEcdsaPrivateKeyFromJsonStr(from.secretKey)
 		if err != nil {
 			return err
 		}
@@ -95,11 +92,11 @@ func (c *MultisigSignCommand) sign() error {
 			return err
 		}
 		// TODO get partial sign
-		ki, idx, err := c.findKfromKlist(msd, []byte(fromPubkey))
+		ki, idx, err := c.findKFromKList(msd, []byte(from.publicKey))
 		if err != nil {
 			return err
 		}
-		si := xcc.GetSiUsingKCRM(priv, ki, msd.C, msd.R, digestHash)
+		si := crypto.GetSiUsingKCRM(ecdsaPrivateKey, ki, msd.C, msd.R, digestHash)
 		psd := &PartialSign{
 			Si:    si,
 			Index: idx,
@@ -116,12 +113,16 @@ func (c *MultisigSignCommand) sign() error {
 	} else if c.signType != "" {
 		return fmt.Errorf("SignType[%s] is not supported", c.signType)
 	} else {
-		signTx, err := c.genSignTx(tx)
+
+		crypto, err := client.CreateCryptoClient(c.cli.RootOptions.Crypto)
 		if err != nil {
-			return errors.New("Sign tx error")
+			return err
 		}
-
-		err = c.genSignFile(fromPubkey, signTx)
+		signInfo, err := from.SignTx(tx, crypto)
+		if err != nil {
+			return err
+		}
+		err = c.genSignFile(signInfo)
 		if err != nil {
 			return err
 		}
@@ -129,33 +130,8 @@ func (c *MultisigSignCommand) sign() error {
 	return nil
 }
 
-// GetSignTx use privatekey to get sign
-func (c *MultisigSignCommand) genSignTx(tx *pb.Transaction) ([]byte, error) {
-	// create crypto client
-	cryptoClient, err := crypto_client.CreateCryptoClient(c.cli.RootOptions.Crypto)
-	if err != nil {
-		return nil, errors.New("Create crypto client error")
-	}
-	fromScrkey, err := readPrivateKey(c.cli.RootOptions.Keys)
-	if err != nil {
-		return nil, err
-	}
-
-	signTx, err := common.ComputeTxSign(cryptoClient, tx, []byte(fromScrkey))
-	if err != nil {
-		return nil, err
-	}
-
-	return signTx, nil
-}
-
 // genSignFile output to file
-func (c *MultisigSignCommand) genSignFile(pubkey string, sign []byte) error {
-	signInfo := &pb.SignatureInfo{
-		PublicKey: pubkey,
-		Sign:      sign,
-	}
-
+func (c *MultisigSignCommand) genSignFile(signInfo *pb.SignatureInfo) error {
 	signJSON, err := json.MarshalIndent(signInfo, "", "  ")
 	if err != nil {
 		return err
@@ -170,8 +146,8 @@ func (c *MultisigSignCommand) genSignFile(pubkey string, sign []byte) error {
 	return nil
 }
 
-func (c *MultisigSignCommand) findKfromKlist(msd *MultisigData, pubJSON []byte) ([]byte, int, error) {
-	xcc, err := crypto_client.CreateCryptoClientFromJSONPublicKey(pubJSON)
+func (c *MultisigSignCommand) findKFromKList(msd *MultisigData, pubJSON []byte) ([]byte, int, error) {
+	xcc, err := client.CreateCryptoClientFromJSONPublicKey(pubJSON)
 	if err != nil {
 		return nil, 0, err
 	}
diff --git a/cmd/client/cmd/transfer.go b/cmd/client/cmd/transfer.go
index 7d6dc3bfc..98c8b013c 100644
--- a/cmd/client/cmd/transfer.go
+++ b/cmd/client/cmd/transfer.go
@@ -100,19 +100,20 @@ func readKeys(file string) (string, error) {
 	return string(buf), nil
 }
 
-func readAddress(keypath string) (string, error) {
-	return readKeys(filepath.Join(keypath, "address"))
+// TODO: remove redundant caller
+func readAddress(path string) (string, error) {
+	return readKeys(filepath.Join(path, FileAddress))
 }
 
-func readPublicKey(keypath string) (string, error) {
-	return readKeys(filepath.Join(keypath, "public.key"))
+func readPublicKey(path string) (string, error) {
+	return readKeys(filepath.Join(path, FilePublicKey))
 }
 
-func readPrivateKey(keypath string) (string, error) {
-	return readKeys(filepath.Join(keypath, "private.key"))
+func readPrivateKey(path string) (string, error) {
+	return readKeys(filepath.Join(path, FilePrivateKey))
 }
 
-type invokeRequestWraper struct {
+type invokeRequestWrapper struct {
 	pb.InvokeRequest
 	// 取巧的手段来shadow pb.InvokeRequest里面的Args字段
 	Args map[string]string `json:"args,omitempty"`
diff --git a/cmd/client/cmd/utxo_merge.go b/cmd/client/cmd/utxo_merge.go
index aa0608093..4f1ce0189 100644
--- a/cmd/client/cmd/utxo_merge.go
+++ b/cmd/client/cmd/utxo_merge.go
@@ -9,12 +9,12 @@ import (
 	"time"
 
 	"github.com/spf13/cobra"
+	"github.com/xuperchain/xupercore/bcs/ledger/xledger/state/utxo"
+	"github.com/xuperchain/xupercore/lib/utils"
 
 	"github.com/xuperchain/xuperchain/service/common"
 	"github.com/xuperchain/xuperchain/service/pb"
-	"github.com/xuperchain/xupercore/bcs/ledger/xledger/state/utxo"
 	aclUtils "github.com/xuperchain/xupercore/kernel/permission/acl/utils"
-	"github.com/xuperchain/xupercore/lib/utils"
 )
 
 // MergeUtxoCommand necessary parameter for merge utxo
@@ -23,7 +23,7 @@ type MergeUtxoCommand struct {
 	cmd *cobra.Command
 	// account will be merged
 	account string
-	// white merge an contract account, it can not be null
+	// white merge a contract account, it can not be null
 	accountPath string
 }
 
@@ -48,8 +48,8 @@ func (c *MergeUtxoCommand) addFlags() {
 	c.cmd.Flags().StringVarP(&c.accountPath, "accountPath", "P", "", "The account path, which is required for an account.")
 }
 
-func (c *MergeUtxoCommand) mergeUtxo(ctx context.Context) error {
-	if aclUtils.IsAccount(c.account) == 1 && c.accountPath == "" {
+func (c *MergeUtxoCommand) mergeUtxo(_ context.Context) error {
+	if aclUtils.IsAccount(c.account) && c.accountPath == "" {
 		return errors.New("accountPath can not be null because account is an Account name")
 	}
 
@@ -89,9 +89,9 @@ func (c *MergeUtxoCommand) mergeUtxo(ctx context.Context) error {
 	txOutputs = append(txOutputs, txOutput)
 	tx.TxOutputs = txOutputs
 
-	tx.AuthRequire, err = genAuthRequire(c.account, c.accountPath)
+	tx.AuthRequire, err = genAuthRequirement(c.account, c.accountPath)
 	if err != nil {
-		return errors.New("genAuthRequire error")
+		return fmt.Errorf("genAuthRequirement error: %s", err)
 	}
 
 	// preExe
@@ -112,25 +112,25 @@ func (c *MergeUtxoCommand) mergeUtxo(ctx context.Context) error {
 	tx.TxInputsExt = preExeRes.GetResponse().GetInputs()
 	tx.TxOutputsExt = preExeRes.GetResponse().GetOutputs()
 
-	tx.InitiatorSigns, err = ct.genInitSign(tx)
+	tx.InitiatorSigns, err = ct.signTxForInitiator(tx)
 	if err != nil {
 		return err
 	}
-	tx.AuthRequireSigns, err = ct.genAuthRequireSignsFromPath(tx, c.accountPath)
+	tx.AuthRequireSigns, err = ct.signTx(tx, c.accountPath)
 	if err != nil {
 		return err
 	}
 
-	// calculate txid
+	// calculate tx ID
 	tx.Txid, err = common.MakeTxId(tx)
 	if err != nil {
 		return err
 	}
-	txid, err := ct.postTx(context.Background(), tx)
+	txID, err := ct.postTx(context.Background(), tx)
 	if err != nil {
 		return err
 	}
-	fmt.Println(txid)
+	fmt.Println(txID)
 
 	return nil
 }
diff --git a/cmd/client/cmd/utxo_split.go b/cmd/client/cmd/utxo_split.go
index d9de5d246..9f319a027 100644
--- a/cmd/client/cmd/utxo_split.go
+++ b/cmd/client/cmd/utxo_split.go
@@ -10,22 +10,22 @@ import (
 	"time"
 
 	"github.com/spf13/cobra"
+	"github.com/xuperchain/xupercore/bcs/ledger/xledger/state/utxo"
+	"github.com/xuperchain/xupercore/lib/utils"
 
 	"github.com/xuperchain/xuperchain/service/common"
 	"github.com/xuperchain/xuperchain/service/pb"
-	"github.com/xuperchain/xupercore/bcs/ledger/xledger/state/utxo"
 	aclUtils "github.com/xuperchain/xupercore/kernel/permission/acl/utils"
-	"github.com/xuperchain/xupercore/lib/utils"
 )
 
 // SplitUtxoCommand split utxo of ak or account
 type SplitUtxoCommand struct {
 	cli *Cli
 	cmd *cobra.Command
-	// account will be splited
+	// account will be split
 	account string
 	num     int64
-	// while spliting a Account, it can not be null
+	// while splitting an account, it can not be null
 	accountPath string
 	isGenRawTx  bool
 	multiAddrs  string
@@ -49,7 +49,7 @@ func NewSplitUtxoCommand(cli *Cli) *cobra.Command {
 }
 
 func (c *SplitUtxoCommand) addFlags() {
-	c.cmd.Flags().StringVarP(&c.account, "account", "A", "", "The account/address to be splited (default ./data/keys/address).")
+	c.cmd.Flags().StringVarP(&c.account, "account", "A", "", "The account/address to be split (default ./data/keys/address).")
 	c.cmd.Flags().Int64VarP(&c.num, "num", "N", 1, "The number to split.")
 	c.cmd.Flags().StringVarP(&c.accountPath, "accountPath", "P", "", "The account path, which is required for an account.")
 	c.cmd.Flags().BoolVarP(&c.isGenRawTx, "raw", "m", false, "Is only generate raw tx output.")
@@ -57,21 +57,18 @@ func (c *SplitUtxoCommand) addFlags() {
 	c.cmd.Flags().StringVarP(&c.multiAddrs, "multiAddrs", "M", "data/acl/addrs", "MultiAddrs to fill required accounts/addresses.")
 }
 
-func (c *SplitUtxoCommand) splitUtxo(ctx context.Context) error {
+func (c *SplitUtxoCommand) splitUtxo(_ context.Context) error {
 	if c.num <= 0 {
-		return errors.New("illegal splitutxo num, num > 0 required")
-	}
-	if aclUtils.IsAccount(c.account) == 0 && c.accountPath == "" {
-		return errors.New("accountPath can not be null because account is an Account name")
+		return errors.New("illegal split utxo num, num > 0 required")
 	}
 
-	initAk, err := readAddress(c.cli.RootOptions.Keys)
-	if c.account == "" {
-		c.account = initAk
+	initiator, err := readAddress(c.cli.RootOptions.Keys)
+	if err != nil {
+		return fmt.Errorf("read init AK error: %s", err)
 	}
 
-	if aclUtils.IsAccount(c.account) == 1 && c.account != initAk {
-		return errors.New("parse account error")
+	if err := c.SetUpAccount(initiator); err != nil {
+		return err
 	}
 
 	tx := &pb.Transaction{
@@ -79,7 +76,7 @@ func (c *SplitUtxoCommand) splitUtxo(ctx context.Context) error {
 		Coinbase:  false,
 		Nonce:     utils.GenNonce(),
 		Timestamp: time.Now().UnixNano(),
-		Initiator: initAk,
+		Initiator: initiator,
 	}
 
 	amount, err := c.getBalanceHelper()
@@ -126,9 +123,9 @@ func (c *SplitUtxoCommand) splitUtxo(ctx context.Context) error {
 		}
 		tx.AuthRequire = multiAddrs
 	} else {
-		tx.AuthRequire, err = genAuthRequire(c.account, c.accountPath)
+		tx.AuthRequire, err = genAuthRequirement(c.account, c.accountPath)
 		if err != nil {
-			return errors.New("genAuthRequire error")
+			return errors.New("genAuthRequirement error")
 		}
 	}
 
@@ -139,7 +136,7 @@ func (c *SplitUtxoCommand) splitUtxo(ctx context.Context) error {
 		Header: &pb.Header{
 			Logid: utils.GenLogId(),
 		},
-		Initiator:   initAk,
+		Initiator:   initiator,
 		AuthRequire: tx.AuthRequire,
 	}
 	preExeRes, err := ct.XchainClient.PreExec(context.Background(), preExeRPCReq)
@@ -154,25 +151,49 @@ func (c *SplitUtxoCommand) splitUtxo(ctx context.Context) error {
 		return ct.GenTxFile(tx)
 	}
 
-	tx.InitiatorSigns, err = ct.genInitSign(tx)
+	tx.InitiatorSigns, err = ct.signTxForInitiator(tx)
 	if err != nil {
 		return err
 	}
-	tx.AuthRequireSigns, err = ct.genAuthRequireSignsFromPath(tx, c.accountPath)
+	tx.AuthRequireSigns, err = ct.signTx(tx, c.accountPath)
 	if err != nil {
 		return err
 	}
 
-	// calculate txid
+	// calculate tx ID
 	tx.Txid, err = common.MakeTxId(tx)
 	if err != nil {
 		return err
 	}
-	txid, err := ct.postTx(context.Background(), tx)
-	fmt.Println(txid)
+	txID, err := ct.postTx(context.Background(), tx)
+	fmt.Println(txID)
 	return err
 }
 
+// SetUpAccount will set up a valid account as one of below:
+// 1. account
+// 2. initiator AK (default value)
+func (c *SplitUtxoCommand) SetUpAccount(initiator string) error {
+	// set default value
+	if c.account == "" {
+		c.account = initiator
+	}
+
+	t, isValid := aclUtils.ParseAddressType(c.account)
+	if !isValid {
+		return errors.New("empty account")
+	}
+
+	if t == aclUtils.AddressAccount && c.accountPath == "" {
+		return errors.New("accountPath can not be null because account is an Account name")
+	}
+
+	if t == aclUtils.AddressAK && c.account != initiator {
+		return errors.New("parse account error")
+	}
+	return nil
+}
+
 func (c *SplitUtxoCommand) getBalanceHelper() (string, error) {
 	as := &pb.AddressStatus{}
 	as.Address = c.account
@@ -187,12 +208,12 @@ func (c *SplitUtxoCommand) getBalanceHelper() (string, error) {
 	return r.Bcs[0].Balance, nil
 }
 
-func (c *SplitUtxoCommand) genSplitOutputs(toralNeed *big.Int) ([]*pb.TxOutput, error) {
+func (c *SplitUtxoCommand) genSplitOutputs(totalNeed *big.Int) ([]*pb.TxOutput, error) {
 	txOutputs := []*pb.TxOutput{}
 	amount := big.NewInt(0)
-	rest := toralNeed
+	rest := totalNeed
 	if big.NewInt(c.num).Cmp(rest) == 1 {
-		return nil, errors.New("illegal splitutxo, splitutxo <= BALANCE required")
+		return nil, errors.New("illegal split utxo, split utxo <= BALANCE required")
 	}
 	amount.Div(rest, big.NewInt(c.num))
 	output := pb.TxOutput{}
diff --git a/go.mod b/go.mod
index c03736087..d154199bb 100644
--- a/go.mod
+++ b/go.mod
@@ -14,7 +14,7 @@ require (
 	github.com/spf13/cobra v1.0.0
 	github.com/spf13/viper v1.6.2
 	github.com/xuperchain/crypto v0.0.0-20211221122406-302ac826ac90
-	github.com/xuperchain/xupercore v0.0.0-20221124025709-7591a38f52dc
+	github.com/xuperchain/xupercore v0.0.0-20221206131501-5a3396e9215d
 	google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013
 	google.golang.org/grpc v1.35.0
 )
diff --git a/go.sum b/go.sum
index dd7552222..dc7029c8c 100644
--- a/go.sum
+++ b/go.sum
@@ -838,8 +838,8 @@ github.com/xuperchain/log15 v0.0.0-20190620081506-bc88a9198230 h1:AWFZFbmLhY6VG6
 github.com/xuperchain/log15 v0.0.0-20190620081506-bc88a9198230/go.mod h1:90Da9GDXy9Yle79ZHSJY1c7X+1meBKsoX0vkRy09xis=
 github.com/xuperchain/wagon v0.6.1-0.20200313164333-db544e251599 h1:xh8MpzUZFmNOpeJyiiBCYOJq7gq7nRBU647y6e78Qms=
 github.com/xuperchain/wagon v0.6.1-0.20200313164333-db544e251599/go.mod h1:PjShksGcTLuvtHxudQ7nOdlvlw2NdbZrTn8jvdY9Mkw=
-github.com/xuperchain/xupercore v0.0.0-20221124025709-7591a38f52dc h1:ioMI9WSnnoiEb//AeWig005lhkANVGR1CsB/5DN+dS4=
-github.com/xuperchain/xupercore v0.0.0-20221124025709-7591a38f52dc/go.mod h1:oLWrACfaVNzwyo3J56RzTJqXojgsUPNamrJhKZjTq0A=
+github.com/xuperchain/xupercore v0.0.0-20221206131501-5a3396e9215d h1:vrpSnYXWNex6c3wCMPaXKwFG1iBRUMEwLwb3SdkGaCI=
+github.com/xuperchain/xupercore v0.0.0-20221206131501-5a3396e9215d/go.mod h1:oLWrACfaVNzwyo3J56RzTJqXojgsUPNamrJhKZjTq0A=
 github.com/xuperchain/xvm v0.0.0-20210126142521-68fd016c56d7 h1:ARg101vOoX4N+6hbwtud6b0P/bb+7JtrCfVXAHa/xHU=
 github.com/xuperchain/xvm v0.0.0-20210126142521-68fd016c56d7/go.mod h1:XTaJSLDGYlcAPFb5vWH4vVALckO3V5+wa4zl1mpKMjg=
 github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
diff --git a/models/chain_handle.go b/models/chain_handle.go
index e06f70d8e..c74d8f1d8 100644
--- a/models/chain_handle.go
+++ b/models/chain_handle.go
@@ -5,33 +5,33 @@ import (
 	"strconv"
 
 	lpb "github.com/xuperchain/xupercore/bcs/ledger/xledger/xldgpb"
-	xctx "github.com/xuperchain/xupercore/kernel/common/xcontext"
-	ecom "github.com/xuperchain/xupercore/kernel/engines/xuperos/common"
+	xCtx "github.com/xuperchain/xupercore/kernel/common/xcontext"
+	"github.com/xuperchain/xupercore/kernel/engines/xuperos/common"
 	"github.com/xuperchain/xupercore/kernel/engines/xuperos/reader"
 	"github.com/xuperchain/xupercore/kernel/engines/xuperos/xpb"
-	aclUtils "github.com/xuperchain/xupercore/kernel/permission/acl/utils"
-	cryptoHash "github.com/xuperchain/xupercore/lib/crypto/hash"
 	"github.com/xuperchain/xupercore/lib/logs"
 	"github.com/xuperchain/xupercore/protos"
 
-	sctx "github.com/xuperchain/xuperchain/service/context"
+	sCtx "github.com/xuperchain/xuperchain/service/context"
+	aclUtils "github.com/xuperchain/xupercore/kernel/permission/acl/utils"
+	cryptoHash "github.com/xuperchain/xupercore/lib/crypto/hash"
 )
 
 type ChainHandle struct {
 	bcName string
-	reqCtx sctx.ReqCtx
+	reqCtx sCtx.ReqCtx
 	log    logs.Logger
-	chain  ecom.Chain
+	chain  common.Chain
 }
 
-func NewChainHandle(bcName string, reqCtx sctx.ReqCtx) (*ChainHandle, error) {
+func NewChainHandle(bcName string, reqCtx sCtx.ReqCtx) (*ChainHandle, error) {
 	if bcName == "" || reqCtx == nil || reqCtx.GetEngine() == nil {
-		return nil, ecom.ErrParameter
+		return nil, common.ErrParameter
 	}
 
 	chain, err := reqCtx.GetEngine().Get(bcName)
 	if err != nil {
-		return nil, ecom.ErrChainNotExist
+		return nil, common.ErrChainNotExist
 	}
 
 	obj := &ChainHandle{
@@ -43,136 +43,154 @@ func NewChainHandle(bcName string, reqCtx sctx.ReqCtx) (*ChainHandle, error) {
 	return obj, nil
 }
 
-func (t *ChainHandle) SubmitTx(tx *lpb.Transaction) error {
-	return t.chain.SubmitTx(t.genXctx(), tx)
+func (h *ChainHandle) SubmitTx(tx *lpb.Transaction) error {
+	return h.chain.SubmitTx(h.ctx(), tx)
 }
 
-func (t *ChainHandle) PreExec(req []*protos.InvokeRequest,
+func (h *ChainHandle) PreExec(req []*protos.InvokeRequest,
 	initiator string, authRequires []string) (*protos.InvokeResponse, error) {
-	return t.chain.PreExec(t.genXctx(), req, initiator, authRequires)
+	return h.chain.PreExec(h.ctx(), req, initiator, authRequires)
 }
 
-func (t *ChainHandle) QueryTx(txId []byte) (*xpb.TxInfo, error) {
-	return reader.NewLedgerReader(t.chain.Context(), t.genXctx()).QueryTx(txId)
+func (h *ChainHandle) QueryTx(txId []byte) (*xpb.TxInfo, error) {
+	return h.ledgerReader().QueryTx(txId)
 }
 
-func (t *ChainHandle) SelectUtxo(account string, need *big.Int, isLock, isExclude bool,
+func (h *ChainHandle) SelectUtxo(account string, need *big.Int, isLock, isExclude bool,
 	pubKey string, sign []byte) (*lpb.UtxoOutput, error) {
 	// 如果需要临时锁定utxo，需要校验权限
-	ok := t.checkSelectUtxoSign(account, pubKey, sign, isLock, need)
+	ok := h.checkSelectUtxoSign(account, pubKey, sign, isLock, need)
 	if !ok {
-		t.reqCtx.GetLog().Warn("select utxo verify sign failed", "account", account, "isLock", isLock)
-		return nil, ecom.ErrUnauthorized
+		h.reqCtx.GetLog().Warn("select utxo verify sign failed", "account", account, "isLock", isLock)
+		return nil, common.ErrUnauthorized
 	}
 
-	return reader.NewUtxoReader(t.chain.Context(), t.genXctx()).SelectUTXO(account, need,
+	return h.utxoReader().SelectUTXO(account, need,
 		isLock, isExclude)
 }
 
-func (t *ChainHandle) SelectUTXOBySize(account string, isLock, isExclude bool,
+func (h *ChainHandle) SelectUTXOBySize(account string, isLock, isExclude bool,
 	pubKey string, sign []byte) (*lpb.UtxoOutput, error) {
 	// 如果需要临时锁定utxo，需要校验权限
-	ok := t.checkSelectUtxoSign(account, pubKey, sign, isLock, big.NewInt(0))
+	ok := h.checkSelectUtxoSign(account, pubKey, sign, isLock, big.NewInt(0))
 	if !ok {
-		t.reqCtx.GetLog().Warn("select utxo verify sign failed", "account", account, "isLock", isLock)
-		return nil, ecom.ErrUnauthorized
+		h.reqCtx.GetLog().Warn("select utxo verify sign failed", "account", account, "isLock", isLock)
+		return nil, common.ErrUnauthorized
 	}
 
-	return reader.NewUtxoReader(t.chain.Context(), t.genXctx()).SelectUTXOBySize(account,
-		isLock, isExclude)
+	return h.utxoReader().SelectUTXOBySize(account, isLock, isExclude)
+}
+
+func (h *ChainHandle) QueryContractStatData() (*protos.ContractStatData, error) {
+	return h.contractReader().QueryContractStatData()
+}
+
+func (h *ChainHandle) QueryUtxoRecord(account string, count int64) (*lpb.UtxoRecordDetail, error) {
+	return h.utxoReader().QueryUtxoRecord(account, count)
+}
+
+func (h *ChainHandle) QueryAccountACL(account string) (*protos.Acl, error) {
+	return h.contractReader().QueryAccountACL(account)
+}
+
+func (h *ChainHandle) QueryContractMethodACL(contract, method string) (*protos.Acl, error) {
+	return h.contractReader().QueryContractMethodACL(contract, method)
 }
 
-func (t *ChainHandle) QueryContractStatData() (*protos.ContractStatData, error) {
-	return reader.NewContractReader(t.chain.Context(), t.genXctx()).QueryContractStatData()
+func (h *ChainHandle) GetAccountContracts(account string) ([]*protos.ContractStatus, error) {
+	return h.contractReader().GetAccountContracts(account)
 }
 
-func (t *ChainHandle) QueryUtxoRecord(account string, count int64) (*lpb.UtxoRecordDetail, error) {
-	return reader.NewUtxoReader(t.chain.Context(), t.genXctx()).QueryUtxoRecord(account, count)
+func (h *ChainHandle) GetBalance(account string) (string, error) {
+	return h.utxoReader().GetBalance(account)
 }
 
-func (t *ChainHandle) QueryAccountACL(account string) (*protos.Acl, error) {
-	return reader.NewContractReader(t.chain.Context(), t.genXctx()).QueryAccountACL(account)
+func (h *ChainHandle) GetFrozenBalance(account string) (string, error) {
+	return h.utxoReader().GetFrozenBalance(account)
 }
 
-func (t *ChainHandle) QueryContractMethodACL(contract, method string) (*protos.Acl, error) {
-	return reader.NewContractReader(t.chain.Context(),
-		t.genXctx()).QueryContractMethodACL(contract, method)
+func (h *ChainHandle) GetBalanceDetail(account string) ([]*lpb.BalanceDetailInfo, error) {
+	return h.utxoReader().GetBalanceDetail(account)
 }
 
-func (t *ChainHandle) GetAccountContracts(account string) ([]*protos.ContractStatus, error) {
-	return reader.NewContractReader(t.chain.Context(),
-		t.genXctx()).GetAccountContracts(account)
+func (h *ChainHandle) QueryBlock(blkId []byte, needContent bool) (*xpb.BlockInfo, error) {
+	return h.ledgerReader().QueryBlock(blkId, needContent)
 }
 
-func (t *ChainHandle) GetBalance(account string) (string, error) {
-	return reader.NewUtxoReader(t.chain.Context(), t.genXctx()).GetBalance(account)
+func (h *ChainHandle) QueryChainStatus() (*xpb.ChainStatus, error) {
+	return h.chainReader().GetChainStatus()
 }
 
-func (t *ChainHandle) GetFrozenBalance(account string) (string, error) {
-	return reader.NewUtxoReader(t.chain.Context(), t.genXctx()).GetFrozenBalance(account)
+func (h *ChainHandle) QueryConsensusStatus() (*xpb.ConsensusStatus, error) {
+	return h.chainReader().GetConsensusStatus()
 }
 
-func (t *ChainHandle) GetBalanceDetail(account string) ([]*lpb.BalanceDetailInfo, error) {
-	return reader.NewUtxoReader(t.chain.Context(), t.genXctx()).GetBalanceDetail(account)
+func (h *ChainHandle) IsTrunkTipBlock(blockId []byte) (bool, error) {
+	return h.chainReader().IsTrunkTipBlock(blockId)
 }
 
-func (t *ChainHandle) QueryBlock(blkId []byte, needContent bool) (*xpb.BlockInfo, error) {
-	return reader.NewLedgerReader(t.chain.Context(), t.genXctx()).QueryBlock(blkId, needContent)
+func (h *ChainHandle) QueryBlockByHeight(height int64, needContent bool) (*xpb.BlockInfo, error) {
+	return h.ledgerReader().QueryBlockByHeight(height, needContent)
 }
 
-func (t *ChainHandle) QueryChainStatus() (*xpb.ChainStatus, error) {
-	return reader.NewChainReader(t.chain.Context(), t.genXctx()).GetChainStatus()
+func (h *ChainHandle) GetAccountByAK(address string) ([]string, error) {
+	return h.contractReader().GetAccountByAK(address)
 }
 
-func (t *ChainHandle) QueryConsensusStatus() (*xpb.ConsensusStatus, error) {
-	return reader.NewChainReader(t.chain.Context(), t.genXctx()).GetConsensusStatus()
+// Helper functions
+
+// contractReader generate a new contract reader
+func (h *ChainHandle) contractReader() reader.ContractReader {
+	return reader.NewContractReader(h.chain.Context(), h.ctx())
 }
 
-func (t *ChainHandle) IsTrunkTipBlock(blockId []byte) (bool, error) {
-	return reader.NewChainReader(t.chain.Context(), t.genXctx()).IsTrunkTipBlock(blockId)
+// ledgerReader generate a new ledger reader
+func (h *ChainHandle) ledgerReader() reader.LedgerReader {
+	return reader.NewLedgerReader(h.chain.Context(), h.ctx())
 }
 
-func (t *ChainHandle) QueryBlockByHeight(height int64, needContent bool) (*xpb.BlockInfo, error) {
-	return reader.NewLedgerReader(t.chain.Context(), t.genXctx()).QueryBlockByHeight(height, needContent)
+// chainReader generate a new chain reader
+func (h *ChainHandle) chainReader() reader.ChainReader {
+	return reader.NewChainReader(h.chain.Context(), h.ctx())
 }
 
-func (t *ChainHandle) GetAccountByAK(address string) ([]string, error) {
-	return reader.NewContractReader(t.chain.Context(), t.genXctx()).GetAccountByAK(address)
+// utxoReader generate a new UTXO reader
+func (h *ChainHandle) utxoReader() reader.UtxoReader {
+	return reader.NewUtxoReader(h.chain.Context(), h.ctx())
 }
 
-func (t *ChainHandle) genXctx() xctx.XContext {
-	return &xctx.BaseCtx{
-		XLog:  t.reqCtx.GetLog(),
-		Timer: t.reqCtx.GetTimer(),
+func (h *ChainHandle) ctx() xCtx.XContext {
+	return &xCtx.BaseCtx{
+		XLog:  h.reqCtx.GetLog(),
+		Timer: h.reqCtx.GetTimer(),
 	}
 }
 
-func (t *ChainHandle) checkSelectUtxoSign(account, pubKey string, sign []byte,
+func (h *ChainHandle) checkSelectUtxoSign(account, pubKey string, sign []byte,
 	isLock bool, need *big.Int) bool {
 	// 只对需要临时锁定utxo的校验
-	if aclUtils.IsAccount(account) == 1 || !isLock {
+	if aclUtils.IsAccount(account) || !isLock {
 		return true
 	}
 
-	crypto := t.chain.Context().Crypto
+	crypto := h.chain.Context().Crypto
 	publicKey, err := crypto.GetEcdsaPublicKeyFromJsonStr(pubKey)
 	if err != nil {
 		return false
 	}
+	hashKey := h.bcName + account + need.String() + strconv.FormatBool(isLock)
+	hashValue := cryptoHash.DoubleSha256([]byte(hashKey))
 
-	hashStr := t.bcName + account + need.String() + strconv.FormatBool(isLock)
-	doubleHash := cryptoHash.DoubleSha256([]byte(hashStr))
-	checkSignResult, err := crypto.VerifyECDSA(publicKey, sign, doubleHash)
+	// verify sign
+	passed, err := crypto.VerifyECDSA(publicKey, sign, hashValue)
 	if err != nil {
 		return false
 	}
-	if checkSignResult != true {
-		return false
-	}
-	addrMatchCheckResult, _ := crypto.VerifyAddressUsingPublicKey(account, publicKey)
-	if addrMatchCheckResult != true {
+	if !passed {
 		return false
 	}
 
-	return true
+	// verify account
+	matched, _ := crypto.VerifyAddressUsingPublicKey(account, publicKey)
+	return matched
 }


Test patch:
diff --git a/cmd/client/cmd/ak_test.go b/cmd/client/cmd/ak_test.go
new file mode 100644
index 000000000..4b3cf225b
--- /dev/null
+++ b/cmd/client/cmd/ak_test.go
@@ -0,0 +1,549 @@
+/*
+ * Copyright (c) 2022. Baidu Inc. All Rights Reserved.
+ */
+
+package cmd
+
+import (
+	"crypto/ecdsa"
+	"errors"
+	"math/big"
+	"path/filepath"
+	"reflect"
+	"testing"
+
+	"github.com/xuperchain/crypto/common/account"
+	"github.com/xuperchain/xuperchain/service/pb"
+)
+
+// test data path
+var (
+	testDataDir  = "test_data"
+	validAKDir   = filepath.Join(testDataDir, "valid-ak")
+	invalidAKDir = filepath.Join(testDataDir, "invalid-ak")
+)
+
+// test data
+var (
+	testAccount = "XC1111111111111111@xuper"
+
+	testPublicKey  = `{"Curvname":"P-256","X":36505150171354363400464126431978257855318414556425194490762274938603757905292,"Y":79656876957602994269528255245092635964473154458596947290316223079846501380076}`
+	testPrivateKey = `{"Curvname":"P-256","X":36505150171354363400464126431978257855318414556425194490762274938603757905292,"Y":79656876957602994269528255245092635964473154458596947290316223079846501380076,"D":111497060296999106528800133634901141644446751975433315540300236500052690483486}`
+
+	mockSign = []byte("mockSign")
+
+	secretKeySucc                             = testPrivateKey
+	secretKeyGetEcdsaPrivateKeyFromJsonStrErr = "GetEcdsaPrivateKeyFromJsonStrErr"
+	secretKeySignECDSAErr                     = "SignECDSAErr"
+
+	ecdsaPrivateKeySignECDSAErr = new(ecdsa.PrivateKey)
+)
+
+func Test_listAKs(t *testing.T) {
+	tests := []struct {
+		name    string
+		root    string
+		want    []AK
+		wantErr bool
+	}{
+		{
+			name: "normal",
+			root: validAKDir,
+			want: []AK{
+				newAK(filepath.Join(validAKDir, "keys")),
+			},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			got, err := listAKs(tt.root)
+			if (err != nil) != tt.wantErr {
+				t.Errorf("listAKs() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+			if !reflect.DeepEqual(got, tt.want) {
+				t.Errorf("listAKs() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func TestAK_IsAKDir(t *testing.T) {
+	tests := []struct {
+		name string
+		path string
+		want bool
+	}{
+		{
+			name: "AK dir",
+			path: filepath.Join(validAKDir, "keys"),
+			want: true,
+		},
+		{
+			name: "not AK dir",
+			path: filepath.Join(validAKDir, "not-ak-dir"),
+			want: false,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			ak := AK{
+				path: tt.path,
+			}
+			if got := ak.IsAKDir(); got != tt.want {
+				t.Errorf("AK.IsAKDir() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func TestAK_AuthRequirementFrom(t *testing.T) {
+	type fields struct {
+		path string
+	}
+	tests := []struct {
+		name    string
+		fields  fields
+		want    string
+		wantErr bool
+	}{
+		{
+			name:   "valid AK",
+			fields: fields{path: filepath.Join(validAKDir, "keys")},
+			want:   "XC1111111111111111@xuper/TeyyPLpp9L7QAcxHangtcHTu7HUZ6iydY",
+		},
+		{
+			name:    "invalid AK",
+			fields:  fields{path: filepath.Join(validAKDir, "not-ak-dir")},
+			wantErr: true,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			ak := &AK{
+				path: tt.fields.path,
+			}
+			got, err := ak.AuthRequirementFrom(testAccount)
+			if (err != nil) != tt.wantErr {
+				t.Errorf("AK.AuthRequirementFrom() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+			if got != tt.want {
+				t.Errorf("AK.AuthRequirementFrom() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func TestAK_Info(t *testing.T) {
+	type fields struct {
+		path string
+	}
+	tests := []struct {
+		name     string
+		fields   fields
+		wantInfo AKInfo
+		wantErr  bool
+	}{
+		{
+			name:   "valid AK",
+			fields: fields{path: filepath.Join(validAKDir, "keys")},
+			wantInfo: AKInfo{
+				address: "TeyyPLpp9L7QAcxHangtcHTu7HUZ6iydY",
+				KeyPair: KeyPair{
+					publicKey: testPublicKey,
+					secretKey: testPrivateKey,
+				},
+			},
+		},
+		{
+			name:    "AK without address",
+			fields:  fields{path: filepath.Join(invalidAKDir, "no-address")},
+			wantErr: true,
+		},
+		{
+			name:    "AK without key",
+			fields:  fields{path: filepath.Join(invalidAKDir, "no-public-key")},
+			wantErr: true,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			ak := &AK{
+				path: tt.fields.path,
+			}
+			gotInfo, err := ak.Info()
+			if (err != nil) != tt.wantErr {
+				t.Errorf("AK.Info() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+			if !reflect.DeepEqual(gotInfo, tt.wantInfo) {
+				t.Errorf("AK.Info() = %v, \n want %v", gotInfo, tt.wantInfo)
+			}
+		})
+	}
+}
+
+func TestAK_keyPair(t *testing.T) {
+	type fields struct {
+		path string
+	}
+	tests := []struct {
+		name    string
+		fields  fields
+		want    KeyPair
+		wantErr bool
+	}{
+		{
+			name:   "valid key pair",
+			fields: fields{path: filepath.Join(validAKDir, "keys")},
+			want: KeyPair{
+				publicKey: testPublicKey,
+				secretKey: testPrivateKey,
+			},
+		},
+		{
+			name:    "no public key",
+			fields:  fields{path: filepath.Join(invalidAKDir, "no-public-key")},
+			wantErr: true,
+		},
+		{
+			name:    "no secret key",
+			fields:  fields{path: filepath.Join(invalidAKDir, "no-private-key")},
+			wantErr: true,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			ak := &AK{
+				path: tt.fields.path,
+			}
+			got, err := ak.keyPair()
+			if (err != nil) != tt.wantErr {
+				t.Errorf("AK.keyPair() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+			if !reflect.DeepEqual(got, tt.want) {
+				t.Errorf("AK.keyPair() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func TestAK_SignTx(t *testing.T) {
+	type fields struct {
+		path string
+	}
+	type args struct {
+		tx *pb.Transaction
+	}
+	tx := new(pb.Transaction)
+	tests := []struct {
+		name    string
+		fields  fields
+		args    args
+		want    *pb.SignatureInfo
+		wantErr bool
+	}{
+
+		{
+			name:   "valid AK",
+			fields: fields{path: filepath.Join(validAKDir, "keys")},
+			args:   args{tx: tx},
+			want: &pb.SignatureInfo{
+				PublicKey: testPublicKey,
+				Sign:      mockSign,
+			},
+		},
+		{
+			name:    "AK without key",
+			args:    args{tx: tx},
+			fields:  fields{path: filepath.Join(invalidAKDir, "no-public-key")},
+			wantErr: true,
+		},
+		{
+			name:    "key pair sign fail",
+			args:    args{tx: nil},
+			fields:  fields{path: filepath.Join(validAKDir, "keys")},
+			wantErr: true,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			ak := &AK{
+				path: tt.fields.path,
+			}
+			got, err := ak.SignTx(tt.args.tx, mockCryptoClient{})
+			if (err != nil) != tt.wantErr {
+				t.Errorf("AK.SignTx() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+			if !reflect.DeepEqual(got, tt.want) {
+				t.Errorf("AK.SignTx() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+// TODO: mock common.ComputeTxSign after unit test covers
+func TestKeyPair_SignTx(t *testing.T) {
+	type fields struct {
+		publicKey string
+		secretKey string
+	}
+	type args struct {
+		tx *pb.Transaction
+	}
+	tests := []struct {
+		name    string
+		fields  fields
+		args    args
+		want    *pb.SignatureInfo
+		wantErr bool
+	}{
+		{
+			name:   "tx is normal",
+			fields: fields{secretKey: secretKeySucc},
+			args:   args{tx: new(pb.Transaction)},
+			want: &pb.SignatureInfo{
+				PublicKey: testPublicKey,
+				Sign:      mockSign,
+			},
+		},
+		{
+			name:    "tx is nil",
+			fields:  fields{secretKey: secretKeySucc},
+			args:    args{tx: nil},
+			wantErr: true,
+		},
+		{
+			name:    "GetEcdsaPrivateKeyFromJsonStr() fail",
+			fields:  fields{secretKey: secretKeyGetEcdsaPrivateKeyFromJsonStrErr},
+			args:    args{tx: new(pb.Transaction)},
+			wantErr: true,
+		},
+		{
+			name:    "SignECDSA() fail",
+			fields:  fields{secretKey: secretKeySignECDSAErr},
+			args:    args{tx: new(pb.Transaction)},
+			wantErr: true,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			p := &KeyPair{
+				publicKey: testPublicKey,
+				secretKey: tt.fields.secretKey,
+			}
+			got, err := p.SignTx(tt.args.tx, mockCryptoClient{})
+			if (err != nil) != tt.wantErr {
+				t.Errorf("KeyPair.SignTx() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+			if !reflect.DeepEqual(got, tt.want) {
+				t.Errorf("KeyPair.SignTx() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func TestKeyPair_SignUtxo(t *testing.T) {
+	type fields struct {
+		publicKey string
+		secretKey string
+	}
+	tests := []struct {
+		name    string
+		fields  fields
+		want    pb.SignatureInfo
+		wantErr bool
+	}{
+		{
+			name:   "normal",
+			fields: fields{secretKey: secretKeySucc},
+			want: pb.SignatureInfo{
+				PublicKey: testPublicKey,
+				Sign:      mockSign,
+			},
+		},
+		{
+			name:    "GetEcdsaPrivateKeyFromJsonStr() fail",
+			fields:  fields{secretKey: secretKeyGetEcdsaPrivateKeyFromJsonStrErr},
+			wantErr: true,
+		},
+		{
+			name:    "SignECDSA() fail",
+			fields:  fields{secretKey: secretKeySignECDSAErr},
+			wantErr: true,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			p := &KeyPair{
+				publicKey: testPublicKey,
+				secretKey: tt.fields.secretKey,
+			}
+			got, err := p.SignUtxo("xuper", testAccount, big.NewInt(1), mockCryptoClient{})
+			if (err != nil) != tt.wantErr {
+				t.Errorf("KeyPair.SignUtxo() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+			if !reflect.DeepEqual(got, tt.want) {
+				t.Errorf("KeyPair.SignUtxo() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+type mockCryptoClient struct {
+}
+
+func (m mockCryptoClient) GenerateKeyBySeed(_ []byte) (*ecdsa.PrivateKey, error) {
+	panic("implement me")
+}
+
+func (m mockCryptoClient) SignECDSA(key *ecdsa.PrivateKey, _ []byte) (signature []byte, err error) {
+	if key == ecdsaPrivateKeySignECDSAErr {
+		return nil, errors.New("SignECDSAErr")
+	}
+	return mockSign, nil
+}
+
+func (m mockCryptoClient) VerifyECDSA(_ *ecdsa.PublicKey, _, _ []byte) (valid bool, err error) {
+	panic("implement me")
+}
+
+func (m mockCryptoClient) VerifyXuperSignature(_ []*ecdsa.PublicKey, _ []byte, _ []byte) (valid bool, err error) {
+	panic("implement me")
+}
+
+func (m mockCryptoClient) EncryptByEcdsaKey(_ *ecdsa.PublicKey, _ []byte) (cypherText []byte, err error) {
+	panic("implement me")
+}
+
+func (m mockCryptoClient) DecryptByEcdsaKey(_ *ecdsa.PrivateKey, _ []byte) (msg []byte, err error) {
+	panic("implement me")
+}
+
+func (m mockCryptoClient) GetAddressFromPublicKey(_ *ecdsa.PublicKey) (string, error) {
+	panic("implement me")
+}
+
+func (m mockCryptoClient) CheckAddressFormat(_ string) (bool, uint8) {
+	panic("implement me")
+}
+
+func (m mockCryptoClient) VerifyAddressUsingPublicKey(_ string, _ *ecdsa.PublicKey) (bool, uint8) {
+	panic("implement me")
+}
+
+func (m mockCryptoClient) GetBinaryEcdsaPrivateKeyFromFile(_ string, _ string) ([]byte, error) {
+	panic("implement me")
+}
+
+func (m mockCryptoClient) GetEcdsaPrivateKeyFromFile(_ string) (*ecdsa.PrivateKey, error) {
+	panic("implement me")
+}
+
+func (m mockCryptoClient) GetEcdsaPrivateKeyFromFileByPassword(_ string, _ string) (*ecdsa.PrivateKey, error) {
+	panic("implement me")
+}
+
+func (m mockCryptoClient) GetEcdsaPublicKeyFromFile(_ string) (*ecdsa.PublicKey, error) {
+	panic("implement me")
+}
+
+func (m mockCryptoClient) GenerateEntropy(_ int) ([]byte, error) {
+	panic("implement me")
+}
+
+func (m mockCryptoClient) GetEcdsaPrivateKeyFromJsonStr(secretKey string) (*ecdsa.PrivateKey, error) {
+	switch secretKey {
+	case secretKeyGetEcdsaPrivateKeyFromJsonStrErr:
+		return nil, errors.New("GetEcdsaPrivateKeyFromJsonStrErr")
+	case secretKeySignECDSAErr:
+		return ecdsaPrivateKeySignECDSAErr, nil
+	default:
+		return nil, nil
+	}
+}
+
+func (m mockCryptoClient) GetEcdsaPublicKeyFromJsonStr(_ string) (*ecdsa.PublicKey, error) {
+	panic("implement me")
+}
+
+func (m mockCryptoClient) GetEcdsaPrivateKeyJsonFormatStr(_ *ecdsa.PrivateKey) (string, error) {
+	panic("implement me")
+}
+
+func (m mockCryptoClient) GetEcdsaPublicKeyJsonFormatStr(_ *ecdsa.PrivateKey) (string, error) {
+	panic("implement me")
+}
+
+func (m mockCryptoClient) ExportNewAccount(_ string) error {
+	panic("implement me")
+}
+
+func (m mockCryptoClient) CreateNewAccountWithMnemonic(_ int, _ uint8) (*account.ECDSAAccount, error) {
+	panic("implement me")
+}
+
+func (m mockCryptoClient) ExportNewAccountWithMnemonic(_ string, _ int, _ uint8) error {
+	panic("implement me")
+}
+
+func (m mockCryptoClient) RetrieveAccountByMnemonic(_ string, _ int) (*account.ECDSAAccount, error) {
+	panic("implement me")
+}
+
+func (m mockCryptoClient) RetrieveAccountByMnemonicAndSavePrivKey(_ string, _ int, _ string, _ string) (*account.ECDSAInfo, error) {
+	panic("implement me")
+}
+
+func (m mockCryptoClient) EncryptAccount(_ *account.ECDSAAccount, _ string) (*account.ECDSAAccountToCloud, error) {
+	panic("implement me")
+}
+
+func (m mockCryptoClient) GenerateMnemonic(_ []byte, _ int) (string, error) {
+	panic("implement me")
+}
+
+func (m mockCryptoClient) GenerateSeedWithErrorChecking(_ string, _ string, _ int, _ int) ([]byte, error) {
+	panic("implement me")
+}
+
+func (m mockCryptoClient) GetRandom32Bytes() ([]byte, error) {
+	panic("implement me")
+}
+
+func (m mockCryptoClient) GetRiUsingRandomBytes(_ *ecdsa.PublicKey, _ []byte) []byte {
+	panic("implement me")
+}
+
+func (m mockCryptoClient) GetRUsingAllRi(_ *ecdsa.PublicKey, _ [][]byte) []byte {
+	panic("implement me")
+}
+
+func (m mockCryptoClient) GetSharedPublicKeyForPublicKeys(_ []*ecdsa.PublicKey) ([]byte, error) {
+	panic("implement me")
+}
+
+func (m mockCryptoClient) GetSiUsingKCRM(_ *ecdsa.PrivateKey, _ []byte, _ []byte, _ []byte, _ []byte) []byte {
+	panic("implement me")
+}
+
+func (m mockCryptoClient) GetSUsingAllSi(_ [][]byte) []byte {
+	panic("implement me")
+}
+
+func (m mockCryptoClient) GenerateMultiSignSignature(_ []byte, _ []byte) ([]byte, error) {
+	panic("implement me")
+}
+
+func (m mockCryptoClient) VerifyMultiSig(_ []*ecdsa.PublicKey, _, _ []byte) (bool, error) {
+	panic("implement me")
+}
+
+func (m mockCryptoClient) MultiSign(_ []*ecdsa.PrivateKey, _ []byte) ([]byte, error) {
+	panic("implement me")
+}
diff --git a/cmd/client/cmd/test_data/invalid-ak/no-address/private.key b/cmd/client/cmd/test_data/invalid-ak/no-address/private.key
new file mode 100644
index 000000000..63748e08e
--- /dev/null
+++ b/cmd/client/cmd/test_data/invalid-ak/no-address/private.key
@@ -0,0 +1,1 @@
+{"Curvname":"P-256","X":36505150171354363400464126431978257855318414556425194490762274938603757905292,"Y":79656876957602994269528255245092635964473154458596947290316223079846501380076,"D":111497060296999106528800133634901141644446751975433315540300236500052690483486}
\ No newline at end of file
diff --git a/cmd/client/cmd/test_data/invalid-ak/no-address/public.key b/cmd/client/cmd/test_data/invalid-ak/no-address/public.key
new file mode 100644
index 000000000..86982006b
--- /dev/null
+++ b/cmd/client/cmd/test_data/invalid-ak/no-address/public.key
@@ -0,0 +1,1 @@
+{"Curvname":"P-256","X":36505150171354363400464126431978257855318414556425194490762274938603757905292,"Y":79656876957602994269528255245092635964473154458596947290316223079846501380076}
\ No newline at end of file
diff --git a/cmd/client/cmd/test_data/invalid-ak/no-private-key/address b/cmd/client/cmd/test_data/invalid-ak/no-private-key/address
new file mode 100644
index 000000000..00538d3ea
--- /dev/null
+++ b/cmd/client/cmd/test_data/invalid-ak/no-private-key/address
@@ -0,0 +1,1 @@
+TeyyPLpp9L7QAcxHangtcHTu7HUZ6iydY
\ No newline at end of file
diff --git a/cmd/client/cmd/test_data/invalid-ak/no-private-key/public.key b/cmd/client/cmd/test_data/invalid-ak/no-private-key/public.key
new file mode 100644
index 000000000..86982006b
--- /dev/null
+++ b/cmd/client/cmd/test_data/invalid-ak/no-private-key/public.key
@@ -0,0 +1,1 @@
+{"Curvname":"P-256","X":36505150171354363400464126431978257855318414556425194490762274938603757905292,"Y":79656876957602994269528255245092635964473154458596947290316223079846501380076}
\ No newline at end of file
diff --git a/cmd/client/cmd/test_data/invalid-ak/no-public-key/address b/cmd/client/cmd/test_data/invalid-ak/no-public-key/address
new file mode 100644
index 000000000..00538d3ea
--- /dev/null
+++ b/cmd/client/cmd/test_data/invalid-ak/no-public-key/address
@@ -0,0 +1,1 @@
+TeyyPLpp9L7QAcxHangtcHTu7HUZ6iydY
\ No newline at end of file
diff --git a/cmd/client/cmd/test_data/invalid-ak/no-public-key/private.key b/cmd/client/cmd/test_data/invalid-ak/no-public-key/private.key
new file mode 100644
index 000000000..63748e08e
--- /dev/null
+++ b/cmd/client/cmd/test_data/invalid-ak/no-public-key/private.key
@@ -0,0 +1,1 @@
+{"Curvname":"P-256","X":36505150171354363400464126431978257855318414556425194490762274938603757905292,"Y":79656876957602994269528255245092635964473154458596947290316223079846501380076,"D":111497060296999106528800133634901141644446751975433315540300236500052690483486}
\ No newline at end of file
diff --git a/cmd/client/cmd/test_data/valid-ak/keys/address b/cmd/client/cmd/test_data/valid-ak/keys/address
new file mode 100644
index 000000000..00538d3ea
--- /dev/null
+++ b/cmd/client/cmd/test_data/valid-ak/keys/address
@@ -0,0 +1,1 @@
+TeyyPLpp9L7QAcxHangtcHTu7HUZ6iydY
\ No newline at end of file
diff --git a/cmd/client/cmd/test_data/valid-ak/keys/private.key b/cmd/client/cmd/test_data/valid-ak/keys/private.key
new file mode 100644
index 000000000..63748e08e
--- /dev/null
+++ b/cmd/client/cmd/test_data/valid-ak/keys/private.key
@@ -0,0 +1,1 @@
+{"Curvname":"P-256","X":36505150171354363400464126431978257855318414556425194490762274938603757905292,"Y":79656876957602994269528255245092635964473154458596947290316223079846501380076,"D":111497060296999106528800133634901141644446751975433315540300236500052690483486}
\ No newline at end of file
diff --git a/cmd/client/cmd/test_data/valid-ak/keys/public.key b/cmd/client/cmd/test_data/valid-ak/keys/public.key
new file mode 100644
index 000000000..86982006b
--- /dev/null
+++ b/cmd/client/cmd/test_data/valid-ak/keys/public.key
@@ -0,0 +1,1 @@
+{"Curvname":"P-256","X":36505150171354363400464126431978257855318414556425194490762274938603757905292,"Y":79656876957602994269528255245092635964473154458596947290316223079846501380076}
\ No newline at end of file