forked from eoscanada/eosc
/
toolsSellAccount.go
114 lines (93 loc) · 4.96 KB
/
toolsSellAccount.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
package cmd
import (
"context"
"fmt"
"os"
"time"
eos "github.com/sebastianmontero/eos-go"
"github.com/sebastianmontero/eos-go/msig"
"github.com/sebastianmontero/eos-go/system"
"github.com/sebastianmontero/eos-go/token"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
var toolsSellAccountCmd = &cobra.Command{
Use: "sell-account [sold account] [buyer account] [beneficiary account] [amount]",
Short: "Create a multisig transaction that both parties need to approve in order to do an atomic sale of your account.",
Long: `Create a multisig transaction that both parties need to approve in order to do an atomic sale of your account.
Transfers both "owner" and "active" authority to a clone of the buyer's account's authority.
MAKE SURE TO INSPECT THE GENERATED MULTISIG TRANSACTION BEFORE APPROVING IT.
`,
Args: cobra.ExactArgs(4),
Run: func(cmd *cobra.Command, args []string) {
ctx := context.Background()
soldAccount := toAccount(args[0], "sold account")
buyerAccount := toAccount(args[1], "buyer account")
beneficiaryAccount := toAccount(args[2], "beneficiary account")
saleAmount := toCoreAsset(args[3], "amount")
proposalName := viper.GetString("tools-sell-account-cmd-proposal-name")
memo := viper.GetString("tools-sell-account-cmd-memo")
api := getAPI()
soldAccountData, err := api.GetAccount(ctx, soldAccount)
errorCheck("could not find sold account on chain: "+string(soldAccount), err)
if len(soldAccountData.Permissions) > 2 {
fmt.Println("WARNING: your account has more than 2 permissions.")
fmt.Println("This operation hands off control of `owner` and `active` keys.")
fmt.Println("Please clean-up your permissions before selling your account.")
os.Exit(1)
}
buyerAccountData, err := api.GetAccount(ctx, buyerAccount)
errorCheck("could not find buyer's account on chain", err)
_, err = api.GetAccount(ctx, beneficiaryAccount)
errorCheck("could not find beneficiary's account on chain", err)
buyerPermText := viper.GetString("tools-sell-account-cmd-buyer-permission")
if buyerPermText == "" {
buyerPermText = string(buyerAccount)
}
buyerPerm, err := eos.NewPermissionLevel(buyerPermText)
errorCheck(`invalid "buyer-permission"`, err)
myPermText := viper.GetString("tools-sell-account-cmd-seller-permission")
if myPermText == "" {
myPermText = string(soldAccount)
}
myPerm, err := eos.NewPermissionLevel(myPermText)
errorCheck(`invalid "seller-permission"`, err)
targetOwnerAuth, err := sellAccountFindAuthority(buyerAccountData, "owner")
errorCheck("error finding buyer's owner permission", err)
targetActiveAuth, err := sellAccountFindAuthority(buyerAccountData, "active")
errorCheck("error finding buyer's owner permission", err)
infoResp, err := api.GetInfo(ctx)
errorCheck("couldn't get_info from chain", err)
tx := eos.NewTransaction([]*eos.Action{
system.NewUpdateAuth(soldAccount, eos.PermissionName("owner"), eos.PermissionName(""), targetOwnerAuth, eos.PermissionName("owner")),
system.NewUpdateAuth(soldAccount, eos.PermissionName("active"), eos.PermissionName("owner"), targetActiveAuth, eos.PermissionName("active")),
token.NewTransfer(buyerAccount, beneficiaryAccount, saleAmount, memo),
}, &eos.TxOptions{HeadBlockID: infoResp.HeadBlockID})
tx.SetExpiration(viper.GetDuration("tools-sell-account-cmd-sale-expiration"))
fmt.Println("Submitting `eosio.msig` proposal:")
fmt.Printf(" proposer: %s\n", soldAccount)
fmt.Printf(" proposal_name: %s\n", proposalName)
fmt.Println("If this transaction is successful, have the other party approve and execute the multisig proposal to an atomic swap.")
fmt.Println("Review this proposal with:")
fmt.Printf(" eosc multisig review %s %s", soldAccount, proposalName)
fmt.Println("")
msigPermissions := []eos.PermissionLevel{buyerPerm, myPerm, eos.PermissionLevel{Actor: soldAccount, Permission: eos.PermissionName("owner")}}
pushEOSCActions(ctx, api, msig.NewPropose(soldAccount, eos.Name(proposalName), msigPermissions, tx))
},
}
func init() {
toolsCmd.AddCommand(toolsSellAccountCmd)
toolsSellAccountCmd.Flags().StringP("memo", "", "", "Memo message to attach to transfer")
toolsSellAccountCmd.Flags().StringP("proposal-name", "", "sellaccount", "Proposal name to use in the eosio.msig contract")
toolsSellAccountCmd.Flags().StringP("buyer-permission", "", "", "Permission required of the buyer (to authorized 'eosio.token::transfer')")
toolsSellAccountCmd.Flags().StringP("seller-permission", "", "", "Permission required of the seller (you, to authorize 'eosio::updateauth')")
toolsSellAccountCmd.Flags().DurationP("sale-expiration", "", 1*time.Hour, "Expire proposed transaction after this amount of time (30m, 1h, etc..)")
}
func sellAccountFindAuthority(data *eos.AccountResp, targetPerm string) (eos.Authority, error) {
for _, perm := range data.Permissions {
if perm.PermName == targetPerm {
return perm.RequiredAuth, nil
}
}
return eos.Authority{}, fmt.Errorf("permission %q not found in account %q", targetPerm, data.AccountName)
}