Init repo

This commit is contained in:
armaniferrante 2021-03-10 05:00:13 -08:00
commit 1fea0ca16d
No known key found for this signature in database
GPG Key ID: 58BEF301E91F7828
11 changed files with 1454 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
.anchor
target

46
.travis.yml Normal file
View File

@ -0,0 +1,46 @@
dist: bionic
language: rust
rust:
- nightly
cache: cargo
env:
- NODE_VERSION="14.7.0"
before_deploy:
- anchor build --verifiable
- echo "### SHA256 Checksums" > release_notes.md
- sha256sum target/deploy/multisig.so > binary.txt
- sha256sum target/idl/multisig.json > idl.txt
- cat *.txt >> release_notes.md
deploy:
provider: releases
edge: true
file:
- "target/deploy/multisig.so"
- "target/idl/multisig.json"
release_notes_file: release_notes.md
skip_cleanup: true
on:
tags: true
api_key:
secure: MRahuKj/FhxUwkkvqiI3wJYWKzJ0PVl25ZfFhp5lA7xyYYj/heQOdX1rE8I3MkyBOWlSNAN89JXKQ61czOrkpjK/vjBt7/49iCkWuBd+ZQ0SOjrdFubAMl4ypd3C56v28Q/Rh5bAgm8IiJNeCidfWjiu36ibjAHMAxkwAssp76AV0hboWMJx6i4i8W/iFC8hQhiFa4npkTkrCtL4Vt8qY0fwqNRRpMZBIz22ZglYbhWpkaPMeikFun7Fjn9dvT0PM/xtcjTYOf4sxdjItpYjR0fUF+thuR+z4McgeYko3AZG9Sv8RMvw6yU1Hpq/Okk1wXcxNHyDtz/YriwiPgVzcIW2SGW2YxXh8YZEQFJuVodM8udYjFuNHy+qcNDiCvcoNIj2zYP3iWEVpiv4a3Hr33T/+iGTqLkjlnHcLKI8m2ykbHFtmNEmg6P4faayYkDSeEKRMZSDuA+CKh07LVlBQFyIRB3tfw3+tdBGQXQojgxAwuxnfANhScMpSdjZtdJCS912ijzVeSGa6C33+/fpAqQtCQqwJx+Bl6Bytvq+nBSjojWJZUqvE53IFwD5/bSd6FUIyAQMnQ6t8dOF+OWx0a1rFtpfLYYKZwei8kZlWNd4BLs+V0jkyHTzy0Cztre/EcmXdAHxAX8XrcrWt9sC1gwpApdrtZ20zZhEHsdgY/k=
_defaults: &defaults
before_install:
- nvm install $NODE_VERSION
- npm install -g mocha
- npm install -g @project-serum/anchor
- sudo apt-get install -y pkg-config build-essential libudev-dev
- sh -c "$(curl -sSfL https://release.solana.com/v1.5.5/install)"
- export PATH="/home/travis/.local/share/solana/install/active_release/bin:$PATH"
- export NODE_PATH="/home/travis/.nvm/versions/node/v$NODE_VERSION/lib/node_modules/:$NODE_PATH"
- yes | solana-keygen new
- cargo install --git https://github.com/project-serum/anchor anchor-cli --locked
jobs:
include:
- <<: *defaults
name: Runs the tests
script:
- anchor test

2
Anchor.toml Normal file
View File

@ -0,0 +1,2 @@
cluster = "localnet"
wallet = "~/.config/solana/id.json"

932
Cargo.lock generated Normal file
View File

@ -0,0 +1,932 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "ahash"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "739f4a8db6605981345c5654f3a85b056ce52f37a39d34da03f25bf2151ea16e"
[[package]]
name = "aho-corasick"
version = "0.7.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5"
dependencies = [
"memchr",
]
[[package]]
name = "anchor-attribute-access-control"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "476873adeb35a1b53d49ceda8fbe913a6601a3379552b9399dd38c4dbf8f755c"
dependencies = [
"anchor-syn",
"anyhow",
"proc-macro2",
"quote",
"regex",
"syn",
]
[[package]]
name = "anchor-attribute-account"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b65f521e0b4ac27b4df15f5dd65c8c468887debc62a2e553fbb34b3172d09a0"
dependencies = [
"anchor-syn",
"anyhow",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "anchor-attribute-error"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4f778a066327b8ae905a31cdf80fbc7476a0601c745f08e7010c4e1728125f6f"
dependencies = [
"anchor-syn",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "anchor-attribute-interface"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "200f17ff304a8b501194f1028ee6bbcb88c1c820f47a4f5e589cb24458da4bcf"
dependencies = [
"anchor-syn",
"anyhow",
"heck",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "anchor-attribute-program"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84459fc50f5c9c2b39226c0f06a831b4f341046ec27f5e87449f536db372116f"
dependencies = [
"anchor-syn",
"anyhow",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "anchor-attribute-state"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7857e7b9cf52321653ec89b5ab0486d189953128274e4be2d131e70f274e85c5"
dependencies = [
"anchor-syn",
"anyhow",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "anchor-derive-accounts"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc3d3d0bf656d6606be906418c671540e79748de28787017ef2e1f88af452544"
dependencies = [
"anchor-syn",
"anyhow",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "anchor-lang"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d32e5b3b27593f5f2de3d980423c3ec8aef1350fbc5052b671001811743575f"
dependencies = [
"anchor-attribute-access-control",
"anchor-attribute-account",
"anchor-attribute-error",
"anchor-attribute-interface",
"anchor-attribute-program",
"anchor-attribute-state",
"anchor-derive-accounts",
"serum-borsh",
"solana-program",
"thiserror",
]
[[package]]
name = "anchor-syn"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c40b707f33392ee103f2255b392a703204f6c9c07652ba689abff3a35cdec8e"
dependencies = [
"anyhow",
"bs58",
"heck",
"proc-macro2",
"quote",
"serde",
"serde_json",
"sha2 0.9.3",
"syn",
"thiserror",
]
[[package]]
name = "anyhow"
version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afddf7f520a80dbf76e6f50a35bca42a2331ef227a28b3b6dc5c2e2338d114b1"
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi",
"libc",
"winapi",
]
[[package]]
name = "autocfg"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]]
name = "bincode"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d175dfa69e619905c4c3cdb7c3c203fa3bdd5d51184e3afdb2742c0280493772"
dependencies = [
"byteorder",
"serde",
]
[[package]]
name = "block-buffer"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b"
dependencies = [
"block-padding",
"byte-tools",
"byteorder",
"generic-array 0.12.4",
]
[[package]]
name = "block-buffer"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
dependencies = [
"generic-array 0.14.4",
]
[[package]]
name = "block-padding"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5"
dependencies = [
"byte-tools",
]
[[package]]
name = "borsh-derive"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "307f3740906bac2c118a8122fe22681232b244f1369273e45f1156b45c43d2dd"
dependencies = [
"borsh-derive-internal",
"borsh-schema-derive-internal",
"proc-macro-crate",
"proc-macro2",
"syn",
]
[[package]]
name = "borsh-derive-internal"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2104c73179359431cc98e016998f2f23bc7a05bc53e79741bcba705f30047bc"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "borsh-schema-derive-internal"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae29eb8418fcd46f723f8691a2ac06857d31179d33d2f2d91eb13967de97c728"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "bs58"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "476e9cd489f9e121e02ffa6014a8ef220ecb15c05ed23fc34cca13925dc283fb"
[[package]]
name = "bv"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8834bb1d8ee5dc048ee3124f2c7c1afcc6bc9aed03f11e9dfd8c69470a5db340"
dependencies = [
"feature-probe",
"serde",
]
[[package]]
name = "byte-tools"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
[[package]]
name = "byteorder"
version = "1.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cpuid-bool"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634"
[[package]]
name = "curve25519-dalek"
version = "2.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "434e1720189a637d44fe464f4df1e6eb900b4835255b14354497c78af37d9bb8"
dependencies = [
"byteorder",
"digest 0.8.1",
"rand_core",
"subtle",
"zeroize",
]
[[package]]
name = "digest"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5"
dependencies = [
"generic-array 0.12.4",
]
[[package]]
name = "digest"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
dependencies = [
"generic-array 0.14.4",
]
[[package]]
name = "either"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
[[package]]
name = "env_logger"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17392a012ea30ef05a610aa97dfb49496e71c9f676b27879922ea5bdf60d9d3f"
dependencies = [
"atty",
"humantime",
"log",
"regex",
"termcolor",
]
[[package]]
name = "fake-simd"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
[[package]]
name = "feature-probe"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "835a3dc7d1ec9e75e2b5fb4ba75396837112d2060b03f7d43bc1897c7f7211da"
[[package]]
name = "generic-array"
version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd"
dependencies = [
"typenum",
]
[[package]]
name = "generic-array"
version = "0.14.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817"
dependencies = [
"serde",
"typenum",
"version_check",
]
[[package]]
name = "getrandom"
version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "hashbrown"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04"
dependencies = [
"ahash",
]
[[package]]
name = "heck"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87cbf45460356b7deeb5e3415b5563308c0a9b057c85e12b06ad551f98d0a6ac"
dependencies = [
"unicode-segmentation",
]
[[package]]
name = "hermit-abi"
version = "0.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c"
dependencies = [
"libc",
]
[[package]]
name = "hex"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "humantime"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
name = "itertools"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b"
dependencies = [
"either",
]
[[package]]
name = "itoa"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.88"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03b07a082330a35e43f63177cc01689da34fbffa0105e1246cf0311472cac73a"
[[package]]
name = "log"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
dependencies = [
"cfg-if",
]
[[package]]
name = "memchr"
version = "2.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525"
[[package]]
name = "memmap2"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b70ca2a6103ac8b665dc150b142ef0e4e89df640c9e6cf295d189c3caebe5a"
dependencies = [
"libc",
]
[[package]]
name = "multisig"
version = "0.1.0"
dependencies = [
"anchor-lang",
]
[[package]]
name = "num-derive"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "num-traits"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
dependencies = [
"autocfg",
]
[[package]]
name = "once_cell"
version = "1.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3"
[[package]]
name = "opaque-debug"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
[[package]]
name = "opaque-debug"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
[[package]]
name = "ppv-lite86"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
[[package]]
name = "proc-macro-crate"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785"
dependencies = [
"toml",
]
[[package]]
name = "proc-macro2"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
dependencies = [
"unicode-xid",
]
[[package]]
name = "quote"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
dependencies = [
"getrandom",
"libc",
"rand_chacha",
"rand_core",
"rand_hc",
]
[[package]]
name = "rand_chacha"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
dependencies = [
"getrandom",
]
[[package]]
name = "rand_hc"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
dependencies = [
"rand_core",
]
[[package]]
name = "regex"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9251239e129e16308e70d853559389de218ac275b515068abc96829d05b948a"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
"thread_local",
]
[[package]]
name = "regex-syntax"
version = "0.6.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5eb417147ba9860a96cfe72a0b93bf88fee1744b5636ec99ab20c1aa9376581"
[[package]]
name = "rustc_version"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
dependencies = [
"semver",
]
[[package]]
name = "rustversion"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb5d2a036dc6d2d8fd16fde3498b04306e29bd193bf306a57427019b823d5acd"
[[package]]
name = "ryu"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
[[package]]
name = "semver"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
dependencies = [
"semver-parser",
]
[[package]]
name = "semver-parser"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
[[package]]
name = "serde"
version = "1.0.118"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06c64263859d87aa2eb554587e2d23183398d617427327cf2b3d0ed8c69e4800"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_bytes"
version = "0.11.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "16ae07dd2f88a366f15bd0632ba725227018c69a1c8550a927324f8eb8368bb9"
dependencies = [
"serde",
]
[[package]]
name = "serde_derive"
version = "1.0.118"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c84d3526699cd55261af4b941e4e725444df67aa4f9e6a3564f18030d12672df"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "serum-borsh"
version = "0.8.1-serum.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4fed3f601b23f15dc890f6e52ffdbfe2dcf16418a41e0aa016b5f10cf30c892"
dependencies = [
"borsh-derive",
"hashbrown",
"solana-program",
]
[[package]]
name = "sha2"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a256f46ea78a0c0d9ff00077504903ac881a1dafdc20da66545699e7776b3e69"
dependencies = [
"block-buffer 0.7.3",
"digest 0.8.1",
"fake-simd",
"opaque-debug 0.2.3",
]
[[package]]
name = "sha2"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa827a14b29ab7f44778d14a88d3cb76e949c45083f7dbfa507d0cb699dc12de"
dependencies = [
"block-buffer 0.9.0",
"cfg-if",
"cpuid-bool",
"digest 0.9.0",
"opaque-debug 0.3.0",
]
[[package]]
name = "solana-frozen-abi"
version = "1.5.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c3476d3735fcbd907c86095cf4de0272a11753354bfc8484556173d4a9b458e"
dependencies = [
"bs58",
"bv",
"generic-array 0.14.4",
"log",
"memmap2",
"rustc_version",
"serde",
"serde_derive",
"sha2 0.9.3",
"solana-frozen-abi-macro",
"solana-logger",
"thiserror",
]
[[package]]
name = "solana-frozen-abi-macro"
version = "1.5.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33137fde347f368f3a44992544a799e9cd64276d391b9e7339468512e919ffac"
dependencies = [
"lazy_static",
"proc-macro2",
"quote",
"rustc_version",
"syn",
]
[[package]]
name = "solana-logger"
version = "1.5.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70991babdd9869469fbe29119958ce5a26bad54418ed3248ce172807e112f106"
dependencies = [
"env_logger",
"lazy_static",
"log",
]
[[package]]
name = "solana-program"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a7df63d84d4ba7f67365d179b9994f2690554f313e219f29810b4583077e066"
dependencies = [
"bincode",
"bs58",
"bv",
"curve25519-dalek",
"hex",
"itertools",
"lazy_static",
"log",
"num-derive",
"num-traits",
"rand",
"rustc_version",
"rustversion",
"serde",
"serde_bytes",
"serde_derive",
"sha2 0.8.2",
"solana-frozen-abi",
"solana-frozen-abi-macro",
"solana-logger",
"solana-sdk-macro",
"thiserror",
]
[[package]]
name = "solana-sdk-macro"
version = "1.5.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a41c78a955eb8c4b5cd72c2450520fc9434b1953f9398f91d13a89d5db841505"
dependencies = [
"bs58",
"proc-macro2",
"quote",
"rustversion",
"syn",
]
[[package]]
name = "subtle"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e81da0851ada1f3e9d4312c704aa4f8806f0f9d69faaf8df2f3464b4a9437c2"
[[package]]
name = "syn"
version = "1.0.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4211ce9909eb971f111059df92c45640aad50a619cf55cd76476be803c4c68e6"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]]
name = "termcolor"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4"
dependencies = [
"winapi-util",
]
[[package]]
name = "thiserror"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0f4a65597094d4483ddaed134f409b2cb7c1beccf25201a9f73c719254fa98e"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "thread_local"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8018d24e04c95ac8790716a5987d0fec4f8b27249ffa0f7d33f1369bdfb88cbd"
dependencies = [
"once_cell",
]
[[package]]
name = "toml"
version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa"
dependencies = [
"serde",
]
[[package]]
name = "typenum"
version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33"
[[package]]
name = "unicode-segmentation"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796"
[[package]]
name = "unicode-xid"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
[[package]]
name = "version_check"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
[[package]]
name = "wasi"
version = "0.9.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
dependencies = [
"winapi",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "zeroize"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81a974bcdd357f0dca4d41677db03436324d45a4c9ed2d0b873a5a360ce41c36"

4
Cargo.toml Normal file
View File

@ -0,0 +1,4 @@
[workspace]
members = [
"programs/*"
]

20
README.md Normal file
View File

@ -0,0 +1,20 @@
# Multisig
An example of a multisig to execute arbitrary Solana transactions.
This program can be used to allow a multisig to govern anything a regular
Pubkey can govern. One can use the multisig as a BPF program upgrade
authority, a mint authority, etc.
To use, one must first create a `Multisig` account, specifying two important
parameters:
1. Owners - the set of addresses that sign transactions for the multisig.
2. Threshold - the number of signers required to execute a transaction.
Once the `Multisig` account is created, one can create a `Transaction`
account, specifying the parameters for a normal solana transaction.
To sign, owners should invoke the `approve` instruction, and finally,
the `execute_transaction`, once enough (i.e. `threhsold`) of the owners have
signed.

12
migrations/deploy.js Normal file
View File

@ -0,0 +1,12 @@
// Migrations are an early feature. Currently, they're nothing more than this
// single deploy script that's invoked from the CLI, injecting a provider
// configured from the workspace's Anchor.toml.
const anchor = require("@project-serum/anchor");
module.exports = async function (provider) {
// Configure client to use the provider.
anchor.setProvider(provider);
// Add your deploy script here.
}

View File

@ -0,0 +1,18 @@
[package]
name = "multisig"
version = "0.1.0"
description = "Created with Anchor"
edition = "2018"
[lib]
crate-type = ["cdylib", "lib"]
name = "multisig"
[features]
no-entrypoint = []
no-idl = []
cpi = ["no-entrypoint"]
default = []
[dependencies]
anchor-lang = "0.2.1"

View File

@ -0,0 +1,2 @@
[target.bpfel-unknown-unknown.dependencies.std]
features = []

View File

@ -0,0 +1,283 @@
//! An example of a multisig to execute arbitrary Solana transactions.
//!
//! This program can be used to allow a multisig to govern anything a regular
//! Pubkey can govern. One can use the multisig as a BPF program upgrade
//! authority, a mint authority, etc.
//!
//! To use, one must first create a `Multisig` account, specifying two important
//! parameters:
//!
//! 1. Owners - the set of addresses that sign transactions for the multisig.
//! 2. Threshold - the number of signers required to execute a transaction.
//!
//! Once the `Multisig` account is created, one can create a `Transaction`
//! account, specifying the parameters for a normal solana transaction.
//!
//! To sign, owners should invoke the `approve` instruction, and finally,
//! the `execute_transaction`, once enough (i.e. `threhsold`) of the owners have
//! signed.
#![feature(proc_macro_hygiene)]
use anchor_lang::prelude::*;
use anchor_lang::solana_program;
use anchor_lang::solana_program::instruction::Instruction;
use std::convert::Into;
#[program]
pub mod multisig {
use super::*;
// Initializes a new multisig account with a set of owners and a threshold.
pub fn create_multisig(
ctx: Context<CreateMultisig>,
owners: Vec<Pubkey>,
threshold: u64,
nonce: u8,
) -> Result<()> {
let multisig = &mut ctx.accounts.multisig;
multisig.owners = owners;
multisig.threshold = threshold;
multisig.nonce = nonce;
Ok(())
}
// Creates a new transaction account, automatically signed by the creator,
// which must be one of the owners of the multisig.
pub fn create_transaction(
ctx: Context<CreateTransaction>,
pid: Pubkey,
accs: Vec<TransactionAccount>,
data: Vec<u8>,
) -> Result<()> {
let owner_index = ctx
.accounts
.multisig
.owners
.iter()
.position(|a| a == ctx.accounts.proposer.key)
.ok_or(ErrorCode::InvalidOwner)?;
let mut signers = Vec::new();
signers.resize(ctx.accounts.multisig.owners.len(), false);
signers[owner_index] = true;
let tx = &mut ctx.accounts.transaction;
tx.program_id = pid;
tx.accounts = accs;
tx.data = data;
tx.signers = signers;
tx.multisig = *ctx.accounts.multisig.to_account_info().key;
tx.did_execute = false;
Ok(())
}
// Approves a transaction on behalf of an owner of the multisig.
pub fn approve(ctx: Context<Approve>) -> Result<()> {
let owner_index = ctx
.accounts
.multisig
.owners
.iter()
.position(|a| a == ctx.accounts.owner.key)
.ok_or(ErrorCode::InvalidOwner)?;
ctx.accounts.transaction.signers[owner_index] = true;
Ok(())
}
// Sets the owners field on the multisig. The only way this can be invoked
// is via a recursive call from execute_transaction -> set_owners.
pub fn set_owners(ctx: Context<Auth>, owners: Vec<Pubkey>) -> Result<()> {
let multisig = &mut ctx.accounts.multisig;
if (owners.len() as u64) < multisig.threshold {
multisig.threshold = owners.len() as u64;
}
multisig.owners = owners;
Ok(())
}
// Changes the execution threshold of the multisig. The only way this can be
// invoked is via a recursive call from execute_transaction ->
// change_threshold.
pub fn change_threshold(ctx: Context<Auth>, threshold: u64) -> Result<()> {
if threshold > ctx.accounts.multisig.owners.len() as u64 {
return Err(ErrorCode::InvalidThreshold.into());
}
let multisig = &mut ctx.accounts.multisig;
multisig.threshold = threshold;
Ok(())
}
// Executes the given transaction if threshold owners have signed it.
pub fn execute_transaction(ctx: Context<ExecuteTransaction>) -> Result<()> {
// Has this been executed already?
if ctx.accounts.transaction.did_execute {
return Err(ErrorCode::AlreadyExecuted.into());
}
// Do we have enough signers.
let sig_count = ctx
.accounts
.transaction
.signers
.iter()
.filter_map(|s| match s {
false => None,
true => Some(true),
})
.collect::<Vec<_>>()
.len() as u64;
if sig_count < ctx.accounts.multisig.threshold {
return Err(ErrorCode::NotEnoughSigners.into());
}
// Execute the transaction signed by the multisig.
let mut ix: Instruction = (&*ctx.accounts.transaction).into();
ix.accounts = ix
.accounts
.iter()
.map(|acc| {
if &acc.pubkey == ctx.accounts.multisig_signer.key {
AccountMeta::new_readonly(acc.pubkey, true)
} else {
acc.clone()
}
})
.collect();
let seeds = &[
ctx.accounts.multisig.to_account_info().key.as_ref(),
&[ctx.accounts.multisig.nonce],
];
let signer = &[&seeds[..]];
let accounts = ctx.remaining_accounts;
solana_program::program::invoke_signed(&ix, &accounts, signer)?;
// Burn the transaction to ensure one time use.
ctx.accounts.transaction.did_execute = true;
Ok(())
}
}
#[derive(Accounts)]
pub struct CreateMultisig<'info> {
#[account(init)]
multisig: ProgramAccount<'info, Multisig>,
rent: Sysvar<'info, Rent>,
}
#[derive(Accounts)]
pub struct CreateTransaction<'info> {
multisig: ProgramAccount<'info, Multisig>,
#[account(init)]
transaction: ProgramAccount<'info, Transaction>,
// One of the owners. Checked in the handler.
#[account(signer)]
proposer: AccountInfo<'info>,
rent: Sysvar<'info, Rent>,
}
#[derive(Accounts)]
pub struct Approve<'info> {
multisig: ProgramAccount<'info, Multisig>,
#[account(mut, belongs_to = multisig)]
transaction: ProgramAccount<'info, Transaction>,
// One of the multisig owners. Checked in the handler.
#[account(signer)]
owner: AccountInfo<'info>,
}
#[derive(Accounts)]
pub struct Auth<'info> {
#[account(mut)]
multisig: ProgramAccount<'info, Multisig>,
#[account(signer, seeds = [
multisig.to_account_info().key.as_ref(),
&[multisig.nonce],
])]
multisig_signer: AccountInfo<'info>,
}
#[derive(Accounts)]
pub struct ExecuteTransaction<'info> {
multisig: ProgramAccount<'info, Multisig>,
#[account(seeds = [
multisig.to_account_info().key.as_ref(),
&[multisig.nonce],
])]
multisig_signer: AccountInfo<'info>,
#[account(mut, belongs_to = multisig)]
transaction: ProgramAccount<'info, Transaction>,
}
#[account]
pub struct Multisig {
owners: Vec<Pubkey>,
threshold: u64,
nonce: u8,
}
#[account]
pub struct Transaction {
// The multisig account this transaction belongs to.
multisig: Pubkey,
// Target program to execute against.
program_id: Pubkey,
// Accounts requried for the transaction.
accounts: Vec<TransactionAccount>,
// Instruction data for the transaction.
data: Vec<u8>,
// signers[index] is true iff multisig.owners[index] signed the transaction.
signers: Vec<bool>,
// Boolean ensuring one time execution.
did_execute: bool,
}
impl From<&Transaction> for Instruction {
fn from(tx: &Transaction) -> Instruction {
Instruction {
program_id: tx.program_id,
accounts: tx.accounts.clone().into_iter().map(Into::into).collect(),
data: tx.data.clone(),
}
}
}
#[derive(AnchorSerialize, AnchorDeserialize, Clone)]
pub struct TransactionAccount {
pubkey: Pubkey,
is_signer: bool,
is_writable: bool,
}
impl From<TransactionAccount> for AccountMeta {
fn from(account: TransactionAccount) -> AccountMeta {
match account.is_writable {
false => AccountMeta::new_readonly(account.pubkey, account.is_signer),
true => AccountMeta::new(account.pubkey, account.is_signer),
}
}
}
#[error]
pub enum ErrorCode {
#[msg("The given owner is not part of this multisig.")]
InvalidOwner,
#[msg("Not enough owners signed this transaction.")]
NotEnoughSigners,
#[msg("Cannot delete a transaction that has been signed by an owner.")]
TransactionAlreadySigned,
#[msg("Overflow when adding.")]
Overflow,
#[msg("Cannot delete a transaction the owner did not create.")]
UnableToDelete,
#[msg("The given transaction has already been executed.")]
AlreadyExecuted,
#[msg("Threshold must be less than or equal to the number of owners.")]
InvalidThreshold,
}

133
tests/multisig.js Normal file
View File

@ -0,0 +1,133 @@
const anchor = require("@project-serum/anchor");
const assert = require("assert");
describe("multisig", () => {
// Configure the client to use the local cluster.
anchor.setProvider(anchor.Provider.env());
const program = anchor.workspace.Multisig;
it("Tests the multisig program", async () => {
const multisig = new anchor.web3.Account();
const [
multisigSigner,
nonce,
] = await anchor.web3.PublicKey.findProgramAddress(
[multisig.publicKey.toBuffer()],
program.programId
);
const multisigSize = 200; // Big enough.
const ownerA = new anchor.web3.Account();
const ownerB = new anchor.web3.Account();
const ownerC = new anchor.web3.Account();
const ownerD = new anchor.web3.Account();
const owners = [ownerA.publicKey, ownerB.publicKey, ownerC.publicKey];
const threshold = new anchor.BN(2);
await program.rpc.createMultisig(owners, threshold, nonce, {
accounts: {
multisig: multisig.publicKey,
rent: anchor.web3.SYSVAR_RENT_PUBKEY,
},
instructions: [
await program.account.multisig.createInstruction(
multisig,
multisigSize
),
],
signers: [multisig],
});
let multisigAccount = await program.account.multisig(multisig.publicKey);
assert.equal(multisigAccount.nonce, nonce);
assert.ok(multisigAccount.threshold.eq(new anchor.BN(2)));
assert.deepEqual(multisigAccount.owners, owners);
const pid = program.programId;
const accounts = [
{
pubkey: multisig.publicKey,
isWritable: true,
isSigner: false,
},
{
pubkey: multisigSigner,
isWritable: false,
isSigner: true,
},
];
const newOwners = [ownerA.publicKey, ownerB.publicKey, ownerD.publicKey];
const data = program.coder.instruction.encode('set_owners', {
owners: newOwners,
});
const transaction = new anchor.web3.Account();
const txSize = 1000; // Big enough, cuz I'm lazy.
await program.rpc.createTransaction(pid, accounts, data, {
accounts: {
multisig: multisig.publicKey,
transaction: transaction.publicKey,
proposer: ownerA.publicKey,
rent: anchor.web3.SYSVAR_RENT_PUBKEY,
},
instructions: [
await program.account.transaction.createInstruction(
transaction,
txSize
),
],
signers: [transaction, ownerA],
});
const txAccount = await program.account.transaction(transaction.publicKey);
assert.ok(txAccount.programId.equals(pid));
assert.deepEqual(txAccount.accounts, accounts);
assert.deepEqual(txAccount.data, data);
assert.ok(txAccount.multisig.equals(multisig.publicKey));
assert.equal(txAccount.didExecute, false);
// Other owner approves transactoin.
await program.rpc.approve({
accounts: {
multisig: multisig.publicKey,
transaction: transaction.publicKey,
owner: ownerB.publicKey,
},
signers: [ownerB],
});
// Now that we've reached the threshold, send the transactoin.
await program.rpc.executeTransaction({
accounts: {
multisig: multisig.publicKey,
multisigSigner,
transaction: transaction.publicKey,
},
remainingAccounts: program.instruction.setOwners
.accounts({
multisig: multisig.publicKey,
multisigSigner,
})
// Change the signer status on the vendor signer since it's signed by the program, not the client.
.map((meta) =>
meta.pubkey.equals(multisigSigner)
? { ...meta, isSigner: false }
: meta
)
.concat({
pubkey: program.programId,
isWritable: false,
isSigner: false,
}),
});
multisigAccount = await program.account.multisig(multisig.publicKey);
assert.equal(multisigAccount.nonce, nonce);
assert.ok(multisigAccount.threshold.eq(new anchor.BN(2)));
assert.deepEqual(multisigAccount.owners, newOwners);
});
});