| 243 | } |
| 244 | |
| 245 | func (m *Manager) createControlProgram(ctx context.Context, accountID string, change bool, expiresAt time.Time) (*controlProgram, error) { |
| 246 | account, err := m.findByID(ctx, accountID) |
| 247 | if err != nil { |
| 248 | return nil, err |
| 249 | } |
| 250 | |
| 251 | idx, err := m.nextIndex(ctx) |
| 252 | if err != nil { |
| 253 | return nil, err |
| 254 | } |
| 255 | |
| 256 | path := signers.Path(account, signers.AccountKeySpace, idx) |
| 257 | derivedXPubs := chainkd.DeriveXPubs(account.XPubs, path) |
| 258 | derivedPKs := chainkd.XPubKeys(derivedXPubs) |
| 259 | control, err := vmutil.P2SPMultiSigProgram(derivedPKs, account.Quorum) |
| 260 | if err != nil { |
| 261 | return nil, err |
| 262 | } |
| 263 | return &controlProgram{ |
| 264 | accountID: account.ID, |
| 265 | keyIndex: idx, |
| 266 | controlProgram: control, |
| 267 | change: change, |
| 268 | expiresAt: expiresAt, |
| 269 | }, nil |
| 270 | } |
| 271 | |
| 272 | // CreateControlProgram creates a control program |
| 273 | // that is tied to the Account and stores it in the database. |