diff --git a/scripts/lint.sh b/scripts/lint.sh index a592efc664fa..13026b162941 100755 --- a/scripts/lint.sh +++ b/scripts/lint.sh @@ -9,7 +9,7 @@ fi # The -P option is not supported by the grep version installed by # default on macos. Since `-o errexit` is ignored in an if -# conditional, triggering the problem here ensures script failure whenTESTS +# conditional, triggering the problem here ensures script failure when # using an unsupported version of grep. grep -P 'lint.sh' scripts/lint.sh &> /dev/null || (\ >&2 echo "error: This script requires a recent version of gnu grep.";\ diff --git a/vms/platformvm/addrstate/camino_address_state.go b/vms/platformvm/addrstate/camino_address_state.go index e9e8ece57553..21bcc4d54cdc 100644 --- a/vms/platformvm/addrstate/camino_address_state.go +++ b/vms/platformvm/addrstate/camino_address_state.go @@ -27,6 +27,8 @@ const ( AddressStateBitKYCVerified AddressStateBit = 32 // Indicates that address KYC verification is expired. (not yet implemented) AddressStateBitKYCExpired AddressStateBit = 33 + // Indicates that address passed KYB verification + AddressStateBitKYBVerified AddressStateBit = 34 // Indicates that address is member of consortium AddressStateBitConsortium AddressStateBit = 38 // Indicates that a node owned by this address (as consortium member) is deferred @@ -58,6 +60,9 @@ const ( AddressStateKYCVerified = AddressState(1) << AddressStateBitKYCVerified // 0b0000000000000000000000000000001000000000000000000000000000000000 AddressStateKYCExpired = AddressState(1) << AddressStateBitKYCExpired + // 0b0000000000000000000000000000010000000000000000000000000000000000 + AddressStateKYBVerified = AddressState(1) << AddressStateBitKYBVerified + // 0b0000000000000000000000000100000000000000000000000000000000000000 AddressStateConsortium = AddressState(1) << AddressStateBitConsortium // 0b0000000000000000000000001000000000000000000000000000000000000000 @@ -75,10 +80,10 @@ const ( AddressStateNodeDeferred // 0b0000000000000100000000000000000000000000000000000000000000000100 AddressStateAthensPhaseBits = AddressStateRoleOffersAdmin | AddressStateOffersCreator - // 0b0000000000001000000000000000000000000000000000000000000000001000 + // 0b0000000000001000000000000000010000000000000000000000000000001000 AddressStateBerlinPhaseBits = AddressStateFoundationAdmin | AddressStateRoleConsortiumSecretary | - AddressStateRoleValidatorAdmin - // 0b0000000000001100000000001100001100000000000000000000000000011111 + AddressStateRoleValidatorAdmin | AddressStateKYBVerified + // 0b0000000000001100000000001100011100000000000000000000000000011111 AddressStateValidBits = AddressStateSunrisePhaseBits | AddressStateAthensPhaseBits | AddressStateBerlinPhaseBits diff --git a/vms/platformvm/txs/executor/camino_tx_executor.go b/vms/platformvm/txs/executor/camino_tx_executor.go index 6c3d3aa6d563..59077aa73efb 100644 --- a/vms/platformvm/txs/executor/camino_tx_executor.go +++ b/vms/platformvm/txs/executor/camino_tx_executor.go @@ -2306,7 +2306,7 @@ func (e *CaminoStandardTxExecutor) AddressStateTx(tx *txs.AddressStateTx) error } const ( - addressStateKYCAll = as.AddressStateKYCVerified | as.AddressStateKYCExpired + addressStateKYCAll = as.AddressStateKYCVerified | as.AddressStateKYCExpired | as.AddressStateKYBVerified addressStateRoleBits = as.AddressStateRoleAdmin | as.AddressStateRoleKYCAdmin | as.AddressStateRoleConsortiumSecretary | as.AddressStateRoleOffersAdmin | as.AddressStateRoleValidatorAdmin | as.AddressStateFoundationAdmin @@ -2317,7 +2317,7 @@ func isPermittedToModifyAddrStateBit(isBerlinPhase bool, roles, state as.Address switch { // admin can do anything before BerlinPhase, after that admin can only modify other roles case roles.Is(as.AddressStateRoleAdmin) && (!isBerlinPhase || addressStateRoleBits&state != 0): - // kyc role can change kyc status + // kyc role can change kyc/kyb bits case addressStateKYCAll&state != 0 && roles.Is(as.AddressStateRoleKYCAdmin): // offers admin can assign offers creator role case state == as.AddressStateOffersCreator && roles.Is(as.AddressStateRoleOffersAdmin): diff --git a/vms/platformvm/txs/executor/camino_tx_executor_test.go b/vms/platformvm/txs/executor/camino_tx_executor_test.go index 711a892ce000..49208fc9d426 100644 --- a/vms/platformvm/txs/executor/camino_tx_executor_test.go +++ b/vms/platformvm/txs/executor/camino_tx_executor_test.go @@ -2088,6 +2088,7 @@ func TestCaminoStandardTxExecutorAddressStateTx(t *testing.T) { for _, permissionsMatrix := range permissionsMatrix { permissionsMatrix[as.AddressStateBitRoleKYCAdmin][as.AddressStateBitKYCVerified] = nil permissionsMatrix[as.AddressStateBitRoleKYCAdmin][as.AddressStateBitKYCExpired] = nil + permissionsMatrix[as.AddressStateBitRoleKYCAdmin][as.AddressStateBitKYBVerified] = nil permissionsMatrix[as.AddressStateBitRoleOffersAdmin][as.AddressStateBitOffersCreator] = nil permissionsMatrix[as.AddressStateBitRoleValidatorAdmin][as.AddressStateBitNodeDeferred] = nil } diff --git a/vms/platformvm/txs/executor/dac/camino_dac.go b/vms/platformvm/txs/executor/dac/camino_dac.go index 6e028c2ab8ae..54e0c0ddae39 100644 --- a/vms/platformvm/txs/executor/dac/camino_dac.go +++ b/vms/platformvm/txs/executor/dac/camino_dac.go @@ -22,7 +22,7 @@ var ( _ dac.Executor = (*proposalExecutor)(nil) _ dac.BondTxIDsGetter = (*proposalBondTxIDsGetter)(nil) - errNotKYCVerified = errors.New("address is not KYC verified") + errNotVerifiedAddress = errors.New("address is not KYC or KYB verified") errNotConsortiumMember = errors.New("address isn't consortium member") errConsortiumMember = errors.New("address is consortium member") errNotPermittedToCreateProposal = errors.New("don't have permission to create proposal of this type") @@ -144,14 +144,14 @@ func (*proposalBondTxIDsGetter) BaseFeeProposal(*dac.BaseFeeProposalState) ([]id func (e *proposalVerifier) AddMemberProposal(proposal *dac.AddMemberProposal) error { // verify that address isn't consortium member and is KYC verified - applicantAddress, err := e.state.GetAddressStates(proposal.ApplicantAddress) + applicantAddrState, err := e.state.GetAddressStates(proposal.ApplicantAddress) switch { case err != nil: return err - case applicantAddress.Is(as.AddressStateConsortium): + case applicantAddrState.Is(as.AddressStateConsortium): return fmt.Errorf("%w (applicant)", errConsortiumMember) - case applicantAddress.IsNot(as.AddressStateKYCVerified): - return fmt.Errorf("%w (applicant)", errNotKYCVerified) + case !isVerifiedAddrState(applicantAddrState): + return fmt.Errorf("%w (applicant)", errNotVerifiedAddress) } // verify that there is no existing add member proposal for this address @@ -428,3 +428,9 @@ func mustHaveActiveValidator(s state.Chain, address ids.ShortID) error { } return err } + +const addrStateVerifiedBits = as.AddressStateKYCVerified | as.AddressStateKYBVerified + +func isVerifiedAddrState(addrState as.AddressState) bool { + return addrState&addrStateVerifiedBits != 0 +} diff --git a/vms/platformvm/txs/executor/dac/camino_dac_test.go b/vms/platformvm/txs/executor/dac/camino_dac_test.go index 85696473949e..ffa99238f2cb 100644 --- a/vms/platformvm/txs/executor/dac/camino_dac_test.go +++ b/vms/platformvm/txs/executor/dac/camino_dac_test.go @@ -262,7 +262,7 @@ func TestProposalVerifierAddMemberProposal(t *testing.T) { }, expectedErr: errConsortiumMember, }, - "Applicant address is not kyc verified": { + "Applicant address is not kyc or kyb verified": { state: func(c *gomock.Controller, utx *txs.AddProposalTx) *state.MockDiff { s := state.NewMockDiff(c) s.EXPECT().GetAddressStates(applicantAddress).Return(as.AddressStateEmpty, nil) @@ -279,7 +279,7 @@ func TestProposalVerifierAddMemberProposal(t *testing.T) { signers: [][]*secp256k1.PrivateKey{ {feeOwnerKey}, {bondOwnerKey}, {proposerKey}, }, - expectedErr: errNotKYCVerified, + expectedErr: errNotVerifiedAddress, }, "Already active AddMemberProposal for this applicant": { state: func(c *gomock.Controller, utx *txs.AddProposalTx) *state.MockDiff { @@ -307,7 +307,7 @@ func TestProposalVerifierAddMemberProposal(t *testing.T) { }, expectedErr: errAlreadyActiveProposal, }, - "OK": { + "OK: Applicant address is kyc verified": { state: func(c *gomock.Controller, utx *txs.AddProposalTx) *state.MockDiff { s := state.NewMockDiff(c) proposalsIterator := state.NewMockProposalsIterator(c) @@ -332,6 +332,30 @@ func TestProposalVerifierAddMemberProposal(t *testing.T) { {feeOwnerKey}, {bondOwnerKey}, {proposerKey}, }, }, + "OK: Applicant address is kyb verified": { + state: func(c *gomock.Controller, utx *txs.AddProposalTx) *state.MockDiff { + s := state.NewMockDiff(c) + proposalsIterator := state.NewMockProposalsIterator(c) + proposalsIterator.EXPECT().Next().Return(false) + proposalsIterator.EXPECT().Release() + proposalsIterator.EXPECT().Error().Return(nil) + + s.EXPECT().GetAddressStates(applicantAddress).Return(as.AddressStateKYBVerified, nil) + s.EXPECT().GetProposalIterator().Return(proposalsIterator, nil) + return s + }, + utx: func() *txs.AddProposalTx { + return &txs.AddProposalTx{ + BaseTx: baseTx, + ProposalPayload: proposalBytes, + ProposerAddress: proposerAddr, + ProposerAuth: &secp256k1fx.Input{SigIndices: []uint32{0}}, + } + }, + signers: [][]*secp256k1.PrivateKey{ + {feeOwnerKey}, {bondOwnerKey}, {proposerKey}, + }, + }, } for name, tt := range tests { t.Run(name, func(t *testing.T) {