version | solidity | status |
---|---|---|
0.3.0 |
0.4.24 |
experimental |
Splash Securities Standard - S3 has grown out of the Splash Exchange's efforts to automate certain aspects of running a compliant alternatives exchange. Currently, it consists of a smart contract library and a typescript library for manipulating these contracts. However, the full scope includes a standard protocol that exchanges an compliance providers can use to communicate in order to maintain the trading invariants required by the SEC for securities to keep their filing exemptions.
If you would like to contribute, please see contributing.md
before you begin.
Then, take a look at the setup instructions below.
The simplified S3 architecture provides a permissioned token with no rule checking on chain. There are three classes of contracts.
CapTables
: All securities issued on S3 share this contract, which is only responsible for being the single source of truth for cap tables.TokenFront
: This contract provides a fixed Ethereum address for a given security. All calls are forwarded to a contract expressing rule logic.SimpliedLogic
: This contract implements a two stage clearing and settlement protocol. Users create token transfer requests by callingtransfer
andtransferFrom
on the associatedTokenFront
. Then a third party resolves each transfer request by providing an error code. Only on error code0
is the transfer settled.
Start by having a look at src/Types.ts
. Here is a simple example of
programmatic online issuing:
import * as s3 from "@openfinance/smart-securities-standard";
import { readFileSync, writeFileSync } from "fs";
import * as Web3 from "web3";
const capTablesAddress = readFileSync("soon-to-be-deployed-s3-capTables.address", "utf8");
const security: s3.BaseSecurity = JSON.parse(readFileSync("mySecurity.json", "utf8"));
const prov = new Web3.providers.HttpProvider("http://localhost:8545");
const web3 = new Web3(prov);
async function go() {
const record = await s3.issue(
security,
capTablesAddress,
deploymentAddress,
Web3.eth
);
writeFileSync("my-deployment-record.json", JSON.stringify(record), "utf8");
}
go();
S3 ships with a command line tool you can access at npm run cli -- --help
.
To use the tool, create two files: config.json
and spec.json
and any number
of secrurity declarations. See here for the appropriate format
for these files, where the BigNumber
fields can be either string or numbers
in the json
declaration files.
Summary of commands:
init
: Deploy an instance ofCapTables
(this is safe to do online)issueOnline
: This is a convenience function for making sure that your deployment matches the declaration.issueOffline
: Use this function in an offline environment to generate transactions. It is safe to copy the generated transcripts to an online environment. This flow uses an ephemeral keypair to run the deployment.issueOffline -s 1
(plus other flags as needed) will create a transcript file with the transaction data to perform the initial configuration of theCapTables
contract, getting a newsecurityId
. Note the controller address andbase64
-encoded key material generated by this commandpublish -s 1
should be run online and will allow you to select a version of the transaction based on the gas price. Note: the controller address generated in the previous step must be funded before running this step.issueOffline -s 2
will alter the transcript, adding transactions for distributing to investors and setting up the other parts of S3. Pass thebase64
-encoded key material from stage one to this script in thecontroller
environment variable.publish -s 2
will interactively broadcast the remaining transactions
publish
: Run this online to broadcast transactions prepared offline
Manual issuance proceeds in several stages.
- Stage I. Choose a deployed
CapTables
contract and send a transaction which callsinitialize
with your total supply. This will create a new security, owned by the caller and will give you the index of the security. The caller will hold the entire balance. - Stage II. Make calls to
CapTables.transfer
to configure the initial distribution of your security. - Stage III. Deploy
SimplifiedLogic
to addresslogicAddress
, then deployTokenFront
with construction parameterlogicAddress
. CallsetFront
onSimplifiedLogic
with the address of theTokenFront
to authorize it to call in. - Stage IV. Make some provision to detect and resolve transfer requests.
SimplifiedLogic
will logTransferRequest
messages as users attempt to move tokens around. - Stage V. If you need to modify the logic that governs token transfers,
use the
migrate
method ofCapTables
andTokenFront
.
An S3 token can be managed using the handleTransfers<A>
function. To use
this function, you must implement:
// A decider with the restriction logic. It should return a pair [code, x]
// where code is the error code (success = 0) and x is a payload that is consumed
// by the finalizer.
declare decision: (tr: Transfer) => Promise<[number, A]>
// A finalizer, which is used e.g. to persist the resolution hash and error
// code to a database.
declare finalization: (txHash: string, extraData: A) => Promise<void>;
In order to develop S3, you'll need to have some programs installed:
solc
jq
typescript
, which can be installed withnpm install -g typescript
(or through your system package manager)
Then S3 can be set up like this:
$ git clone https://github.com/OpenFinanceIO/smart-securities-standard.git
$ cd smart-securities-standard
$ git submodule init && git submodule update # get OpenZeppelin contracts
$ npm install
$ npm run compile
$ npm run cli -- --help # see cli options
The tests expect to find ganache-cli
listening at localhost:8545
. Once ganache-cli
has been started:
$ # run the test cases
$ npm test -- -t 30000