Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(mixin-ownable): add Ownable mixin and test
- Loading branch information
Showing
14 changed files
with
168 additions
and
207 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
12 changes: 0 additions & 12 deletions
12
packages/neo-one-smart-contract-lib/src/__data__/contracts/TestTransferableContract.ts
This file was deleted.
Oops, something went wrong.
9 changes: 9 additions & 0 deletions
9
packages/neo-one-smart-contract-lib/src/__data__/contracts/ownership/TestOwnable.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import { Deploy, SmartContract } from '@neo-one/smart-contract'; | ||
/*tslint:disable-next-line:no-implicit-dependencies*/ | ||
import { Ownable } from '@neo-one/smart-contract-lib'; | ||
|
||
export class TestOwnable extends Ownable(SmartContract) { | ||
public constructor(protected readonly initialOwner = Deploy.senderAddress) { | ||
super(); | ||
} | ||
} |
105 changes: 0 additions & 105 deletions
105
packages/neo-one-smart-contract-lib/src/__tests__/TestTransferableOwnership.test.ts
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
5 changes: 0 additions & 5 deletions
5
...one-smart-contract-lib/src/__tests__/__snapshots__/TestTransferableOwnership.test.ts.snap
This file was deleted.
Oops, something went wrong.
81 changes: 81 additions & 0 deletions
81
packages/neo-one-smart-contract-lib/src/__tests__/ownership/TestOwnableContract.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
import { common, crypto } from '@neo-one/client-common'; | ||
import { SmartContractAny } from '@neo-one/client-core'; | ||
import { withContracts } from '@neo-one/smart-contract-test'; | ||
import * as path from 'path'; | ||
|
||
const RECIPIENT = { | ||
PRIVATE_KEY: '7d128a6d096f0c14c3a25a2b0c41cf79661bfcb4a8cc95aaaea28bde4d732344', | ||
PUBLIC_KEY: '02028a99826edc0c97d18e22b6932373d908d323aa7f92656a77ec26e8861699ef', | ||
}; | ||
|
||
describe('Ownable', () => { | ||
test('deploy + transfer', async () => { | ||
await withContracts<{ testOwnable: SmartContractAny }>( | ||
[ | ||
{ | ||
filePath: path.resolve(__dirname, '..', '..', '__data__', 'contracts', 'ownership', 'TestOwnable.ts'), | ||
name: 'TestOwnable', | ||
}, | ||
], | ||
async ({ client, networkName, testOwnable: smartContract, masterAccountID }) => { | ||
crypto.addPublicKey( | ||
common.stringToPrivateKey(RECIPIENT.PRIVATE_KEY), | ||
common.stringToECPoint(RECIPIENT.PUBLIC_KEY), | ||
); | ||
|
||
const deployResult = await smartContract.deploy(masterAccountID.address, { from: masterAccountID }); | ||
const deployReceipt = await deployResult.confirmed({ timeoutMS: 2500 }); | ||
if (deployReceipt.result.state !== 'HALT') { | ||
throw new Error(deployReceipt.result.message); | ||
} | ||
|
||
expect(deployReceipt.result.gasConsumed.toString()).toMatchSnapshot('deploy consumed'); | ||
expect(deployReceipt.result.gasCost.toString()).toMatchSnapshot('deploy cost'); | ||
expect(deployReceipt.result.value).toBeTruthy(); | ||
|
||
const [initialOwner, recipient] = await Promise.all([ | ||
smartContract.owner.confirmed(), | ||
client.providers.memory.keystore.addUserAccount({ | ||
network: networkName, | ||
name: 'recipient', | ||
privateKey: RECIPIENT.PRIVATE_KEY, | ||
}), | ||
]); | ||
|
||
expect(initialOwner.result.value).toEqual(masterAccountID.address); | ||
|
||
const transferReceipt = await smartContract.transferOwnership.confirmed(recipient.userAccount.id.address, { | ||
from: masterAccountID, | ||
}); | ||
const newOwner = await smartContract.owner.confirmed(); | ||
if (transferReceipt.result.state !== 'HALT') { | ||
throw new Error(transferReceipt.result.message); | ||
} | ||
expect(newOwner.result.value).toEqual(recipient.userAccount.id.address); | ||
|
||
const bogusTransferReceipt = await smartContract.transferOwnership.confirmed(masterAccountID.address, { | ||
from: masterAccountID, | ||
}); | ||
expect(bogusTransferReceipt.result.state).toEqual('FAULT'); | ||
expect(bogusTransferReceipt.result.value).toBeFalsy(); | ||
|
||
const finalOwner = await smartContract.owner.confirmed(); | ||
expect(finalOwner.result.value).toEqual(recipient.userAccount.id.address); | ||
|
||
const renounceReceipt = await smartContract.renounceOwnership.confirmed({ | ||
from: recipient.userAccount.id, | ||
}); | ||
expect(renounceReceipt.result.state).toEqual('HALT'); | ||
const noOwner = await smartContract.owner.confirmed(); | ||
expect(noOwner.result.value).toEqual(undefined); | ||
|
||
await expect( | ||
smartContract.ownerOrThrow.confirmed({ | ||
from: recipient.userAccount.id, | ||
}), | ||
).rejects.toBeDefined(); | ||
}, | ||
{ deploy: false }, | ||
); | ||
}); | ||
}); |
5 changes: 5 additions & 0 deletions
5
...smart-contract-lib/src/__tests__/ownership/__snapshots__/TestOwnableContract.test.ts.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
// Jest Snapshot v1, https://goo.gl/fbAQLP | ||
|
||
exports[`Ownable deploy + transfer: deploy consumed 1`] = `"0"`; | ||
|
||
exports[`Ownable deploy + transfer: deploy cost 1`] = `"1.299"`; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,2 @@ | ||
// tslint:disable-next-line export-name | ||
export { NEP5Token } from './NEP5Token'; | ||
export { DesignatedCaller } from './ownership/DesignatedCaller'; | ||
export { TransferableOwnership } from './ownership/TransferableOwnership'; | ||
export { Ownable } from './ownership'; |
62 changes: 62 additions & 0 deletions
62
packages/neo-one-smart-contract-lib/src/ownership/Ownable.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
import { Address, SmartContract, createEventNotifier } from '@neo-one/smart-contract'; | ||
|
||
const ownershipTransferred = createEventNotifier<Address | undefined, Address>('transferred_ownership', 'from', 'to'); | ||
|
||
export function Ownable<TBase extends Constructor<SmartContract>>(base: TBase) { | ||
abstract class OwnableClass extends base { | ||
protected abstract initialOwner: Address; | ||
private mutableOwner: Address | undefined = undefined; | ||
private mutableOwnerInitialized = false; | ||
|
||
// tslint:disable-next-line:no-any | ||
public constructor(...args: any[]) { | ||
super(args); | ||
} | ||
|
||
public get owner(): Address | undefined { | ||
return this.mutableOwner ? this.mutableOwner : this.initializeOwner(); | ||
} | ||
|
||
public renounceOwnership() { | ||
this.onlyOwner(); | ||
|
||
this.mutableOwner = undefined; | ||
} | ||
|
||
public transferOwnership(to: Address): boolean { | ||
this.onlyOwner(); | ||
|
||
ownershipTransferred(this.mutableOwner, to); | ||
this.mutableOwner = to; | ||
|
||
return true; | ||
} | ||
|
||
protected ownerOrThrow(): Address { | ||
const owner = this.owner; | ||
|
||
if (owner === undefined) { | ||
throw new Error('no owner'); | ||
} | ||
|
||
return owner; | ||
} | ||
|
||
protected onlyOwner() { | ||
if (this.mutableOwner && !Address.isCaller(this.mutableOwner)) { | ||
throw new Error('not owner'); | ||
} | ||
} | ||
|
||
private initializeOwner() { | ||
if (!this.mutableOwner && !this.mutableOwnerInitialized) { | ||
this.mutableOwner = this.initialOwner; | ||
this.mutableOwnerInitialized = true; | ||
} | ||
|
||
return this.mutableOwner; | ||
} | ||
} | ||
|
||
return OwnableClass; | ||
} |
76 changes: 0 additions & 76 deletions
76
packages/neo-one-smart-contract-lib/src/ownership/TransferableOwnership.ts
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
// tslint:disable: export-name | ||
export { Ownable } from './Ownable'; |
Oops, something went wrong.