mirror of
https://github.com/status-im/github-oracle.git
synced 2026-08-27 09:51:10 +00:00
@@ -0,0 +1,711 @@
|
||||
/*
|
||||
* @title String & slice utility library for Solidity contracts.
|
||||
* @author Nick Johnson <arachnid@notdot.net>
|
||||
*
|
||||
* @dev Functionality in this library is largely implemented using an
|
||||
* abstraction called a 'slice'. A slice represents a part of a string -
|
||||
* anything from the entire string to a single character, or even no
|
||||
* characters at all (a 0-length slice). Since a slice only has to specify
|
||||
* an offset and a length, copying and manipulating slices is a lot less
|
||||
* expensive than copying and manipulating the strings they reference.
|
||||
*
|
||||
* To further reduce gas costs, most functions on slice that need to return
|
||||
* a slice modify the original one instead of allocating a new one; for
|
||||
* instance, `s.split(".")` will return the text up to the first '.',
|
||||
* modifying s to only contain the remainder of the string after the '.'.
|
||||
* In situations where you do not want to modify the original slice, you
|
||||
* can make a copy first with `.copy()`, for example:
|
||||
* `s.copy().split(".")`. Try and avoid using this idiom in loops; since
|
||||
* Solidity has no memory management, it will result in allocating many
|
||||
* short-lived slices that are later discarded.
|
||||
*
|
||||
* Functions that return two slices come in two versions: a non-allocating
|
||||
* version that takes the second slice as an argument, modifying it in
|
||||
* place, and an allocating version that allocates and returns the second
|
||||
* slice; see `nextRune` for example.
|
||||
*
|
||||
* Functions that have to copy string data will return strings rather than
|
||||
* slices; these can be cast back to slices for further processing if
|
||||
* required.
|
||||
*
|
||||
* For convenience, some functions are provided with non-modifying
|
||||
* variants that create a new slice and return both; for instance,
|
||||
* `s.splitNew('.')` leaves s unmodified, and returns two values
|
||||
* corresponding to the left and right parts of the string.
|
||||
*/
|
||||
pragma solidity ^0.4.11;
|
||||
|
||||
library strings {
|
||||
struct slice {
|
||||
uint _len;
|
||||
uint _ptr;
|
||||
}
|
||||
|
||||
function memcpy(uint dest, uint src, uint len) private {
|
||||
// Copy word-length chunks while possible
|
||||
for(; len >= 32; len -= 32) {
|
||||
assembly {
|
||||
mstore(dest, mload(src))
|
||||
}
|
||||
dest += 32;
|
||||
src += 32;
|
||||
}
|
||||
|
||||
// Copy remaining bytes
|
||||
uint mask = 256 ** (32 - len) - 1;
|
||||
assembly {
|
||||
let srcpart := and(mload(src), not(mask))
|
||||
let destpart := and(mload(dest), mask)
|
||||
mstore(dest, or(destpart, srcpart))
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @dev Returns a slice containing the entire string.
|
||||
* @param self The string to make a slice from.
|
||||
* @return A newly allocated slice containing the entire string.
|
||||
*/
|
||||
function toSlice(string self) internal returns (slice) {
|
||||
uint ptr;
|
||||
assembly {
|
||||
ptr := add(self, 0x20)
|
||||
}
|
||||
return slice(bytes(self).length, ptr);
|
||||
}
|
||||
|
||||
/*
|
||||
* @dev Returns the length of a null-terminated bytes32 string.
|
||||
* @param self The value to find the length of.
|
||||
* @return The length of the string, from 0 to 32.
|
||||
*/
|
||||
function len(bytes32 self) internal returns (uint) {
|
||||
uint ret;
|
||||
if (self == 0)
|
||||
return 0;
|
||||
if (self & 0xffffffffffffffffffffffffffffffff == 0) {
|
||||
ret += 16;
|
||||
self = bytes32(uint(self) / 0x100000000000000000000000000000000);
|
||||
}
|
||||
if (self & 0xffffffffffffffff == 0) {
|
||||
ret += 8;
|
||||
self = bytes32(uint(self) / 0x10000000000000000);
|
||||
}
|
||||
if (self & 0xffffffff == 0) {
|
||||
ret += 4;
|
||||
self = bytes32(uint(self) / 0x100000000);
|
||||
}
|
||||
if (self & 0xffff == 0) {
|
||||
ret += 2;
|
||||
self = bytes32(uint(self) / 0x10000);
|
||||
}
|
||||
if (self & 0xff == 0) {
|
||||
ret += 1;
|
||||
}
|
||||
return 32 - ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* @dev Returns a slice containing the entire bytes32, interpreted as a
|
||||
* null-termintaed utf-8 string.
|
||||
* @param self The bytes32 value to convert to a slice.
|
||||
* @return A new slice containing the value of the input argument up to the
|
||||
* first null.
|
||||
*/
|
||||
function toSliceB32(bytes32 self) internal returns (slice ret) {
|
||||
// Allocate space for `self` in memory, copy it there, and point ret at it
|
||||
assembly {
|
||||
let ptr := mload(0x40)
|
||||
mstore(0x40, add(ptr, 0x20))
|
||||
mstore(ptr, self)
|
||||
mstore(add(ret, 0x20), ptr)
|
||||
}
|
||||
ret._len = len(self);
|
||||
}
|
||||
|
||||
/*
|
||||
* @dev Returns a new slice containing the same data as the current slice.
|
||||
* @param self The slice to copy.
|
||||
* @return A new slice containing the same data as `self`.
|
||||
*/
|
||||
function copy(slice self) internal returns (slice) {
|
||||
return slice(self._len, self._ptr);
|
||||
}
|
||||
|
||||
/*
|
||||
* @dev Copies a slice to a new string.
|
||||
* @param self The slice to copy.
|
||||
* @return A newly allocated string containing the slice's text.
|
||||
*/
|
||||
function toString(slice self) internal returns (string) {
|
||||
var ret = new string(self._len);
|
||||
uint retptr;
|
||||
assembly { retptr := add(ret, 32) }
|
||||
|
||||
memcpy(retptr, self._ptr, self._len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* @dev Returns the length in runes of the slice. Note that this operation
|
||||
* takes time proportional to the length of the slice; avoid using it
|
||||
* in loops, and call `slice.empty()` if you only need to know whether
|
||||
* the slice is empty or not.
|
||||
* @param self The slice to operate on.
|
||||
* @return The length of the slice in runes.
|
||||
*/
|
||||
function len(slice self) internal returns (uint) {
|
||||
// Starting at ptr-31 means the LSB will be the byte we care about
|
||||
var ptr = self._ptr - 31;
|
||||
var end = ptr + self._len;
|
||||
for (uint len = 0; ptr < end; len++) {
|
||||
uint8 b;
|
||||
assembly { b := and(mload(ptr), 0xFF) }
|
||||
if (b < 0x80) {
|
||||
ptr += 1;
|
||||
} else if(b < 0xE0) {
|
||||
ptr += 2;
|
||||
} else if(b < 0xF0) {
|
||||
ptr += 3;
|
||||
} else if(b < 0xF8) {
|
||||
ptr += 4;
|
||||
} else if(b < 0xFC) {
|
||||
ptr += 5;
|
||||
} else {
|
||||
ptr += 6;
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
/*
|
||||
* @dev Returns true if the slice is empty (has a length of 0).
|
||||
* @param self The slice to operate on.
|
||||
* @return True if the slice is empty, False otherwise.
|
||||
*/
|
||||
function empty(slice self) internal returns (bool) {
|
||||
return self._len == 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* @dev Returns a positive number if `other` comes lexicographically after
|
||||
* `self`, a negative number if it comes before, or zero if the
|
||||
* contents of the two slices are equal. Comparison is done per-rune,
|
||||
* on unicode codepoints.
|
||||
* @param self The first slice to compare.
|
||||
* @param other The second slice to compare.
|
||||
* @return The result of the comparison.
|
||||
*/
|
||||
function compare(slice self, slice other) internal returns (int) {
|
||||
uint shortest = self._len;
|
||||
if (other._len < self._len)
|
||||
shortest = other._len;
|
||||
|
||||
var selfptr = self._ptr;
|
||||
var otherptr = other._ptr;
|
||||
for (uint idx = 0; idx < shortest; idx += 32) {
|
||||
uint a;
|
||||
uint b;
|
||||
assembly {
|
||||
a := mload(selfptr)
|
||||
b := mload(otherptr)
|
||||
}
|
||||
if (a != b) {
|
||||
// Mask out irrelevant bytes and check again
|
||||
uint mask = ~(2 ** (8 * (32 - shortest + idx)) - 1);
|
||||
var diff = (a & mask) - (b & mask);
|
||||
if (diff != 0)
|
||||
return int(diff);
|
||||
}
|
||||
selfptr += 32;
|
||||
otherptr += 32;
|
||||
}
|
||||
return int(self._len) - int(other._len);
|
||||
}
|
||||
|
||||
/*
|
||||
* @dev Returns true if the two slices contain the same text.
|
||||
* @param self The first slice to compare.
|
||||
* @param self The second slice to compare.
|
||||
* @return True if the slices are equal, false otherwise.
|
||||
*/
|
||||
function equals(slice self, slice other) internal returns (bool) {
|
||||
return compare(self, other) == 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* @dev Extracts the first rune in the slice into `rune`, advancing the
|
||||
* slice to point to the next rune and returning `self`.
|
||||
* @param self The slice to operate on.
|
||||
* @param rune The slice that will contain the first rune.
|
||||
* @return `rune`.
|
||||
*/
|
||||
function nextRune(slice self, slice rune) internal returns (slice) {
|
||||
rune._ptr = self._ptr;
|
||||
|
||||
if (self._len == 0) {
|
||||
rune._len = 0;
|
||||
return rune;
|
||||
}
|
||||
|
||||
uint len;
|
||||
uint b;
|
||||
// Load the first byte of the rune into the LSBs of b
|
||||
assembly { b := and(mload(sub(mload(add(self, 32)), 31)), 0xFF) }
|
||||
if (b < 0x80) {
|
||||
len = 1;
|
||||
} else if(b < 0xE0) {
|
||||
len = 2;
|
||||
} else if(b < 0xF0) {
|
||||
len = 3;
|
||||
} else {
|
||||
len = 4;
|
||||
}
|
||||
|
||||
// Check for truncated codepoints
|
||||
if (len > self._len) {
|
||||
rune._len = self._len;
|
||||
self._ptr += self._len;
|
||||
self._len = 0;
|
||||
return rune;
|
||||
}
|
||||
|
||||
self._ptr += len;
|
||||
self._len -= len;
|
||||
rune._len = len;
|
||||
return rune;
|
||||
}
|
||||
|
||||
/*
|
||||
* @dev Returns the first rune in the slice, advancing the slice to point
|
||||
* to the next rune.
|
||||
* @param self The slice to operate on.
|
||||
* @return A slice containing only the first rune from `self`.
|
||||
*/
|
||||
function nextRune(slice self) internal returns (slice ret) {
|
||||
nextRune(self, ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* @dev Returns the number of the first codepoint in the slice.
|
||||
* @param self The slice to operate on.
|
||||
* @return The number of the first codepoint in the slice.
|
||||
*/
|
||||
function ord(slice self) internal returns (uint ret) {
|
||||
if (self._len == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint word;
|
||||
uint len;
|
||||
uint div = 2 ** 248;
|
||||
|
||||
// Load the rune into the MSBs of b
|
||||
assembly { word:= mload(mload(add(self, 32))) }
|
||||
var b = word / div;
|
||||
if (b < 0x80) {
|
||||
ret = b;
|
||||
len = 1;
|
||||
} else if(b < 0xE0) {
|
||||
ret = b & 0x1F;
|
||||
len = 2;
|
||||
} else if(b < 0xF0) {
|
||||
ret = b & 0x0F;
|
||||
len = 3;
|
||||
} else {
|
||||
ret = b & 0x07;
|
||||
len = 4;
|
||||
}
|
||||
|
||||
// Check for truncated codepoints
|
||||
if (len > self._len) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (uint i = 1; i < len; i++) {
|
||||
div = div / 256;
|
||||
b = (word / div) & 0xFF;
|
||||
if (b & 0xC0 != 0x80) {
|
||||
// Invalid UTF-8 sequence
|
||||
return 0;
|
||||
}
|
||||
ret = (ret * 64) | (b & 0x3F);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* @dev Returns the keccak-256 hash of the slice.
|
||||
* @param self The slice to hash.
|
||||
* @return The hash of the slice.
|
||||
*/
|
||||
function keccak(slice self) internal returns (bytes32 ret) {
|
||||
assembly {
|
||||
ret := sha3(mload(add(self, 32)), mload(self))
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @dev Returns true if `self` starts with `needle`.
|
||||
* @param self The slice to operate on.
|
||||
* @param needle The slice to search for.
|
||||
* @return True if the slice starts with the provided text, false otherwise.
|
||||
*/
|
||||
function startsWith(slice self, slice needle) internal returns (bool) {
|
||||
if (self._len < needle._len) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (self._ptr == needle._ptr) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool equal;
|
||||
assembly {
|
||||
let len := mload(needle)
|
||||
let selfptr := mload(add(self, 0x20))
|
||||
let needleptr := mload(add(needle, 0x20))
|
||||
equal := eq(sha3(selfptr, len), sha3(needleptr, len))
|
||||
}
|
||||
return equal;
|
||||
}
|
||||
|
||||
/*
|
||||
* @dev If `self` starts with `needle`, `needle` is removed from the
|
||||
* beginning of `self`. Otherwise, `self` is unmodified.
|
||||
* @param self The slice to operate on.
|
||||
* @param needle The slice to search for.
|
||||
* @return `self`
|
||||
*/
|
||||
function beyond(slice self, slice needle) internal returns (slice) {
|
||||
if (self._len < needle._len) {
|
||||
return self;
|
||||
}
|
||||
|
||||
bool equal = true;
|
||||
if (self._ptr != needle._ptr) {
|
||||
assembly {
|
||||
let len := mload(needle)
|
||||
let selfptr := mload(add(self, 0x20))
|
||||
let needleptr := mload(add(needle, 0x20))
|
||||
equal := eq(sha3(selfptr, len), sha3(needleptr, len))
|
||||
}
|
||||
}
|
||||
|
||||
if (equal) {
|
||||
self._len -= needle._len;
|
||||
self._ptr += needle._len;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/*
|
||||
* @dev Returns true if the slice ends with `needle`.
|
||||
* @param self The slice to operate on.
|
||||
* @param needle The slice to search for.
|
||||
* @return True if the slice starts with the provided text, false otherwise.
|
||||
*/
|
||||
function endsWith(slice self, slice needle) internal returns (bool) {
|
||||
if (self._len < needle._len) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var selfptr = self._ptr + self._len - needle._len;
|
||||
|
||||
if (selfptr == needle._ptr) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool equal;
|
||||
assembly {
|
||||
let len := mload(needle)
|
||||
let needleptr := mload(add(needle, 0x20))
|
||||
equal := eq(sha3(selfptr, len), sha3(needleptr, len))
|
||||
}
|
||||
|
||||
return equal;
|
||||
}
|
||||
|
||||
/*
|
||||
* @dev If `self` ends with `needle`, `needle` is removed from the
|
||||
* end of `self`. Otherwise, `self` is unmodified.
|
||||
* @param self The slice to operate on.
|
||||
* @param needle The slice to search for.
|
||||
* @return `self`
|
||||
*/
|
||||
function until(slice self, slice needle) internal returns (slice) {
|
||||
if (self._len < needle._len) {
|
||||
return self;
|
||||
}
|
||||
|
||||
var selfptr = self._ptr + self._len - needle._len;
|
||||
bool equal = true;
|
||||
if (selfptr != needle._ptr) {
|
||||
assembly {
|
||||
let len := mload(needle)
|
||||
let needleptr := mload(add(needle, 0x20))
|
||||
equal := eq(sha3(selfptr, len), sha3(needleptr, len))
|
||||
}
|
||||
}
|
||||
|
||||
if (equal) {
|
||||
self._len -= needle._len;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
// Returns the memory address of the first byte of the first occurrence of
|
||||
// `needle` in `self`, or the first byte after `self` if not found.
|
||||
function findPtr(uint selflen, uint selfptr, uint needlelen, uint needleptr) private returns (uint) {
|
||||
uint ptr;
|
||||
uint idx;
|
||||
|
||||
if (needlelen <= selflen) {
|
||||
if (needlelen <= 32) {
|
||||
// Optimized assembly for 68 gas per byte on short strings
|
||||
assembly {
|
||||
let mask := not(sub(exp(2, mul(8, sub(32, needlelen))), 1))
|
||||
let needledata := and(mload(needleptr), mask)
|
||||
let end := add(selfptr, sub(selflen, needlelen))
|
||||
ptr := selfptr
|
||||
loop:
|
||||
jumpi(exit, eq(and(mload(ptr), mask), needledata))
|
||||
ptr := add(ptr, 1)
|
||||
jumpi(loop, lt(sub(ptr, 1), end))
|
||||
ptr := add(selfptr, selflen)
|
||||
exit:
|
||||
}
|
||||
return ptr;
|
||||
} else {
|
||||
// For long needles, use hashing
|
||||
bytes32 hash;
|
||||
assembly { hash := sha3(needleptr, needlelen) }
|
||||
ptr = selfptr;
|
||||
for (idx = 0; idx <= selflen - needlelen; idx++) {
|
||||
bytes32 testHash;
|
||||
assembly { testHash := sha3(ptr, needlelen) }
|
||||
if (hash == testHash)
|
||||
return ptr;
|
||||
ptr += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return selfptr + selflen;
|
||||
}
|
||||
|
||||
// Returns the memory address of the first byte after the last occurrence of
|
||||
// `needle` in `self`, or the address of `self` if not found.
|
||||
function rfindPtr(uint selflen, uint selfptr, uint needlelen, uint needleptr) private returns (uint) {
|
||||
uint ptr;
|
||||
|
||||
if (needlelen <= selflen) {
|
||||
if (needlelen <= 32) {
|
||||
// Optimized assembly for 69 gas per byte on short strings
|
||||
assembly {
|
||||
let mask := not(sub(exp(2, mul(8, sub(32, needlelen))), 1))
|
||||
let needledata := and(mload(needleptr), mask)
|
||||
ptr := add(selfptr, sub(selflen, needlelen))
|
||||
loop:
|
||||
jumpi(ret, eq(and(mload(ptr), mask), needledata))
|
||||
ptr := sub(ptr, 1)
|
||||
jumpi(loop, gt(add(ptr, 1), selfptr))
|
||||
ptr := selfptr
|
||||
jump(exit)
|
||||
ret:
|
||||
ptr := add(ptr, needlelen)
|
||||
exit:
|
||||
}
|
||||
return ptr;
|
||||
} else {
|
||||
// For long needles, use hashing
|
||||
bytes32 hash;
|
||||
assembly { hash := sha3(needleptr, needlelen) }
|
||||
ptr = selfptr + (selflen - needlelen);
|
||||
while (ptr >= selfptr) {
|
||||
bytes32 testHash;
|
||||
assembly { testHash := sha3(ptr, needlelen) }
|
||||
if (hash == testHash)
|
||||
return ptr + needlelen;
|
||||
ptr -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return selfptr;
|
||||
}
|
||||
|
||||
/*
|
||||
* @dev Modifies `self` to contain everything from the first occurrence of
|
||||
* `needle` to the end of the slice. `self` is set to the empty slice
|
||||
* if `needle` is not found.
|
||||
* @param self The slice to search and modify.
|
||||
* @param needle The text to search for.
|
||||
* @return `self`.
|
||||
*/
|
||||
function find(slice self, slice needle) internal returns (slice) {
|
||||
uint ptr = findPtr(self._len, self._ptr, needle._len, needle._ptr);
|
||||
self._len -= ptr - self._ptr;
|
||||
self._ptr = ptr;
|
||||
return self;
|
||||
}
|
||||
|
||||
/*
|
||||
* @dev Modifies `self` to contain the part of the string from the start of
|
||||
* `self` to the end of the first occurrence of `needle`. If `needle`
|
||||
* is not found, `self` is set to the empty slice.
|
||||
* @param self The slice to search and modify.
|
||||
* @param needle The text to search for.
|
||||
* @return `self`.
|
||||
*/
|
||||
function rfind(slice self, slice needle) internal returns (slice) {
|
||||
uint ptr = rfindPtr(self._len, self._ptr, needle._len, needle._ptr);
|
||||
self._len = ptr - self._ptr;
|
||||
return self;
|
||||
}
|
||||
|
||||
/*
|
||||
* @dev Splits the slice, setting `self` to everything after the first
|
||||
* occurrence of `needle`, and `token` to everything before it. If
|
||||
* `needle` does not occur in `self`, `self` is set to the empty slice,
|
||||
* and `token` is set to the entirety of `self`.
|
||||
* @param self The slice to split.
|
||||
* @param needle The text to search for in `self`.
|
||||
* @param token An output parameter to which the first token is written.
|
||||
* @return `token`.
|
||||
*/
|
||||
function split(slice self, slice needle, slice token) internal returns (slice) {
|
||||
uint ptr = findPtr(self._len, self._ptr, needle._len, needle._ptr);
|
||||
token._ptr = self._ptr;
|
||||
token._len = ptr - self._ptr;
|
||||
if (ptr == self._ptr + self._len) {
|
||||
// Not found
|
||||
self._len = 0;
|
||||
} else {
|
||||
self._len -= token._len + needle._len;
|
||||
self._ptr = ptr + needle._len;
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
/*
|
||||
* @dev Splits the slice, setting `self` to everything after the first
|
||||
* occurrence of `needle`, and returning everything before it. If
|
||||
* `needle` does not occur in `self`, `self` is set to the empty slice,
|
||||
* and the entirety of `self` is returned.
|
||||
* @param self The slice to split.
|
||||
* @param needle The text to search for in `self`.
|
||||
* @return The part of `self` up to the first occurrence of `delim`.
|
||||
*/
|
||||
function split(slice self, slice needle) internal returns (slice token) {
|
||||
split(self, needle, token);
|
||||
}
|
||||
|
||||
/*
|
||||
* @dev Splits the slice, setting `self` to everything before the last
|
||||
* occurrence of `needle`, and `token` to everything after it. If
|
||||
* `needle` does not occur in `self`, `self` is set to the empty slice,
|
||||
* and `token` is set to the entirety of `self`.
|
||||
* @param self The slice to split.
|
||||
* @param needle The text to search for in `self`.
|
||||
* @param token An output parameter to which the first token is written.
|
||||
* @return `token`.
|
||||
*/
|
||||
function rsplit(slice self, slice needle, slice token) internal returns (slice) {
|
||||
uint ptr = rfindPtr(self._len, self._ptr, needle._len, needle._ptr);
|
||||
token._ptr = ptr;
|
||||
token._len = self._len - (ptr - self._ptr);
|
||||
if (ptr == self._ptr) {
|
||||
// Not found
|
||||
self._len = 0;
|
||||
} else {
|
||||
self._len -= token._len + needle._len;
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
/*
|
||||
* @dev Splits the slice, setting `self` to everything before the last
|
||||
* occurrence of `needle`, and returning everything after it. If
|
||||
* `needle` does not occur in `self`, `self` is set to the empty slice,
|
||||
* and the entirety of `self` is returned.
|
||||
* @param self The slice to split.
|
||||
* @param needle The text to search for in `self`.
|
||||
* @return The part of `self` after the last occurrence of `delim`.
|
||||
*/
|
||||
function rsplit(slice self, slice needle) internal returns (slice token) {
|
||||
rsplit(self, needle, token);
|
||||
}
|
||||
|
||||
/*
|
||||
* @dev Counts the number of nonoverlapping occurrences of `needle` in `self`.
|
||||
* @param self The slice to search.
|
||||
* @param needle The text to search for in `self`.
|
||||
* @return The number of occurrences of `needle` found in `self`.
|
||||
*/
|
||||
function count(slice self, slice needle) internal returns (uint count) {
|
||||
uint ptr = findPtr(self._len, self._ptr, needle._len, needle._ptr) + needle._len;
|
||||
while (ptr <= self._ptr + self._len) {
|
||||
count++;
|
||||
ptr = findPtr(self._len - (ptr - self._ptr), ptr, needle._len, needle._ptr) + needle._len;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @dev Returns True if `self` contains `needle`.
|
||||
* @param self The slice to search.
|
||||
* @param needle The text to search for in `self`.
|
||||
* @return True if `needle` is found in `self`, false otherwise.
|
||||
*/
|
||||
function contains(slice self, slice needle) internal returns (bool) {
|
||||
return rfindPtr(self._len, self._ptr, needle._len, needle._ptr) != self._ptr;
|
||||
}
|
||||
|
||||
/*
|
||||
* @dev Returns a newly allocated string containing the concatenation of
|
||||
* `self` and `other`.
|
||||
* @param self The first slice to concatenate.
|
||||
* @param other The second slice to concatenate.
|
||||
* @return The concatenation of the two strings.
|
||||
*/
|
||||
function concat(slice self, slice other) internal returns (string) {
|
||||
var ret = new string(self._len + other._len);
|
||||
uint retptr;
|
||||
assembly { retptr := add(ret, 32) }
|
||||
memcpy(retptr, self._ptr, self._len);
|
||||
memcpy(retptr + self._len, other._ptr, other._len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* @dev Joins an array of slices, using `self` as a delimiter, returning a
|
||||
* newly allocated string.
|
||||
* @param self The delimiter to use.
|
||||
* @param parts A list of slices to join.
|
||||
* @return A newly allocated string containing all the slices in `parts`,
|
||||
* joined with `self`.
|
||||
*/
|
||||
function join(slice self, slice[] parts) internal returns (string) {
|
||||
if (parts.length == 0)
|
||||
return "";
|
||||
|
||||
uint len = self._len * (parts.length - 1);
|
||||
for(uint i = 0; i < parts.length; i++)
|
||||
len += parts[i]._len;
|
||||
|
||||
var ret = new string(len);
|
||||
uint retptr;
|
||||
assembly { retptr := add(ret, 32) }
|
||||
|
||||
for(i = 0; i < parts.length; i++) {
|
||||
memcpy(retptr, parts[i]._ptr, parts[i]._len);
|
||||
retptr += parts[i]._len;
|
||||
if (i < parts.length - 1) {
|
||||
memcpy(retptr, self._ptr, self._len);
|
||||
retptr += self._len;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
pragma solidity ^0.4.9;
|
||||
|
||||
import "lib/ethereans/management/Owned.sol";
|
||||
|
||||
import "Owned.sol";
|
||||
|
||||
pragma solidity ^0.4.11;
|
||||
|
||||
contract BountyBank is Owned {
|
||||
|
||||
enum State {CLOSED, OPEN, CLAIMED}
|
||||
@@ -42,10 +42,10 @@ contract BountyBank is Owned {
|
||||
bounties[num].points += points;
|
||||
}
|
||||
|
||||
function close(uint num) only_owner {
|
||||
function close(uint num, uint _closedAt) only_owner {
|
||||
if(bounties[num].state == State.CLAIMED) throw;
|
||||
bounties[num].state = State.CLOSED;
|
||||
bounties[num].closedAt = now;
|
||||
bounties[num].closedAt = _closedAt;
|
||||
}
|
||||
|
||||
function claim(uint num){
|
||||
|
||||
@@ -1,96 +0,0 @@
|
||||
pragma solidity ^0.4.8;
|
||||
|
||||
/**
|
||||
* Contract that oracle github API
|
||||
*
|
||||
* GitHubOracle register users and create GitHubToken contracts
|
||||
* Registration requires user create a gist with only their account address
|
||||
* GitHubOracle will create one GitHubToken contract per repository
|
||||
* GitHubToken mint tokens by commit only for registered users in GitHubOracle
|
||||
* GitHubToken is a LockableCoin, that accept donatations and can be withdrawn by Token Holders
|
||||
* The lookups are done by Oraclize that charge a small fee
|
||||
* The contract itself will never charge any fee
|
||||
*
|
||||
* By Ricardo Guilherme Schmidt
|
||||
* Released under GPLv3 License
|
||||
*/
|
||||
|
||||
import "lib/oraclize/oraclizeAPI_0.4.sol";
|
||||
import "lib/ethereans/management/Owned.sol";
|
||||
import "./DGitDB.sol";
|
||||
import "./GitHubAPI.sol";
|
||||
import "./GitRepository.sol";
|
||||
|
||||
contract DGit is Owned, DGitI {
|
||||
|
||||
DGitDBI public db;
|
||||
GitHubAPI public gitHubApi;
|
||||
|
||||
function initialize() only_owner {
|
||||
db = DBFactory.newStorage();
|
||||
gitHubApi = QueryFactory.newGitHubAPI();
|
||||
}
|
||||
|
||||
function register(string _github_user, string _gistid) payable{
|
||||
gitHubApi.register.value(msg.value)(msg.sender,_github_user,_gistid);
|
||||
}
|
||||
function updateCommits(string _repository) payable{
|
||||
gitHubApi.updateCommits.value(msg.value)(_repository,db.getClaimedHead(_repository));
|
||||
}
|
||||
function addRepository(string _repository) payable{
|
||||
gitHubApi.addRepository.value(msg.value)(_repository);
|
||||
}
|
||||
function updateIssue(string _repository, string issue) payable{
|
||||
gitHubApi.updateIssue.value(msg.value)(_repository,issue);
|
||||
}
|
||||
function getRepository(uint projectId) constant returns (address){
|
||||
return db.getRepositoryAddress(projectId);
|
||||
}
|
||||
function getRepository(string full_name) constant returns (address){
|
||||
return db.getRepositoryAddress(full_name);
|
||||
}
|
||||
|
||||
modifier only_gitapi{
|
||||
if (msg.sender != address(gitHubApi)) throw;
|
||||
_;
|
||||
}
|
||||
|
||||
event UserSet(string githubLogin);
|
||||
function __register(address addrLoaded, uint256 userId, string login)
|
||||
only_gitapi {
|
||||
UserSet(login);
|
||||
db.addUser(userId, login, 0, addrLoaded);
|
||||
}
|
||||
|
||||
event GitRepositoryRegistered(uint256 projectId, string full_name, uint256 watchers, uint256 subscribers);
|
||||
function __setRepository(uint256 projectId, string full_name, uint256 watchers, uint256 subscribers) only_gitapi //[83725290, "ethereans/github-token", 4, 2]
|
||||
{
|
||||
uint256 ownerId; string memory name; //TODO
|
||||
address repository = db.getRepositoryAddress(projectId);
|
||||
if(repository == 0x0){
|
||||
GitRepositoryRegistered(projectId,full_name,watchers,subscribers);
|
||||
repository = GitFactory.newGitRepository(projectId,full_name);
|
||||
db.addRepository(projectId,ownerId,name,full_name,repository);
|
||||
}
|
||||
GitRepositoryI(repository).setStats(subscribers,watchers);
|
||||
}
|
||||
|
||||
event NewPoints(string repository, uint userId, uint total);
|
||||
function __newPoints(string repository, uint userId, uint total)
|
||||
only_gitapi {
|
||||
NewPoints(repository,userId,total);
|
||||
GitRepositoryI repoaddr = GitRepositoryI(db.getRepositoryAddress(repository));
|
||||
if(!repoaddr.claim(db.getUserAddress(userId), total)){ //try to claim points
|
||||
db.setPending(repository, userId, total); //set as a pending points
|
||||
}
|
||||
}
|
||||
|
||||
//claims pending points
|
||||
function claimPending(uint repoId, uint userId){
|
||||
GitRepositoryI repoaddr = GitRepositoryI(db.getRepositoryAddress(repoId));
|
||||
uint total = db.claimPending(repoId,userId);
|
||||
if(!repoaddr.claim(db.getUserAddress(userId), total)) throw;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,239 +0,0 @@
|
||||
pragma solidity ^0.4.9;
|
||||
|
||||
import "lib/oraclize/oraclizeAPI_0.4.sol";
|
||||
import "lib/StringLib.sol";
|
||||
import "lib/JSONLib.sol";
|
||||
import "lib/ethereans/management/Owned.sol";
|
||||
|
||||
|
||||
contract GitHubAPI{
|
||||
function register(address _sender, string _github_user, string _gistid) payable;
|
||||
function updateCommits(string _full_name, string _branch, bytes20 _commitid) payable;
|
||||
function addRepository(string _full_name) payable;
|
||||
function updateIssue(string _full_name, string _issue) payable;
|
||||
}
|
||||
|
||||
contract DGitI {
|
||||
function __register(address addrLoaded, uint256 userId, string login);
|
||||
function __addRepository(uint256 projectId, string full_name, string default_branch);
|
||||
function __setHead(uint256 projectId, string branch, bytes20 head);
|
||||
function __setTail(uint256 projectId, string branch, bytes20 tail);
|
||||
function __newPoints(uint256 projectId, uint256 userId, uint total);
|
||||
function __setIssue(uint256 projectId, uint256 issueId, bool state, uint256 closedAt);
|
||||
function __setIssuePoints(uint256 projectId, uint256 issueId, uint256 userId, uint256 points);
|
||||
}
|
||||
|
||||
contract GitHubAPIOraclize is GitHubAPI, Owned, usingOraclize{
|
||||
using StringLib for string;
|
||||
DGitI dGit
|
||||
|
||||
string private cred = "f94095ba1d48038d4a81,36ae0e8b1bc5ad261c936e8f7f730f6c827c221f";
|
||||
string private credentials = "?client_id=f94095ba1d48038d4a81&client_secret=36ae0e8b1bc5ad261c936e8f7f730f6c827c221f";
|
||||
string private script = "QmU6pSQMDSg8do9eZLAfjzZYcC9JpsMZeB4ZoteGkSe94y";
|
||||
|
||||
enum OracleType { ADD_REPOSITORY, SET_USER, CLAIM_COMMIT, CLAIM_CONTINUE, UPDATE_ISSUE }
|
||||
mapping (bytes32 => OracleType) claimType; //temporary db enumerating oraclize calls
|
||||
mapping (bytes32 => CommitClaim) commitClaim; //temporary db for oraclize commit token claim calls
|
||||
mapping (bytes32 => UserClaim) userClaim; //temporary db for oraclize user register queries
|
||||
|
||||
//stores temporary data for oraclize user register request
|
||||
struct UserClaim {
|
||||
address sender;
|
||||
string githubid;
|
||||
}
|
||||
//stores temporary data for oraclize repository commit claim
|
||||
struct CommitClaim {
|
||||
string repository;
|
||||
bytes20 commitid;
|
||||
}
|
||||
|
||||
function GitHubAPIOraclize(){
|
||||
dGit = DGitI(msg.sender);
|
||||
oraclize_setProof(proofType_TLSNotary | proofStorage_IPFS);
|
||||
}
|
||||
|
||||
//register or change a github user ethereum address. 100000000000000000
|
||||
function register(address _sender, string _github_user, string _gistid)
|
||||
payable only_owner{
|
||||
bytes32 ocid = oraclize_query("nested", StringLib.concat("[identity] ${[URL] https://gist.githubusercontent.com/",_github_user,"/",_gistid,"/raw/}, ${[URL] json(https://api.github.com/gists/").concat(_gistid,credentials,").owner.[id,login]}"));
|
||||
claimType[ocid] = OracleType.SET_USER;
|
||||
userClaim[ocid] = UserClaim({sender: _sender, githubid: _github_user});
|
||||
}
|
||||
|
||||
function addRepository(string _repository)
|
||||
payable only_owner{
|
||||
bytes32 ocid = oraclize_query("URL", StringLib.concat("json(https://api.github.com/repos/",_repository,credentials,").$.id,full_name,default_branch"),4000000);
|
||||
claimType[ocid] = OracleType.ADD_REPOSITORY;
|
||||
}
|
||||
|
||||
function updateCommits(string _repository, string _branch, bytes20 _commitid)
|
||||
payable only_owner{
|
||||
bytes32 ocid = oraclize_query("computation", [script, "update-new",_repository.concat(",", _branch,",",toString(_commitid)),cred]);
|
||||
claimType[ocid] = OracleType.CLAIM_COMMIT;
|
||||
commitClaim[ocid] = CommitClaim( { repository: _repository, commitid:_commitid});
|
||||
}
|
||||
|
||||
function continueUpdateCommits(string _repository, string _branch, bytes20 _lastCommit,bytes20 _limitCommit)
|
||||
payable only_owner{
|
||||
bytes32 ocid = oraclize_query("computation", [script, "update-old",_repository.concat(",", _branch,",",toString(_lastCommit)).concat(",",toString(_limitCommit)),cred]);
|
||||
claimType[ocid] = OracleType.CLAIM_CONTINUE;
|
||||
}
|
||||
|
||||
function updateIssue(string _repository, string issue) payable only_owner{
|
||||
bytes32 ocid = oraclize_query("computation", [script, "issue-update",_repository.concat(",",issue),cred]);
|
||||
}
|
||||
|
||||
event OracleEvent(bytes32 myid, string result, bytes proof);
|
||||
//oraclize response callback
|
||||
function __callback(bytes32 myid, string result, bytes proof) {
|
||||
OracleEvent(myid,result,proof);
|
||||
if (msg.sender != oraclize.cbAddress()){
|
||||
throw;
|
||||
}else if(claimType[myid]==OracleType.SET_USER){
|
||||
_register(myid, result);
|
||||
}else if(claimType[myid] == OracleType.ADD_REPOSITORY){
|
||||
_addRepository(myid, result);
|
||||
}else if(claimType[myid]==OracleType.CLAIM_COMMIT){
|
||||
_updateCommits(myid, result, false);
|
||||
}else if(claimType[myid]==OracleType.CLAIM_CONTINUE){
|
||||
_updateCommits(myid, result, true);
|
||||
}else if(claimType[myid] == OracleType.UPDATE_ISSUE){
|
||||
_updateIssue(myid, result);
|
||||
}
|
||||
delete claimType[myid]; //should always be deleted
|
||||
}
|
||||
|
||||
function _register(bytes32 myid, string result)
|
||||
internal {
|
||||
uint256 userId; string memory login; address addrLoaded;
|
||||
uint8 utype; //TODO
|
||||
bytes memory v = bytes(result);
|
||||
uint8 pos = 0;
|
||||
(addrLoaded,pos) = JSONLib.getNextAddr(v,pos);
|
||||
(userId,pos) = JSONLib.getNextUInt(v,pos);
|
||||
(login,pos) = JSONLib.getNextString(v,pos);
|
||||
if(userClaim[myid].sender == addrLoaded){
|
||||
dGit.__register(addrLoaded, userId, login);
|
||||
}
|
||||
delete userClaim[myid]; //should always be deleted
|
||||
}
|
||||
|
||||
|
||||
function _addRepository(bytes32 myid, string result) internal //[85743750, "ethereans/TheEtherian", "master"]
|
||||
{
|
||||
bytes memory v = bytes(result);
|
||||
uint8 pos = 0;
|
||||
string memory temp;
|
||||
uint256 projectId;
|
||||
(projectId,pos) = JSONLib.getNextUInt(v,pos);
|
||||
string memory full_name;
|
||||
(full_name,pos) = JSONLib.getNextString(v,pos);
|
||||
string memory default_branch;
|
||||
(default_branch,pos) = JSONLib.getNextString(v,pos);
|
||||
dGit.__addRepository(projectId,full_name,default_branch);
|
||||
}
|
||||
|
||||
function _updateCommits(bytes32 myid, string result, bool continuing)
|
||||
internal {
|
||||
bytes memory v = bytes(result);
|
||||
uint8 pos = 0;
|
||||
string memory temp;
|
||||
uint256 projectId;
|
||||
(projectId,pos) = JSONLib.getNextUInt(v,pos);
|
||||
string memory branch;
|
||||
(branch,pos) = JSONLib.getNextString(v,pos);
|
||||
(temp,pos) = JSONLib.getNextString(v,pos);
|
||||
bytes20 head = temp.toBytes20();
|
||||
(temp,pos) = JSONLib.getNextString(v,pos);
|
||||
bytes20 tail = temp.toBytes20();
|
||||
uint numAuthors;
|
||||
(numAuthors,pos) = JSONLib.getNextUInt(v,pos);
|
||||
uint userId;
|
||||
uint points;
|
||||
dGit.__setHead(projectId,branch,head);
|
||||
if(continuing){
|
||||
dGit.__setTail(projectId,branch,tail);
|
||||
}else{
|
||||
bytes20 oldCommit = commitUpdate[myid].commitid;
|
||||
if(oldCommit == 0x0){
|
||||
dGit.__setTail(projectId,branch,tail);
|
||||
}else if (oldCommit != tail){
|
||||
//TODO: acceptContinueUpdateUntilLimit(tail,oldCommit)
|
||||
}
|
||||
}
|
||||
for(uint i; i < numAuthors; i++){
|
||||
(userId,pos) = JSONLib.getNextUInt(v,pos);
|
||||
(points,pos) = JSONLib.getNextUInt(v,pos);
|
||||
dGit.__newPoints(projectId,userId,points);
|
||||
}
|
||||
}
|
||||
|
||||
function _updateIssue(bytes32 myid, string result)
|
||||
internal {
|
||||
bytes memory v = bytes(result);
|
||||
uint8 pos = 0;
|
||||
string memory temp;
|
||||
uint256 projectId;
|
||||
(projectId,pos) = JSONLib.getNextUInt(v,pos);
|
||||
uint256 issueId;
|
||||
(issueId,pos) = JSONLib.getNextUInt(v,pos);
|
||||
bool state;
|
||||
(temp,pos) = JSONLib.getNextString(v,pos);
|
||||
state = (temp.compare("open") == 0);
|
||||
uint256 closedAt;
|
||||
(closedAt,pos) = JSONLib.getNextUInt(v,pos);
|
||||
uint numAuthors;
|
||||
(numAuthors,pos) = JSONLib.getNextUInt(v,pos);
|
||||
uint userId;
|
||||
uint points;
|
||||
dGit.__setIssue(projectId,issueId,state,closedAt);
|
||||
for(uint i; i < numAuthors; i++){
|
||||
(userId,pos) = JSONLib.getNextUInt(v,pos);
|
||||
(points,pos) = JSONLib.getNextUInt(v,pos);
|
||||
dGit.__setIssuePoints(projectId,issueId,userId,points);
|
||||
}
|
||||
}
|
||||
|
||||
//owner management
|
||||
function setAPICredentials(string _client_id, string _client_secret)
|
||||
only_owner {
|
||||
cred = StringLib.concat(_client_id,",", _client_secret);
|
||||
credentials = StringLib.concat("?client_id=",_client_id,"&client_secret="+_client_secret);
|
||||
}
|
||||
|
||||
function setScript(string _script) only_owner{
|
||||
script = _script;
|
||||
}
|
||||
|
||||
function clearAPICredentials()
|
||||
only_owner {
|
||||
cred = "";
|
||||
credentials = "";
|
||||
}
|
||||
|
||||
function toString(bytes20 self) internal constant returns (string) {
|
||||
bytes memory bytesString = new bytes(20);
|
||||
uint charCount = 0;
|
||||
for (uint j = 0; j < 20; j++) {
|
||||
byte char = byte(bytes20(uint(self) * 2 ** (8 * j)));
|
||||
if (char != 0) {
|
||||
bytesString[charCount] = char;
|
||||
charCount++;
|
||||
}
|
||||
}
|
||||
bytes memory bytesStringTrimmed = new bytes(charCount);
|
||||
for (j = 0; j < charCount; j++) {
|
||||
bytesStringTrimmed[j] = bytesString[j];
|
||||
}
|
||||
return string(bytesStringTrimmed);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
library QueryFactory {
|
||||
|
||||
function newGitHubAPI() returns (GitHubAPI){
|
||||
return new GitHubAPIOraclize();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/**
|
||||
* GitHubAPIReg.sol
|
||||
* Abstract Logic for GitHubOracle Registries.
|
||||
* Ricardo Guilherme Schmidt <3esmit@gmail.com>
|
||||
*/
|
||||
import "Owned.sol";
|
||||
import "oraclizeAPI_0.4.sol";
|
||||
import "strings.sol";
|
||||
|
||||
pragma solidity ^0.4.11;
|
||||
|
||||
contract GitHubAPIReg is Owned, usingOraclize {
|
||||
using strings for string;
|
||||
using strings for strings.slice;
|
||||
|
||||
string cred = "";
|
||||
|
||||
event OracleEvent(bytes32 myid, string result, bytes proof);
|
||||
|
||||
function GitHubAPIReg(){
|
||||
oraclize_setProof(proofType_TLSNotary | proofStorage_IPFS);
|
||||
}
|
||||
|
||||
//owner management
|
||||
function setAPICredentials(string _client_id, string _client_secret) only_owner {
|
||||
strings.slice [] memory cm = new strings.slice[](5);
|
||||
cm[0] = strings.toSlice("?client_id=");
|
||||
cm[1] = _client_id.toSlice();
|
||||
cm[2] = strings.toSlice("&client_secret=");
|
||||
cm[4] = _client_secret.toSlice();
|
||||
cred = strings.toSlice("").join(cm);
|
||||
}
|
||||
|
||||
function clearAPICredentials() only_owner {
|
||||
cred = "";
|
||||
}
|
||||
|
||||
function getNextString(bytes _str, uint8 _pos) internal constant returns (string, uint8) {
|
||||
uint8 start = 0;
|
||||
uint8 end = 0;
|
||||
uint strl =_str.length;
|
||||
for (;strl > _pos; _pos++) {
|
||||
if (_str[_pos] == '"'){ //Found quotation mark
|
||||
if(_str[_pos-1] != '\\'){ //is not escaped
|
||||
end = start == 0 ? 0: _pos;
|
||||
start = start == 0 ? (_pos+1) : start;
|
||||
if(end > 0) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
bytes memory str = new bytes(end-start);
|
||||
for(_pos=0; _pos<str.length; _pos++){
|
||||
str[_pos] = _str[start+_pos];
|
||||
}
|
||||
for(_pos=end+1; _pos<_str.length; _pos++) if (_str[_pos] == ','){ _pos++; break; } //end
|
||||
|
||||
return (string(str),_pos);
|
||||
}
|
||||
|
||||
function getNextUInt(bytes _str, uint8 _pos) internal constant returns (uint, uint8) {
|
||||
uint val = 0;
|
||||
uint strl =_str.length;
|
||||
for (; strl > _pos; _pos++) {
|
||||
byte bp = _str[_pos];
|
||||
if (bp == ','){ //Find ends
|
||||
_pos++; break;
|
||||
}else if ((bp >= 48)&&(bp <= 57)){ //only ASCII numbers
|
||||
val *= 10;
|
||||
val += uint(bp) - 48;
|
||||
}
|
||||
}
|
||||
return (val,_pos);
|
||||
}
|
||||
|
||||
function getNextAddr(bytes _str, uint8 _pos) internal constant returns (address, uint8){
|
||||
uint160 iaddr = 0;
|
||||
uint strl =_str.length;
|
||||
for(;strl > _pos; _pos++){
|
||||
byte bp = _str[_pos];
|
||||
if (bp == '0'){
|
||||
if (_str[_pos+1] == 'x'){
|
||||
for (_pos=_pos+2; _pos<2+2*20; _pos+=2){
|
||||
iaddr *= 256;
|
||||
iaddr += (uint160(hexVal(uint160(_str[_pos])))*16+uint160(hexVal(uint160(_str[_pos+1]))));
|
||||
}
|
||||
_pos++;
|
||||
break;
|
||||
}
|
||||
}else if (bp == ','){
|
||||
_pos++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (address(iaddr),_pos);
|
||||
}
|
||||
|
||||
function hexVal(uint val) internal constant returns (uint){
|
||||
return val - (val < 58 ? 48 : (val < 97 ? 55 : 87));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/**
|
||||
* GitHubOracle.sol
|
||||
* Contract that oracle github API
|
||||
* GitHubOracle register users and create GitHubToken contracts
|
||||
* Registration requires user create a gist with only their account address
|
||||
* GitHubOracle will create one GitHubToken contract per repository
|
||||
* GitHubToken mint tokens by commit only for registered users in GitHubOracle
|
||||
* GitHubToken is a LockableCoin, that accept donatations and can be withdrawn by Token Holders
|
||||
* The lookups are done by Oraclize that charge a small fee
|
||||
* The contract itself will never charge any fee
|
||||
*
|
||||
* By Ricardo Guilherme Schmidt
|
||||
* Released under GPLv3 License
|
||||
*/
|
||||
|
||||
import "oraclizeAPI_0.4.sol";
|
||||
import "Owned.sol";
|
||||
import "./GitHubUserReg.sol";
|
||||
import "./GitHubRepositoryReg.sol";
|
||||
import "./GitHubPoints.sol";
|
||||
|
||||
pragma solidity ^0.4.11;
|
||||
|
||||
contract GitHubOracle is Owned, DGitI {
|
||||
|
||||
GitHubUserReg public userReg;
|
||||
GitHubRepositoryReg public repositoryReg;
|
||||
GitHubPoints public gitHubPoints;
|
||||
|
||||
mapping (uint256 => Repository) repositories;
|
||||
mapping (uint256 => mapping (uint256 => uint256)) pending;
|
||||
|
||||
modifier oraclized {
|
||||
if(msg.sender != address(gitHubPoints)) throw;
|
||||
_;
|
||||
}
|
||||
|
||||
struct Repository {
|
||||
string head;
|
||||
string tail;
|
||||
mapping (string => string) pending;
|
||||
}
|
||||
|
||||
function initialize() only_owner {
|
||||
if(address(userReg) == 0x0){
|
||||
userReg = GHUserReg.create();
|
||||
}else if(address(repositoryReg) == 0x0){
|
||||
repositoryReg = GHRepoReg.create();
|
||||
}else if(address(gitHubPoints) == 0x0){
|
||||
gitHubPoints = GHPoints.create();
|
||||
}else throw;
|
||||
}
|
||||
|
||||
function update(string _repository, string _token) payable {
|
||||
uint256 repoId = repositoryReg.getId(_repository);
|
||||
if(repoId == 0) throw;
|
||||
gitHubPoints.update.value(msg.value)(_repository, "master", repositories[repoId].head,_token);
|
||||
}
|
||||
|
||||
function issue(string _repository, string _issue, string _token) payable {
|
||||
gitHubPoints.issue.value(msg.value)(_repository,_issue,_token);
|
||||
}
|
||||
|
||||
function __pendingScan(uint256 _projectId, string _lastCommit, string _pendingTail) oraclized {
|
||||
repositories[_projectId].pending[_pendingTail] = _lastCommit;
|
||||
}
|
||||
|
||||
function __setHead(uint256 _projectId, string _head) oraclized {
|
||||
repositories[_projectId].head = _head;
|
||||
}
|
||||
|
||||
function __setTail(uint256 _projectId, string _tail) oraclized {
|
||||
repositories[_projectId].tail = _tail;
|
||||
}
|
||||
|
||||
function __setIssue(uint256 _projectId, uint256 _issueId, bool _state, uint256 _closedAt) oraclized {
|
||||
GitRepositoryI repo = GitRepositoryI(repositoryReg.getAddr(_projectId));
|
||||
repo.setBounty(_issueId, _state, _closedAt);
|
||||
}
|
||||
|
||||
function __setIssuePoints(uint256 _projectId, uint256 _issueId, uint256 _userId, uint256 _points) oraclized {
|
||||
GitRepositoryI repo = GitRepositoryI(repositoryReg.getAddr(_projectId));
|
||||
repo.setBountyPoints(_issueId, userReg.getAddr(_userId), _points);
|
||||
}
|
||||
|
||||
event NewPoints(uint repoId, uint userId, uint total, bool claimed);
|
||||
|
||||
function __newPoints(uint _repoId, uint _userId, uint _points)
|
||||
only_owner {
|
||||
GitRepositoryI repoaddr = GitRepositoryI(repositoryReg.getAddr(_repoId));
|
||||
bool claimed = repoaddr.claim(userReg.getAddr(_userId), _points);
|
||||
if(!claimed){ //try to claim points
|
||||
pending[_userId][_repoId] += _points; //set as a pending points
|
||||
}
|
||||
NewPoints(_repoId, _userId, _points, claimed);
|
||||
}
|
||||
|
||||
//claims pending points
|
||||
function claimPending(uint _repoId, uint _userId){
|
||||
GitRepositoryI repoaddr = GitRepositoryI(repositoryReg.getAddr(_repoId));
|
||||
uint total = pending[_userId][_repoId];
|
||||
delete pending[_userId][_repoId];
|
||||
if(repoaddr.claim(userReg.getAddr(_userId), total)) {
|
||||
NewPoints(_repoId,_userId,total,true);
|
||||
} else throw;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,281 @@
|
||||
import "oraclizeAPI_0.4.sol";
|
||||
import "Owned.sol";
|
||||
import "strings.sol";
|
||||
|
||||
pragma solidity ^0.4.11;
|
||||
|
||||
contract DGitI {
|
||||
function __setHead(uint256 projectId, string head);
|
||||
function __setTail(uint256 projectId, string tail);
|
||||
function __newPoints(uint256 projectId, uint256 userId, uint total);
|
||||
function __pendingScan(uint256 projectId, string lastCommit, string pendingTail);
|
||||
function __setIssue(uint256 projectId, uint256 issueId, bool state, uint256 closedAt);
|
||||
function __setIssuePoints(uint256 projectId, uint256 issueId, uint256 userId, uint256 points);
|
||||
}
|
||||
|
||||
contract GitHubPoints is Owned, usingOraclize{
|
||||
|
||||
using strings for string;
|
||||
using strings for strings.slice;
|
||||
|
||||
string private cred = "";
|
||||
string private script = "";
|
||||
|
||||
enum Command { UPDATE, RESUME, ISSUE }
|
||||
mapping (bytes32 => Command) command; //temporary db enumerating oraclize calls
|
||||
mapping (bytes32 => string) lastCommits; //temporary db for oraclize commit token claim calls
|
||||
|
||||
//stores temporary data for oraclize repository commit claim
|
||||
struct CommitClaim {
|
||||
string repository;
|
||||
bytes20 commitid;
|
||||
}
|
||||
|
||||
function update(string _repository, string _branch, string _lastCommit, string _cred) payable only_owner {
|
||||
if(bytes(_cred).length == 0) _cred = cred;
|
||||
bytes32 ocid = oraclize_query("nested", _query_update(_repository,_branch,_lastCommit,_cred));
|
||||
command[ocid] = Command.UPDATE;
|
||||
lastCommits[ocid] = _lastCommit;
|
||||
}
|
||||
|
||||
function resume(string _repository, string _branch, string _lastCommit, string _limitCommit, string _cred)
|
||||
payable only_owner {
|
||||
if(bytes(_cred).length == 0) _cred = cred;
|
||||
bytes32 ocid = oraclize_query("nested", _query_resume(_repository,_branch,_lastCommit,_limitCommit,_cred));
|
||||
command[ocid] = Command.RESUME;
|
||||
lastCommits[ocid] = _lastCommit;
|
||||
}
|
||||
|
||||
function issue(string _repository, string _issue, string _cred)
|
||||
payable only_owner {
|
||||
if(bytes(_cred).length == 0) _cred = cred;
|
||||
command[ocid] = Command.ISSUE;
|
||||
bytes32 ocid = oraclize_query("nested", _query_issue(_repository,_issue,_cred));
|
||||
}
|
||||
|
||||
event OracleEvent(bytes32 myid, string result, bytes proof);
|
||||
//oraclize response callback
|
||||
function __callback(bytes32 myid, string result, bytes proof) {
|
||||
OracleEvent(myid, result, proof);
|
||||
if (msg.sender != oraclize.cbAddress()) throw;
|
||||
Command comm = command[myid];
|
||||
if(comm == Command.UPDATE) {
|
||||
_update(lastCommits[myid], result);
|
||||
}else if(comm == Command.ISSUE) {
|
||||
_issue(result);
|
||||
}else if (comm == Command.RESUME) {
|
||||
_resume(lastCommits[myid], result);
|
||||
delete lastCommits[myid];
|
||||
}
|
||||
delete command[myid];
|
||||
}
|
||||
|
||||
function _update(string _lastCommit, string result) internal {
|
||||
DGitI dGit = DGitI(owner);
|
||||
bytes memory v = bytes(result);
|
||||
uint8 pos = 0;
|
||||
string memory temp;
|
||||
uint256 projectId;
|
||||
(projectId,pos) = getNextUInt(v,pos);
|
||||
(temp,pos) = getNextString(v,pos); //branch
|
||||
(temp,pos) = getNextString(v,pos); //head
|
||||
dGit.__setHead(projectId,temp); //head
|
||||
|
||||
(temp,pos) = getNextString(v,pos); //tail
|
||||
if(bytes(_lastCommit).length == 0){
|
||||
dGit.__setTail(projectId,temp);
|
||||
}
|
||||
if (sha3(_lastCommit) != sha3(temp)){ //update didn't reached _lastCommit
|
||||
dGit.__pendingScan(projectId,_lastCommit,temp);
|
||||
}
|
||||
uint numAuthors;
|
||||
(numAuthors,pos) = getNextUInt(v,pos);
|
||||
uint userId;
|
||||
uint points;
|
||||
for(uint i; i < numAuthors; i++){
|
||||
(userId,pos) = getNextUInt(v,pos);
|
||||
(points,pos) = getNextUInt(v,pos);
|
||||
dGit.__newPoints(projectId,userId,points);
|
||||
}
|
||||
}
|
||||
|
||||
function _resume(string _lastCommit, string result) internal {
|
||||
DGitI dGit = DGitI(owner);
|
||||
bytes memory v = bytes(result);
|
||||
uint8 pos = 0;
|
||||
string memory temp;
|
||||
uint256 projectId;
|
||||
(projectId,pos) = getNextUInt(v,pos);
|
||||
string memory branch;
|
||||
(branch,pos) = getNextString(v,pos);
|
||||
string memory head;
|
||||
(head,pos) = getNextString(v,pos);
|
||||
string memory tail;
|
||||
(tail,pos) = getNextString(v,pos);
|
||||
dGit.__setTail(projectId,tail);
|
||||
uint numAuthors;
|
||||
(numAuthors,pos) = getNextUInt(v,pos);
|
||||
uint userId;
|
||||
uint points;
|
||||
for(uint i; i < numAuthors; i++){
|
||||
(userId,pos) = getNextUInt(v,pos);
|
||||
(points,pos) = getNextUInt(v,pos);
|
||||
dGit.__newPoints(projectId,userId,points);
|
||||
}
|
||||
}
|
||||
|
||||
function _issue(string result) internal {
|
||||
DGitI dGit = DGitI(owner);
|
||||
bytes memory v = bytes(result);
|
||||
uint8 pos = 0;
|
||||
string memory temp;
|
||||
uint256 projectId;
|
||||
(projectId,pos) = getNextUInt(v,pos);
|
||||
uint256 issueId;
|
||||
(issueId,pos) = getNextUInt(v,pos);
|
||||
bool state;
|
||||
(temp,pos) = getNextString(v,pos);
|
||||
state = (sha3("open") == sha3(temp));
|
||||
uint256 closedAt;
|
||||
(closedAt,pos) = getNextUInt(v,pos);
|
||||
uint numAuthors;
|
||||
(numAuthors,pos) = getNextUInt(v,pos);
|
||||
uint userId;
|
||||
uint points;
|
||||
dGit.__setIssue(projectId,issueId,state,closedAt);
|
||||
for(uint i; i < numAuthors; i++){
|
||||
(userId,pos) = getNextUInt(v,pos);
|
||||
(points,pos) = getNextUInt(v,pos);
|
||||
dGit.__setIssuePoints(projectId,issueId,userId,points);
|
||||
}
|
||||
}
|
||||
|
||||
//owner management
|
||||
function GitHubPoints(string _script){
|
||||
script = _script;
|
||||
oraclize_setProof(proofType_TLSNotary | proofStorage_IPFS);
|
||||
}
|
||||
|
||||
function setAPICredentials(string _client_id_comma_client_secret) only_owner {
|
||||
cred = _client_id_comma_client_secret;
|
||||
}
|
||||
|
||||
function setScript(string _script) only_owner{
|
||||
script = _script;
|
||||
}
|
||||
|
||||
function clearAPICredentials() only_owner {
|
||||
cred = "";
|
||||
}
|
||||
|
||||
function _query_script(string command, string args, string cred) internal returns (string) {
|
||||
strings.slice memory comma = strings.toSlice("', '");
|
||||
strings.slice [] memory cm = new strings.slice[](4);
|
||||
cm[0] = script.toSlice();
|
||||
cm[1] = command.toSlice();
|
||||
cm[2] = args.toSlice();
|
||||
cm[3] = cred.toSlice();
|
||||
string memory array = comma.join(cm);
|
||||
cm = new strings.slice[](3);
|
||||
cm[0] = strings.toSlice("[computation] ['");
|
||||
cm[1] = array.toSlice();
|
||||
cm[2] = strings.toSlice("']");
|
||||
return strings.toSlice("").join(cm);
|
||||
}
|
||||
|
||||
function _query_update(string _repository, string _branch, string _lastCommit, string _cred) internal returns (string) {
|
||||
strings.slice memory comma = strings.toSlice(",");
|
||||
strings.slice [] memory cm = new strings.slice[](3);
|
||||
cm[0] = _repository.toSlice();
|
||||
cm[1] = _branch.toSlice();
|
||||
cm[2] = _lastCommit.toSlice();
|
||||
return _query_script("update",comma.join(cm),_cred);
|
||||
}
|
||||
|
||||
function _query_resume(string _repository, string _branch, string _lastCommit, string _limitCommit, string _cred) internal constant returns (string){
|
||||
strings.slice memory comma = strings.toSlice(",");
|
||||
strings.slice [] memory cm = new strings.slice[](4);
|
||||
cm[0] = _repository.toSlice();
|
||||
cm[1] = _branch.toSlice();
|
||||
cm[2] = _lastCommit.toSlice();
|
||||
cm[3] = _limitCommit.toSlice();
|
||||
return _query_script("resume",comma.join(cm),_cred);
|
||||
}
|
||||
|
||||
function _query_issue(string _repository, string _issue, string _cred) internal returns(string){
|
||||
strings.slice memory comma = strings.toSlice(",");
|
||||
strings.slice [] memory cm = new strings.slice[](2);
|
||||
cm[0] = _repository.toSlice();
|
||||
cm[1] = _issue.toSlice();
|
||||
return _query_script("resume",comma.join(cm),_cred);
|
||||
}
|
||||
|
||||
|
||||
function toBytes20(string memory source) internal constant returns (bytes20 result) {
|
||||
assembly {
|
||||
result := mload(add(source, 20))
|
||||
}
|
||||
}
|
||||
|
||||
function toString(bytes20 self) internal constant returns (string) {
|
||||
bytes memory bytesString = new bytes(20);
|
||||
uint charCount = 0;
|
||||
for (uint j = 0; j < 20; j++) {
|
||||
byte char = byte(bytes20(uint(self) * 2 ** (8 * j)));
|
||||
if (char != 0) {
|
||||
bytesString[charCount] = char;
|
||||
charCount++;
|
||||
}
|
||||
}
|
||||
bytes memory bytesStringTrimmed = new bytes(charCount);
|
||||
for (j = 0; j < charCount; j++) {
|
||||
bytesStringTrimmed[j] = bytesString[j];
|
||||
}
|
||||
return string(bytesStringTrimmed);
|
||||
}
|
||||
|
||||
function getNextString(bytes _str, uint8 _pos) internal constant returns (string, uint8) {
|
||||
uint8 start = 0;
|
||||
uint8 end = 0;
|
||||
uint strl =_str.length;
|
||||
for (;strl > _pos; _pos++) {
|
||||
if (_str[_pos] == '"'){ //Found quotation mark
|
||||
if(_str[_pos-1] != '\\'){ //is not escaped
|
||||
end = start == 0 ? 0: _pos;
|
||||
start = start == 0 ? (_pos+1) : start;
|
||||
if(end > 0) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
bytes memory str = new bytes(end-start);
|
||||
for(_pos=0; _pos<str.length; _pos++){
|
||||
str[_pos] = _str[start+_pos];
|
||||
}
|
||||
for(_pos=end+1; _pos<_str.length; _pos++) if (_str[_pos] == ','){ _pos++; break; } //end
|
||||
|
||||
return (string(str),_pos);
|
||||
}
|
||||
|
||||
function getNextUInt(bytes _str, uint8 _pos) internal constant returns (uint, uint8) {
|
||||
uint val = 0;
|
||||
uint strl =_str.length;
|
||||
for (; strl > _pos; _pos++) {
|
||||
byte bp = _str[_pos];
|
||||
if (bp == ','){ //Find ends
|
||||
_pos++; break;
|
||||
}else if ((bp >= 48)&&(bp <= 57)){ //only ASCII numbers
|
||||
val *= 10;
|
||||
val += uint(bp) - 48;
|
||||
}
|
||||
}
|
||||
return (val,_pos);
|
||||
}
|
||||
}
|
||||
|
||||
library GHPoints {
|
||||
|
||||
function create() returns (GitHubPoints){
|
||||
return new GitHubPoints("");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,160 +0,0 @@
|
||||
//Author: Ricardo Guilherme Schmidt <3esmit@gmail.com>
|
||||
pragma solidity ^0.4.11;
|
||||
|
||||
import "lib/oraclize/oraclizeAPI_0.4.sol";
|
||||
import "lib/ethereans/management/Owned.sol";
|
||||
|
||||
contract GitHubRegisterEth is Owned, usingOraclize{
|
||||
string private credentials = "";
|
||||
mapping (bytes32 => UserClaim) userClaim; //temporary db for oraclize user register queries
|
||||
mapping (bytes32 => uint256) indexes;
|
||||
mapping (uint256 => User) users;
|
||||
|
||||
event RegisterUpdated(string name);
|
||||
|
||||
//stores temporary data for oraclize user register request
|
||||
struct UserClaim {
|
||||
address sender;
|
||||
string login;
|
||||
}
|
||||
|
||||
struct User {
|
||||
address addr;
|
||||
string login;
|
||||
}
|
||||
|
||||
function GitHubRegisterEth(){
|
||||
oraclize_setProof(proofType_TLSNotary | proofStorage_IPFS);
|
||||
}
|
||||
|
||||
function register(string _github_user, string _gistid) payable {
|
||||
bytes32 ocid = oraclize_query("nested", _getQuery(_github_user, _gistid));
|
||||
userClaim[ocid] = UserClaim({sender: msg.sender, login: _github_user});
|
||||
}
|
||||
|
||||
function getAddr(uint256 _id) public constant returns(address addr) {
|
||||
return users[_id].addr;
|
||||
}
|
||||
|
||||
function getName(address _addr) public constant returns(string name){
|
||||
return users[indexes[sha3(_addr)]].login;
|
||||
}
|
||||
|
||||
function getAddr(string _name) public constant returns(address addr) {
|
||||
return users[indexes[sha3(_name)]].addr;
|
||||
}
|
||||
|
||||
event OracleEvent(bytes32 myid, string result, bytes proof);
|
||||
|
||||
//oraclize response callback
|
||||
function __callback(bytes32 myid, string result, bytes proof) {
|
||||
OracleEvent(myid,result,proof);
|
||||
if (msg.sender != oraclize.cbAddress()){
|
||||
throw;
|
||||
}else {
|
||||
_register(myid, result);
|
||||
}
|
||||
}
|
||||
|
||||
function _register(bytes32 myid, string result) internal {
|
||||
bytes memory v = bytes(result);
|
||||
uint8 pos = 0;
|
||||
address addrLoaded;
|
||||
string memory login;
|
||||
uint256 userId;
|
||||
(addrLoaded,pos) = getNextAddr(v,pos);
|
||||
(login,pos) = getNextString(v,pos);
|
||||
(userId,pos) = getNextUInt(v,pos);
|
||||
if(userClaim[myid].sender == addrLoaded && sha3(userClaim[myid].login) == sha3(login)){
|
||||
RegisterUpdated(login);
|
||||
if(users[userId].addr != 0x0){
|
||||
delete indexes[sha3(users[userId].login)];
|
||||
delete indexes[sha3(users[userId].addr)];
|
||||
}
|
||||
indexes[sha3(addrLoaded)] = userId;
|
||||
indexes[sha3(login)] = userId;
|
||||
users[userId].addr = addrLoaded;
|
||||
users[userId].login = login;
|
||||
}
|
||||
delete userClaim[myid]; //should always be deleted
|
||||
}
|
||||
|
||||
//owner management
|
||||
function setAPICredentials(string _client_id, string _client_secret) only_owner {
|
||||
credentials = strConcat("?client_id=",_client_id,"&client_secret=",_client_secret,"");
|
||||
}
|
||||
|
||||
function clearAPICredentials() only_owner {
|
||||
credentials = "";
|
||||
}
|
||||
|
||||
//internal helper functions
|
||||
function _getQuery(string _github_user, string _gistid) internal constant returns (string){
|
||||
string memory a = strConcat("[identity] ${[URL] https://gist.githubusercontent.com/", _github_user,"/",_gistid,"/raw/registereth.txt}, ${[URL] json(https://api.github.com/gists/");
|
||||
return strConcat(a, _gistid, credentials, ").owner.[login,id]}","");
|
||||
}
|
||||
|
||||
function getNextString(bytes _str, uint8 _pos) internal constant returns (string,uint8) {
|
||||
uint8 start = 0;
|
||||
uint8 end = 0;
|
||||
uint strl =_str.length;
|
||||
for (;strl > _pos; _pos++) {
|
||||
if (_str[_pos] == '"'){ //Found quotation mark
|
||||
if(_str[_pos-1] != '\\'){ //is not escaped
|
||||
end = start == 0 ? 0: _pos;
|
||||
start = start == 0 ? (_pos+1) : start;
|
||||
if(end > 0) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
bytes memory str = new bytes(end-start);
|
||||
for(_pos=0; _pos<str.length; _pos++){
|
||||
str[_pos] = _str[start+_pos];
|
||||
}
|
||||
for(_pos=end+1; _pos<_str.length; _pos++) if (_str[_pos] == ','){ _pos++; break; } //end
|
||||
|
||||
return (string(str),_pos);
|
||||
}
|
||||
|
||||
function getNextUInt(bytes _str, uint8 _pos) internal constant returns (uint,uint8) {
|
||||
uint val = 0;
|
||||
uint strl =_str.length;
|
||||
for (; strl > _pos; _pos++) {
|
||||
byte bp = _str[_pos];
|
||||
if (bp == ','){ //Find ends
|
||||
_pos++; break;
|
||||
}else if ((bp >= 48)&&(bp <= 57)){ //only ASCII numbers
|
||||
val *= 10;
|
||||
val += uint(bp) - 48;
|
||||
}
|
||||
}
|
||||
return (val,_pos);
|
||||
}
|
||||
|
||||
function getNextAddr(bytes _str, uint8 _pos) internal constant returns (address, uint8){
|
||||
uint160 iaddr = 0;
|
||||
uint strl =_str.length;
|
||||
for(;strl > _pos; _pos++){
|
||||
byte bp = _str[_pos];
|
||||
if (bp == '0'){
|
||||
if (_str[_pos+1] == 'x'){
|
||||
for (_pos=_pos+2; _pos<2+2*20; _pos+=2){
|
||||
iaddr *= 256;
|
||||
iaddr += (uint160(hexVal(uint160(_str[_pos])))*16+uint160(hexVal(uint160(_str[_pos+1]))));
|
||||
}
|
||||
_pos++;
|
||||
break;
|
||||
}
|
||||
}else if (bp == ','){
|
||||
_pos++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (address(iaddr),_pos);
|
||||
}
|
||||
|
||||
function hexVal(uint val) internal constant returns (uint){
|
||||
return val - (val < 58 ? 48 : (val < 97 ? 55 : 87));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
/**
|
||||
* GitHubRepositoryReg.sol
|
||||
* Registers the master branch of a Repository for GitHubOracle tracking.
|
||||
* Ricardo Guilherme Schmidt <3esmit@gmail.com>
|
||||
*/
|
||||
|
||||
import "./GitHubAPIReg.sol";
|
||||
import "./NameRegistry.sol";
|
||||
import "./GitRepository.sol";
|
||||
import "strings.sol";
|
||||
|
||||
pragma solidity ^0.4.11;
|
||||
|
||||
contract GitHubRepositoryReg is NameRegistry, GitHubAPIReg {
|
||||
using strings for string;
|
||||
using strings for strings.slice;
|
||||
|
||||
mapping (uint256 => Repository) public repositories;
|
||||
|
||||
event NewRepository(address addr, uint256 projectId, string full_name, string default_branch);
|
||||
|
||||
struct Repository {
|
||||
address addr;
|
||||
string name;
|
||||
string branch;
|
||||
}
|
||||
|
||||
function register(string _repository, string _cred) payable {
|
||||
if(bytes(_cred).length == 0) _cred = cred;
|
||||
uint gas = getAddr(_repository) == 0x00? 4000000 : 1000000;
|
||||
oraclize_query("URL", _query_script(_repository,_cred), gas);
|
||||
}
|
||||
|
||||
function getAddr(uint256 _id) public constant returns(address addr) {
|
||||
return repositories[_id].addr;
|
||||
}
|
||||
|
||||
function getName(address _addr) public constant returns(string name){
|
||||
return repositories[indexes[sha3(_addr)]].name;
|
||||
}
|
||||
|
||||
function getAddr(string _name) public constant returns(address addr) {
|
||||
return repositories[indexes[sha3(_name)]].addr;
|
||||
}
|
||||
|
||||
function getBranch(uint256 _id) public constant returns(string branch) {
|
||||
return repositories[_id].branch;
|
||||
}
|
||||
|
||||
//oraclize response callback
|
||||
function __callback(bytes32 myid, string result, bytes proof) {
|
||||
OracleEvent(myid,result,proof);
|
||||
if (msg.sender != oraclize.cbAddress()){
|
||||
throw;
|
||||
}else {
|
||||
_setRepository(result);
|
||||
}
|
||||
}
|
||||
|
||||
function _setRepository(string result) internal //[85743750, "ethereans/TheEtherian", "master"]
|
||||
{
|
||||
bytes memory v = bytes(result);
|
||||
uint8 pos = 0;
|
||||
uint256 projectId;
|
||||
(projectId,pos) = getNextUInt(v,pos);
|
||||
string memory full_name;
|
||||
(full_name,pos) = getNextString(v,pos);
|
||||
string memory default_branch;
|
||||
(default_branch,pos) = getNextString(v,pos);
|
||||
address repoAddr = repositories[projectId].addr;
|
||||
if(repoAddr == 0x0){
|
||||
GitRepositoryI repo = GitFactory.newGitRepository(projectId, full_name);
|
||||
repo.setOwner(owner);
|
||||
repoAddr = address(repo);
|
||||
indexes[sha3(repoAddr)] = projectId;
|
||||
indexes[sha3(full_name)] = projectId;
|
||||
NewRepository(repoAddr, projectId, full_name, default_branch);
|
||||
repositories[projectId] = Repository({addr: repoAddr, name: full_name, branch: default_branch});
|
||||
}else{
|
||||
bytes32 _new = sha3(full_name);
|
||||
bytes32 _old = sha3(repositories[projectId].name);
|
||||
if(_new != _old){
|
||||
_updateIndex(_old, _new);
|
||||
}
|
||||
}
|
||||
}
|
||||
//internal helper functions
|
||||
function _query_script(string _repository, string _cred) internal returns (string) {
|
||||
strings.slice [] memory cm = new strings.slice[](5);
|
||||
cm[0] = strings.toSlice("json(https://api.github.com/repos/");
|
||||
cm[1] = _repository.toSlice();
|
||||
cm[2] = _cred.toSlice();
|
||||
cm[4] = strings.toSlice(").$.id,full_name,default_branch");
|
||||
return strings.toSlice("").join(cm);
|
||||
}
|
||||
}
|
||||
library GHRepoReg {
|
||||
|
||||
function create() returns (GitHubRepositoryReg){
|
||||
return new GitHubRepositoryReg();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
/**
|
||||
* GitHubUserReg.sol
|
||||
* Registers GitHub user login to an address
|
||||
* Ricardo Guilherme Schmidt <3esmit@gmail.com>
|
||||
*/
|
||||
import "GitHubAPIReg.sol";
|
||||
import "NameRegistry.sol";
|
||||
import "strings.sol";
|
||||
|
||||
pragma solidity ^0.4.11;
|
||||
|
||||
contract GitHubUserReg is NameRegistry, GitHubAPIReg {
|
||||
using strings for string;
|
||||
using strings for strings.slice;
|
||||
|
||||
mapping (bytes32 => UserClaim) userClaim; //temporary db for oraclize user register queries
|
||||
mapping (uint256 => User) users;
|
||||
|
||||
event RegisterUpdated(string name);
|
||||
|
||||
//stores temporary data for oraclize user register request
|
||||
struct UserClaim {
|
||||
address sender;
|
||||
string login;
|
||||
}
|
||||
|
||||
struct User {
|
||||
address addr;
|
||||
string login;
|
||||
}
|
||||
|
||||
function register(string _github_user, string _gistid, string _cred) payable {
|
||||
if(bytes(_cred).length == 0) _cred = cred;
|
||||
bytes32 ocid = oraclize_query("nested", _query_script(_github_user, _gistid,_cred));
|
||||
userClaim[ocid] = UserClaim({sender: msg.sender, login: _github_user});
|
||||
}
|
||||
|
||||
function getAddr(uint256 _id) public constant returns(address addr) {
|
||||
return users[_id].addr;
|
||||
}
|
||||
|
||||
function getName(address _addr) public constant returns(string name){
|
||||
return users[indexes[sha3(_addr)]].login;
|
||||
}
|
||||
|
||||
function getAddr(string _name) public constant returns(address addr) {
|
||||
return users[indexes[sha3(_name)]].addr;
|
||||
}
|
||||
|
||||
//oraclize response callback
|
||||
function __callback(bytes32 myid, string result, bytes proof) {
|
||||
OracleEvent(myid, result, proof);
|
||||
if (msg.sender != oraclize.cbAddress()){
|
||||
throw;
|
||||
}else {
|
||||
_register(myid, result);
|
||||
}
|
||||
}
|
||||
|
||||
function _register(bytes32 myid, string result) internal {
|
||||
bytes memory v = bytes(result);
|
||||
uint8 pos = 0;
|
||||
address addrLoaded;
|
||||
string memory login;
|
||||
uint256 userId;
|
||||
(addrLoaded,pos) = getNextAddr(v,pos);
|
||||
(login,pos) = getNextString(v,pos);
|
||||
(userId,pos) = getNextUInt(v,pos);
|
||||
if(userClaim[myid].sender == addrLoaded && sha3(userClaim[myid].login) == sha3(login)){
|
||||
RegisterUpdated(login);
|
||||
if(users[userId].addr != 0x0){
|
||||
delete indexes[sha3(users[userId].login)];
|
||||
delete indexes[sha3(users[userId].addr)];
|
||||
}
|
||||
indexes[sha3(addrLoaded)] = userId;
|
||||
indexes[sha3(login)] = userId;
|
||||
users[userId].addr = addrLoaded;
|
||||
users[userId].login = login;
|
||||
}
|
||||
delete userClaim[myid]; //should always be deleted
|
||||
}
|
||||
|
||||
function _query_script(string _github_user, string _gistid, string _cred) internal returns (string) {
|
||||
strings.slice [] memory cm = new strings.slice[](8);
|
||||
cm[0] = strings.toSlice("[identity] ${[URL] https://gist.githubusercontent.com/");
|
||||
cm[1] = _github_user.toSlice();
|
||||
cm[2] = strings.toSlice("/");
|
||||
cm[3] = _gistid.toSlice();
|
||||
cm[4] = strings.toSlice("/raw/register.txt}, ${[URL] json(https://api.github.com/gists/");
|
||||
cm[5] = _gistid.toSlice();
|
||||
cm[6] = _cred.toSlice();
|
||||
cm[7] = strings.toSlice(").owner.[login,id]}");
|
||||
return strings.toSlice("").join(cm);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
library GHUserReg{
|
||||
|
||||
function create() returns (GitHubUserReg){
|
||||
return new GitHubUserReg();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,3 @@
|
||||
pragma solidity ^0.4.8;
|
||||
|
||||
/**
|
||||
* Contract that mint tokens by github commit stats
|
||||
*
|
||||
@@ -15,18 +13,20 @@ pragma solidity ^0.4.8;
|
||||
* Released under GPLv3 License
|
||||
*/
|
||||
|
||||
import "lib/ethereans/bank/CollaborationBank.sol";
|
||||
import "lib/ethereans/management/Owned.sol";
|
||||
import "CollaborationBank.sol";
|
||||
import "Owned.sol";
|
||||
import "./BountyBank.sol";
|
||||
import "./GitRepositoryToken.sol";
|
||||
|
||||
pragma solidity ^0.4.11;
|
||||
|
||||
contract GitRepositoryI {
|
||||
contract GitRepositoryI is Owned{
|
||||
function claim(address _user, uint _total) returns (bool) ;
|
||||
function setStats(uint256 _subscribers, uint256 _watchers);
|
||||
function setBounty(uint256 _issueId, bool _state, uint256 _closedAt);
|
||||
function setBountyPoints(uint256 _issueId, address _claimer, uint256 _points);
|
||||
}
|
||||
|
||||
contract GitRepository is GitRepositoryI, Owned {
|
||||
contract GitRepository is GitRepositoryI {
|
||||
|
||||
GitRepositoryToken public token;
|
||||
CollaborationBank public donationBank;
|
||||
@@ -36,9 +36,6 @@ contract GitRepository is GitRepositoryI, Owned {
|
||||
string public name;
|
||||
uint256 public uid;
|
||||
|
||||
uint256 public subscribers;
|
||||
uint256 public watchers;
|
||||
|
||||
function () payable {
|
||||
donationBank.deposit();
|
||||
donators[msg.sender] += msg.value;
|
||||
@@ -53,7 +50,6 @@ contract GitRepository is GitRepositoryI, Owned {
|
||||
bountyBank = new BountyBank();
|
||||
}
|
||||
|
||||
|
||||
//oracle claim request
|
||||
function claim(address _user, uint _total)
|
||||
only_owner returns (bool) {
|
||||
@@ -65,21 +61,15 @@ contract GitRepository is GitRepositoryI, Owned {
|
||||
}
|
||||
}
|
||||
|
||||
function setStats(uint256 _subscribers, uint256 _watchers)
|
||||
only_owner {
|
||||
subscribers = _subscribers;
|
||||
watchers = _watchers;
|
||||
}
|
||||
|
||||
function bountyState(uint issue, bool open) only_owner {
|
||||
if (open) bountyBank.open(issue);
|
||||
else bountyBank.close(issue);
|
||||
}
|
||||
|
||||
function bountyState(uint issue, address claimer, uint points) only_owner {
|
||||
bountyBank.setClaimer(issue,claimer,points);
|
||||
function setBounty(uint256 _issueId, bool _state, uint256 _closedAt) only_owner {
|
||||
if (_state) bountyBank.open(_issueId);
|
||||
else bountyBank.close(_issueId,_closedAt);
|
||||
}
|
||||
|
||||
function setBountyPoints(uint256 _issueId, address _claimer, uint256 _points) only_owner {
|
||||
bountyBank.setClaimer(_issueId,_claimer,_points);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
library GitFactory {
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
pragma solidity ^0.4.8;
|
||||
|
||||
/**
|
||||
* Contract that mint tokens by github commit stats
|
||||
*
|
||||
@@ -15,8 +13,10 @@ pragma solidity ^0.4.8;
|
||||
* Released under GPLv3 License
|
||||
*/
|
||||
|
||||
import "lib/ethereans/token/LockerToken.sol";
|
||||
import "lib/ethereans/management/Owned.sol";
|
||||
import "LockerToken.sol";
|
||||
import "Owned.sol";
|
||||
|
||||
pragma solidity ^0.4.11;
|
||||
|
||||
contract GitRepositoryToken is LockerToken {
|
||||
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* NameRegistry.sol
|
||||
* Interface for Name Registries.
|
||||
* Ricardo Guilherme Schmidt <3esmit@gmail.com>
|
||||
*/
|
||||
pragma solidity ^0.4.11;
|
||||
|
||||
contract NameRegistry {
|
||||
function getAddr(uint256 _id) public constant returns(address addr);
|
||||
function getAddr(string _name) public constant returns(address addr);
|
||||
function getName(address _addr) public constant returns(string name);
|
||||
|
||||
mapping (bytes32 => uint256) indexes;
|
||||
|
||||
function getId(address _addr) public constant returns(uint256 id){
|
||||
return indexes[sha3(_addr)];
|
||||
}
|
||||
|
||||
function getId(string _name) public constant returns(uint256 id) {
|
||||
return indexes[sha3(_name)];
|
||||
}
|
||||
|
||||
function _updateIndex(bytes32 _old, bytes32 _new) internal {
|
||||
indexes[_new] = indexes[_old];
|
||||
delete indexes[_old];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,521 @@
|
||||
// <ORACLIZE_API>
|
||||
/*
|
||||
Copyright (c) 2015-2016 Oraclize SRL
|
||||
Copyright (c) 2016 Oraclize LTD
|
||||
|
||||
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
pragma solidity ^0.4.0;//please import oraclizeAPI_pre0.4.sol when solidity < 0.4.0
|
||||
|
||||
contract OraclizeI {
|
||||
address public cbAddress;
|
||||
function query(uint _timestamp, string _datasource, string _arg) payable returns (bytes32 _id);
|
||||
function query_withGasLimit(uint _timestamp, string _datasource, string _arg, uint _gaslimit) payable returns (bytes32 _id);
|
||||
function query2(uint _timestamp, string _datasource, string _arg1, string _arg2) payable returns (bytes32 _id);
|
||||
function query2_withGasLimit(uint _timestamp, string _datasource, string _arg1, string _arg2, uint _gaslimit) payable returns (bytes32 _id);
|
||||
function queryN(uint _timestamp, string _datasource, bytes _argN) payable returns (bytes32 _id);
|
||||
function queryN_withGasLimit(uint _timestamp, string _datasource, bytes _argN, uint _gaslimit) payable returns (bytes32 _id);
|
||||
function getPrice(string _datasource) returns (uint _dsprice);
|
||||
function getPrice(string _datasource, uint gaslimit) returns (uint _dsprice);
|
||||
function useCoupon(string _coupon);
|
||||
function setProofType(byte _proofType);
|
||||
function setConfig(bytes32 _config);
|
||||
function setCustomGasPrice(uint _gasPrice);
|
||||
}
|
||||
contract OraclizeAddrResolverI {
|
||||
function getAddress() returns (address _addr);
|
||||
}
|
||||
contract usingOraclize {
|
||||
uint constant day = 60*60*24;
|
||||
uint constant week = 60*60*24*7;
|
||||
uint constant month = 60*60*24*30;
|
||||
byte constant proofType_NONE = 0x00;
|
||||
byte constant proofType_TLSNotary = 0x10;
|
||||
byte constant proofStorage_IPFS = 0x01;
|
||||
uint8 constant networkID_auto = 0;
|
||||
uint8 constant networkID_mainnet = 1;
|
||||
uint8 constant networkID_testnet = 2;
|
||||
uint8 constant networkID_morden = 2;
|
||||
uint8 constant networkID_consensys = 161;
|
||||
|
||||
OraclizeAddrResolverI OAR;
|
||||
|
||||
OraclizeI oraclize;
|
||||
modifier oraclizeAPI {
|
||||
if((address(OAR)==0)||(getCodeSize(address(OAR))==0)) oraclize_setNetwork(networkID_auto);
|
||||
oraclize = OraclizeI(OAR.getAddress());
|
||||
_;
|
||||
}
|
||||
modifier coupon(string code){
|
||||
oraclize = OraclizeI(OAR.getAddress());
|
||||
oraclize.useCoupon(code);
|
||||
_;
|
||||
}
|
||||
|
||||
function oraclize_setNetwork(uint8 networkID) internal returns(bool){
|
||||
if (getCodeSize(0x1d3B2638a7cC9f2CB3D298A3DA7a90B67E5506ed)>0){ //mainnet
|
||||
OAR = OraclizeAddrResolverI(0x1d3B2638a7cC9f2CB3D298A3DA7a90B67E5506ed);
|
||||
return true;
|
||||
}
|
||||
if (getCodeSize(0xc03A2615D5efaf5F49F60B7BB6583eaec212fdf1)>0){ //ropsten testnet
|
||||
OAR = OraclizeAddrResolverI(0xc03A2615D5efaf5F49F60B7BB6583eaec212fdf1);
|
||||
return true;
|
||||
}
|
||||
if (getCodeSize(0xB7A07BcF2Ba2f2703b24C0691b5278999C59AC7e)>0){ //kovan testnet
|
||||
OAR = OraclizeAddrResolverI(0xB7A07BcF2Ba2f2703b24C0691b5278999C59AC7e);
|
||||
return true;
|
||||
}
|
||||
if (getCodeSize(0x6f485C8BF6fc43eA212E93BBF8ce046C7f1cb475)>0){ //ethereum-bridge
|
||||
OAR = OraclizeAddrResolverI(0x6f485C8BF6fc43eA212E93BBF8ce046C7f1cb475);
|
||||
return true;
|
||||
}
|
||||
if (getCodeSize(0x20e12A1F859B3FeaE5Fb2A0A32C18F5a65555bBF)>0){ //ether.camp ide
|
||||
OAR = OraclizeAddrResolverI(0x20e12A1F859B3FeaE5Fb2A0A32C18F5a65555bBF);
|
||||
return true;
|
||||
}
|
||||
if (getCodeSize(0x51efaF4c8B3C9AfBD5aB9F4bbC82784Ab6ef8fAA)>0){ //browser-solidity
|
||||
OAR = OraclizeAddrResolverI(0x51efaF4c8B3C9AfBD5aB9F4bbC82784Ab6ef8fAA);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function __callback(bytes32 myid, string result) {
|
||||
__callback(myid, result, new bytes(0));
|
||||
}
|
||||
function __callback(bytes32 myid, string result, bytes proof) {
|
||||
}
|
||||
|
||||
function oraclize_getPrice(string datasource) oraclizeAPI internal returns (uint){
|
||||
return oraclize.getPrice(datasource);
|
||||
}
|
||||
|
||||
function oraclize_getPrice(string datasource, uint gaslimit) oraclizeAPI internal returns (uint){
|
||||
return oraclize.getPrice(datasource, gaslimit);
|
||||
}
|
||||
|
||||
function oraclize_query(string datasource, string arg) oraclizeAPI internal returns (bytes32 id){
|
||||
uint price = oraclize.getPrice(datasource);
|
||||
if (price > 1 ether + tx.gasprice*200000) return 0; // unexpectedly high price
|
||||
return oraclize.query.value(price)(0, datasource, arg);
|
||||
}
|
||||
function oraclize_query(uint timestamp, string datasource, string arg) oraclizeAPI internal returns (bytes32 id){
|
||||
uint price = oraclize.getPrice(datasource);
|
||||
if (price > 1 ether + tx.gasprice*200000) return 0; // unexpectedly high price
|
||||
return oraclize.query.value(price)(timestamp, datasource, arg);
|
||||
}
|
||||
function oraclize_query(uint timestamp, string datasource, string arg, uint gaslimit) oraclizeAPI internal returns (bytes32 id){
|
||||
uint price = oraclize.getPrice(datasource, gaslimit);
|
||||
if (price > 1 ether + tx.gasprice*gaslimit) return 0; // unexpectedly high price
|
||||
return oraclize.query_withGasLimit.value(price)(timestamp, datasource, arg, gaslimit);
|
||||
}
|
||||
function oraclize_query(string datasource, string arg, uint gaslimit) oraclizeAPI internal returns (bytes32 id){
|
||||
uint price = oraclize.getPrice(datasource, gaslimit);
|
||||
if (price > 1 ether + tx.gasprice*gaslimit) return 0; // unexpectedly high price
|
||||
return oraclize.query_withGasLimit.value(price)(0, datasource, arg, gaslimit);
|
||||
}
|
||||
function oraclize_query(string datasource, string arg1, string arg2) oraclizeAPI internal returns (bytes32 id){
|
||||
uint price = oraclize.getPrice(datasource);
|
||||
if (price > 1 ether + tx.gasprice*200000) return 0; // unexpectedly high price
|
||||
return oraclize.query2.value(price)(0, datasource, arg1, arg2);
|
||||
}
|
||||
function oraclize_query(uint timestamp, string datasource, string arg1, string arg2) oraclizeAPI internal returns (bytes32 id){
|
||||
uint price = oraclize.getPrice(datasource);
|
||||
if (price > 1 ether + tx.gasprice*200000) return 0; // unexpectedly high price
|
||||
return oraclize.query2.value(price)(timestamp, datasource, arg1, arg2);
|
||||
}
|
||||
function oraclize_query(uint timestamp, string datasource, string arg1, string arg2, uint gaslimit) oraclizeAPI internal returns (bytes32 id){
|
||||
uint price = oraclize.getPrice(datasource, gaslimit);
|
||||
if (price > 1 ether + tx.gasprice*gaslimit) return 0; // unexpectedly high price
|
||||
return oraclize.query2_withGasLimit.value(price)(timestamp, datasource, arg1, arg2, gaslimit);
|
||||
}
|
||||
function oraclize_query(string datasource, string arg1, string arg2, uint gaslimit) oraclizeAPI internal returns (bytes32 id){
|
||||
uint price = oraclize.getPrice(datasource, gaslimit);
|
||||
if (price > 1 ether + tx.gasprice*gaslimit) return 0; // unexpectedly high price
|
||||
return oraclize.query2_withGasLimit.value(price)(0, datasource, arg1, arg2, gaslimit);
|
||||
}
|
||||
function oraclize_query(string datasource, string[] argN) oraclizeAPI internal returns (bytes32 id){
|
||||
uint price = oraclize.getPrice(datasource);
|
||||
if (price > 1 ether + tx.gasprice*200000) return 0; // unexpectedly high price
|
||||
bytes memory args = stra2cbor(argN);
|
||||
return oraclize.queryN.value(price)(0, datasource, args);
|
||||
}
|
||||
function oraclize_query(uint timestamp, string datasource, string[] argN) oraclizeAPI internal returns (bytes32 id){
|
||||
uint price = oraclize.getPrice(datasource);
|
||||
if (price > 1 ether + tx.gasprice*200000) return 0; // unexpectedly high price
|
||||
bytes memory args = stra2cbor(argN);
|
||||
return oraclize.queryN.value(price)(timestamp, datasource, args);
|
||||
}
|
||||
function oraclize_query(uint timestamp, string datasource, string[] argN, uint gaslimit) oraclizeAPI internal returns (bytes32 id){
|
||||
uint price = oraclize.getPrice(datasource, gaslimit);
|
||||
if (price > 1 ether + tx.gasprice*gaslimit) return 0; // unexpectedly high price
|
||||
bytes memory args = stra2cbor(argN);
|
||||
return oraclize.queryN_withGasLimit.value(price)(timestamp, datasource, args, gaslimit);
|
||||
}
|
||||
function oraclize_query(string datasource, string[] argN, uint gaslimit) oraclizeAPI internal returns (bytes32 id){
|
||||
uint price = oraclize.getPrice(datasource, gaslimit);
|
||||
if (price > 1 ether + tx.gasprice*gaslimit) return 0; // unexpectedly high price
|
||||
bytes memory args = stra2cbor(argN);
|
||||
return oraclize.queryN_withGasLimit.value(price)(0, datasource, args, gaslimit);
|
||||
}
|
||||
function oraclize_query(string datasource, string[1] args) oraclizeAPI internal returns (bytes32 id) {
|
||||
string[] memory dynargs = new string[](1);
|
||||
dynargs[0] = args[0];
|
||||
return oraclize_query(datasource, dynargs);
|
||||
}
|
||||
function oraclize_query(uint timestamp, string datasource, string[1] args) oraclizeAPI internal returns (bytes32 id) {
|
||||
string[] memory dynargs = new string[](1);
|
||||
dynargs[0] = args[0];
|
||||
return oraclize_query(timestamp, datasource, dynargs);
|
||||
}
|
||||
function oraclize_query(uint timestamp, string datasource, string[1] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
|
||||
string[] memory dynargs = new string[](1);
|
||||
dynargs[0] = args[0];
|
||||
return oraclize_query(timestamp, datasource, dynargs, gaslimit);
|
||||
}
|
||||
function oraclize_query(string datasource, string[1] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
|
||||
string[] memory dynargs = new string[](1);
|
||||
dynargs[0] = args[0];
|
||||
return oraclize_query(datasource, dynargs, gaslimit);
|
||||
}
|
||||
|
||||
function oraclize_query(string datasource, string[2] args) oraclizeAPI internal returns (bytes32 id) {
|
||||
string[] memory dynargs = new string[](2);
|
||||
dynargs[0] = args[0];
|
||||
dynargs[1] = args[1];
|
||||
return oraclize_query(datasource, dynargs);
|
||||
}
|
||||
function oraclize_query(uint timestamp, string datasource, string[2] args) oraclizeAPI internal returns (bytes32 id) {
|
||||
string[] memory dynargs = new string[](2);
|
||||
dynargs[0] = args[0];
|
||||
dynargs[1] = args[1];
|
||||
return oraclize_query(timestamp, datasource, dynargs);
|
||||
}
|
||||
function oraclize_query(uint timestamp, string datasource, string[2] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
|
||||
string[] memory dynargs = new string[](2);
|
||||
dynargs[0] = args[0];
|
||||
dynargs[1] = args[1];
|
||||
return oraclize_query(timestamp, datasource, dynargs, gaslimit);
|
||||
}
|
||||
function oraclize_query(string datasource, string[2] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
|
||||
string[] memory dynargs = new string[](2);
|
||||
dynargs[0] = args[0];
|
||||
dynargs[1] = args[1];
|
||||
return oraclize_query(datasource, dynargs, gaslimit);
|
||||
}
|
||||
function oraclize_query(string datasource, string[3] args) oraclizeAPI internal returns (bytes32 id) {
|
||||
string[] memory dynargs = new string[](3);
|
||||
dynargs[0] = args[0];
|
||||
dynargs[1] = args[1];
|
||||
dynargs[2] = args[2];
|
||||
return oraclize_query(datasource, dynargs);
|
||||
}
|
||||
function oraclize_query(uint timestamp, string datasource, string[3] args) oraclizeAPI internal returns (bytes32 id) {
|
||||
string[] memory dynargs = new string[](3);
|
||||
dynargs[0] = args[0];
|
||||
dynargs[1] = args[1];
|
||||
dynargs[2] = args[2];
|
||||
return oraclize_query(timestamp, datasource, dynargs);
|
||||
}
|
||||
function oraclize_query(uint timestamp, string datasource, string[3] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
|
||||
string[] memory dynargs = new string[](3);
|
||||
dynargs[0] = args[0];
|
||||
dynargs[1] = args[1];
|
||||
dynargs[2] = args[2];
|
||||
return oraclize_query(timestamp, datasource, dynargs, gaslimit);
|
||||
}
|
||||
function oraclize_query(string datasource, string[3] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
|
||||
string[] memory dynargs = new string[](3);
|
||||
dynargs[0] = args[0];
|
||||
dynargs[1] = args[1];
|
||||
dynargs[2] = args[2];
|
||||
return oraclize_query(datasource, dynargs, gaslimit);
|
||||
}
|
||||
|
||||
function oraclize_query(string datasource, string[4] args) oraclizeAPI internal returns (bytes32 id) {
|
||||
string[] memory dynargs = new string[](4);
|
||||
dynargs[0] = args[0];
|
||||
dynargs[1] = args[1];
|
||||
dynargs[2] = args[2];
|
||||
dynargs[3] = args[3];
|
||||
return oraclize_query(datasource, dynargs);
|
||||
}
|
||||
function oraclize_query(uint timestamp, string datasource, string[4] args) oraclizeAPI internal returns (bytes32 id) {
|
||||
string[] memory dynargs = new string[](4);
|
||||
dynargs[0] = args[0];
|
||||
dynargs[1] = args[1];
|
||||
dynargs[2] = args[2];
|
||||
dynargs[3] = args[3];
|
||||
return oraclize_query(timestamp, datasource, dynargs);
|
||||
}
|
||||
function oraclize_query(uint timestamp, string datasource, string[4] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
|
||||
string[] memory dynargs = new string[](4);
|
||||
dynargs[0] = args[0];
|
||||
dynargs[1] = args[1];
|
||||
dynargs[2] = args[2];
|
||||
dynargs[3] = args[3];
|
||||
return oraclize_query(timestamp, datasource, dynargs, gaslimit);
|
||||
}
|
||||
function oraclize_query(string datasource, string[4] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
|
||||
string[] memory dynargs = new string[](4);
|
||||
dynargs[0] = args[0];
|
||||
dynargs[1] = args[1];
|
||||
dynargs[2] = args[2];
|
||||
dynargs[3] = args[3];
|
||||
return oraclize_query(datasource, dynargs, gaslimit);
|
||||
}
|
||||
function oraclize_query(string datasource, string[5] args) oraclizeAPI internal returns (bytes32 id) {
|
||||
string[] memory dynargs = new string[](5);
|
||||
dynargs[0] = args[0];
|
||||
dynargs[1] = args[1];
|
||||
dynargs[2] = args[2];
|
||||
dynargs[3] = args[3];
|
||||
dynargs[4] = args[4];
|
||||
return oraclize_query(datasource, dynargs);
|
||||
}
|
||||
function oraclize_query(uint timestamp, string datasource, string[5] args) oraclizeAPI internal returns (bytes32 id) {
|
||||
string[] memory dynargs = new string[](5);
|
||||
dynargs[0] = args[0];
|
||||
dynargs[1] = args[1];
|
||||
dynargs[2] = args[2];
|
||||
dynargs[3] = args[3];
|
||||
dynargs[4] = args[4];
|
||||
return oraclize_query(timestamp, datasource, dynargs);
|
||||
}
|
||||
function oraclize_query(uint timestamp, string datasource, string[5] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
|
||||
string[] memory dynargs = new string[](5);
|
||||
dynargs[0] = args[0];
|
||||
dynargs[1] = args[1];
|
||||
dynargs[2] = args[2];
|
||||
dynargs[3] = args[3];
|
||||
dynargs[4] = args[4];
|
||||
return oraclize_query(timestamp, datasource, dynargs, gaslimit);
|
||||
}
|
||||
function oraclize_query(string datasource, string[5] args, uint gaslimit) oraclizeAPI internal returns (bytes32 id) {
|
||||
string[] memory dynargs = new string[](5);
|
||||
dynargs[0] = args[0];
|
||||
dynargs[1] = args[1];
|
||||
dynargs[2] = args[2];
|
||||
dynargs[3] = args[3];
|
||||
dynargs[4] = args[4];
|
||||
return oraclize_query(datasource, dynargs, gaslimit);
|
||||
}
|
||||
|
||||
function oraclize_cbAddress() oraclizeAPI internal returns (address){
|
||||
return oraclize.cbAddress();
|
||||
}
|
||||
function oraclize_setProof(byte proofP) oraclizeAPI internal {
|
||||
return oraclize.setProofType(proofP);
|
||||
}
|
||||
function oraclize_setCustomGasPrice(uint gasPrice) oraclizeAPI internal {
|
||||
return oraclize.setCustomGasPrice(gasPrice);
|
||||
}
|
||||
function oraclize_setConfig(bytes32 config) oraclizeAPI internal {
|
||||
return oraclize.setConfig(config);
|
||||
}
|
||||
|
||||
function getCodeSize(address _addr) constant internal returns(uint _size) {
|
||||
assembly {
|
||||
_size := extcodesize(_addr)
|
||||
}
|
||||
}
|
||||
|
||||
function parseAddr(string _a) internal returns (address){
|
||||
bytes memory tmp = bytes(_a);
|
||||
uint160 iaddr = 0;
|
||||
uint160 b1;
|
||||
uint160 b2;
|
||||
for (uint i=2; i<2+2*20; i+=2){
|
||||
iaddr *= 256;
|
||||
b1 = uint160(tmp[i]);
|
||||
b2 = uint160(tmp[i+1]);
|
||||
if ((b1 >= 97)&&(b1 <= 102)) b1 -= 87;
|
||||
else if ((b1 >= 48)&&(b1 <= 57)) b1 -= 48;
|
||||
if ((b2 >= 97)&&(b2 <= 102)) b2 -= 87;
|
||||
else if ((b2 >= 48)&&(b2 <= 57)) b2 -= 48;
|
||||
iaddr += (b1*16+b2);
|
||||
}
|
||||
return address(iaddr);
|
||||
}
|
||||
|
||||
function strCompare(string _a, string _b) internal returns (int) {
|
||||
bytes memory a = bytes(_a);
|
||||
bytes memory b = bytes(_b);
|
||||
uint minLength = a.length;
|
||||
if (b.length < minLength) minLength = b.length;
|
||||
for (uint i = 0; i < minLength; i ++)
|
||||
if (a[i] < b[i])
|
||||
return -1;
|
||||
else if (a[i] > b[i])
|
||||
return 1;
|
||||
if (a.length < b.length)
|
||||
return -1;
|
||||
else if (a.length > b.length)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
function indexOf(string _haystack, string _needle) internal returns (int) {
|
||||
bytes memory h = bytes(_haystack);
|
||||
bytes memory n = bytes(_needle);
|
||||
if(h.length < 1 || n.length < 1 || (n.length > h.length))
|
||||
return -1;
|
||||
else if(h.length > (2**128 -1))
|
||||
return -1;
|
||||
else
|
||||
{
|
||||
uint subindex = 0;
|
||||
for (uint i = 0; i < h.length; i ++)
|
||||
{
|
||||
if (h[i] == n[0])
|
||||
{
|
||||
subindex = 1;
|
||||
while(subindex < n.length && (i + subindex) < h.length && h[i + subindex] == n[subindex])
|
||||
{
|
||||
subindex++;
|
||||
}
|
||||
if(subindex == n.length)
|
||||
return int(i);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
function strConcat(string _a, string _b, string _c, string _d, string _e) internal returns (string) {
|
||||
bytes memory _ba = bytes(_a);
|
||||
bytes memory _bb = bytes(_b);
|
||||
bytes memory _bc = bytes(_c);
|
||||
bytes memory _bd = bytes(_d);
|
||||
bytes memory _be = bytes(_e);
|
||||
string memory abcde = new string(_ba.length + _bb.length + _bc.length + _bd.length + _be.length);
|
||||
bytes memory babcde = bytes(abcde);
|
||||
uint k = 0;
|
||||
for (uint i = 0; i < _ba.length; i++) babcde[k++] = _ba[i];
|
||||
for (i = 0; i < _bb.length; i++) babcde[k++] = _bb[i];
|
||||
for (i = 0; i < _bc.length; i++) babcde[k++] = _bc[i];
|
||||
for (i = 0; i < _bd.length; i++) babcde[k++] = _bd[i];
|
||||
for (i = 0; i < _be.length; i++) babcde[k++] = _be[i];
|
||||
return string(babcde);
|
||||
}
|
||||
|
||||
function strConcat(string _a, string _b, string _c, string _d) internal returns (string) {
|
||||
return strConcat(_a, _b, _c, _d, "");
|
||||
}
|
||||
|
||||
function strConcat(string _a, string _b, string _c) internal returns (string) {
|
||||
return strConcat(_a, _b, _c, "", "");
|
||||
}
|
||||
|
||||
function strConcat(string _a, string _b) internal returns (string) {
|
||||
return strConcat(_a, _b, "", "", "");
|
||||
}
|
||||
|
||||
// parseInt
|
||||
function parseInt(string _a) internal returns (uint) {
|
||||
return parseInt(_a, 0);
|
||||
}
|
||||
|
||||
// parseInt(parseFloat*10^_b)
|
||||
function parseInt(string _a, uint _b) internal returns (uint) {
|
||||
bytes memory bresult = bytes(_a);
|
||||
uint mint = 0;
|
||||
bool decimals = false;
|
||||
for (uint i=0; i<bresult.length; i++){
|
||||
if ((bresult[i] >= 48)&&(bresult[i] <= 57)){
|
||||
if (decimals){
|
||||
if (_b == 0) break;
|
||||
else _b--;
|
||||
}
|
||||
mint *= 10;
|
||||
mint += uint(bresult[i]) - 48;
|
||||
} else if (bresult[i] == 46) decimals = true;
|
||||
}
|
||||
if (_b > 0) mint *= 10**_b;
|
||||
return mint;
|
||||
}
|
||||
|
||||
function uint2str(uint i) internal returns (string){
|
||||
if (i == 0) return "0";
|
||||
uint j = i;
|
||||
uint len;
|
||||
while (j != 0){
|
||||
len++;
|
||||
j /= 10;
|
||||
}
|
||||
bytes memory bstr = new bytes(len);
|
||||
uint k = len - 1;
|
||||
while (i != 0){
|
||||
bstr[k--] = byte(48 + i % 10);
|
||||
i /= 10;
|
||||
}
|
||||
return string(bstr);
|
||||
}
|
||||
|
||||
function stra2cbor(string[] arr) internal returns (bytes) {
|
||||
uint arrlen = arr.length;
|
||||
|
||||
// get correct cbor output length
|
||||
uint outputlen = 0;
|
||||
bytes[] memory elemArray = new bytes[](arrlen);
|
||||
for (uint i = 0; i < arrlen; i++) {
|
||||
elemArray[i] = (bytes(arr[i]));
|
||||
outputlen += elemArray[i].length + (elemArray[i].length - 1)/23 + 3; //+3 accounts for paired identifier types
|
||||
}
|
||||
uint ctr = 0;
|
||||
uint cborlen = arrlen + 0x80;
|
||||
outputlen += byte(cborlen).length;
|
||||
bytes memory res = new bytes(outputlen);
|
||||
|
||||
while (byte(cborlen).length > ctr) {
|
||||
res[ctr] = byte(cborlen)[ctr];
|
||||
ctr++;
|
||||
}
|
||||
for (i = 0; i < arrlen; i++) {
|
||||
res[ctr] = 0x5F;
|
||||
ctr++;
|
||||
for (uint x = 0; x < elemArray[i].length; x++) {
|
||||
// if there's a bug with larger strings, this may be the culprit
|
||||
if (x % 23 == 0) {
|
||||
uint elemcborlen = elemArray[i].length - x >= 24 ? 23 : elemArray[i].length - x;
|
||||
elemcborlen += 0x40;
|
||||
uint lctr = ctr;
|
||||
while (byte(elemcborlen).length > ctr - lctr) {
|
||||
res[ctr] = byte(elemcborlen)[ctr - lctr];
|
||||
ctr++;
|
||||
}
|
||||
}
|
||||
res[ctr] = elemArray[i][x];
|
||||
ctr++;
|
||||
}
|
||||
res[ctr] = 0xFF;
|
||||
ctr++;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
// </ORACLIZE_API>
|
||||
Reference in New Issue
Block a user