Skip to content
This repository has been archived by the owner on Feb 23, 2023. It is now read-only.

Expose reverts to mappings #74

Merged
merged 3 commits into from
Sep 2, 2019
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 62 additions & 8 deletions index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export declare namespace store {

/** Host Ethereum interface */
declare namespace ethereum {
function call(call: SmartContractCall): Array<EthereumValue>
function call(call: SmartContractCall): Array<EthereumValue> | null
}

/** Host IPFS interface */
Expand Down Expand Up @@ -656,15 +656,15 @@ export class BigDecimal {

let aTotalLength = BigInt.fromI32(aRelevantDigits as i32) + a.exp
let bTotalLength = BigInt.fromI32(bRelevantDigits as i32) + b.exp

// If a and b are positive then the longer one is larger.
// Otherwise the shorter one is larger.
if (aTotalLength > bTotalLength) {
return aIsNeg ? -1 : 1
} else if (bTotalLength > aTotalLength) {
return aIsNeg ? 1 : -1
}

// We now know that a and b have the same sign and total length. If a and b
// are both negative then the one of lesser magnitude is the largest,
// however since in two's complement the magnitude is flipped, we may use
Expand All @@ -681,7 +681,7 @@ export class BigDecimal {
return 1
}
}

return 0
}
}
Expand Down Expand Up @@ -768,8 +768,9 @@ export class EthereumValue {
}

toTupleArray<T extends EthereumTuple>(): Array<T> {
assert(this.kind == EthereumValueKind.ARRAY || this.kind == EthereumValueKind.FIXED_ARRAY,
'EthereumValue is not an array.'
assert(
this.kind == EthereumValueKind.ARRAY || this.kind == EthereumValueKind.FIXED_ARRAY,
'EthereumValue is not an array.',
)
let valueArray = this.toArray()
let out = new Array<T>(valueArray.length)
Expand Down Expand Up @@ -931,7 +932,7 @@ export class EthereumValue {

static fromTupleArray(values: Array<EthereumTuple>): EthereumValue {
let out = new Array<EthereumValue>(values.length)
for(let i: i32 = 0; i < values.length; i++) {
for (let i: i32 = 0; i < values.length; i++) {
out[i] = EthereumValue.fromTuple(values[i])
}
return EthereumValue.fromArray(out)
Expand Down Expand Up @@ -1381,7 +1382,22 @@ export class SmartContract {

call(name: string, params: Array<EthereumValue>): Array<EthereumValue> {
let call = new SmartContractCall(this._name, this._address, name, params)
return ethereum.call(call)
let result = ethereum.call(call)
assert(
result != null,
'Call reverted, consider using `try_' + name + '` to handle this in the mapping.',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's make this even more useful by mentioning that this usually means an assert/require in the contract has failed. Not everyone will understand what "reverted" means in this case.

)
return ethereum.call(call) as Array<EthereumValue>
}

tryCall(name: string, params: Array<EthereumValue>): CallResult<Array<EthereumValue>> {
let call = new SmartContractCall(this._name, this._address, name, params)
let result = ethereum.call(call)
if (result == null) {
return new CallResult()
} else {
return CallResult.fromValue(result as Array<EthereumValue>)
}
}
}

Expand Down Expand Up @@ -1469,3 +1485,41 @@ export class DataSourceTemplate {
dataSource.create(name, params)
}
}

// This is used to wrap a generic so that it can be unioned with `null`, working around limitations
// with primitives.
class Wrapped<T> {
inner: T

constructor(inner: T) {
this.inner = inner
}
}

export class CallResult<T> {
// `null` indicates a reverted call.
private _value: Wrapped<T> | null

constructor() {
this._value = null
}

static fromValue<T>(value: T): CallResult<T> {
let result = new CallResult<T>()
result._value = new Wrapped(value)
return result
}

get reverted(): bool {
return this._value == null
}

get value(): T {
assert(
!this.reverted,
'accessed value of a reverted call, '
+ 'please check the `reverted` field before accessing the `value` field',
)
return (this._value as Wrapped<T>).inner
}
}