Coder Social home page Coder Social logo

dartroom / contracts Goto Github PK

View Code? Open in Web Editor NEW
3.0 0.0 0.0 219 KB

A package that includes all Dartroom's smart contracts written in TEAL, with complete interfaces in TypeScript to interact with them.

License: MIT License

JavaScript 0.49% TypeScript 99.51%
algorand algorand-smart-contract algorand-teal

contracts's Introduction

A package that includes all Dartroom's smart contracts written in TEAL, with complete interfaces in TypeScript to interact with them.

The package includes the following:

  • Smart contracts (TEAL code that needs to be deployed)
  • Algo & ASA management of contracts (deploy the correct version with either Algo or ASA payments)
  • Transaction validation (enough min balance, NFT still available, state of contracts)
  • Contract-related functions (ABI hash conversion, global state parsing, address encoding)

Planned future expansion:

  • On-chain contract discovery

The interface gets the parameters for the specific contract function and returns an array of transactions that only need to be signed before they can be committed to the network.

Contracts:

npm version Publish License: MIT

Documenation

Warning Please note that all payment amounts in this package should be passed in as the base unit of the token. For details see: Payment Units

Installation

npm install @dartroom/contracts

Setup

You only need a connection to an Algorand Indexer and Node to get started.

import { Contracts } from "@dartroom/contracts" 

const contracts = new Conctract({
  indexer: {
    token: "",
    portNet: "",
    baseServer: "",
  },
  algod: {
    token: "",
    portNet: "",
    baseServer: "",
  },
	signature: false,
	authAddress: false,
})

Options

minBalanceFee?: number

Overwrite the default min balance fee for ASA opt-ins. Only use this if the min balance fee changes from the current default of 0.1 Algo in the future.

extendedTransactionFormat?: boolean

Extends the return format of the contract interaction functions. When enabled, the functions will not only return the standard AlgoSDK transaction format but add additional fields to make working with the transactions easier in a server + client-side setup.

serverSecret?: string

If a secret is provided and the extendedTransactionFormat is enabled, the return format will include a signed hash based on the txID signed with the secret. This will enable the system on the server to verify that the submitted transactions from the client were provided by the server and have not been altered in the client.

transactionBlobEncoding?: "Uint8Array" | "Base64"

If extendedTransactionFormat is enabled, this option will change the encoding of the original transaction in the blob field.

authAddress: boolean

Include the authAddress field in the transaction array return format. Some wallet apps and extensions, such as the AlgoSigner, require the auth field to support the use of rekeyed accounts.

signature: string

Include the server signature in the transaction array return format. The signature will be a hash of the txID signed with the server secret. The signature can be used to validate that a transaction sent back from the client was proposed by the server.

Note that you must provide a serverSecret to create server signatures.

Verify Transactions

import { Contracts } from "@dartroom/contracts" 

const contracts = new Conctract({
  indexer: {
    token: "",
    portNet: "",
    baseServer: "",
  },
  algod: {
    token: "",
    portNet: "",
    baseServer: "",
  },
	extendedTransactionFormat: true,
  serverSecret: serverSecret,
  transactionBlobEncoding: 'Uint8Array',
  authAddress: true,
  signature: true
})

// Request the transactions to perform a specific action on the contract.
const unsignedTxns = await contracts.fixedBid.buy({
  appId: 210217503,
  nNFTs: 2,
  buyerAddress: "FSQW3UTLB5IZ32ZE35MUDPNNAXHCBGMGAKXHR3ENQ5JMT43IB3BET7WPDE"
})

// Normally the unsigned transaction would be sent to the client from the server where they would be signed.For this example, the transactions get signed on the server (which, in practice, makes the server secret setup unnecessary as the transaction would never leave the server).
// All the extended transaction information must be returned from the server for this setup to work. When using a transaction signer, only sign the `blob` property and return it with the other transaction info. 
// When using the Dartroom package, this is not necessary. With that setup, you can provide the full extended transaction, and the sign function will return the full extended transaction info.
const signedTxns = txns.map((txn) => {
  return {
    ...txn,
    blob: decodeUnsignedTransaction(txn.blob).signTxn(sellerAccount.sk)
  }
})

// When receiving the transactions back from the client, the `verifyTxns` function can be used to verify the signature. The transaction will be hashed again and compared to the attached signature. If they are not equal or the signature field is missing, the function will throw an error. This way the server signature can be used to guard API routes from submitting transactions that where not proposed by your API.
contracts.verifyTxns(signedTxns)

Transaction Formatter

import { Contracts } from "@dartroom/contracts" 
import algosdk from "algosdk"

const contracts = new Conctract({
  indexer: {
    token: "",
    portNet: "",
    baseServer: "",
  },
  algod: {
    token: "",
    portNet: "",
    baseServer: "",
  },
	extendedTransactionFormat: true,
  serverSecret: serverSecret,
  transactionBlobEncoding: 'Uint8Array',
  authAddress: true,
  signature: true
})

const address = "FSQW3UTLB5IZ32ZE35MUDPNNAXHCBGMGAKXHR3ENQ5JMT43IB3BET7WPDE"

// For simplicity, we use the `algod` instance generated by the contract setup, but this is just a standard `algod` instance. A separate `algod` instance would work the exact same way.
const account = await contracts.algod.accountInformation(address).do()
let params = await contracts.algod.getTransactionParams().do()

params.flatFee = true
params.fee = 1000

// The first step is to create a new transaction format instance. Every new transaction (group) will require a new instance.
const formater = contracts.newTxnFormatter()

// All transactions are passed into the push function with the additional info for the extended transaction format.
formater.push({
  description: "Send a 0 Algo transaction to yourself to verify your account.",
  txn: algosdk.makePaymentTxnWithSuggestedParams(
    address,
    address,
    0,
    undefined,
    undefined,
    params
  ),
  signers: [address],
  authAddress: account["auth-addr"] || address,
})

// When all transactions are pushed into the formatter, you can get the formatted transactions back by calling `getTxns()`.
// Calling `getTxns()` will convert the `blob` field and attach the `signature` based on the Contract options.
const tnxs = formater.getTxns()

Grouped Transactions

If more than one transaction is pushed to the transaction formatter, the assignGroupID() function should be called. This function will generate a groupId for the transactions, which will create what is known as an Atomic Transfer on Algorand. Atomic Transfer groups can include a maximum of 16 transactions. If more than 16 transactions need to be submitted, the group should be split among multiple transaction fromatters.

txnFormater.assignGroupID()

const tnxs = formater.getTxns()

Payment Units

All Algorand transactions, and by extension contracts, work with integers only. The Algorand token, and all ASA tokens, have a specified decimals property that needs to be used to convert any float values back to integers for use in transactions.

The base unit conversion is not handled by the contract package to remove unnecessary Indexer calls. If you have a specific set of tokens that are allowed to be used on your platform, you can store the decimals statically, such as in the example below. The ASAToBaseInt and ASAToFloat functions can be used to convert the amounts between the contract system and any frontend system you may use.

const tokens: Array<ASA> = [
  {
    index: 0,
    unitName: "ALGO",
    assetName: "ALGO",
    decimals: 6,
  },
  {
    index: 31566704,
    unitName: "USDC",
    assetName: "USDC",
    decimals: 6,

  },
  {
    index: 386195940,
    unitName: "goETH",
    assetName: "goETH",
    decimals: 8,
  }
]

function ASAToBaseInt (asa: ASA, amount: number) {
  return amount * (10 ** asa.decimals)
}

function ASAToFloat (asa: ASA, amount: number) {
  return amount / (10 ** asa.decimals)
}

const unitName = "USDC"
const asa = tokens.find((token) => token.unitName === unitName)

const txns = await contracts.fixedBid.updatePrice({
  appId: 210217503,
  unitPrice: ASAToBaseInt(asa, set.price)
})

If all currencies are allowed on the platform, then the decimal settings can be fetched from the Indexer or Node.

const asaIndex = 386195940
const asaInfo = await algod.getAssetByID(386195940).do()

function ASAToBaseInt (asaInfo: ASAInfo, amount: number) {
  return amount * (10 ** asaInfo.params.decimals)
}

function ASAToFloat (asaInfo: ASAInfo, amount: number) {
  return amount / (10 ** asaInfo.params.decimals)
}

const txns = await contracts.fixedBid.updatePrice({
  appId: 210217503,
  unitPrice: ASAToBaseInt(asa, set.price)
})

contracts's People

Contributors

spencerjibz avatar stefdegroot avatar

Stargazers

 avatar  avatar  avatar

contracts's Issues

TEAL contract for auctions priced in Algo

Create and test a fully featured TEAL 6 contract of an auction with prices in Algo.

Features:

  • Build with a single stateful contract
  • Bidder pays the contract itself
  • end auction function that distributes all the funds
  • configurable payout address
  • configurable shares
  • configurable reserve price
  • configurable duration
  • min bid increase protection (to prevent share division errors)
  • snipe protection (min time to counter bid must be 30 min)
  • bid increment setting independent of share division protection

Tasks:

  • create TEAL contract
  • test all TEAL routes on Testnet

Linked transactions

Linked transactions to sign single depended transactions at once where possible.

Example:

const txns = [
	{
		description: "Opt-into USDCa.",
		blob: "",
		txID: "BHGYUJ6URPNUXIKKWCCF4GSDHOLEZENF5DL3MZUXF3OGX45GWZBA",
		signers: [
			"E3GZF5GUOQDW52TZ4X3PU5YR34447BOTVL6X3OOW3CB5EPHWIEISXK5BCI"
		],
		dependsOn: null,
		sSignature: ""
	},
	{
		description: "Claim USDCa from the revenue sink.",
		blob: "",
		txID: "KHBRJZ2LLIJOUOG6EC7OCIRZFWIPUJ6S55TAZCAOQS2I7V367SIQ",
		signers: [
			"E3GZF5GUOQDW52TZ4X3PU5YR34447BOTVL6X3OOW3CB5EPHWIEISXK5BCI"
		],
		dependsOn: "BHGYUJ6URPNUXIKKWCCF4GSDHOLEZENF5DL3MZUXF3OGX45GWZBA",
		sSignature: ""
	}
]

This way the frontend can be programmed based on the transaction array, dynamically creating an interface with two stages instead of one. In some cases transactions can not be grouped, but can be created already, like with this opt-in example.

We already know what the claim transaction format will be, we just can not send this as a group since the claim transaction can not be send in a round that the user is not opted into yet. So we make the transaction depended and now we know to wait with sending the second until after the first one went trough. (in this case it would not have mattered for signing, only for submitting)

To make the dependency system east to use we probably want to provide a submit transactions function that handles this.

Tasks:

  • add dependsOn property to transaction return format
  • implement a submitTransactions function, which takes into account the dependency order.

Server signed transactions

The current Dartroom systems rely on the submit verification (the method of submitting a transaction to verify the user is the owner of the address), but this is not protected from spoofing. An attacker could change out the blob of the object for another one of their liking and trick us into submitting the transaction. This will not directly affect the on-chain status, but it can make them pass the check in our API and manipulate the database state.

This problem stems mainly from the txID field is not secured, which represents the hash of the transaction values. If we add a signature to the object which is singed with a secret on the server and includes the txID in it's hash, we can verify the signature when the object is returned after signing. We can then decode the blob and check the secret validity against the txID from the blob the verify the correct transaction was send. If the txID is not the same it gets catches by the sig verification and if the blob has been modified to the same txID the Algorand node will report it as a invalid transaction.

const txn = {
	description: "Opt-into USDCa.",
	blob: "",
	txID: "BHGYUJ6URPNUXIKKWCCF4GSDHOLEZENF5DL3MZUXF3OGX45GWZBA",
	signers: [
		"E3GZF5GUOQDW52TZ4X3PU5YR34447BOTVL6X3OOW3CB5EPHWIEISXK5BCI"
	],
	dependsOn: null,
	sSignature: ""
}

We probably want to make this optional, to prevent client side limitations. In that case we expect the user will not care, since it will never update database information in that case. (or at least we are not the leak in that case)

The sSignature can be used to authenticate that the returned transaction originated from your server. If the transaction was manipulated or provided by another server the system will return an authentication error.

Tasks:

  • add sSignature field to return transactions format
  • add createSignature function
  • add verifySignature function

TEAL: AC fixed bid contract

Create and test a fully featured TEAL 6 contract of a fixed price listing with prices in any ASA.

Features:

  • Build with a single stateful contract
  • Buyer pays to the contract itself for individual shareholder claims
  • claim functions for all shareholders
  • configurable payout address
  • configurable shares
  • Multi-asset buying and listing (more than one token can be bought or listed at once in the same contract)
  • Extract tokens function
  • Deposit tokens function
  • close out as a separate function

Tasks:

  • create TEAL contract
  • test all TEAL routes on Testnet

Fixed bid contract interface

An interface that combines the Algo and ASA-priced listings into one system.

Functions:

  • create
  • deposit
  • extract
  • close-out
  • buy
  • claim share (only for ASA payments)
  • get state

Reserve auction contract interface

An interface that combines the Algo and ASA-priced auctions into one system.

Functions:

  • create
  • set (op the contract into the ASA's)
  • bid
  • claim nft
  • claim shares (only for ASA priced)
  • end auction
  • destroy
  • get state

TEAL: AC reserve auction contract

Create and test a fully featured TEAL 6 contract of an auction with prices in ASA.

Features:

  • Build with a single stateful contract
  • Bidder pays the contract itself for individual shareholder claims
  • backup bid repayment address in case of opt-out of the ASA
  • claim functions for all shareholders
  • configurable payout address
  • configurable shares
  • configurable reserve price
  • configurable duration
  • min bid increase protection (to prevent share division errors)
  • snipe protection (min time to counter bid must be 30 min)
  • close out as a separate function

Tasks:

  • create TEAL contract
  • test all TEAL routes on Testnet

TEAL: Algo fixed bid contract

Create and test a fully featured TEAL 6 contract of a fixed price listing with prices in Algorand.

Features:

  • Build with a single stateless contract
  • Direct payment from the buyer to shareholders
  • configurable payout address
  • configurable shares
  • Multi-asset buying and listing (more than one token can be bought or listed at once in the same contract)
  • Extract tokens function
  • Deposit tokens function
  • close out as a separate function

Tasks:

  • create TEAL contract
  • test all TEAL routes on Testnet

Base setup

Create a base setup for the contract interface system.

Tasks:

  • setup folder structure
  • setup base TypeScript interface
  • setup test environment in Node.js and browsers

FixedBid contract events

Find and return all events around the FixedBid contract. All events are parsed, and the original params are returned alongside the full transaction objects if requested.

Tasks:

  • Add new function on the fixed bid provider
  • Fetch all transactions on the /v2/accounts/:account-id/transactions indexer endpoint
  • Parse event types:
    • deploy
    • setup
    • deposit
    • buy
    • extract
    • destroy

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.