diff --git a/src/characters/alice.ts b/src/characters/alice.ts index fa640f668..dfe06d02f 100644 --- a/src/characters/alice.ts +++ b/src/characters/alice.ts @@ -19,15 +19,9 @@ import { ChecksumAddress } from '../types'; import { RemoteBob } from './bob'; export class Alice { - private readonly porter: PorterClient; private readonly keyring: Keyring; - private constructor( - porterUri: string, - secretKey: SecretKey, - public readonly web3Provider: ethers.providers.Web3Provider - ) { - this.porter = new PorterClient(porterUri); + private constructor(secretKey: SecretKey) { this.keyring = new Keyring(secretKey); } @@ -39,12 +33,8 @@ export class Alice { return this.keyring.signer; } - public static fromSecretKey( - porterUri: string, - secretKey: SecretKey, - web3Provider: ethers.providers.Web3Provider - ): Alice { - return new Alice(porterUri, secretKey, web3Provider); + public static fromSecretKey(secretKey: SecretKey): Alice { + return new Alice(secretKey); } public getPolicyEncryptingKeyFromLabel(label: string): PublicKey { @@ -52,30 +42,36 @@ export class Alice { } public async grant( + web3Provider: ethers.providers.Web3Provider, + porterUri: string, policyParameters: BlockchainPolicyParameters, includeUrsulas?: readonly ChecksumAddress[], excludeUrsulas?: readonly ChecksumAddress[] ): Promise { - const ursulas = await this.porter.getUrsulas( + const porter = new PorterClient(porterUri); + const ursulas = await porter.getUrsulas( policyParameters.shares, excludeUrsulas, includeUrsulas ); - const policy = await this.createPolicy(policyParameters); - return await policy.enact(ursulas); + const policy = await this.createPolicy(web3Provider, policyParameters); + return await policy.enact(web3Provider, ursulas); } public async generatePreEnactedPolicy( + web3Provider: ethers.providers.Web3Provider, + porterUri: string, policyParameters: BlockchainPolicyParameters, includeUrsulas?: readonly ChecksumAddress[], excludeUrsulas?: readonly ChecksumAddress[] ): Promise { - const ursulas = await this.porter.getUrsulas( + const porter = new PorterClient(porterUri); + const ursulas = await porter.getUrsulas( policyParameters.shares, excludeUrsulas, includeUrsulas ); - const policy = await this.createPolicy(policyParameters); + const policy = await this.createPolicy(web3Provider, policyParameters); return await policy.generatePreEnactedPolicy(ursulas); } @@ -98,10 +94,11 @@ export class Alice { } private async createPolicy( + web3Provider: ethers.providers.Web3Provider, rawParameters: BlockchainPolicyParameters ): Promise { const { bob, label, threshold, shares, startDate, endDate } = - await this.validatePolicyParameters(rawParameters); + await this.validatePolicyParameters(web3Provider, rawParameters); const { delegatingKey, verifiedKFrags } = this.generateKFrags( bob, label, @@ -122,6 +119,7 @@ export class Alice { } private async validatePolicyParameters( + web3Provider: ethers.providers.Web3Provider, rawParams: BlockchainPolicyParameters ): Promise { const startDate = rawParams.startDate ?? new Date(); @@ -143,8 +141,8 @@ export class Alice { ); } - const blockNumber = await this.web3Provider.getBlockNumber(); - const block = await this.web3Provider.getBlock(blockNumber); + const blockNumber = await web3Provider.getBlockNumber(); + const block = await web3Provider.getBlock(blockNumber); const blockTime = new Date(block.timestamp * 1000); if (endDate < blockTime) { throw new Error( diff --git a/src/config.ts b/src/config.ts index af7698644..4ffd252a6 100644 --- a/src/config.ts +++ b/src/config.ts @@ -9,7 +9,8 @@ const PORTER_URIS: Record = { }; export const getPorterUri = (network: Network): string => { - if (!Object.values(PORTER_URIS).includes(network)) { + const uri = PORTER_URIS[network]; + if (!uri) { throw new Error(`No default Porter URI found for network: ${network}`); } return PORTER_URIS[network]; diff --git a/src/policies/policy.ts b/src/policies/policy.ts index ffe284939..1d3ffcb7d 100644 --- a/src/policies/policy.ts +++ b/src/policies/policy.ts @@ -6,6 +6,7 @@ import { TreasureMap, VerifiedKeyFrag, } from '@nucypher/nucypher-core'; +import { ethers } from 'ethers'; import { PreSubscriptionManagerAgent } from '../agents/subscription-manager'; import { Alice } from '../characters/alice'; @@ -40,26 +41,30 @@ export class PreEnactedPolicy implements IPreEnactedPolicy { public readonly endTimestamp: Date ) {} - public async enact(publisher: Alice): Promise { - const txHash = await this.publish(publisher); + public async enact( + web3Provider: ethers.providers.Web3Provider + ): Promise { + const txHash = await this.publish(web3Provider); return { ...this, txHash, }; } - private async publish(publisher: Alice): Promise { + private async publish( + web3Provider: ethers.providers.Web3Provider + ): Promise { const startTimestamp = toEpoch(this.startTimestamp); const endTimestamp = toEpoch(this.endTimestamp); - const ownerAddress = await publisher.web3Provider.getSigner().getAddress(); + const ownerAddress = await web3Provider.getSigner().getAddress(); const value = await PreSubscriptionManagerAgent.getPolicyCost( - publisher.web3Provider, + web3Provider, this.size, startTimestamp, endTimestamp ); const tx = await PreSubscriptionManagerAgent.createPolicy( - publisher.web3Provider, + web3Provider, value, this.id.toBytes(), this.size, @@ -101,9 +106,12 @@ export class BlockchainPolicy { ); } - public async enact(ursulas: readonly Ursula[]): Promise { + public async enact( + web3Provider: ethers.providers.Web3Provider, + ursulas: readonly Ursula[] + ): Promise { const preEnacted = await this.generatePreEnactedPolicy(ursulas); - return await preEnacted.enact(this.publisher); + return await preEnacted.enact(web3Provider); } public async generatePreEnactedPolicy( diff --git a/src/sdk/strategy/pre-strategy.ts b/src/sdk/strategy/pre-strategy.ts index d7ab66253..f6695973b 100644 --- a/src/sdk/strategy/pre-strategy.ts +++ b/src/sdk/strategy/pre-strategy.ts @@ -62,13 +62,11 @@ export class PreStrategy { } public async deploy( - provider: ethers.providers.Web3Provider, + web3Provider: ethers.providers.Web3Provider, label: string, - threshold?: number, - shares?: number + threshold = Math.floor(this.cohort.numUrsulas / 2) + 1, + shares = this.cohort.numUrsulas ): Promise { - shares = shares || this.cohort.numUrsulas; - threshold = threshold || Math.floor(shares / 2) + 1; if (shares > this.cohort.numUrsulas) { throw new Error( `Threshold ${threshold} cannot be greater than the number of Ursulas in the cohort ${this.cohort.numUrsulas}` @@ -76,7 +74,7 @@ export class PreStrategy { } const porterUri = this.cohort.porterUri; - const alice = Alice.fromSecretKey(porterUri, this.aliceSecretKey, provider); + const alice = Alice.fromSecretKey(this.aliceSecretKey); const bob = new Bob(porterUri, this.bobSecretKey); const policyParams = { bob, @@ -86,7 +84,12 @@ export class PreStrategy { startDate: this.startDate, endDate: this.endDate, }; - const policy = await alice.grant(policyParams, this.cohort.ursulaAddresses); + const policy = await alice.grant( + web3Provider, + porterUri, + policyParams, + this.cohort.ursulaAddresses + ); return DeployedPreStrategy.create(this.cohort, policy, this.bobSecretKey); } diff --git a/test/acceptance/alice-grants.test.ts b/test/acceptance/alice-grants.test.ts index a887004a0..66c2cbca8 100644 --- a/test/acceptance/alice-grants.test.ts +++ b/test/acceptance/alice-grants.test.ts @@ -13,8 +13,10 @@ import { bytesEqual, fakeAlice, fakeBob, + fakePorterUri, fakeRemoteBob, fakeUrsulas, + fakeWeb3Provider, fromBytes, mockEncryptTreasureMap, mockGenerateKFrags, @@ -32,6 +34,7 @@ describe('story: alice shares message with bob through policy', () => { const startDate = new Date(); const endDate = new Date(Date.now() + 60 * 1000); const mockedUrsulas = fakeUrsulas().slice(0, shares); + const web3Provider = fakeWeb3Provider(); // Intermediate variables used for mocking let encryptedTreasureMap: EncryptedTreasureMap; @@ -62,7 +65,7 @@ describe('story: alice shares message with bob through policy', () => { startDate, endDate, }; - policy = await alice.grant(policyParams); + policy = await alice.grant(web3Provider, fakePorterUri, policyParams); expect( bytesEqual( diff --git a/test/acceptance/delay-enact.test.ts b/test/acceptance/delay-enact.test.ts index 61574df95..545e9abee 100644 --- a/test/acceptance/delay-enact.test.ts +++ b/test/acceptance/delay-enact.test.ts @@ -1,21 +1,24 @@ import { bytesEqual, fakeAlice, + fakePorterUri, fakeRemoteBob, fakeUrsulas, + fakeWeb3Provider, mockEncryptTreasureMap, mockGenerateKFrags, mockGetUrsulas, mockPublishToBlockchain, } from '../utils'; -describe('story: alice1 creates a policy but alice2 enacts it', () => { +describe('story: alice creates a policy but someone else enacts it', () => { const threshold = 2; const shares = 3; const startDate = new Date(); const endDate = new Date(Date.now() + 60 * 1000); // 60s later const mockedUrsulas = fakeUrsulas().slice(0, shares); const label = 'fake-data-label'; + const web3Provider = fakeWeb3Provider(); it('alice generates a new policy', async () => { const getUrsulasSpy = mockGetUrsulas(mockedUrsulas); @@ -23,8 +26,7 @@ describe('story: alice1 creates a policy but alice2 enacts it', () => { const publishToBlockchainSpy = mockPublishToBlockchain(); const encryptTreasureMapSpy = mockEncryptTreasureMap(); - const alice1 = fakeAlice('fake-secret-key-32-bytes-alice-1'); - const alice2 = fakeAlice('fake-secret-key-32-bytes-alice-2'); + const alice = fakeAlice('fake-secret-key-32-bytes-alice-1'); const bob = fakeRemoteBob(); const policyParams = { bob, @@ -35,18 +37,20 @@ describe('story: alice1 creates a policy but alice2 enacts it', () => { endDate, }; - const preEnactedPolicy = await alice1.generatePreEnactedPolicy( + const preEnactedPolicy = await alice.generatePreEnactedPolicy( + web3Provider, + fakePorterUri, policyParams ); expect( bytesEqual( preEnactedPolicy.aliceVerifyingKey.toCompressedBytes(), - alice1.verifyingKey.toCompressedBytes() + alice.verifyingKey.toCompressedBytes() ) ).toBeTruthy(); expect(preEnactedPolicy.label).toBe(label); - const enacted = await preEnactedPolicy.enact(alice2); + const enacted = await preEnactedPolicy.enact(web3Provider); expect(enacted.txHash).toBeDefined(); expect(getUrsulasSpy).toHaveBeenCalled(); diff --git a/test/docs/cbd.test.ts b/test/docs/cbd.test.ts index cffde9aac..e657827c7 100644 --- a/test/docs/cbd.test.ts +++ b/test/docs/cbd.test.ts @@ -1,7 +1,13 @@ import { MessageKit, VerifiedKeyFrag } from '@nucypher/nucypher-core'; import { providers } from 'ethers'; -import { Cohort, conditions, PreStrategy, SecretKey } from '../../src'; +import { + Cohort, + conditions, + getPorterUri, + PreStrategy, + SecretKey, +} from '../../src'; import { Ursula } from '../../src/porter'; import { toBytes } from '../../src/utils'; import { @@ -60,7 +66,7 @@ describe('Get Started (CBD PoC)', () => { // // 2. Build a Cohort - const porterUri = 'https://porter-tapir.nucypher.community'; + const porterUri = getPorterUri('tapir'); const numUrsulas = 5; const newCohort = await Cohort.create(porterUri, numUrsulas); diff --git a/test/utils.ts b/test/utils.ts index 9792e6b6a..87154d021 100644 --- a/test/utils.ts +++ b/test/utils.ts @@ -59,13 +59,13 @@ export const bytesEqual = (first: Uint8Array, second: Uint8Array): boolean => export const fromBytes = (bytes: Uint8Array): string => new TextDecoder().decode(bytes); -const porterUri = 'https://_this_should_crash.com/'; +export const fakePorterUri = 'https://_this_should_crash.com/'; export const fakeBob = (): Bob => { const secretKey = SecretKey.fromBEBytes( toBytes('fake-secret-key-32-bytes-bob-xxx') ); - return Bob.fromSecretKey(porterUri, secretKey); + return Bob.fromSecretKey(fakePorterUri, secretKey); }; export const fakeRemoteBob = (): RemoteBob => { @@ -75,12 +75,11 @@ export const fakeRemoteBob = (): RemoteBob => { export const fakeAlice = (aliceKey = 'fake-secret-key-32-bytes-alice-x') => { const secretKey = SecretKey.fromBEBytes(toBytes(aliceKey)); - const provider = fakeWeb3Provider(secretKey.toBEBytes()); - return Alice.fromSecretKey(porterUri, secretKey, provider); + return Alice.fromSecretKey(secretKey); }; export const fakeWeb3Provider = ( - secretKeyBytes: Uint8Array, + secretKeyBytes = SecretKey.random().toBEBytes(), blockNumber?: number, blockTimestamp?: number ): ethers.providers.Web3Provider => {